Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Прерывание UART
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Timofey
Контроллер - Mega32 16AU
Стоит внешний кварц на 16 МГц
CKSEL=0F (выбран внешний кварц)
Среда программирования IAR for AVR 5.30
Проблема: никак не могу включить прерывание по приему хотя бы одного байта
Код
#include <iom32.h>

#define FOSC              16000000
#define UBRR_9600         (((FOSC/16)/9600)-1)


#pragma vector=USART_RXC_vect
__interrupt void Receive_Byte(void);

__interrupt void Receive_Byte(void)
{
   unsigned char _data;
   PORTD&=~AVR_PIO_D_OK; //по приему хотя бы одного байта, должен загореться индикатор
   while ( !(UCSRA & (1<<RXC)) );
   _data = UDR;
}

void Init_UART (void)
{  
   Set_DE(0);
   UBRRH = (unsigned char)(UBRR_9600>>8);
   UBRRL = (unsigned char)(UBRR_9600);
  
   UCSRB = ((1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<TXCIE));
  
   UCSRC = ((1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0)|(1<<UPM1)|(1<<UPM0));//8bit,stop-bit 1, part - ODD  
}

Запускаю терминал, выставляю настройки порта нужные, отправляю один байт - индикатор не горит.
Осцилографом посмотрел, байт до контроллера доходит, но прерывание так и не срабатывает.
Сама программа при этом запускается и работает нормально (другой светодиод моргает). Что нужно еще установить (включить)?
Спасибо.

З.Ы. Как сделать так, чтобы код в посте был компактный (с прокруткой), а не занимал большую часть поста?
MrYuran
А разрешить прерывания не забыли?

Цитата(Timofey @ Jun 1 2010, 09:09) *
З.Ы. Как сделать так, чтобы код в посте был компактный (с прокруткой), а не занимал большую часть поста?

Используйте тэг
codebox
...
/codebox
Вверху слева менюшка "спец.элементы"
Timofey
Включил и прерывания и приемник с передатчиком
Код
UCSRB = ((1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<TXCIE));
Сергей Борщ
Цитата(Timofey @ Jun 1 2010, 09:14) *
Включил и прерывания и приемник с передатчиком
Теперь выкиньте цикл while ( !(UCSRA & (1<<RXC)) ); из обработчика прерывания и ту книгу, в которой вы такой пример нашли.
GDI
В симуляторе проверьте, все ли регистры реально правильно загружаются.
mempfis_
Код
__interrupt void Receive_Byte(void)
{
   unsigned char _data;
   PORTD&=~AVR_PIO_D_OK; //по приему хотя бы одного байта, должен загореться индикатор
   while ( !(UCSRA & (1<<RXC)) );
   _data = UDR;
}


Не надо тут опрашивать флаг - он сам сбросится.

А перед основным циклом программы прерывания разрешили? (команда __enable_interrupt())
Timofey
Цитата(Сергей Борщ @ Jun 1 2010, 12:31) *


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

Цитата(GDI @ Jun 1 2010, 12:31) *

В симуляторе получилось следующее:
Сначала загружаются регистры UBRRH, UBRRL, UCSRB. Все значения, которые и требовались
Когда происходить запись в регистр UCSRC, одновременно вижу, что тоже самое и в регистре UBRRH. Но это, я так понимаю, потому что по одному адресу расположены.
MrYuran
Цитата(Timofey @ Jun 1 2010, 10:14) *
Включил и прерывания и приемник с передатчиком
Код
UCSRB = ((1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<TXCIE));

Глобальный флаг надо разрешить, иначе все остальные будут хлопать впустую.
По умолчанию он запрещён.
Timofey
Все, заработало. Всем спасибо. Тема закрыта.
Karaox
Доброго времени суток!
Я новичок в девайсостроении и у меня аналогичный, как мне кажется, случай, только у меня, по-моему, не «глобальное разрешение прерываний».
Помогите, пожалуйста, разобраться в следующем:
В моём устройстве используется МК ATMega8L, который связывается по SPI с некоторым сторонним устройством, и по USART с BlueTooth модулем BlueNiceCom IV от AMBER wireless (AMB2300). Ноги USART’a соединены: крест накрест TX_BT (на ВТ-модуле) <--> RXD (на МК), RX_BT <--> TXD, CTS_BT <--> RTS, RTS_BT <--> CTS. RTS (output, active low), CTS (input, active low) – на МК выделенные мной ножки для контроля протокола. СTS на МК фактически не используется.
К МК написана прошивка на базе WinAVR 4.1.1 (WinAVR 20070122).
МК работает от внутреннего калибруемого RC осциллятора на частоте 2 МГц, конфигурационные биты и калибрующее значение для внутреннего генератора читаются и шьются (как и прошивка) программатором ChipProg-ISP без проблем и ругани со стороны программатора.
На старте МК RTS на МК выставляется в low, после чего инициализируется USART следующим кодом:

CODE
cli();

//9600 на 2000 кГц;
UBRRH = 0;
UBRRL = 12;

