Форум программистов, компьютерный форум, киберфорум
Наши страницы
Микроконтроллеры Atmega AVR
Войти
Регистрация
Восстановить пароль
 
Turgenev
0 / 0 / 1
Регистрация: 14.11.2012
Сообщений: 148
#1

Выход из цикла в функции обработчика прерывания - Atmega AVR микроконтроллер

10.01.2018, 10:07. Просмотров 271. Ответов 5
Метки нет (Все метки)

Здравствуйте. Понадобилась программа работающая по прерыванию, а именно по приему данных через UART. Пишу в CodeVision AVR. Использую терминал RealTerm.
Суть программы: сижу в программе main в цикле while (1){}, жду пока пришлют данные. Пришли данные, срабатывает прерывание и в зависимости от того, что пришло совершаю соответствующее действие. Для примера пришел символ "С" в кодировке ASCII, посредством switch в функции обработчике прерывания (далее ФОП) переключаюсь на соответствующуй код и выполняю его. Всё это я написал, зашил, проверил- все работает, код приведен ниже (для примера в программе мигаем светодиодом на языке С, если по юарту пришел символ "С" и на ассемблере если пришел символ "А" и я отлично понимаю что разницы во времени исполнения не будет для столь малого кода, это просто пример).

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <mega8.h>
#include <stdio.h>
 
//unsigned char  S;
 
interrupt [USART_RXC] void usart_rx_isr(void)
{
switch (UDR){
 
case 67: // если введено C
printf("Blink on C \n\r");
while (1)
{
PORTC.4=1;
PORTC.4=0;
}
break;
 
case 65:  //  если введено A
printf("Blink on Assembler \n\r");
#asm 
START:
SBI  0x15,4
CBI  0x15,4
RJMP START
#endasm 
break;
 
default: printf("WRONG, TRY AGAIN \n\r");
} //скобка закрывающая Switch
 
} //скобка закрывающая ФОП
 
void main(void)
{
printf("Please enter C to blink on C language or A to blink on ASM language \n\r") ;
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 4800
UCSRA=(0<<RXC) | (0<<TXC) | (0<<UDRE) | (0<<FE) | (0<<DOR) | (0<<UPE) | (0<<U2X) | (0<<MPCM);
UCSRB=(1<<RXCIE) | (1<<TXCIE) | (0<<UDRIE) | (1<<RXEN) | (1<<TXEN) | (0<<UCSZ2) | (0<<RXB8) | (0<<TXB8);
UCSRC=(1<<URSEL) | (0<<UMSEL) | (0<<UPM1) | (0<<UPM0) | (0<<USBS) | (1<<UCSZ1) | (1<<UCSZ0) | (0<<UCPOL);
UBRRH=0x00;
UBRRL=0x0C;
 
// Global enable interrupts
#asm("sei")
DDRC.4=1;
PORTC.4=0;
 
while (1)
      {
 
      } 
}
В этой программе мне не хватает возможности выходить из цикла while (1){...} в ФОП при мигании светодиодом, т.е. прислал я символ С- началось мигание; присылаю любой другой символ- ФОП закончилось, возвращаюсь в программу main, сижу в цикле while, жду очередного байта по юарту.
Думал реализовать это посредством немедленного перехода goto, но метка на которую ссылается этот оператор должна быть в пределах ФОП, что по сути тоже самое и делу не поможет.
Дальше думал поставить в цикле while условие, проверяющее содержимое регистра UDR, то есть пока в UDR хранится код символа "C", то выполеняем мигание, как только содержимое регистра UDR изменится новым пришедшим байтом, то выходим из цикла и из ФОП:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
unsigned char T=67;
 
interrupt [USART_RXC] void usart_rx_isr(void)
{
switch (UDR){
 
case 67: // если введено C
printf("Blink on C \n\r");
while (UDR==T) //каждый раз проверяем, введено ли С в UDR
{
PORTC.4=1;
PORTC.4=0;
}
break;
 
}
}
Но это не работает: при вводе символа С светодиод зажигается, но при вводе чего-либо другого ничего не происходит.
Подскажите, пожалуйста, как правильно реализовать выход из этого цикла по средством изменения содержимого регистра UDR?

P.S.: не понимаю почему в первом листинге в 36й строчке сообщение выводится непрерывно забивая весь терминал, пока не появится прерывание, почему? Я же не в цикл его засунул.
http://www.cyberforum.ru/avr/thread2087039.html
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
10.01.2018, 10:07
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Выход из цикла в функции обработчика прерывания (Atmega AVR микроконтроллер):

Принудительный выход из прерывания на СИ
Доброго времени всем форумчанам. Столкнулся с проблемой - нужно выйти из...

Выход из прерывания в нужное место
Доброго дня суток! Есть небольшая задачка. Помогите с решением. При...

Выход из прерывания для CAN (AT90CAN128)
Всем привет! Столкнулся с такой проблемой: Вот моя мейновая функция: void...

Вызов прерывания в обработке прерывания
В программе,нажатие кнопки вызывает прерывание,в котором оно...

Выход из обработчика прерывания
Задача: По прерыванию (нажатие кнопки) нужно покинуть рабочий цикл и передать...

