Перейти к содержанию
    

Дорый день!

 

Немного удивляет поведение юарта в этом МК.

Исходник

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;

он обрабатывает только при первом принятом символе. Дльше никаких дёрганий.

В чем может быть Ошибка.

Спасиба!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Может до строки PORTD &=~0x80; он и не доходит. Попробуй при входе в прерывание запрещать их

asm("cli");

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Немного удивляет поведение юарта в этом МК.

попробуйте вот так хотя я ине уверен

 

#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;

}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Использовал эту мегу в качестве модема с полным управлением потоком. Как програмным так и аппаратным. Делается лет пять (начиналось с at90s4414). Никаких претензий нет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

#pragma vector = USART_RXC_vect
__interrupt void USART_Receive(void)
{
  PORTD |=0x80; 
  USART_Transmit(UDR);
  PORTD &=~0x80;
}

 

.. он обрабатывает только при первом принятом символе. Дльше никаких дёрганий.

В чем может быть Ошибка.

 

Состояние седьмой ноги PortD меняется в прерывании дважды - т.е возвращается в первоначальное состояние - это может быть просто не заметно глазу. Я бы рекомендовал делать просто инверсию бита на 7 ноге. Тогда при первом принятом символе загорится, при втором - потухнет и т.д.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Всем спасибо.

 

 

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

Изменено пользователем Denisvak

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

void USART_Transmit( unsigned char data )

{

while ( !( UCSRA & (1<<5)) );

UDR = data;

}

Я знаю в чем баг. У меня был практически такой же глюк.

Проблема вот в чем:

while ( !( UCSRA & (1<<5)) );

 

Он ждет очистки UDR от предыдущего символа. А так как раньше ничего не отправлялось, то

и ждать он будет до бесконечности.

 

Тоесть надо отправить хотябы один символ. Затем UDR станет пустым и будет выставлятся UDRE флаг.

 

:) Подумайте с чего это биту UDRE быть установленным? если мы до этого ничего не отправляем.

Получается что при первом отправлении запись while ( !( UCSRA & (1<<5)) ); тут не причем.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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;

}

 

тоже неплохо работает, да и взято с того же самого даташита :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 Denisvak - Вообще то при вниматьном прочтении ДШ на этот кристалл замечаем на странице 151 такую вещь как начальное состояние битов регистра UCSRA, так, если приглядется получше то можно увидеть что он изначально установлен в 1.

То есть Amper25 всё правильно написал.

То есть Amper25 написал все с точностью до наоборот. Действительно, UDRE равен единице, UCSR0A & (1<<UDRE0) равен (1<<UDRE0), т.е не нулю, а !(UCSR0A & (1<<UDRE0)) равен нулю. Поэтому никакого зависания в цикле в начале не будет. И ничего отправлять предварительно не нужно.
З.Ы. Мне просто этой ногой нужно переключать направление 485-го.
Тогда вам нужно для выключения передатчика использовать прерывание по TXC

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 Сергей Борщ - я имел ввиду что, согласен с тем что "... запись ( !( UCSRA & (1<<5)) ) - не очень корректная..." - всмысле что тут смотреть надо, и привёл свой пример решения этой задачи.

:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Оператор ! это не побитная инверсия, а логическая.

При этом UCSRA&0х10 = true или false. Инверсия этого будет соответственно false или true.

Так что запись while(!(UCSRA&(1<<5))) правильна.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кстати, недавно была дискуссия по похожему поводу - в операторе if(условие) аргумент "условие" также не был логическим выражением.
Все подобные дискуссии - от отсутствия знаний. Вам уже IgorKossak написал, чем операция ! отличается от операции ~. А про отквоченное - так в книжках по С и в стандарте языка четко сказано: в языке С 0 считается false а все, что не 0 считается true. И никиаких ограничений на "логическость" аргумента оператора if (и while и т.д.) не накладывается. Это одна из основ языка С. Зная ее, приходишь к пониманию, что while ( !( UCSR0A & (1<<UDRE0)) ) - конструкция абсолютно нормальная и правильная.

Возможно, оператор while воспринимает 0хFF, как "true", а всё остальное, как "false", а может и наоборот(:-(,
Нет, в языке С такое невозможно. А если вы такое допускаете - вы не знаете элементарных основ языка С.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вписал туда задержку и все нормально стало.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...