Поиск

RS-485 на STM32


Сегодня весь день пытался добиться надежной работы RS-485 на STM32F042 (исходники). Оказывается, это не настолько уж и тривиально, как просто поднять UART и радоваться!

Так как 485 работает в полудуплексе, необходимо перед приемом/передачей выставить соответствующий уровень на ноге, контролирующей направление передачи.
Выставляю — бац, косяк: сообщения «обрубаются» на последней паре символов. Оказалось, что переключать направление приемопередатчика из прерывания по окончанию передачи DMA нельзя, т.к. USART в это время еще не передал все данные.
Ладно, добавляю простой конечный автомат:

void usart_proc(){ switch(st){ case SENDING: if(txrdy) st = WAITING; break; case WAITING: if(USARTX->ISR & USART_ISR_TXE){ // last byte done -> Rx _485_Rx(); } break; default: break; }
}


И опять косяк! «\n» в конце каждой передачи отсутствует! Тут до меня дошло: ведь USART_ISR_TXE выставляется, когда буфер для отправки пуст, но это отнюдь не значит, что данные уже «уехали». Заменил этот флаг на USART_ISR_TC, и передача пошла нормально.
Но тут появились проблемы с приемом: в принимающий буфер постоянно попадал какой-то мусор. Видимо, «китайские» MAX485 (хотя вроде бы эта партия покупалась у нормальных поставщиков) не закрывают полностью канал RO при подаче на ~RE единицы, либо 3.3В им не хватает!.. (схема рассчитана на MAX3485, у которых напряжение питания 3.3В, а впаял я первое, что под руку подвернулось — MAX485E, а судя по даташиту, этому 5В подавай!)
В общем, проблема приема мусора тоже решилась: USART я стал включать либо только на прием, либо только на передачу, переделав макросы переключения Rx/Tx:

#define _485_Rx() do{RS485_RX(); st = READING; USARTX->CR1 = (USARTX->CR1 & ~USART_CR1_TE) | USART_CR1_RE;}while(0)
#define _485_Tx() do{RS485_TX(); st = SENDING; USARTX->CR1 = (USARTX->CR1 & ~USART_CR1_RE) | USART_CR1_TE;}while(0)


Зачем я отдельно Rx и Tx подключал — тоже сейчас не вспомню, ведь намного логичней было бы сразу работать в single wire half-duplex: Rx/Tx MAX3485 соединить вместе и подать на Tx микроконтроллера. Правда, пришлось бы выпаивать MAX485 и впаивать вместо него MAX3485, чтобы избавиться от «мусора».
Вот такие пироги с казалось бы простейшим интерфейсом!
А ведь еще надо будет добавить обработку адреса устройства… Думаю, протокол будет таким же текстовым, как и по USB, но перед командой нужно будет писать число — адрес, выставляемый на плате переключателями (на фото он трехразрядный, хотя должен быть четырех — но мне с али еще новые dip-switches не пришли). Этот же адрес будет задавать идентификатор устройства на CAN-шине. Как закончу с обработкой адреса по RS-485, перейду к CAN’у. Для его отладки у меня есть старая девборда, которую надо будет по-быстрому переделать в USB<>CAN адаптер (а заодно и протокол придумать, по которому можно будет пакеты отправлять/принимать). Уже, кстати, давненько подумываю о том, что нужно на МК сделать какой-то «эмулятор баша» для отладки: чтобы при ручном вводе команд можно было стрелочками по истории гулять + табом автодополнение делать. По идее, оперативки у средних STM’ок столько, что они запросто эту хотелку должны потянуть!
Справа внизу на фото — переходник на основе PL2303 для работы с RS-485, который я брал когда-то на али. На 115200 бод и коротком шнурке вполне нормально справляется, с бóльшими скоростями как-то работать не планирую.

eddy_em.livejournal.com

Добавить комментарий