|
2 USART под RS485 на ATMega162 |
|
|
|
Mar 15 2009, 20:31
|
Группа: Новичок
Сообщений: 13
Регистрация: 28-06-08
Пользователь №: 38 608

|
Здравия желаю всем !
Делаю устройство на Mega162 с двумя протоколами modbus. USART0 - master, посылает всего 11 разных запросов. USART1 - slave, отвечает на эти 11 запросов с некоторыми корректировками. То есть устройство устанавливается между master и slave и общается с ними с нужными мне исправлениями.
В общем, сделал отдельно master и slave - работает, но когда все в целом, то работает только slave, а master зацикливается на 1-й посылке, иногда 2-я проскакивает.
Вроде проблема с прерываниями, т.к. slave постоянно принимает и отвечает, и не дает master работать. Игрался с запретом прерываний, но ничего не помогло.
Также делал чтобы slave принял, ответил, а потом master послал, принял, поочередно, но так теряется слейвом фреймы.
У кого могут быть какие идеи? Такое устройство возможно ли вообще?
Мега162, кварц - 3,6864... Параметры связи обоих 2400-О-1...
|
|
|
|
|
Mar 15 2009, 21:09
|
Частый гость
 
Группа: Участник
Сообщений: 149
Регистрация: 2-06-08
Из: Москва
Пользователь №: 38 003

|
Цитата(vetalxh @ Mar 15 2009, 23:31)  ... У кого могут быть какие идеи? Такое устройство возможно ли вообще? ... Устройство, понятное дело, возможно. Думаю стоит смотреть в сторону буферизации приемника слейва и уменьшения длительности выполнения обработчиков прерывания. А вообще стандартная фраза: Код в студию!
|
|
|
|
|
Mar 15 2009, 21:31
|
Группа: Новичок
Сообщений: 13
Регистрация: 28-06-08
Пользователь №: 38 608