UCSRB = (1<<RXEN) | (1<<TXEN);
UCSRB = UCSRB | (1<<RXCIE);

sei();


Скорость, я вроде, установил правильно – проверял по таблице в Datasheet’е ATMega8L, остальные параметра как я понимаю всё тот же Datasheet автоматически выставляются в 8-битовый кадр без чётности и 1 стоп битом, чего собственно и хочется.

Далее устройство работает – по прерыванию таймера2 в SPI выдаётся сигнал и принимающее устройство его читает и реагирует как надо, т.е. правильно. Тут проблем нет.
Но вот при попытке связаться с этой конструкцией через BlueTooth’у с компа происходит следующее: после отсылки с компа через терминальную программу (порт, формат кадра, чётность и т.п. настроены правильно) на ножке RXD МК (и естественно на TX_BT) я осциллографом вижу приходящие биты, но вот прерывания приёма в МК НЕ ВОЗНИКАЕТ! (по прерыванию приёма МК должен перевести одну из свободных ног в высокое состояние – чего не происходит):

Код в прерывании:


CODE
ISR(USART_RXC_vect)
{

PORT_TEST = PORT_TEST | (1<<NUM_TEST); //Тестовая нога;

PORT_RTS = PORT_RTS | (1<<NUM_RTS);

/*код обработки принятого байта*/

PORT_RTS = PORT_RTS & ~(1<<NUM_RTS);
}


При этом имена прерываний заданы правильно (проверял по инструкции к WinAVR) и компилятор не ругается на то, что это «похоже на misspelled interrupt name…»

Помогите понять, что именно я упустил из виду.
Заранее благодарен.
defunct
Цитата(Karaox @ Sep 13 2010, 12:19) *
Помогите понять, что именно я упустил из виду.


Возможно вы забыли сконфигурировать UCSRC:

Код
    UBRRH = (temp >> 8) & 0x0F;  <-- bod rate
    UBRRL = (temp & 0xFF);

    UCSRB = (1 << RXEN) | (1 << TXEN) | (1 << RXCIE) | (1 << TXCIE); // interrupt driven config
    UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0); // 8 bit, 1 stop
=GM=
Karaox, чтобы сработало Receive Complete interrupt, надо ещё разрешить бит RXC в UCSRA.

И зачем вы дёргаете RTS в прерывании по приёму? RTS (цепь 105) нужна для начала передачи в модем, а не для приёма из него.
defunct
Цитата(=GM= @ Sep 13 2010, 18:41) *
RTS (цепь 105) нужна для начала передачи в модем, а не для приёма из него.

RTS/CTS handshaking
Further information: Hardware flow control
In older versions of the specification, RS-232's use of the RTS and CTS lines is asymmetric: The DTE asserts RTS to indicate a desire to transmit to the DCE, and the DCE asserts CTS in response to grant permission. This allows for half-duplex modems that disable their transmitters when not required, and must transmit a synchronization preamble to the receiver when they are re-enabled. This scheme is also employed on present-day RS-232 to RS-485 converters, where the RS-232's RTS signal is used to ask the converter to take control of the RS-485 bus - a concept that doesn't otherwise exist in RS-232. There is no way for the DTE to indicate that it is unable to accept data from the DCE.

A non-standard symmetric alternative, commonly called "RTS/CTS handshaking," was developed by various equipment manufacturers: CTS indicates permission from the DCE for the DTE to send data to the DCE (and is controlled by the DCE independent of RTS), and RTS indicates permission from the DTE for the DCE to send data to the DTE. This was eventually codified in version RS-232-E (actually TIA-232-E by that time) by defining a new signal, "RTR (Ready to Receive)," which is CCITT V.24 circuit 133. TIA-232-E and the corresponding international standards were updated to show that circuit 133, when implemented, shares the same pin as RTS (Request to Send), and that when 133 is in use, RTS is assumed by the DCE to be ON at all times.[9]

Thus, with this alternative usage, one can think of RTS asserted (positive voltage, logic 0) meaning that the DTE is indicating it is "ready to receive" from the DCE, rather than requesting permission from the DCE to send characters to the DCE.

Note that equipment using this protocol must be prepared to buffer some extra data, since a transmission may have begun just before the control line state change.


Для embedded модемов / bluetooth модулей чаще применяется симметричная схема в виду особенности их принемения - где в системе может не быть досаточно большого буфера чтобы принимать все подряд от модема.
С помощью RTS сигнала сообщается модему, что система "готова принимать данные".
Karaox
Благодарю за ответы.

to defunct:

в datasheet’е при описании регистра UCSRC говорится, что значения необходимые для 8 битного кадра с 1 стоп битом асинхронной передачей задаются как значения по умолчанию.
Тем не менее, я воспользовался Вашим кодом и задал эти значения явно. К сожалению, к желаемому результату это не привело.

to =GM=:

Опять таки по datasheet’у этот бит описывается как с возможностью только чтения и говориться, что он 0 по умолчанию и что он выставляется автоматически в 1 когда в приёмный буфер (регистр UDR, как я понимаю) приходят данные и они не прочитаны, а как только я их читаю (что я делаю в обработчике прерывания) RXC сбрасывается.
Я вставил в код строку UCSRA = UCSRA | (1 << RXC) до начала работы с USATR. Это, к сожалению, также не помогло.

