|
UART Mega8, Странное поведенеие |
|
|
|
Apr 26 2007, 16:29
|
Частый гость
 
Группа: Участник
Сообщений: 141
Регистрация: 7-03-06
Из: Санкт-Петербург
Пользователь №: 15 038

|
Дорый день! Немного удивляет поведение юарта в этом МК. Исходник Код void main( void ) { UCSRA=0x00;//UART init UCSRB=0x98; UCSRC=0x86; UBRRH=0x00; UBRRL=0x5F;
DDRC |=0x03; DDRD |=0x80; PORTC=0x00; asm("sei"); while(1) { } } void USART_Transmit( unsigned char data ) { while ( !( UCSRA & (1<<5)) ); UDR = data; } Обработчик Код #pragma vector = USART_RXC_vect __interrupt void USART_Receive(void) { PORTD |=0x80; USART_Transmit(UDR); PORTD &=~0x80; } Прикол в том что если с терминала ему слать данные то он нормально отвечает то что и принял. А вот строки Код PORTD |=0x80; и Код PORTD &=~0x80; он обрабатывает только при первом принятом символе. Дльше никаких дёрганий. В чем может быть Ошибка. Спасиба!!!
|
|
|
|
|
Apr 26 2007, 17:29
|

Местный
  
Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530

|
Цитата(Denisvak @ Apr 26 2007, 16:29)  Немного удивляет поведение юарта в этом МК. попробуйте вот так хотя я ине уверен #define UDRE 5 char i=0; void USART_Transmit( unsigned char data ) { if (i =1){ while ( !( UCSRA & (1<<UDRE)) ); UDR = data; } i =0; } Обработчик #pragma vector = USART_RXC_vect __interrupt void USART_Receive(void) { i = 1; PORTD |=0x80; data = UDR; USART_Transmit(data); PORTD &=~0x80; }
--------------------
нельзя недооценивать предсказуемость глупости
|
|
|
|
|
Apr 26 2007, 19:28
|
Участник

Группа: Новичок
Сообщений: 41
Регистрация: 7-02-05
Пользователь №: 2 473

|
Цитата(Denisvak @ Apr 26 2007, 17:29)  Код #pragma vector = USART_RXC_vect __interrupt void USART_Receive(void) { PORTD |=0x80; USART_Transmit(UDR); PORTD &=~0x80; } .. он обрабатывает только при первом принятом символе. Дльше никаких дёрганий. В чем может быть Ошибка. Состояние седьмой ноги PortD меняется в прерывании дважды - т.е возвращается в первоначальное состояние - это может быть просто не заметно глазу. Я бы рекомендовал делать просто инверсию бита на 7 ноге. Тогда при первом принятом символе загорится, при втором - потухнет и т.д.
|
|
|
|
|
Apr 26 2007, 20:42
|
Частый гость
 
Группа: Участник
Сообщений: 141
Регистрация: 7-03-06
Из: Санкт-Петербург
Пользователь №: 15 038

|
Цитата(Amper25 @ Apr 26 2007, 21:21)  void USART_Transmit( unsigned char data ) { while ( !( UCSRA & (1<<5)) ); UDR = data; } Я знаю в чем баг. У меня был практически такой же глюк. Проблема вот в чем: while ( !( UCSRA & (1<<5)) );
Он ждет очистки UDR от предыдущего символа. А так как раньше ничего не отправлялось, то и ждать он будет до бесконечности.
Тоесть надо отправить хотябы один символ. Затем UDR станет пустым и будет выставлятся UDRE флаг.  Подумайте с чего это биту UDRE быть установленным? если мы до этого ничего не отправляем. Получается что при первом отправлении запись while ( !( UCSRA & (1<<5)) ); тут не причем.
|
|
|
|
|
Apr 26 2007, 21:13
|

Гуру
     
Группа: Свой
Сообщений: 3 304
Регистрация: 13-02-07
Из: 55°55′5″ 37°52′16″
Пользователь №: 25 329