|
Кода вообще много... Постараюсь основное. Сильно не пинайте, т.к. учусь уму разуму... Это один из вариантов. Но не один из них корректно не работает CODE void StartTrans0(void) { DisableReceive0; SetBit(PORTA,1); TrCount0=0; GoTrans0; } void StartTrans1(void) { SetBit(PORTA,0); TrCount1=0; GoTrans1; }
interrupt [USART0_DRE] void usart0_udre_isr(void) { if (TrCount0<cNumTrByte0-1) { UDR0=cmTrBuf0[TrCount0]; TrCount0++; } else { UDR0=cmTrBuf0[cNumTrByte0-1]; StopTrans0; TrCount0=0; FinTrans=1; } } interrupt [USART0_TXC] void usart0_tx_isr(void) { if (TrCount0<cNumTrByte0-1) { StopTrans0; FinTrans=1; ClrBit(PORTA,1); EnableReceive0; } interrupt [USART0_RXC] void usart0_rx_isr(void) // USART0 I?a?uaaiea i?eaiieea IANOA?A { char status; status=UCSR0A; if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0) { if (StartRec0==0) { StartRec0=1; RcCount0=0; cmRcBuf0[RcCount0++]=UDR0; TCCR1B=0x05; TCNT1H=0xFF; TCNT1L=0xEA; } else { cmRcBuf0[RcCount0++]=UDR0; TCNT1H=0xFF; TCNT1L=0xEA; } } }
interrupt [USART1_RXC] void usart1_rx_isr(void) { char status,data; status=UCSR1A; data=UDR1; if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0) { if (StartRec1==0) { StartRec1=1; RcCount1=0; cmRcBuf1[RcCount1++]=data; TCNT0=0xE9; TCCR0=0x05; } else { if (RcCount1<MaxLenghtRecBuf1) { cmRcBuf1[RcCount1++]=data; } else { cmRcBuf1[MaxLenghtRecBuf1-1]=data; } TCNT0=0xE9; } } }
interrupt [USART1_DRE] void usart1_udre_isr(void) // USART1 I?a?uaaiea ia?aaao?eea IIA?EIAIIIAI { if (TrCount1<cNumTrByte1+1) { UDR1=cmTrBuf1[TrCount1]; TrCount1++; } else { StopTrans1; //ClrBit(DDRA,0); ClrBit(PORTA,0); //PA0 a 0 - ?aaioa a?aeaa?a 485 ia i?eai //EnableReceive1; TrCount1=0; } }
interrupt [TIM0_OVF] void timer0_ovf_isr(void) {
if (StartRec1==1) { StartRec1=0; cNumRcByte1=RcCount1; bModBus1=1; TCCR0=0; } }
char ModBus0 (void) { int TempI; if (cmRcBuf0[0]==0x01 && cmRcBuf0[1]==0x03 && cmRcBuf0[2]==0x02) { ... } }
char ModBus2 (void) { switch (ModFlag) { case (1): { ... } } }
interrupt [TIM1_OVF] void timer1_ovf_isr(void) { if (StartRec0==1) { StartRec0=0; cNumRcByte0=RcCount0; bModBus0=1; TCCR1B=0x00; DisableReceive0; } else { TCCR1B=0x00; TCNT2=0x00; TCCR2=0x07; DisableReceive0; } }
interrupt [TIM2_OVF] void timer2_ovf_isr(void) { TrCount0=0; cNumTrByte0=ModBus2(); StartTrans0(); TCCR2=0x00; }
char ModBus1 (char NumByte) { ... } } void main(void) { Setup(); StartUART0(); StartUART1(); SetBit(DDRD,0);SetBit(PORTD,0); ClrBit(DDRD,1);ClrBit(PORTD,1); SetBit(PORTA,1); ClrBit(DDRB,2);ClrBit(PORTB,2); SetBit(DDRB,3);SetBit(PORTB,3); EnableReceive1; ClrBit(PORTA,0); TCCR2=0x07; TCNT2=0x00; #asm("sei") while (1) { #asm("cli") if (bModBus0==1) { ModBus0(); bModBus0=0; TCNT2=0x00; TCCR2=0x07; } if (bModBus1==1) { cNumTrByte1=ModBus1(cNumRcByte1); if (cNumTrByte1!=0) StartTrans1(); bModBus1=0; } #asm("sei") } }
|
|
|
|
|
Mar 15 2009, 22:38
|
Группа: Новичок
Сообщений: 13
Регистрация: 28-06-08
Пользователь №: 38 608

|
Цитата(smac @ Mar 16 2009, 01:09)  Устройство, понятное дело, возможно. Думаю стоит смотреть в сторону буферизации приемника слейва и уменьшения длительности выполнения обработчиков прерывания. А вообще стандартная фраза: Код в студию! Буфферизация приемника слейва, думАю, не поможет, т.к. мне нужно сразу же отвечать на запрос главного в течении времени 3.5 передачи символа, а обработку тоже старался сделать быструю с минимумом подсчетов... Может проще все это сделать на 2х мегах8 и соединить их через spi? Не будет ли оно также конфликтовать? Если в коде не понятны фукции какие-то, пишите..расскажу
|
|
|
|
|
Mar 15 2009, 22:43
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Не разбирался, но взглянул. Заметил такое: выключение передачи - StopTrans1- делается не по TXC, следовательно может подрезать последний байт (стоп-бит). Проверить подручными средствами этот момент проще, если убрать 485 и подключить UART-ы напрямую, но, ИМХО, и так видно. Не думаю, что это единственная проблемка. Цитата мне нужно сразу же отвечать на запрос главного в течении времени 3.5 передачи символа это чего-то надуманное - минимальная пауза нужна как маркер пакета, а реально пауза может достигать сотен миллисекунд и более. В продвинутых реализация даже поддерживается ответ слейва типа "я занят, пинай позже"
--------------------
aka Vit
|
|
|
|
|
Mar 15 2009, 22:57
|
Группа: Новичок
Сообщений: 13
Регистрация: 28-06-08
Пользователь №: 38 608

|
1) С работой слейва проблем не возникало. Смотрю модбас монитором. Но впринципе, спасибо, можно подправить... 2) Вопрос с 3.5 задержкой связан с готовым устройством (мастером), который при отсутствии ответа генерит ошибки в своей программе...На 2-й запрос - точно... Для "моего" то мастера можно и больше задержки делать..
Сообщение отредактировал vetalxh - Mar 15 2009, 23:00
|
|
|
|
|
Mar 15 2009, 23:06
|
Гуру
     
Группа: Участник
Сообщений: 3 928
Регистрация: 28-03-07
Из: РФ
Пользователь №: 26 588

|
Цитата(vetalxh @ Mar 15 2009, 20:31)  Вроде проблема с прерываниями, т.к. slave постоянно принимает и отвечает, и не дает master работать. Игрался с запретом прерываний, но ничего не помогло. Откажитесь от прерываний и сделайте опрос уартов в прерывании от таймера. А вообще, если включить телепатию, я думаю, у вас грабли. Предположительно нет запрета прерываний от передатчика после того, как данные для передачи закончились. Цитата(vetalxh @ Mar 15 2009, 20:31)  Мега162, кварц - 3,6864... Параметры связи обоих 2400-О-1... Так поднимимите кварц, раза в четыре. Хотя на 2400 нагрузка небольшая.
|
|
|
|
|
Mar 15 2009, 23:06
|
Профессионал
    