Как новичок, я возможно запутался в названии ног. Нога RTS (Request To Send =запрос на передачу) на МК в моём коде названа так мной и физически подключена к входу CTS_BT (Clear To Send = можно передавать), названным так производителем BlueTooth модуля. Переводя её в высокое состояние я думал запретить приём данных на время обработки принятого байта в прерывании. Собственно, когда я так делал в основном цикле программы – вне прерывания поток данных от BlueTooth модуля действительно был остановлен, а RX стала постоянно высоким, так, кажется, и должно быть.

Буду благодарен за любые советы!
defunct
Цитата(Karaox @ Sep 14 2010, 07:28) *
Как новичок, я возможно запутался в названии ног. Нога RTS (Request To Send =запрос на передачу) на МК в моём коде названа так мной и физически подключена к входу CTS_BT (Clear To Send = можно передавать), названным так производителем BlueTooth модуля.

Прочитайте документацию на модуль, что предполагает сигнал CTS_BT, т.к. в стандарте двояко...
Обычно достаточно RTS константно держать в 0 весь сеанс связи.

Цитата
Буду благодарен за любые советы!

1. Попробуйте разрешить TXC прерывание, и отправить пару символов чтобы проверить возникают ли TX прерывания.

После чего
2. Закоротите пины TX / RX на МК, при этом отключив их от BlueTooth модуля, и повторите отправку - чтобы убедиться возникает ли RXC прерывание в loopback.
Karaox
Большое спасибо,
За советы.
Я разобрался в своём вопросе. biggrin.gif
Пишу это, для того, чтобы помочь другим новичкам вроде меня избежать аналогичных проблем.

В моём случае имела место совокупность ошибок:
1. Прерывание приёма на самом деле всё-таки возникало всё это время, однако, в конце кода его обработки (к сожалению, рассматривать её как источник ошибок я стал слишком поздно) стояла строка вида UCSRB = UCSRB | (1<<UDRIE); разрешающая прерывания освобождения буфера USART, обработчик которого не был объявлен, что является багом. Это вызывало циклический RESERT МК, напрочь стирая все следы возникновения прерываний. Нужно было внимательнее партировать код из доступного примера rolleyes.gif
2. после того, как я исправил это, USART всё равно принимал/посылал кашу. Виной было то, что я упустил из виду хрестоматийную истину о важности точного клока для UART – я использовал внутренний генератор системного клока для ATMega8L, который по даташиту «не надёжен». Как только я запаял внешний кварцевый резонатор – всё заработало как надо.

Удачи всём тем, кто работает с USART’ом.
И большое спасибо всем откликнувшимся!
ArtemKAD
Цитата
Виной было то, что я упустил из виду хрестоматийную истину о важности точного клока для UART – я использовал внутренний генератор системного клока для ATMega8L, который по даташиту «не надёжен».

По даташиту он "с завода с точностью +/-3%" для Vcc=5В и температуры 25гр. В принципе должно хватать(+/-5% достаточно) и с температурой меняется не сильно. Но скорее всего у Вас не 5В, а 3В при которых частота 1.9МГц +/-3% т.е. еще на 5% ниже.
Проблема может решаться алгоритмом автокаллибровки по символам из потока если внешнее устройство первым при включении начинает обмен.
Karaox
Цитата(ArtemKAD @ Oct 26 2010, 14:37) *
Но скорее всего у Вас не 5В, а 3В при которых частота 1.9МГц +/-3% т.е. еще на 5% ниже.


Да у меня именно 3В и шла каша.

Цитата(ArtemKAD @ Oct 26 2010, 14:37) *
Проблема может решаться алгоритмом автокаллибровки по символам из потока если внешнее устройство первым при включении начинает обмен.


Автокаллибровка – классная идея, спасибо, возьму на вооружение, на будущее. Типа, когда приёмник в начале калибровки знает, что посылает источник, т.е. первые N пакетов и «устанавливает таблицу соответствия».
ArtemKAD
Цитата
т.е. первые N пакетов и «устанавливает таблицу соответствия».

Достаточно одного символа в котором N фронтов между которыми меряешь времянку. Перепады можно мерять прерыванием по изменению порта (PCINT).
Karaox
Цитата(ArtemKAD @ Oct 26 2010, 23:43) *
Достаточно одного символа в котором N фронтов между которыми меряешь времянку. Перепады можно мерять прерыванием по изменению порта (PCINT).



Никак не возьму в толк как может помочь знание таймингов между фронтами в 1 посылке?
Палыч
Цитата(Karaox @ Nov 25 2010, 14:37) *
Никак не возьму в толк как может помочь знание таймингов между фронтами в 1 посылке?
Вот посмотрите это. И пример применения.
Karaox
Цитата(Палыч @ Nov 25 2010, 18:37) *
Вот посмотрите это. И пример применения.



Большое спасибо! smile.gif
Обязательно посмотрю.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.