|
2 Denisvak - Вообще то при вниматьном прочтении ДШ на этот кристалл замечаем на странице 151 такую вещь как начальное состояние битов регистра UCSRA, так, если приглядется получше то можно увидеть что он изначально установлен в 1. То есть Amper25 всё правильно написал. Но на счёт ( ( UCSRA & (1<<5)) != 0x00 ) - я думаю это уж слишком... Это - //send char proc void USART_Transmit( unsigned char data ) { /* Wait for empty transmit buffer */ while ( !( UCSR0A & (1<<UDRE0)) ) ; /* Put data into buffer, sends the data */ UDR0 = data; } тоже неплохо работает, да и взято с того же самого даташита
|
|
|
|
|
Apr 26 2007, 22:21
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(Kuzmi4 @ Apr 26 2007, 20:13)  2 Denisvak - Вообще то при вниматьном прочтении ДШ на этот кристалл замечаем на странице 151 такую вещь как начальное состояние битов регистра UCSRA, так, если приглядется получше то можно увидеть что он изначально установлен в 1. То есть Amper25 всё правильно написал. То есть Amper25 написал все с точностью до наоборот. Действительно, UDRE равен единице, UCSR0A & (1<<UDRE0) равен (1<<UDRE0), т.е не нулю, а !(UCSR0A & (1<<UDRE0)) равен нулю. Поэтому никакого зависания в цикле в начале не будет. И ничего отправлять предварительно не нужно. Цитата(Denisvak @ Apr 26 2007, 18:51)  З.Ы. Мне просто этой ногой нужно переключать направление 485-го. Тогда вам нужно для выключения передатчика использовать прерывание по TXC
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 27 2007, 02:01
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(Amper25 @ Apr 26 2007, 17:21)  Кстати, запись ( !( UCSRA & (1<<5)) ) - не очень корректная. Лучше использовать ( ( UCSRA & (1<<5)) != 0x00 ). А умный компилятор с оптимизатором потом сам все упростит. Вы совершенно правы, говоря, что запись while(!(UCSRA&(1<<5))) - не очень корректна. Я бы сказал совсем некорректна. И вот почему. В операторе while (условие) {...;...;...}; аргумент "условие" должен быть логическим выражением, а оператор выполняется до тех пор, пока это условие равно "true". Что мы имеем в нашем случае? UCSRA&(1<<5) или UCSRA&0х10 есть побитное логическое "И" двух восьмибитных операндов - содержимого регистра UCSRA и числа 0х10. Результат может быть равен или 0х00 или 0х10. Далее идёт побитная инверсия результата, т.е. будет 0хFF или 0xEF. В итоге будет либо оператор while(0хFF), либо оператор while(0хЕF). Неожиданный результат, не так ли? Не знаю, как вся конструкция работает, могу только предполагать. Например, для данного компилятора 0х00 - это "false", а инверсная к нему величина 0хFF - "true". Возможно, оператор while воспринимает 0хFF, как "true", а всё остальное, как "false", а может и наоборот(:-(, надо смотреть код после компилятора. Ну вот, чтобы избежать таких подвохов, надо писать правильно, а именно while((UCSRA & (1<<5))==0х00); //стоять здесь и ждать, пока бит UDRE не станет равным 1. Так что, примеры, приведенные в даташитах, не всегда верны(:-(. Кстати, недавно была дискуссия по похожему поводу - в операторе if(условие) аргумент "условие" также не был логическим выражением.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Apr 27 2007, 09:55
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(=GM= @ Apr 27 2007, 01:01)  Кстати, недавно была дискуссия по похожему поводу - в операторе if(условие) аргумент "условие" также не был логическим выражением. Все подобные дискуссии - от отсутствия знаний. Вам уже IgorKossak написал, чем операция ! отличается от операции ~. А про отквоченное - так в книжках по С и в стандарте языка четко сказано: в языке С 0 считается false а все, что не 0 считается true. И никиаких ограничений на "логическость" аргумента оператора if (и while и т.д.) не накладывается. Это одна из основ языка С. Зная ее, приходишь к пониманию, что while ( !( UCSR0A & (1<<UDRE0)) ) - конструкция абсолютно нормальная и правильная. Цитата(=GM= @ Apr 27 2007, 01:01)  Возможно, оператор while воспринимает 0хFF, как "true", а всё остальное, как "false", а может и наоборот(:-(, Нет, в языке С такое невозможно. А если вы такое допускаете - вы не знаете элементарных основ языка С.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 27 2007, 11:14
|
Участник

Группа: Новичок
Сообщений: 41
Регистрация: 7-02-05
Пользователь №: 2 473

|
Цитата(Denisvak @ Apr 26 2007, 20:51)  Вписал туда задержку и все нормально стало. Вставлять в обработчик прерывания задержку равно, как и ожидание, обсуждаемое выше - плохой стиль. Лучше, тот же Transmit вызывать в бесконечном цикле по флагу в main_e, а в прерывании этот самый флаг взводить.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|