Denisvak 0 26 апреля, 2007 Опубликовано 26 апреля, 2007 · Жалоба Дорый день! Немного удивляет поведение юарта в этом МК. Исходник 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; он обрабатывает только при первом принятом символе. Дльше никаких дёрганий. В чем может быть Ошибка. Спасиба!!! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexBoy 0 26 апреля, 2007 Опубликовано 26 апреля, 2007 · Жалоба Может до строки PORTD &=~0x80; он и не доходит. Попробуй при входе в прерывание запрещать их asm("cli"); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sKWO 0 26 апреля, 2007 Опубликовано 26 апреля, 2007 · Жалоба Немного удивляет поведение юарта в этом МК. попробуйте вот так хотя я ине уверен #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; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SapegoAL 0 26 апреля, 2007 Опубликовано 26 апреля, 2007 · Жалоба Использовал эту мегу в качестве модема с полным управлением потоком. Как програмным так и аппаратным. Делается лет пять (начиналось с at90s4414). Никаких претензий нет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
freux 0 26 апреля, 2007 Опубликовано 26 апреля, 2007 · Жалоба #pragma vector = USART_RXC_vect __interrupt void USART_Receive(void) { PORTD |=0x80; USART_Transmit(UDR); PORTD &=~0x80; } .. он обрабатывает только при первом принятом символе. Дльше никаких дёрганий. В чем может быть Ошибка. Состояние седьмой ноги PortD меняется в прерывании дважды - т.е возвращается в первоначальное состояние - это может быть просто не заметно глазу. Я бы рекомендовал делать просто инверсию бита на 7 ноге. Тогда при первом принятом символе загорится, при втором - потухнет и т.д. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Denisvak 0 26 апреля, 2007 Опубликовано 26 апреля, 2007 (изменено) · Жалоба По ходу дела все таки он их обрабатывает, просто я осцилом не замечаю. Вписал туда задержку и все нормально стало. Интересно только почему он первый раз прерывание дольше обрабатывает. первую посылку я успеваю заметить. Всем спасибо. З.Ы. Мне просто этой ногой нужно переключать направление 485-го. Изменено 26 апреля, 2007 пользователем Denisvak Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Amper25 0 26 апреля, 2007 Опубликовано 26 апреля, 2007 (изменено) · Жалоба void USART_Transmit( unsigned char data ) { while ( !( UCSRA & (1<<5)) ); UDR = data; } Я знаю в чем баг. У меня был практически такой же глюк. Проблема вот в чем: while ( !( UCSRA & (1<<5)) ); Он ждет очистки UDR от предыдущего символа. А так как раньше ничего не отправлялось, то и ждать он будет до бесконечности. Тоесть надо отправить хотябы один символ. Затем UDR станет пустым и будет выставлятся UDRE флаг. Кстати, запись ( !( UCSRA & (1<<5)) ) - не очень корректная. Лучше использовать ( ( UCSRA & (1<<5)) != 0x00 ). А умный компилятор с оптимизатором потом сам все упростит. Изменено 26 апреля, 2007 пользователем Amper25 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Denisvak 0 26 апреля, 2007 Опубликовано 26 апреля, 2007 · Жалоба void USART_Transmit( unsigned char data ) { while ( !( UCSRA & (1<<5)) ); UDR = data; } Я знаю в чем баг. У меня был практически такой же глюк. Проблема вот в чем: while ( !( UCSRA & (1<<5)) ); Он ждет очистки UDR от предыдущего символа. А так как раньше ничего не отправлялось, то и ждать он будет до бесконечности. Тоесть надо отправить хотябы один символ. Затем UDR станет пустым и будет выставлятся UDRE флаг. :) Подумайте с чего это биту UDRE быть установленным? если мы до этого ничего не отправляем. Получается что при первом отправлении запись while ( !( UCSRA & (1<<5)) ); тут не причем. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kuzmi4 0 26 апреля, 2007 Опубликовано 26 апреля, 2007 · Жалоба 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; } тоже неплохо работает, да и взято с того же самого даташита :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 121 26 апреля, 2007 Опубликовано 26 апреля, 2007 · Жалоба 2 Denisvak - Вообще то при вниматьном прочтении ДШ на этот кристалл замечаем на странице 151 такую вещь как начальное состояние битов регистра UCSRA, так, если приглядется получше то можно увидеть что он изначально установлен в 1. То есть Amper25 всё правильно написал. То есть Amper25 написал все с точностью до наоборот. Действительно, UDRE равен единице, UCSR0A & (1<<UDRE0) равен (1<<UDRE0), т.е не нулю, а !(UCSR0A & (1<<UDRE0)) равен нулю. Поэтому никакого зависания в цикле в начале не будет. И ничего отправлять предварительно не нужно.З.Ы. Мне просто этой ногой нужно переключать направление 485-го.Тогда вам нужно для выключения передатчика использовать прерывание по TXC Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
=GM= 0 27 апреля, 2007 Опубликовано 27 апреля, 2007 · Жалоба Кстати, запись ( !( 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(условие) аргумент "условие" также не был логическим выражением. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kuzmi4 0 27 апреля, 2007 Опубликовано 27 апреля, 2007 · Жалоба 2 Сергей Борщ - я имел ввиду что, согласен с тем что "... запись ( !( UCSRA & (1<<5)) ) - не очень корректная..." - всмысле что тут смотреть надо, и привёл свой пример решения этой задачи. :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
IgorKossak 0 27 апреля, 2007 Опубликовано 27 апреля, 2007 · Жалоба Оператор ! это не побитная инверсия, а логическая. При этом UCSRA&0х10 = true или false. Инверсия этого будет соответственно false или true. Так что запись while(!(UCSRA&(1<<5))) правильна. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 121 27 апреля, 2007 Опубликовано 27 апреля, 2007 · Жалоба Кстати, недавно была дискуссия по похожему поводу - в операторе if(условие) аргумент "условие" также не был логическим выражением.Все подобные дискуссии - от отсутствия знаний. Вам уже IgorKossak написал, чем операция ! отличается от операции ~. А про отквоченное - так в книжках по С и в стандарте языка четко сказано: в языке С 0 считается false а все, что не 0 считается true. И никиаких ограничений на "логическость" аргумента оператора if (и while и т.д.) не накладывается. Это одна из основ языка С. Зная ее, приходишь к пониманию, что while ( !( UCSR0A & (1<<UDRE0)) ) - конструкция абсолютно нормальная и правильная. Возможно, оператор while воспринимает 0хFF, как "true", а всё остальное, как "false", а может и наоборот(:-(,Нет, в языке С такое невозможно. А если вы такое допускаете - вы не знаете элементарных основ языка С. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
freux 0 27 апреля, 2007 Опубликовано 27 апреля, 2007 · Жалоба Вписал туда задержку и все нормально стало. Вставлять в обработчик прерывания задержку равно, как и ожидание, обсуждаемое выше - плохой стиль. Лучше, тот же Transmit вызывать в бесконечном цикле по флагу в main_e, а в прерывании этот самый флаг взводить. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться