Форум РадиоКот https://radiokot.ru/forum/ |
|
USART на PIC16 https://radiokot.ru/forum/viewtopic.php?f=58&t=101251 |
Страница 1 из 1 |
Автор: | Zhuk72 [ Сб мар 01, 2014 16:39:37 ] |
Заголовок сообщения: | USART на PIC16 |
C весной вас, коты! Возникла такая проблема. Необходимо организовать асинхронную передачу (а в дальнейшем и прием) с параметрами 9600-8-N-2 на 16-м ПИКе. Т.к. "железно" поддерживается только 1 стоп-бит, вычитал в сети, что для передачи 2-го стоп-бита достаточно сделать задержку длительностью в 1 бит (около 104 мкс для 9600) перед отправкой следующего байта. Но как бы я с этим ни извращался, куда бы ее не вставлял, в виртуальном терминале Протеуса выводится мусор в виде одного единственного байта F8. Когда переключаю терминал на 1 стоп-бит, последовательность из необходимых 13 байтов выводится нормально. Кусок кода с отправкой таков (прерывание не используется): Спойлерsendbsf RCSTA,SPEN ; Включаю порт bsf STATUS,RP0 bsf TXSTA,TXEN ; Разрешаю передачу bcf STATUS,RP0 movlw 1-й байт ; Отправка байтов call tx movlw 2-й байт call tx movlw 3-й байт call tx ...... movlw 13-й байт call tx bsf STATUS,RP0 bcf TXSTA,TXEN ; Отключаю передатчик bcf STATUS,RP0 clrf command return tx btfss PIR1,TXIF ; Ожидаем опустошения goto $-1 ; буфера перед movwf TXREG ; отправкой в его регистр байта. return Пытался играть с длительностью задержки, даже делал ее 2 раза для верности - всё бестолку. Вставлял ее перед movwf TXREG, делал отдельную проверку по биту TRMT (1=TSR empty, 0=TSR full), но он почему-то никогда не выходит в 1. Как-то раз даже извратился: отключил USART, настроил порт ТХ на выход (для USART`a он и RX должны быть настроены на вход) и выставил на нем 1 на нужный период, но и это не помогло. Что посоветуете сделать для передачи 2-го стоп-бита? |
Автор: | otest [ Сб мар 01, 2014 21:55:06 ] |
Заголовок сообщения: | Re: USART на PIC16 |
Какой именно МК используеш. Если МК с модулем на борту (о чём говорит код), то зачем заморачиваешся с задержками битов и прочей лабудой. Настрой модуль на передачу загрузи в него что надо и передай . Всё. ДШ в помощь. |
Автор: | Zhuk72 [ Сб мар 01, 2014 22:22:19 ] |
Заголовок сообщения: | Re: USART на PIC16 |
Я же писал, что мне надо 2-й стоп-бит эмулировать. С одним стоп-битом все работает нормально. PIC16F628A, хотя это никакого значения не имеет, модули у всех 8-битников одинаковые. |
Автор: | otest [ Сб мар 01, 2014 22:43:57 ] |
Заголовок сообщения: | Re: USART на PIC16 |
Цитата: модули у всех 8-битников одинаковые. Читаем ДШ 2 раза. |
Автор: | Аlex [ Сб мар 01, 2014 23:04:30 ] |
Заголовок сообщения: | Re: USART на PIC16 |
Настройте модуль на 9-ти битный режим и передавайте девятым битом единичку. И будет Вам ещё один дополнительный бит, с точным временем, без всяких задержек. |
Автор: | Zhuk72 [ Сб мар 01, 2014 23:18:04 ] |
Заголовок сообщения: | Re: USART на PIC16 |
Аlex писал(а): Настройте модуль на 9-ти битный режим и передавайте девятым битом единичку. И будет Вам ещё один дополнительный бит, с точным временем, без всяких задержек. Ок, спасибо! Сейчас попробую. |
Автор: | Zhuk72 [ Сб мар 01, 2014 23:32:44 ] |
Заголовок сообщения: | Re: USART на PIC16 |
Сделал посредством 9-битной передачи. Судя по анализатору в Протеусе, два стопа теперь передаются, но его терминал по-прежнему выдает ерунду. Буду проверять на железе, т.к. Протеус явно халтурит. Но при этом в режиме 8-1 он все отображает правильно. Спасибо за помощь! |
Автор: | Zhuk72 [ Вт мар 18, 2014 12:06:37 ] |
Заголовок сообщения: | Re: USART на PIC16 |
Доброго времени суток, Коты! Требуется получить по USART один за другим 8 байт, разместив их соответственно по регистрам с dd0 по dd7. Я это сделал кривым методом, он работает, но хочется утонченности компактности кода. Не подскажете алгоритм на АСМе? Сейчас это делается запуском счетчика с приходом 1-го байта, наращивания его с приходом каждого нового байта, сравнивания его значения с 0-7 и размещением в соответствующие регистры. Чувствую, что должен быть иной, универсальный и компактный метод, основанный на косвенной адресации, но как это сделать - не знаю. Подсобите, пожалуйста ![]() Почти подобрался к финалу, забил память так, что осталось всего 15 слов свободных, хочется немного освободить места, оптимизировав программу. Тут, кстати, у меня тоже вопрос есть, но это потом. ПИК тот же, 628-й. |
Автор: | abc [ Вт мар 18, 2014 13:57:16 ] |
Заголовок сообщения: | Re: USART на PIC16 |
Код: dd0 equ 0x70
READ_DATA_PACKET movlw dd0 movwf FSR movlw 8 movwf count READ_DATA_LOOP ;8 data bytes to buffer btfss PIR1,RCIF ;RX ? goto $-1 ;no movf RCREG,w movwf INDF incf FSR,f decfsz count,f goto READ_DATA_LOOP |
Автор: | Zhuk72 [ Вт мар 18, 2014 18:16:41 ] |
Заголовок сообщения: | Re: USART на PIC16 |
Спасибо! Дома попробую после некоторой модификации. А я никак не мог понять логику, как эти 2 регистра связаны между собой и как их привязать к конкретному регистру )) Добавлено 19.03.2014: Все получилось! Код сократился аж на 60 слов. Еще раз большое спасибо! |
Автор: | Smen [ Чт мар 20, 2014 09:22:45 ] |
Заголовок сообщения: | Re: USART на PIC16 |
Косвенная адресация - великая сила! Освоить её надо обязательно. Только учтите, что, если вы ею пользуетесь и в программе, и в обработчике прерываний, то, при входе в обработчик, регистр-указатель необходимо сохранять, а при выходе, восстанавливать (аналогично регистрам статуса и аккумулятора). |
Автор: | Zhuk72 [ Чт мар 20, 2014 11:55:50 ] |
Заголовок сообщения: | Re: USART на PIC16 |
Да, об этом я знаю. Прерывания используются, но если я, вернее программа, туда попаду, значит произошел таймаут и дальнейшая судьба этого указателя уже неважна. Поэтому не стал его сохранять. |
Автор: | iGraphicsS [ Пт мар 21, 2014 11:57:28 ] |
Заголовок сообщения: | Re: USART на PIC16 |
Код: 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 расширенное ядро, и процессорные регистры сами сохраняются и восстанавливаются. |
Автор: | Smen [ Пн мар 24, 2014 09:06:47 ] |
Заголовок сообщения: | Re: USART на PIC16 |
iGraphicsS писал(а): и процессорные регистры сами сохраняются и восстанавливаются. Но тогда же должно быть:Код: RETFIE FAST
|
Автор: | Zhuk72 [ Пн мар 24, 2014 10:04:02 ] |
Заголовок сообщения: | Re: USART на PIC16 |
iGraphicsS писал(а): ORG 0X04 ;ПРЕРЫВАНИЯ BCF INTCON,7 ;ВЫКЛЮЧАЕМ ПРЕРЫВАНИЯ ... BSF INTCON,7 RETFIE При переходе на вектор прерываний 7-й бит INTCON (GIE) автоматически опускается, а по команде RETFIE поднимается. Так что вручную поднимать и опускать его не нужно. |
Автор: | iGraphicsS [ Пн мар 24, 2014 13:46:30 ] |
Заголовок сообщения: | Re: USART на PIC16 |
Это уже привычка, оставшаяся с каких то незапамятных времён или других процессоров... |
Автор: | Dmitry Dubrovenko [ Пн мар 24, 2014 23:13:31 ] |
Заголовок сообщения: | Re: USART на PIC16 |
iGraphicsS писал(а): Ещё у меня проверка CRC8 табличным методом А CRC-7 не подскажете?
|
Автор: | iGraphicsS [ Вт мар 25, 2014 14:41:53 ] |
Заголовок сообщения: | Re: USART на PIC16 |
Полином X7+X3+1 или 0x44. Делаем табличку в экселе от "0" до "n", прописываем формулу для каждого значения (одна и та же) и получаем табличные данные. Это устройство эмулирует прибор в охранной сигнализации, по этому, в моем случае, это не совсем CRC8. Она очень похожа на Dallas-овскую, но отличается 5 значениями (видимо специально изменили). Если лень в экселе, можно посчитать тут: http://ghsi.de/CRC/ Вписываем свой полином "1000100" и последовательно заполняем таблицу. Удобнее работать с байтом, по этому значения от 0 до 255 (0x00 ... 0xFF). То есть на выходе таблица с 255 значениями. У меня это выглядит так: Код: CRC8_RX CLRF TEMP ;ПОДПРОГРАММА ВЫЧИСЛЕНИЯ CRC8 ПРИНЯТОГО СООБЩЕНИЯ , гдеMOVLW 0X20 ;курсов FSR на буфер принятого сообщения MOVWF FSR0H MOVLW 0X00 MOVWF FSR0L ;ВСТАЛИ НА ПЕРВЫЙ БАЙТ BANKSEL 0X21 MOVFW 0X21 ;в посылке указывается число байтов MOVWF TEMP1 ;СКОЛЬКО НАДО БАЙТОВ ВЫЧИСЛИТЬ INCF TEMP1 CRC2 MOVFW INDF0 ;ПРОЧИТАЛИ ЗНАЧЕНИЕ XORWF TEMP,1 ;ПРОКСОРИЛИ С ПРЕДЪИДЩИМ MOVFW TEMP CALL CRC8_TABLE ;ВЗЯЛИ ИЗ ТАБЛИЦЫ MOVWF TEMP ;ЗАПИСАЛИ ВО ВРЕМЕННЫЙ INCF FSR0L ;СЛЕДУЮЩИЙ АДРЕС DECFSZ TEMP1 ;УМЕНЬШИЛИ ЧИСЛО БАЙТОВ GOTO CRC2 MOVLW 0X00 ADDWF TEMP BTFSC STATUS,2 ;РЕЗУЛЬТАТ РАВЕН НУЛЮ? GOTO CRC3 ;ДА, ВСЁ ВЕРНО BCF FLAG485,1 ;НЕТ, ОШИКА ПРИЕМА. RETURN CRC3 BSF FLAG485,1 RETURN CRC8_TABLE BRW ;ТАБЛИЦА ДЛЯ ВЫЧИСЛЕНИЯ CRC8 RETLW 0X00 RETLW 0X5E RETLW 0XBC RETLW 0XE2 ........ CRC8_table - это таблица с заранее вычисленными значениями CRC, в моем случае из дизасма ПО, так как по далассовской были сбои. Если надо получить значение CRC, то последнее XOR делать не надо, то есть в моем случае на 1 байт меньше. То есть у меня вычисленное значение XORиться с принятым, и если ноль, то корректно. Можно вообще в ручную вычислять, со сдвигами n-битного числа (у меня сообщения до 80 байт и займет ~700 проходов по 50-100 слов) и проверкой старшего на 1 или 0 в соответствии с полиномом , и всё это в цикле на N-бит. Учитывая что в контроллере уживаются I2C и RS485 это не приемлемо по времени. По этому табличный, 300 слов в памяти не такая уж и дорогая плата. |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |