eddy_em: (Default)
[personal profile] eddy_em
Сегодня весь день пытался добиться надежной работы 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 бод и коротком шнурке вполне нормально справляется, с бóльшими скоростями как-то работать не планирую.

This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

If you are unable to use this captcha for any reason, please contact us by email at support@dreamwidth.org

October 2025

S M T W T F S
   1234
567 89 1011
121314 15161718
19202122232425
2627 28293031 

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Feb. 25th, 2026 01:23 am
Powered by Dreamwidth Studios