Код: Выделить всё
LIST P=PIC16F1825
INCLUDE <P16F1825.INC>
errorlevel -305
errorlevel -302
;ПОДПРОГРАММЫ:
;EEPROM_WR - ЗАПИСЬ В EEPROM ПО АДРЕСУ В W И ДАННЫМИ В TEMP
;EEPROM_RD - ЧТЕНИЕ ИЗ EEPROM ПО АДРЕСУ В W
;DIR_TX - ПЕРЕВОД ПРИЕМОПЕРЕДАТЧИКА В РЕЖИМ "ПЕРЕДАЧА"
;DIR_RX - ПЕРЕВОД ПРИЕМОПЕРЕДАТЧИКА В РЕЖИМ "ПРИЕМ"
;CRC8_TX - ВЫЧИСЛЕНИЕ CRC8 ПЕРЕДАВАЕМОГО СООБЩЕНИЯ. ДОБАВЛЕНИЕ CRC8 В КОНЕЦ СООБЩЕНИЯ
;CRC8_RX - ВЫЧИСЛЕНИЕ CRC8 ПРИНЯТОГО СООБЩЕНИЯ. ЕСЛИ ОШИБКА, ТО УСТАНАВЛИВЕТСЯ FLAGS,0, ИНАЧЕ НИЧЕГО НЕ ПРОИСХОДИТ.
;ОПИСАНИЕ:
;TRM6 НАСТРОЕН НА ПЕРИОД В 0.77 МС, ДЛЯ ДЕТЕКТИРОВАНИЯ КОНЦА СООБЩЕНИЯ И ОЖИДАНИЯ ПРИЕМА СЛЕДУЮЩЕГО
;TMR3 НАСТРОЕН НА ПЕРИОД В 2 МС, ДЛЯ ПАУЗЫ ОТВЕТА
ADRES1 EQU 0X70 ;АДРЕС ПРИБОРА 1. ЧТЕНИЕ ИЗ EEPROM
I2C_TEMP1 EQU 0X71 ;TEMP РЕГИСТР I2C
KEY EQU 0X72 ;КЛЮЧ ПРИ ПЕРЕХОДЕ НА ШИФРАЦИЮ ПРИБОРА 1
RAND EQU 0X73 ;ЧИСЛО ШИФРАЦИИ ПРИБОРА 1
INC_N EQU 0X74 ;ИНКРЕМЕНТИРУЮЩЕЕСЯ ЧИСЛО КОМАНДЫ C_02
ERR_BUF EQU 0X75 ;БУФЕР ОШИБОК I2C
ADRES_TEMP EQU 0X76
N_BYTE EQU 0X77
FLAG485 EQU 0X78 ;0-(0-НЕТ ПРИЕМА;1-ЕСТЬ ПРИЕМ);1-(0-НЕТ СООБЩЕНИЯ;1-ЕСТЬ СООБЩЕНИЕ);2-0-НЕТ ПЕРЕДАЧИ;1-ИДЕТ ПЕРЕДАЧА);3-(0-НЕТ ШИФРАЦИИ;1-ЕСТЬ ШИФРАЦИЯ)
FLAGI2C EQU 0X79 ;0-(0-НЕТ ПРИЕМОПЕРЕДАЧИ;1-ИДЕТ ПРИЕМОПЕРЕДАЧА);1-(
TEMP EQU 0X7A
TEMP1 EQU 0X7B
I2C_OP EQU 0X7C ;РЕГИСТР ОПЕРАЦИЙ I2C
I2C_COM EQU 0X7E
I2C_ADD EQU 0X7F ;ТЕКУЩИЙ АДРЕС I2C. ДИАПАЗОН: 0X80 ДО 0XA8 (128 ДО 168)
BUF_OLD EQU 0X1A0 ;АДРЕС СТАРОГО СООБЩЕНИЯ
BUF_NEW EQU 0X1A1 ;АДРЕС НОВОГО СООБЩЕНИЯ
N_HS EQU 0X1A8
__CONFIG 8007h, 0X0F84
__CONFIG 8008h, 0X1AFF
ORG 0X00
GOTO MAIN
ORG 0X04 ;ПРЕРЫВАНИЯ
BCF INTCON,7 ;ВЫКЛЮЧАЕМ ПРЕРЫВАНИЯ
BANKSEL PIR1
BTFSC PIR3,1 ;ПАУЗА ОТВЕТА
GOTO P_OTVET
BTFSC PIR1,4 ;ПЕРЕДАЧА СОВЕРШЕНА?
GOTO RS_485_TX ;ДА, ПЕРЕХОД НА ОБРАБОТКУ
INT1 BTFSC PIR1,5 ;ПРИЕМ СОВЕРШЕН?
GOTO RS_485_RX ;ДА, ПЕРЕХОД НА ОБРАБОТКУ
BTFSC PIR3,3 ;ТАЙМЕР СИНХРОНИЗАЦИИ СРАБОТАЛ?
GOTO SYNS ;ДА, ПЕРЕХОД НА ОБРАБОТКУ
P_OTVET CALL DIR_TX ;ПАУЗА ОТВЕТА
BANKSEL T4CON
CLRF T4CON
BANKSEL PIR3
BCF PIR3,1
BANKSEL TXSTA
BSF TXSTA,5
BANKSEL PIE1
BSF PIE1,4
BSF INTCON,7
RETFIE
SYNS NOP
BANKSEL BAUDCON
BTFSS BAUDCON,6
GOTO SS1
BCF FLAG485,0 ;ПРИЕМ ОКОНЧЕН. (0-НЕТ ПРИЕМА)
BANKSEL PORTA
BCF PORTA,4
CALL CRC8_RX
CALL RX_ER ;ПРОВЕРКА НА НУЛИ
;ВЫКЛЮЧАЕМ ПРЕРЫВАНИЯ ОТ ПЕРИФЕРИИ
SS1 NOP
BANKSEL PIR3
BCF PIR3,3
BANKSEL T6CON
CLRF T6CON
RETFIE
RS_485_RX BTFSC FLAG485,0 ;ПРИЕМ
GOTO RX1
CLRF ADRES_TEMP
CALL LED_485_RX
BSF FLAG485,0 ;УСТАНАВЛИВАЕМ ФЛАГ ПРИЕМА (1-ИДЁТ ПРИЕМ)
RX1 MOVFW ADRES_TEMP ;ЗАГРУЗКА В БУФЕР СЛЕДУЮЩЕГО БАЙТА
MOVWF FSR0L
MOVLW 0X20
MOVWF FSR0H
BANKSEL RCREG
MOVFW RCREG
MOVWF INDF0
INCF ADRES_TEMP
BANKSEL PIR3
BCF PIR3,3
BANKSEL T6CON
MOVLW B'00010101' ;СБРАСЫВАЕМ ТАЙМЕР СИНХРОНИЗАЦИИ
MOVWF T6CON
BSF INTCON,7
RETFIE
RS_485_TX BTFSC FLAG485,2 ;ШЛА ПЕРЕДАЧА?
GOTO TX1 ;ДА, ПРОДОЛЖАЕМ
MOVLW 0X20 ;НЕТ, НАЧАЛО НОВОЙ
MOVWF FSR0H
MOVLW 0X50
MOVWF ADRES_TEMP
BANKSEL 0XA0
MOVFW 0XA1
MOVWF N_BYTE
INCF N_BYTE
CALL LED_485_TX
BSF FLAG485,2 ;УСТАНАВЛИВАЕМ ФЛАГ ПЕРЕДАЧИ (1-ИДЕТ ПЕРЕДАЧА)
GOTO TX3 ;ЗАГРУЖАЕМ ПЕРЕДАТЧИК
TX1 NOP ;ПРЕРЫВАНИЯ ВЫКЛЮЧЕНЫ?
BANKSEL PIE1
BTFSC PIE1,4
GOTO TX3 ;НЕТ, ЗАГРУЖАЕМ ПЕРЕДАТЧИК
NOP ;ДА, ЖДЁМ ОКОНЧАНИЯ ПЕРЕДАЧИ
BANKSEL TXSTA
BTFSC TXSTA,1 ;ПЕРЕДАЧА ЗАВЕРШЕНА?
GOTO INT2
BANKSEL PIR1 ;НЕТ, ПРОВЕРЯЕМ СЛЕДУЮЩЕЕ СОБЫТИЕ INT
GOTO INT1
INT2 CALL DIR_RX ;ДА, ВКЛЮЧЕНИЕ ПРИЕМНИКА
BANKSEL TXSTA
BCF TXSTA,5 ;ПЕРЕДАТЧИК ВЫКЛЮЧЕН
BSF RCSTA,4 ;ПРИЕМНИК ВКЛЮЧЕН
CALL LED_485_TX
BCF FLAG485,2 ;ПЕРЕДАЧА ЗАВЕРШЕНА
BSF INTCON,7
RETFIE
TX3 MOVFW ADRES_TEMP ;ЗАГРУЗКА ПЕРЕДАТЧИКА
MOVWF FSR0L
BANKSEL TXREG
MOVFW INDF0
MOVWF TXREG
INCF ADRES_TEMP
DECFSZ N_BYTE
GOTO TX2
BANKSEL PIE1
BCF PIE1,4
TX2 BSF INTCON,7
RETFIE
Рабочая программа (кусок) работы по RS485. Все действа (прием и передача) происходят в прерываниях. Можно отправить или получить сообщение до 80 байт. В основной программе я проверяю только регистры-флаги. Передача работает так: когда надо ответить (передать), готовиться ответ (пишется в буфер) и запускается таймер паузы ответа, по прерыванию которого запускается передача. При приеме, детектируется конец сообщения путем прерывания от таймера. То есть если в период таймера был принят байт, таймер сбрасывается. Если не был принят, то таймер генерирует по переполнению прерывание, которое и указывает на конец посылки. Ещё у меня проверка CRC8 табличным методом, и проверка на нули. Там у меня ещё интерфейс I2C тоже по прерываниям, может чего лишнего и оставил. По поводу сохранения контекста, в PIC16F1825 расширенное ядро, и процессорные регистры сами сохраняются и восстанавливаются.