Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: 2 USART под RS485 на ATMega162
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
vetalxh
Здравия желаю всем !

Делаю устройство на 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...
smac
Цитата(vetalxh @ Mar 15 2009, 23:31) *
...
У кого могут быть какие идеи? Такое устройство возможно ли вообще?
...

Устройство, понятное дело, возможно. Думаю стоит смотреть в сторону буферизации приемника слейва и уменьшения длительности выполнения обработчиков прерывания. А вообще стандартная фраза: Код в студию!
vetalxh
Кода вообще много... Постараюсь основное. Сильно не пинайте, т.к. учусь уму разуму...
Это один из вариантов. Но не один из них корректно не работает


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")
}
}
vetalxh
Цитата(smac @ Mar 16 2009, 01:09) *
Устройство, понятное дело, возможно. Думаю стоит смотреть в сторону буферизации приемника слейва и уменьшения длительности выполнения обработчиков прерывания. А вообще стандартная фраза: Код в студию!

Буфферизация приемника слейва, думАю, не поможет, т.к. мне нужно сразу же отвечать на запрос главного в течении времени 3.5 передачи символа, а обработку тоже старался сделать быструю с минимумом подсчетов...
Может проще все это сделать на 2х мегах8 и соединить их через spi? Не будет ли оно также конфликтовать?
Если в коде не понятны фукции какие-то, пишите..расскажу
sensor_ua
Не разбирался, но взглянул. Заметил такое: выключение передачи - StopTrans1- делается не по TXC, следовательно может подрезать последний байт (стоп-бит). Проверить подручными средствами этот момент проще, если убрать 485 и подключить UART-ы напрямую, но, ИМХО, и так видно. Не думаю, что это единственная проблемка.
Цитата
мне нужно сразу же отвечать на запрос главного в течении времени 3.5 передачи символа
это чего-то надуманное - минимальная пауза нужна как маркер пакета, а реально пауза может достигать сотен миллисекунд и более. В продвинутых реализация даже поддерживается ответ слейва типа "я занят, пинай позже"
vetalxh
1) С работой слейва проблем не возникало. Смотрю модбас монитором. Но впринципе, спасибо, можно подправить...
2) Вопрос с 3.5 задержкой связан с готовым устройством (мастером), который при отсутствии ответа генерит ошибки в своей программе...На 2-й запрос - точно... Для "моего" то мастера можно и больше задержки делать..
Огурцов
Цитата(vetalxh @ Mar 15 2009, 20:31) *
Вроде проблема с прерываниями, т.к. slave постоянно принимает и отвечает, и не дает master работать. Игрался с запретом прерываний, но ничего не помогло.

Откажитесь от прерываний и сделайте опрос уартов в прерывании от таймера.
А вообще, если включить телепатию, я думаю, у вас грабли. Предположительно нет запрета прерываний от передатчика после того, как данные для передачи закончились.

Цитата(vetalxh @ Mar 15 2009, 20:31) *
Мега162, кварц - 3,6864... Параметры связи обоих 2400-О-1...

Так поднимимите кварц, раза в четыре. Хотя на 2400 нагрузка небольшая.
sensor_ua
Цитата
Вопрос с 3.5 задержкой связан с готовым устройством (мастером)

По спецификации Modbus_over_serial_line время 3.5 Тсимвола (точнее параметр описан там же) не задержка на начало ответа, а МИНИМАЛЬНАЯ ПАУЗА, позволяющая определить конец пакета
vetalxh
sensor_ua, спасибо, буду думать...
А можно по-подробнее про "Откажитесь от прерываний и сделайте опрос уартов в прерывании от таймера" ?
Огурцов
Организуйте прерывание от таймера и проверяйте в нем готовность приемника и передатчика, наличие данных и места в буфере. Только так сможете управлять последовательностью обработки и приоритетами уартов. Кроме того, это позволит исключить затраты на вызовы уартовских прерываний.
vetalxh
Цитата(Огурцов @ Mar 16 2009, 03:51) *
Организуйте прерывание от таймера и проверяйте в нем готовность приемника и передатчика, наличие данных и места в буфере. Только так сможете управлять последовательностью обработки и приоритетами уартов. Кроме того, это позволит исключить затраты на вызовы уартовских прерываний.

Спасибо...Подумаю над этим тоже
vetalxh
В прерывании таймера проверять оба уарта? А если по прерыванию я попаду на середину фрейма? Если отказаться от прерываний уартов, то как данные попадут в буфер? Что-то туговато...А кусочком кода никто не поделится? Или алгоритмом хотябы...Спасибо
smac
Цитата(vetalxh @ Mar 16 2009, 12:08) *
В прерывании таймера проверять оба уарта? А если по прерыванию я попаду на середину фрейма?

Так там же буферизированный приемник, если TXC не установился - значит нет данных, если установился - значит есть, если при этом DOR сброшен, значит данные валидны.
vetalxh
Короче, думал-думал...Решил обойти все это еще одним способом.

1. Разрешаю прием Slave.
2. Slave получил, обработал, ответил.
3. Slave опять получил, обработал, ответил
...
Так раза 3-4...
6. Запрещаю прием Slave и разрешаю посылку Master.
7. Master послал, принял, обработал.
И опять в начало "Разрешаю прием Slave"

В принципе, такое тоже должно меня устроить, но после того, как запретил прием Slave

CODE
UCSR1B&=~(1<<4); UCSR1B&=~(1<<7)


не могу заново разрешить его разрешить... help.gif
Делаю так