5
COKPOWEHEU
839 / 603 / 137
Регистрация: 09.09.2017
Сообщений: 2,661
10.01.2018, 15:02 #2
Делать сколь-нибудь длинные задержки в прерывании - плохая идея. Самое простое - реализовать автомат состояний и обрабатывать его в основном цикле
На avr-gcc примерно так:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
volatile char cmd=0; //не забываем volatile !
ISR(UART_RXC_vect){
  cmd = UDR; //в прерывании выполняем только самые неотложные действия. Например, сохранение принятого байта в переменную
}
int main(){
...
  while(1){
    if(cmd == 'C'){
      PORTC ^= (1<<4);
      _delay_ms(500);
    }else if(cmd == 'A'){
      PORTC ^= (1<<4);
      _delay_ms(100);
    }
  }
}
Добавлено через 15 минут
C
1
2
3
} //скобка закрывающая Switch
 
} //скобка закрывающая ФОП
Это, конечно, ужас. Вместо того, чтобы освоить форматирование текста пишете комментарии какая скобка чему соответствует. Оно, конечно, можно, но не взамен а в дополнение. Небольшой, как у вас, код, должен быть понятен и без подобных комментариев.
C
1
2
3
4
5
6
7
8
9
10
11
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 4800
UCSRA=(0<<RXC) | (0<<TXC) | (0<<UDRE) | (0<<FE) | (0<<DOR) | (0<<UPE) | (0<<U2X) | (0<<MPCM);
UCSRB=(1<<RXCIE) | (1<<TXCIE) | (0<<UDRIE) | (1<<RXEN) | (1<<TXEN) | (0<<UCSZ2) | (0<<RXB8) | (0<<TXB8);
UCSRC=(1<<URSEL) | (0<<UMSEL) | (0<<UPM1) | (0<<UPM0) | (0<<USBS) | (1<<UCSZ1) | (1<<UCSZ0) | (0<<UCPOL);
UBRRH=0x00;
UBRRL=0x0C;
А-а-а-а, что это за автогенерированный мусор! Вы бы хоть прибрались за cvavr, стыдно должно быть такое людям показывать.
Должно быть примерно так:
C
1
2
3
4
UCSRA = 0;
UCSRB = (1<<RXCIE | 1<<TXCIE | 1<<RXEN | 1<<TXEN);
UCSRC = (1<<URSEL | 0<<UMSEL | 0b00<<UPM0 | 0<<USBS | 0b11<<UCSZ0 | 0<<UCPOL); //async mode, parity:disabled, 0 stop-bits, 8-bit data, non-invert polarity
UBRR = 12;
Обратите внимание что представление данных зависит от них самих. одиночные флаги задаются одним битом (0/1), наборы битов - двоичным числом (как в UCSZ, UPM), делители и прочее - одним десятичным.
1
Turgenev
0 / 0 / 1
Регистрация: 14.11.2012
Сообщений: 148
10.01.2018, 21:35  [ТС] #3
Понял, спасибо.
Не подскажите почему printf на 36й строчке бесконечно выводит в терминал своё сообщение? Вроде так должно было быть если printf был бы в цикле while, но это же не так...
0
ValeryS
Модератор
7124 / 5392 / 669
Регистрация: 14.02.2011
Сообщений: 18,210
10.01.2018, 22:02 #4
Цитата Сообщение от Turgenev Посмотреть сообщение
Не подскажите почему printf на 36й строчке бесконечно выводит в терминал своё сообщение?
наверно потому, что работает тоже с последовательным портом и вызывает прерывание
0
COKPOWEHEU
839 / 603 / 137
Регистрация: 09.09.2017
Сообщений: 2,661
11.01.2018, 11:02 #5
Так он же на вывод работает (UART_TXC / UART_UDRE) а не на ввод (UART_RXC). Скорее, из-за того что прерывания TXC и UDRE разрешены, но обработчики не прописаны, идет обращение к ненастроенной таблице векторов и сброс контроллера.
Разумеется, если в данном случае printf работает через UART, что совсем не обязательно.
0
Kukuxumushu
752 / 475 / 89
Регистрация: 13.06.2015
Сообщений: 1,629
Завершенные тесты: 2
12.01.2018, 22:52 #6
Цитата Сообщение от Turgenev Посмотреть сообщение
в ФОП при мигании светодиодом, т.е. прислал я символ С- началось мигание
У вас вся проблема вот в этой фразе заложена, т.к. вы не описали вариант развития событий, что должно происходить, когда следующий байт придёт по усарту в то время, пока предыдущий ещё "не домигал". Вот когда с этим вопросом определитесь - сразу поймёте куда мигалку вставлять.
0
12.01.2018, 22:52
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
12.01.2018, 22:52
Привет! Вот еще темы с решениями:

Выход из цикла и обработчика события
Пишу код в обработчике события нажатия на кнопку (Visual Studio 2008): ...

Прерывания в ОСи: прототип функции-обработчика
Как реализовать прерывания на C++. Какой должен быть прототип...

Возврат из обработчика прерывания.
Продублирую вопрос сюда, ибо в &quot;Мелких вопросах&quot; висит он неприкаянно: Как...

Замена обработчика прерывания
Здравствуйте! Мне нужно заменить вектор прерывания int 9h, чтобы выполнялись...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru