Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: проблема с уарт Mega64
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
CrazyAlex
не могу понять в чем дело:

устройство: Мега->485->Adam->PC

софт: iccAVR6.31a, AVRstudio, jtag ice mk2 (не совсем софт), на PC самописный модбас-мастер (проверен временем), а также терминалка.

протокол модбас RTU, чтение регистров (03) идет на ура, запись (06) в регистр значение 511 - все отвечает правильно. запись значения 512 - вместо ответа какая-то хрень, число байт хрени совпадает с числом байт в ответе. причем эта самая хрень каждый раз разная. хотя запрос один и тот же.

смотрю в авр студии.
пакет приходит, регистр меняется на нужное значение, формируется в буферном массиве frame1 ответ (правильный ответ).
Портится на этапе UDR1=frame1[0], UDR1=frame1[outbytecnt]. т.е. в UDR1 или пишется что-то не то, или в нем самом портится..., т.е. PC принимает совсем не то что я записываю в UDR.
Если поставить точку останова на UDR1=frame1[0], и потом по шагам, то все отвечает нормально.

Исходники прилагаю.

Уже мозг сломал. Подскажите кто-нибудь где копать???
Александр Куличок
А ждать завершения передачи (или опустошения буфера передачи) кто будет? (флаги TXC или UDRE)
CrazyAlex
Цитата(Александр Куличок @ Jun 4 2007, 17:31) *
А ждать завершения передачи (или опустошения буфера передачи) кто будет? (флаги TXC или UDRE)


Думаю что ждать его будет мега. Если помотреть исходники, то видно, что все это в прерывании. Но все равно спасибо за участие.
Dog Pawlowa
Цитата(CrazyAlex @ Jun 4 2007, 09:45) *
Уже мозг сломал. Подскажите кто-нибудь где копать???

В детали Вашей алгоритмизации я вряд ли вникну, но прерывание по передаче мне не нравится. Мне кажется, что должен быть запрет прерывания, если весь буфер передан. Может быть, мега передает больше буфера? (Проверить можно осциллографом или терминалкой)
Причин не очень то много может быть - или память затирается (проверить, поставив останов в конце передачи), или индекс и длина массива портится во время передачи (проверить аналогично).
Памяти свободной ведь много, можно организовать буфер для отладки и писать туда все, что ушло в UDR1.

Код
void Uart1TXint(void) /**/
{
static unsigned char byteoutcnt1=1;

if (OutPacketLength1)
{
  UDR1=frame1[byteoutcnt1];
  OutPacketLength1--;
  byteoutcnt1++;
}
else
{
  SetRE1;
  ResetDE1;
  byteoutcnt1=1;
}
}


У меня так:
Код
#pragma vector=USART_UDRE_vect
__interrupt void USART_transmit(void)
{    
  if ((uart0.tx_status==Uart0Transmitting)&&
      (uart0.tx_tail < uart0.tx_head))

        {   UDR = *uart0.tx_tail;    
            uart0.tx_tail ++;        
        }
  else  UCSRB &= ~(1 << UDRIE);
}
Александр Куличок
Цитата
Думаю что ждать его будет мега. Если помотреть исходники, то видно, что все это в прерывании

Детально не изучал Вашу программу и никогда не работал с модбас, но отмечу следующее:
Мега ждать не будет. У Вас постоянно осуществляется передача по Uart1TXint(). Одновременно с этим после выставлении флага FrameReady1 в Uart1RXint() осуществляется вызов PrepareRespone1(), который тоже что-то пишет в UDR1 (функции readhr1() и sethr1() ).
Laksus
Я не уверен, но по моему, ожидание отправки байта происходит,
а после окончания отправки группы байт бит TXC вроде-бы остается сброшен.
Да и если бы проблема была в отсутствии ожидания,
то число байт, наверное, отличалось бы от ожидаемого.

Хотя я бы для отправки байтов использовал прерывание UDRE,
а TXC для отключения передатчика, но, по моему, должно работать и так.
______________________

Я глубоко конечно не разбирался, но первая мысль при чтении
Цитата
причем эта самая хрень каждый раз разная. хотя запрос один и тот же.