CODE
UCSR1B|=(1<<4); UCSR1B|=(1<<7)


Может нога RX повисла в левом состоянии.. Но я включал подтяжку для нее в начале программы (вместе для мастера и слейва)

CODE
void Setup(void)
{
PORTB=0x04;
DDRB=0x00;
PORTD=0x01;
DDRD=0x00;
}


И еще...Может ли камень уходить в рестарт?? Иногда модбас монитором замечаю, что идет цикл программы, а потом Мастер начинает посылку с 1й...По ходу выполнения программы такое не возможно, т.е. имхо или сброс, или хз что...
defunct
Цитата(vetalxh @ Mar 15 2009, 22:31) *
У кого могут быть какие идеи? Такое устройство возможно ли вообще?

А какие проблемы? далаете нормальный протоколо-независимый драйвер UART'а c буферизированным приемом и передачей.
Пишете две функции-задачи по очереди вызываемые в основном цикле программы, одна для обслуживания мастера, вторая для слейва. Никаких Delay_ms и прочий хлам не использовать!! Если слейв требует какого-то реалтайма для выдержки 3.5 символьного интервала, что организуется одним из таймеров, то modbus мастер - это совершенно неприхотливая задача. Выплевывать данные в UART и забирать ответ через скажем 100ms. Вот и вся ее суть.

Цитата
Мега162, кварц - 3,6864... Параметры связи обоих 2400-О-1...

Какой смысл ставить такой медленный кварц, и пользовать только ~20% производительности МК?
vetalxh
Цитата(defunct @ Mar 17 2009, 03:19) *
А какие проблемы? далаете нормальный протоколо-независимый драйвер UART'а c буферизированным приемом и передачей.
Пишете две функции-задачи по очереди вызываемые в основном цикле программы, одна для обслуживания мастера, вторая для слейва. Никаких Delay_ms и прочий хлам не использовать!! Если слейв требует какого-то реалтайма для выдержки 3.5 символьного интервала, что организуется одним из таймеров, то modbus мастер - это совершенно неприхотливая задача. Выплевывать данные в UART и забирать ответ через скажем 100ms. Вот и вся ее суть.

В принципе, я так и сделал. На Slave постоянно включено прерывание по приему. И по завершению приема фрейма посылается ответ... А Master вызывается по прерыванию tim2. И вопрос в том, что Slave перебивает работу Mastera своими прерываниями. И Master посылает все время 1й запрос...А если выключаю устройство, которое подключено к Slave (то есть Slave не работает), Master начинает работать нормально...
А если на время работы Мастера запрещать Слейв, то обратно включить не могу его..Молчит..Может подскажите что?
Цитата(defunct @ Mar 17 2009, 03:19) *
Какой смысл ставить такой медленный кварц, и пользовать только ~20% производительности МК?

Ну это да, согласен, что протупил...Исправлю...
_Pasha
Цитата(defunct @ Mar 17 2009, 04:19) *
для выдержки 3.5 символьного интервала, что организуется одним из таймеров

Можно вообще обнаглеть и использовать dummy writes при выключенном передатчике. Будет 4. Кунсткамера, но экономненько smile.gif
Палыч
Цитата(vetalxh @ Mar 17 2009, 11:15) *
И вопрос в том, что Slave перебивает работу Mastera своими прерываниями. И Master посылает все время 1й запрос...А если выключаю устройство, которое подключено к Slave (то есть Slave не работает), Master начинает работать нормально...
Очень похоже, что у Slave разрешено какое-то прерывание, а соответствующей процедуры обработки этого прерывания - нет. При этом происходит переход на ячейку с адресом 0, и всё - заново с первой посылки Master'а...
vetalxh
Цитата(Палыч @ Mar 17 2009, 11:52) *
Очень похоже, что у Slave разрешено какое-то прерывание, а соответствующей процедуры обработки этого прерывания - нет. При этом происходит переход на ячейку с адресом 0, и всё - заново с первой посылки Master'а...

Точно. a14.gif
Напутал с регистром UCSR1B. Разрешил прерывание по "завершению передачи" (его вообще в программе не использовал), а прерывание по "очистке регистра передатчика" вообще не включено было.. Как оно вообще работало...хз... biggrin.gif
Спасибо beer.gif
Вечером попробую на устройстве..Отпишусь
sitafern
Цитата(vetalxh @ Mar 15 2009, 22:31) *
Здравия желаю всем !

Делаю устройство на 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...

Делал такое: модбас на меге 162 в два USARTA, без прерываний (только переполнение таймера для интервалов), работает устойчиво на 115200. Кстати, действительно, почему такая маленькая частота кварца? Подсчёт контрольной суммы "на лету". Написано на ассемблере. Если интересно могу выслать исходник без дешифратора команд и других "прибамбасов".
Только работа USATR'ов. Мой адрес sitafern@ukr.net
_Pasha
Цитата(sitafern @ Mar 22 2009, 14:13) *
Если интересно могу выслать исходник без дешифратора команд и других "прибамбасов".

Недавний опыт общения показал: не надо сишников снабжать асмовыми исходниками. Пусть задохнутся. sad.gif
vetalxh
Цитата(_Pasha @ Mar 22 2009, 15:44) *
Недавний опыт общения показал: не надо сишников снабжать асмовыми исходниками. Пусть задохнутся. sad.gif


А к чему это написано??
vetalxh
Утройство сделал. Даже хватило кварца на 3,6864....Всем спасибо за помощь. Отдельное спасибо defunct и Палыч a14.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.