реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> UART Mega8, Странное поведенеие
Denisvak
сообщение Apr 26 2007, 16:29
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 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;
он обрабатывает только при первом принятом символе. Дльше никаких дёрганий.
В чем может быть Ошибка.
Спасиба!!!
Go to the top of the page
 
+Quote Post
AlexBoy
сообщение Apr 26 2007, 16:43
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 205
Регистрация: 19-12-05
Из: Kiev
Пользователь №: 12 394



Может до строки PORTD &=~0x80; он и не доходит. Попробуй при входе в прерывание запрещать их
asm("cli");
Go to the top of the page
 
+Quote Post
sKWO
сообщение Apr 26 2007, 17:29
Сообщение #3


Местный
***

Группа: Участник
Сообщений: 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;
}


--------------------
нельзя недооценивать предсказуемость глупости
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Apr 26 2007, 19:09
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Использовал эту мегу в качестве модема с полным управлением потоком. Как програмным так и аппаратным. Делается лет пять (начиналось с at90s4414). Никаких претензий нет.
Go to the top of the page
 
+Quote Post
freux
сообщение Apr 26 2007, 19:28
Сообщение #5


Участник
*

Группа: Новичок
Сообщений: 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 ноге. Тогда при первом принятом символе загорится, при втором - потухнет и т.д.
Go to the top of the page
 
+Quote Post
Denisvak
сообщение Apr 26 2007, 19:51
Сообщение #6


Частый гость
**

Группа: Участник
Сообщений: 141
Регистрация: 7-03-06
Из: Санкт-Петербург
Пользователь №: 15 038



По ходу дела все таки он их обрабатывает, просто я осцилом не замечаю. Вписал туда задержку и все нормально стало.
Интересно только почему он первый раз прерывание дольше обрабатывает. первую посылку я успеваю заметить.
Всем спасибо.


З.Ы. Мне просто этой ногой нужно переключать направление 485-го.

Сообщение отредактировал Denisvak - Apr 26 2007, 19:53
Go to the top of the page
 
+Quote Post
Amper25
сообщение Apr 26 2007, 20:21
Сообщение #7


Местный
***

Группа: Свой
Сообщений: 215
Регистрация: 10-04-07
Пользователь №: 26 929



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 ).
А умный компилятор с оптимизатором потом сам все упростит.

Сообщение отредактировал Amper25 - Apr 26 2007, 20:26
Go to the top of the page
 
+Quote Post
Denisvak
сообщение Apr 26 2007, 20:42
Сообщение #8


Частый гость
**

Группа: Участник
Сообщений: 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 флаг.


smile.gif Подумайте с чего это биту UDRE быть установленным? если мы до этого ничего не отправляем.
Получается что при первом отправлении запись while ( !( UCSRA & (1<<5)) ); тут не причем.
Go to the top of the page
 
+Quote Post
Kuzmi4
сообщение Apr 26 2007, 21:13
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 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;
}

тоже неплохо работает, да и взято с того же самого даташита smile.gif
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Apr 26 2007, 22:21
Сообщение #10


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
=GM=
сообщение Apr 27 2007, 02:01
Сообщение #11


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(условие) аргумент "условие" также не был логическим выражением.


--------------------
Делай сразу хорошо, плохо само получится
Go to the top of the page
 
+Quote Post
Kuzmi4
сообщение Apr 27 2007, 08:33
Сообщение #12


Гуру
******

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



2 Сергей Борщ - я имел ввиду что, согласен с тем что "... запись ( !( UCSRA & (1<<5)) ) - не очень корректная..." - всмысле что тут смотреть надо, и привёл свой пример решения этой задачи.
smile.gif
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Apr 27 2007, 09:39
Сообщение #13


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



Оператор ! это не побитная инверсия, а логическая.
При этом UCSRA&0х10 = true или false. Инверсия этого будет соответственно false или true.
Так что запись while(!(UCSRA&(1<<5))) правильна.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Apr 27 2007, 09:55
Сообщение #14


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
freux
сообщение Apr 27 2007, 11:14
Сообщение #15


Участник
*

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



Цитата(Denisvak @ Apr 26 2007, 20:51) *
Вписал туда задержку и все нормально стало.

Вставлять в обработчик прерывания задержку равно, как и ожидание, обсуждаемое выше - плохой стиль. Лучше, тот же Transmit вызывать в бесконечном цикле по флагу в main_e, а в прерывании этот самый флаг взводить.
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 19:52
Рейтинг@Mail.ru


Страница сгенерированна за 0.01476 секунд с 7
ELECTRONIX ©2004-2016