Группа: Свой
Сообщений: 1 266
Регистрация: 22-04-05
Из: Киев
Пользователь №: 4 387

|
Цитата Вопрос с 3.5 задержкой связан с готовым устройством (мастером) По спецификации Modbus_over_serial_line время 3.5 Тсимвола (точнее параметр описан там же) не задержка на начало ответа, а МИНИМАЛЬНАЯ ПАУЗА, позволяющая определить конец пакета
--------------------
aka Vit
|
|
|
|
|
Mar 15 2009, 23:42
|
Группа: Новичок
Сообщений: 13
Регистрация: 28-06-08
Пользователь №: 38 608

|
sensor_ua, спасибо, буду думать... А можно по-подробнее про "Откажитесь от прерываний и сделайте опрос уартов в прерывании от таймера" ?
|
|
|
|
|
Mar 16 2009, 00:11
|
Группа: Новичок
Сообщений: 13
Регистрация: 28-06-08
Пользователь №: 38 608

|
Цитата(Огурцов @ Mar 16 2009, 03:51)  Организуйте прерывание от таймера и проверяйте в нем готовность приемника и передатчика, наличие данных и места в буфере. Только так сможете управлять последовательностью обработки и приоритетами уартов. Кроме того, это позволит исключить затраты на вызовы уартовских прерываний. Спасибо...Подумаю над этим тоже
|
|
|
|
|
Mar 16 2009, 09:08
|
Группа: Новичок
Сообщений: 13
Регистрация: 28-06-08
Пользователь №: 38 608

|
В прерывании таймера проверять оба уарта? А если по прерыванию я попаду на середину фрейма? Если отказаться от прерываний уартов, то как данные попадут в буфер? Что-то туговато...А кусочком кода никто не поделится? Или алгоритмом хотябы...Спасибо
|
|
|
|
|
Mar 16 2009, 19:37
|
Частый гость
 
Группа: Участник
Сообщений: 149
Регистрация: 2-06-08
Из: Москва
Пользователь №: 38 003

|
Цитата(vetalxh @ Mar 16 2009, 12:08)  В прерывании таймера проверять оба уарта? А если по прерыванию я попаду на середину фрейма? Так там же буферизированный приемник, если TXC не установился - значит нет данных, если установился - значит есть, если при этом DOR сброшен, значит данные валидны.
|
|
|
|
|
Mar 16 2009, 22:26
|
Группа: Новичок
Сообщений: 13
Регистрация: 28-06-08
Пользователь №: 38 608

|
Короче, думал-думал...Решил обойти все это еще одним способом. 1. Разрешаю прием Slave. 2. Slave получил, обработал, ответил. 3. Slave опять получил, обработал, ответил ... Так раза 3-4... 6. Запрещаю прием Slave и разрешаю посылку Master. 7. Master послал, принял, обработал. И опять в начало "Разрешаю прием Slave" В принципе, такое тоже должно меня устроить, но после того, как запретил прием Slave CODE UCSR1B&=~(1<<4); UCSR1B&=~(1<<7) не могу заново разрешить его разрешить... Делаю так CODE UCSR1B|=(1<<4); UCSR1B|=(1<<7) Может нога RX повисла в левом состоянии.. Но я включал подтяжку для нее в начале программы (вместе для мастера и слейва) CODE void Setup(void) { PORTB=0x04; DDRB=0x00; PORTD=0x01; DDRD=0x00; } И еще...Может ли камень уходить в рестарт?? Иногда модбас монитором замечаю, что идет цикл программы, а потом Мастер начинает посылку с 1й...По ходу выполнения программы такое не возможно, т.е. имхо или сброс, или хз что...
|
|
|
|
|
Mar 17 2009, 00:19
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(vetalxh @ Mar 15 2009, 22:31)  У кого могут быть какие идеи? Такое устройство возможно ли вообще? А какие проблемы? далаете нормальный протоколо-независимый драйвер UART'а c буферизированным приемом и передачей. Пишете две функции-задачи по очереди вызываемые в основном цикле программы, одна для обслуживания мастера, вторая для слейва. Никаких Delay_ms и прочий хлам не использовать!! Если слейв требует какого-то реалтайма для выдержки 3.5 символьного интервала, что организуется одним из таймеров, то modbus мастер - это совершенно неприхотливая задача. Выплевывать данные в UART и забирать ответ через скажем 100ms. Вот и вся ее суть. Цитата Мега162, кварц - 3,6864... Параметры связи обоих 2400-О-1... Какой смысл ставить такой медленный кварц, и пользовать только ~20% производительности МК?
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|