Код:
list p=10F200 ; list directive to define processor
#include <p10F200.inc> ; processor specific variable definitions
__CONFIG _MCLRE_OFF & _CP_OFF & _WDT_ON
; '__CONFIG' directive is used to embed configuration word within .asm file.
; The lables following the directive are located in the respective .inc file.
; See respective data sheet for additional information on configuration word.
;***** VARIABLE DEFINITIONS
TMR_Bit EQU 10 ; Для выдерживания битового интервала
WREG EQU 11 ; Временный буфер для передаваемого байта
CRC_L EQU 12 ; Для хранения CRC (контрольной суммы)
CRC_H EQU 13
; Оставшиеся 12 ячеек - приемный буфер
;**********************************************************************
ORG 0xFF ; processor reset vector
; Internal RC calibration value is placed at location 0xFF by Microchip
; as a movlw k, where the k is a literal value.
ORG 0x000 ; coding begins here
movwf OSCCAL ; update register with factory cal value
bcf GPIO, 0 ; Настройка выходов
movlw 0xE
tris GPIO
movlw 0xF7 ; WDT timeout примерно 16ms
option
;----------------------------------------------------------------------
Start:
movlw 0x14 ; Указатель на 12 байтный буфер
movwf FSR
call ReadByteWDT ; Прием 1-го байта
incf FSR, F
call ReadByte ; Прием 2-го байта
incf FSR, F
call ReadByte ; Прием 3-го байта
incf FSR, F
call ReadByte ; Прием 4-го байта
movlw 0xF3 ; Инициализация CRC = 0xF309
movwf CRC_H ; Можна расчитать на https://crccalc.com/
movlw 0x09 ; для последовательности 01 00 00 00 02 04
movwf CRC_L
movlw 0x14 ; Расчет CRC
movwf FSR ; Добавляем к CRC 1-й байт
call CalcCRC
incf FSR, F ; Добавляем к CRC 2-й байт
call CalcCRC
incf FSR, F ; Добавляем к CRC 3-й байт
call CalcCRC
incf FSR, F ; Добавляем к CRC 4-й байт
call CalcCRC
movlw WREG ; Передача Modbus-заголовка
movwf FSR
movlw 0x01 ; 0x01 - Адрес ПР-ки
movwf INDF
call WriteByte
movlw 0x10 ; 0x00 - Modbus-команда на запись группы регистров
movwf INDF
call WriteByte
movlw 0x00 ; 0x00 - Старший байт адреса начального регистра
movwf INDF
call WriteByte
movlw 0x00 ; 0x00 - Младший байт адреса начального регистра
movwf INDF
call WriteByte
movlw 0x00 ; 0x00 - Старший байт количества регистров
movwf INDF
call WriteByte
movlw 0x02 ; 0x02 - Младший байт количества регистров
movwf INDF
call WriteByte
movlw 0x04 ; 0x04 - Длина данных в байтах
movwf INDF
call WriteByte
movlw 0x14 ; Теперь сами данные
movwf FSR ; 1-й байт
call WriteByte
incf FSR, F ; 2-й байт
call WriteByte
incf FSR, F ; 3-й байт
call WriteByte
incf FSR, F ; 4-й байт
call WriteByte
movlw CRC_L ; Младший байт CRC
movwf FSR
call WriteByte
incf FSR, F ; Старший байт CRC
call WriteByte
goto Start ; Все с начала
;----------------------------------------------------------------------
CalcCRC:
movf INDF, W
xorwf CRC_L, F
call CalcCRCBit
call CalcCRCBit
call CalcCRCBit
call CalcCRCBit
call CalcCRCBit
call CalcCRCBit
call CalcCRCBit
goto CalcCRCBit
CalcCRCBit:
bcf STATUS, C
rrf CRC_H, F
rrf CRC_L, F
btfss STATUS, C
retlw 0
movlw 0xA0
xorwf CRC_H, F
movlw 0x01
xorwf CRC_L, F
retlw 0
;----------------------------------------------------------------------
ReadByteWDT:
clrwdt ; со сбросом WDT
btfsc GPIO, 3 ; Ждем спад (начало Start-бита)
goto $-2
ReadByte:
btfsc GPIO, 3 ; Ждем спад (начало Start-бита)
goto $-1
nop
nop
nop
call ReadBit ; Выборка Start-бита
nop ; +1us
call ReadBit ; +2us Выборка бита D0
rrf INDF, F
call ReadBit ; Выборка бита D1
rrf INDF, F
call ReadBit ; Выборка бита D2
rrf INDF, F
call ReadBit ; Выборка бита D3
rrf INDF, F
call ReadBit ; Выборка бита D4
rrf INDF, F
call ReadBit ; Выборка бита D5
rrf INDF, F
call ReadBit ; Выборка бита D6
rrf INDF, F
call ReadBit ; Выборка бита D7
rrf INDF, F
retlw 0
;----------------------------------------------------------------------
ReadBit:
btfsc GPIO, 3 ; +1us Фиксируем бит с входа GP3
bsf STATUS, C ; +1(2)us
btfss GPIO, 3 ; +1us
bcf STATUS, C ; +1(2)us
movlw D'31' ; +1us Выдерживаем битовый интервал
movwf TMR_Bit ; +1us
decfsz TMR_Bit, F ; +1(2)us | цикл +3us * 31 = 93us
goto $-1 ; +2us |
retlw 0 ; +2us = 7us + 93us + 2us + 3us = 105us (что соответствует 9600 Baud)
;----------------------------------------------------------------------
WriteByte:
bcf STATUS, C ; Формируем Start-бит
call WriteBit
rrf INDF, F ; Формируем бит D0
call WriteBit
rrf INDF, F ; Формируем бит D1
call WriteBit
rrf INDF, F ; Формируем бит D2
call WriteBit
rrf INDF, F ; Формируем бит D3
call WriteBit
rrf INDF, F ; Формируем бит D4
call WriteBit
rrf INDF, F ; Формируем бит D5
call WriteBit
rrf INDF, F ; Формируем бит D6
call WriteBit
rrf INDF, F ; Формируем бит D7
call WriteBit
bsf STATUS, C ; Формируем Stop-бит
goto WriteBit
;----------------------------------------------------------------------
WriteBit:
btfsc STATUS, C ; +1us Выставляем значение бита на вывод GP0
bcf GPIO, 0 ; +1(2)us
btfss STATUS, C ; +1us
bsf GPIO, 0 ; +1(2)us
movlw D'31' ; +1us Выдерживаем битовый интервал
movwf TMR_Bit ; +1us
decfsz TMR_Bit, F ; +1(2)us | цикл +3us * 31 = 93us
goto $-1 ; +2us |
retlw 0 ; +2us = 7us + 93us + 2us + 3us = 105us (что соответствует 9600 Baud)
;----------------------------------------------------------------------
END ; directive 'end of program'
Работа программы в Proteus.