А не результат ли это работы АЦП? Типа какой-нибудь шум, наводки.

И еще, а Вы пробовали делать ресет. А потом посылать запросы.
То есть, отличаются ли первые, вторые и тд ответы после сброса,
или только первый от второго, второй от третьего (после сброса)?
_________________________________________
Общий совет - надо упрощать пока не пропадет ошибка.
Если Вы, автор, не разберетесь, то постороннему тем-более трудно.


============================================================

Это не по теме, но может Вам будет интересно.
-----------------------------------------------------------

Код
93:        unsigned int tmp=0;
+00000474:   24AA        CLR     R10              Clear Register
+00000475:   24BB        CLR     R11              Clear Register
97:        tmp=ADCL;            //Read 8 low bits first (important)
+00000476:   B0A4        IN      R10,0x04         In from I/O location
+00000477:   24BB        CLR     R11              Clear Register
98:        tmp|=(int)ADCH << 8; //read 2 high bits and shift into top byte
+00000478:   B025        IN      R2,0x05          In from I/O location
+00000479:   2433        CLR     R3               Clear Register
+0000047A:   2C32        MOV     R3,R2            Copy register
+0000047B:   2422        CLR     R2               Clear Register
+0000047C:   28A2        OR      R10,R2           Logical OR
+0000047D:   28B3        OR      R11,R3           Logical OR
100:       sum[adc]=sum[adc]-(sum[adc]>>8)+tmp;

Это, конечно, не ошибка

но, по моему, так красивше
Код
93:        unsigned int tmp=0;
+00000474:   24AA        CLR     R10              Clear Register
+00000475:   24BB        CLR     R11              Clear Register
99:        tmp= ADC;/// А нормальный компилятор должен знать порядок чтения байт
+00000476:   B0A4        IN      R10,0x04         In from I/O location
+00000477:   B0B5        IN      R11,0x05         In from I/O location
100:       sum[adc]=sum[adc]-(sum[adc]>>8)+tmp;

============================================================
И еще, в
Код
unsigned int crc16(void *ptr,unsigned int n)


Код
return ((crcl<<8)|crch);

может надо так?
Код
return ((crch<<8)|crcl);


============================================================
Совершенно мне не ясно, что получим в результате
Код
sum[adc]=sum[adc]-(sum[adc]>>8)+tmp;

но это тоже навряд ли повлияет.
CrazyAlex
Спасибо всем за участие, попробую ответить, может натолкнет на что-то еще.

to Dog Pawlowa

Цитата
В детали ... , но прерывание по передаче мне не нравится. Мне кажется, что должен быть запрет прерывания, если весь буфер передан. Может быть, мега передает больше буфера? (Проверить можно осциллографом или терминалкой)

Проверял терминалкой, в порт уходит нужное число байт.
Цитата
... - или память затирается (проверить, поставив останов в конце передачи), или индекс и длина массива портится во время передачи (проверить аналогично).

Смотрел, все остается как было, ничего не портится.

to Александр Куличок

Цитата
У Вас постоянно осуществляется передача по Uart1TXint(). Одновременно с этим после выставлении флага FrameReady1 в Uart1RXint() осуществляется вызов PrepareRespone1(), который тоже что-то пишет в UDR1 (функции readhr1() и sethr1() ).

Передача по TXint (по опустошению ВСЕХ регистров, участвующих в передаче) осуществляется столько раз сколько записано в UDR, т.е. после записи последнего байта, прерывание вызовется последний раз, и поскольку больше обращения к UDR не было, то и прерывание больше не возникнет. В readhr1 и sethr1 осуществляется первая запись в UDR которая и вызывает первое прерывание Uart1TXint().

to Laksus

Цитата
Хотя я бы для отправки байтов использовал прерывание UDRE,
а TXC для отключения передатчика, но, по моему, должно работать и так.

Ноги такой работы с уартом растут из моего опыта работы с 51. Хотя изначально в Меге я использовал прерывание по UDRE, мне не понравилось. что надо разрешать/запрещать прерывания и я "ушел" на TXC. Мне лично оно кажется более логичным.

Цитата
А не результат ли это работы АЦП? Типа какой-нибудь шум, наводки.

Пробовал, не помогает.

Цитата
И еще, а Вы пробовали делать ресет. А потом посылать запросы.
То есть, отличаются ли первые, вторые и тд ответы после сброса,
или только первый от второго, второй от третьего (после сброса)?

Мысль интересная,попробую проверить.

Цитата
Общий совет - надо упрощать пока не пропадет ошибка.
Если Вы, автор, не разберетесь, то постороннему тем-более трудно.

В общем то, расчет был на то что кто-нибудь сталкивался с подобным.

Цитата
но, по моему, так красивше...
99: tmp= ADC;/// А нормальный компилятор должен знать порядок чтения байт

Дело в том что ImageCraft трудно отнести к нормальным компиляторам :-), но за неимением гербовой...
А эту структуру они сами настоятельно рекомендуют использовать.

Цитата
И еще, в unsigned int crc16(void *ptr,unsigned int n) return ((crcl<<8)|crch);
может надо так? return ((crch<<8)|crcl);

В модбасе сначала идет младший байт срс, а потом старший.

Цитата
Совершенно мне не ясно, что получим в результате
sum[adc]=sum[adc]-(sum[adc]>>8)+tmp;
но это тоже навряд ли повлияет.

Не помню как это правильно называется, навскидку вспоминается "экспоненциальное слаживание" и "скользящее среднее". В данном случае получается усреднение по 256 выборкам (почти среднее, математики оспорят, но меня устраивает).


Еще раз хочу обратить внимание, что на все запросы чтения ответ идет правильный, и на отдельные запросы записи тоже. Битые ответы, идут на строго фиксированные запросы, т.е. на 511 - все ок, на 512 - битый. и еще на некоторые другие запросы (78, 1101).
sensor_ua
void PrepareRespone0(void){
. . .
addr=(frame0[2]<<8)|frame0[3];
value=(frame0[4]<<8)|frame0[5];
. . .
}
value для функции 16 вообще-то сдвинуто на 3 байта -
[0] - unicast address
[1] - function code
[2][3] - reference
[4][5] - word count,
[6] - byte count,
[7][8] - data
нужно:
value=(frame0[7]<<8)|frame0[8];

Ещё открою маленькую тайнуwink.gif - вот так:
crc=crc16((unsigned *)frame0,6);
if (crc==((frame0[7]<<8)|frame0[6]))
делать не надо - досчитав в CRC ещё и последние 2 байта, содержащие CRC, Вы получите (при совпадении конечно) красивый ноль. if(!(crc=crc16((unsigned *)frame0,8))){;}
defunct
Цитата(CrazyAlex @ Jun 4 2007, 09:45) *
Если поставить точку останова на UDR1=frame1[0], и потом по шагам, то все отвечает нормально.

Возможно у вас перетирается буфер.
Насколько это видно из кода программы в тот же буфер frame1 пишутся данные в RX обработчике.

Я бы здесь посоветовал завести два непересекающийхся буфера. Один строго на отправку, второй строго на прием.
oran-be
Цитата
В модбасе сначала идет младший байт срс, а потом старший.

В AVR компиляторах, в частности в IAR, тоже идет сначала младший, потом старший, в отличии от компилеров семейства 51, в частности Keil.


У AVR'ов в UARTе есть еще один глюк (не знаю, правда, может его уже втихаря и починили) - это старт условие запуска приема байта генерируется не по перепаду уровня с 1 на 0, а по уровню 0. То есть, если подключить драйвер 485 к порту и отключить подтяжки, то при переключениии на передачу нога RX повиснет в воздухе и если уровень на ней станет низким и если приемник не будет отключен, то он начнет долбить прерывания. Приемник может в этот момент натворить очень много дел.
CrazyAlex
Спасибо огромное всем кто откликнулся.

Напомнили мне пару вещей, которые надо бы использовать в программах.

Я в свою очередь с"катализировал" работу мысли у народа. smile.gif

А ларчик открывался просто: глючный (полуубитый) преобразователь 232-485 от ADAM.

поставил новый такой же и все стало ОК.

Еще раз всем спасибо.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.