Прерывание по поступлению байта, USART прерывание - Arduino mega 2560

babtist
Offline
Зарегистрирован: 06.09.2013
Добрый день!

Вот решил разместить здесь мануальчик по работе с прерыванием USART, может кому понадобится.
Мне понадобилось работать с этим прерыванием, но поиск по форуму мне ничего вразумительного недал пришлось гумозить самому вот результат.    

        
           /* ARDUINO MEGA 2560 */
            /* Простой пример */
/* Обработка прерываний по поступлению байта */


#include <avr/interrupt.h> //библиотека прерываний

char s[2];//Массив для приема байтов
int i=0;//счетчик принятых байтов

void USART_Init(int baudrate ) //Функция инициализации USART
 {
   /* Set baud rate */
   UBRR0H = baudrate>>8;
   UBRR0L = baudrate;
   //Разрешение на прием и на передачу через USART, прерывания по поступлению и по опустошению 
   UCSR0B = (1<<RXCIE0)|(1<<TXCIE0)|(1<<RXEN0)|(1<<TXEN0);
   UCSR0C = (1<<UCSZ01)|(1<<UCSZ00); //размер слова 8 разрядов
   sei();
   
 } // USART_Init



// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.
  pinMode(15, OUTPUT);    
 
 USART_Init(103);// число 103 соответствует baudrate 9600 при 16MHz. смотреть datasheet нa ATMega 2560 
}


void USART_Transmit( unsigned char data )//Функция отправки данных
{
  /* Wait for empty transmit buffer */
  while ( !( UCSR0A & (1<<UDRE0)) );
  /* Put data into buffer, sends the data */
  UDR0 = data;
}

unsigned char USART_Receive( void )//Функция приема данных
{
  /* Wait for data to be received */
  while ( !(UCSR0A & (1<<RXC0)) );
  /* Get and return received data from buffer */
  return UDR0;
}

//Обрабатываем прерывание по поступлению байта
ISR(USART0_RX_vect) 
{
  s[i]=UDR0;//принимаем байт в массив char
  i++;
  if (i == 2)//если приняли 2 байта
   {
     if (s[0] == 'o' and s[1] == 'n')//проверяем что приняли, если команду "on"
      {
        digitalWrite(15, HIGH);//зажигаем светодиод
      /* отправляем обратно  в порт команду "on" (типо все ок команда принята) */  
        USART_Transmit('o');
        delay(1);
        USART_Transmit('n');
      }
      
     if (s[0] == 'o' and s[1] == 'f')//проверяем что приняли, если команду "of"
      {
        digitalWrite(15, LOW);//гасим светодиод
      /* отправляем обратно  в порт команду "of" (типо все ок команда принята) */
        USART_Transmit('o');
        delay(1);
        USART_Transmit('f');
      } 
     // сбрасываем все 
     i=0;
     s[0]='0';
     s[1]='0'; 
   }  
}


// the loop routine runs over and over again forever:
void loop() {
             
}

 

maksim
Offline
Зарегистрирован: 12.02.2012
babtist
Offline
Зарегистрирован: 06.09.2013

Ухты тоже не плохо. Спасибо!

Вот мой аналог  этого скетча (файл прошивки весит в три раза меньше) :

           
           /* ARDUINO MEGA 2560 */
            /* Простой пример */
/* Обработка прерываний по поступлению байта */


#include <avr/interrupt.h> //библиотека прерываний

char s[255];//Массив для приема байтов
int i=0;//счетчик принятых байтов

void USART_Init(int baudrate ) //Функция инициализации USART
 {
   /* Set baud rate */
   UBRR0H = baudrate>>8;
   UBRR0L = baudrate;
   //Разрешение на прием и на передачу через USART, прерывания по поступлению и по опустошению 
   UCSR0B = (1<<RXCIE0)|(1<<TXCIE0)|(1<<RXEN0)|(1<<TXEN0);
   UCSR0C = (1<<UCSZ01)|(1<<UCSZ00); //размер слова 8 разрядов
   sei();
   
 } // USART_Init



// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.
  pinMode(15, OUTPUT);    
 
 USART_Init(103);// число 103 соответствует baudrate 9600 при 16MHz. смотреть datasheet нa ATMega 2560 
}


void USART_Transmit( unsigned char data )//Функция отправки данных
{
  /* Wait for empty transmit buffer */
  while ( !( UCSR0A & (1<<UDRE0)) );
  /* Put data into buffer, sends the data */
  UDR0 = data;
}

unsigned char USART_Receive( void )//Функция приема данных
{
  /* Wait for data to be received */
  while ( !(UCSR0A & (1<<RXC0)) );
  /* Get and return received data from buffer */
  return UDR0;
}

//Обрабатываем прерывание по поступлению байта
ISR(USART0_RX_vect) 
{
  s[i]=UDR0;//принимаем байт в массив char
  i++;
  
  if (s[i-1] == '\n')
   {
     for (int i2=0; i2 < i-1; i2++)
      {
        USART_Transmit(s[i2]); 
         delay(1);
       } 
     i=0;
     memset(s, '\0', 255); // Очищаем массив
   }

}


// the loop routine runs over and over again forever:
void loop() {
             
}

 

MDV
Offline
Зарегистрирован: 08.08.2013

бабтист вы на форуме бываете естьвопрос по прерываниям

Garry
Garry аватар
Offline
Зарегистрирован: 07.04.2012

SerialEvent() не работает по прерыванию, а вызывается в главном цикле loop() программы.

Т.о., если поставить большую задержку (или выпонять громоздкий код) в главном цикле,

то получим перезатирание буфера RX.

 

 

issaom
Offline
Зарегистрирован: 22.10.2016

babtist пишет:

Добрый день!

Вот решил разместить здесь мануальчик по работе с прерыванием USART, может кому понадобится.
Мне понадобилось работать с этим прерыванием, но поиск по форуму мне ничего вразумительного недал пришлось гумозить самому вот результат.    

        
           /* ARDUINO MEGA 2560 */
            /* Простой пример */
/* Обработка прерываний по поступлению байта */


#include <avr/interrupt.h> //библиотека прерываний

char s[2];//Массив для приема байтов
int i=0;//счетчик принятых байтов

void USART_Init(int baudrate ) //Функция инициализации USART
 {
   /* Set baud rate */
   UBRR0H = baudrate>>8;
   UBRR0L = baudrate;
   //Разрешение на прием и на передачу через USART, прерывания по поступлению и по опустошению 
   UCSR0B = (1<<RXCIE0)|(1<<TXCIE0)|(1<<RXEN0)|(1<<TXEN0);
   UCSR0C = (1<<UCSZ01)|(1<<UCSZ00); //размер слова 8 разрядов
   sei();
   
 } // USART_Init



// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.
  pinMode(15, OUTPUT);    
 
 USART_Init(103);// число 103 соответствует baudrate 9600 при 16MHz. смотреть datasheet нa ATMega 2560 
}


void USART_Transmit( unsigned char data )//Функция отправки данных
{
  /* Wait for empty transmit buffer */
  while ( !( UCSR0A & (1<<UDRE0)) );
  /* Put data into buffer, sends the data */
  UDR0 = data;
}

unsigned char USART_Receive( void )//Функция приема данных
{
  /* Wait for data to be received */
  while ( !(UCSR0A & (1<<RXC0)) );
  /* Get and return received data from buffer */
  return UDR0;
}

//Обрабатываем прерывание по поступлению байта
ISR(USART0_RX_vect) 
{
  s[i]=UDR0;//принимаем байт в массив char
  i++;
  if (i == 2)//если приняли 2 байта
   {
     if (s[0] == 'o' and s[1] == 'n')//проверяем что приняли, если команду "on"
      {
        digitalWrite(15, HIGH);//зажигаем светодиод
      /* отправляем обратно  в порт команду "on" (типо все ок команда принята) */  
        USART_Transmit('o');
        delay(1);
        USART_Transmit('n');
      }
      
     if (s[0] == 'o' and s[1] == 'f')//проверяем что приняли, если команду "of"
      {
        digitalWrite(15, LOW);//гасим светодиод
      /* отправляем обратно  в порт команду "of" (типо все ок команда принята) */
        USART_Transmit('o');
        delay(1);
        USART_Transmit('f');
      } 
     // сбрасываем все 
     i=0;
     s[0]='0';
     s[1]='0'; 
   }  
}


// the loop routine runs over and over again forever:
void loop() {
             
}

 

Фиговый мануальчик - после отправки данных на терминал Arduino перезагружается
Зачем нужна функция //Функция приема данных ? В которой части кода она используется ?

Aleksk
Offline
Зарегистрирован: 08.06.2016

Код работает , как надо. Ничего не перезагружается. По команде "on" подает 5 вольт на 15 ногу и шлет в сериал  "on", по команде "of" сбрасывает напряжение до нуля и шлет в сериал  "of". 

issaom
Offline
Зарегистрирован: 22.10.2016

Aleksk пишет:

Код работает , как надо. Ничего не перезагружается. По команде "on" подает 5 вольт на 15 ногу и шлет в сериал  "on", по команде "of" сбрасывает напряжение до нуля и шлет в сериал  "of". 

А вы подключите экранчик или еще что-нибудь и результат Вас приятно удивит ;-)

issaom
Offline
Зарегистрирован: 22.10.2016

Где в Вашем коде обработчик (1<<TXCIE0) по опустошению ? Программа действительно все делает до конца, а поскольку обработчика данного прерывания нет Arduino благополучно уходит в перезагрузку обнуляя все переменные (регистры при аварийной перезагрузке не обнуляются) в этом легко убедиться если воткнуть экран и выводить время с помощью функции millis(); Скопировали откуда-то код а как он работает не разобрались.

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Такая длинная обработка в прерывании не есть хорошо... Делаи и диджиталврайты в прерывании это сильно.

and.pi
Offline
Зарегистрирован: 06.01.2020

люди, простите за безграмотность в микроконтроллерах, но в двух словах: зачем в вышеприведенном примере описывается процедура 

unsigned char USART_Receive( void )//Функция приема данных
49 {
50   /* Wait for data to be received */
51   while ( !(UCSR0A & (1<<RXC0)) );
52   /* Get and return received data from buffer */
53   return UDR0;
54 }

если явно она нигде не вызывается?

как она вызывается, в каких условиях, когда...

 

alexbmd
Offline
Зарегистрирован: 15.01.2016

and.pi она не вызывается. т.к. настроен прием по прерыванию. если отключить прерывание то надо задействовать эту функцию.

b707
Offline
Зарегистрирован: 26.05.2017

алекс, на даты смотрим? Вопрос протух давно, да к тому же ваш ответ ну ничего ценного не несет

alexbmd
Offline
Зарегистрирован: 15.01.2016

Привет.  Второй день ни как не получается словить оба спец символа \n\r. Вчера ловил n сегодня r и на этом передача заканчивается.

Принимаю в таком прерывании для nano

ISR(USART_RX_vect) {
  while (!(UCSR0A & (1<<RXC0)));
  switch (UDR0)
  {
    case '1': PORTB |=  (1 << 5); break;
    case '0': PORTB &= ~(1 << 5); break;
    case '\n': UDR0 = 'N'; delay(3); break;
    case '\r': UDR0 = 'R'; delay(3); break;
    default: break;
  }

Подскажите как подправить код чтоб словить оба спец символа ?

b707
Offline
Зарегистрирован: 26.05.2017

alexbmd пишет:

на этом передача заканчивается.

не удивительно. функцию delay() в прерывании использовать нельзя.

Кстати. нафига она тут?

alexbmd
Offline
Зарегистрирован: 15.01.2016

без delay тоже самое. это я уже в конце эксперементировал.  может буфер не успевал опусташаться.

b707
Offline
Зарегистрирован: 26.05.2017

c делей точно работать не будет.  А почему без нее не работает...

Вот вы пишете в другой теме. что понимаете, что по UART приходят байты. Я вот по коду вижу - что нифига не понимаете.

Попробуйте записать свои "\r" "\n" как байты в числовом виде - 100% не уверен. но что-то мне подсказывает. что может помочь

rkit
Онлайн
Зарегистрирован: 23.11.2016

alexbmd пишет:

может буфер не успевал опусташаться.

Какой, в болото, буфер?

alexbmd
Offline
Зарегистрирован: 15.01.2016

b707 если проблема в "байты в числовом виде" ни один вариант не срабатывал бы. логично?

но байты тоже писал. местами строки переставлял , через переменные, флаги и прочее... плюс вообще не понятно вчера N печатал только а сегодня (другая компелация) только R...

b707
Offline
Зарегистрирован: 26.05.2017

alexbmd пишет:

b707 если проблема в "байты в числовом виде" ни один вариант не срабатывал бы. логично?

нет, не логично. Я бы вам вообще посоветовал ничего в программировании исходя из своей логики не решать, ибо вы логику программного кода не понимаете вовсе. Читайте учебники.

Запись '1' - это один символ, а '\n' - это непонятно что, ни два ни полтора, ибо эскейп-последовательности работают только в двойных кавычках.

alexbmd пишет:

но байты тоже писал. местами строки переставлял , через переменные, флаги и прочее... плюс вообще не понятно вчера N печатал только а сегодня (другая компелация) только R...

я ответ давно знаю. И вы тоже. Просто вы - .... ну вы знаете.

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

Я не знаю, почему у вас байты не срабатывали. Может вы их с делеями пробовали, может еще какую хрень учудили. Да и остальной код я не видел. Но сам результат  меня  абсолютно не удивляет

alexbmd
Offline
Зарегистрирован: 15.01.2016
void loop() {
  if (Serial.available()) {
    char c = Serial.read();
    if (c == 10) Serial.println("N ");
    if (c == 13) Serial.println("R ");
    if (c > 32) Serial.print(c);
  }
}

так тоже только R печатает. может это зависит от ардуино монитора ? может он N не предает

b707
Offline
Зарегистрирован: 26.05.2017

alexbmd пишет:

может это зависит от ардуино монитора ? может он N не предает

пипец... а настройки монитора посмотреть?

выделено внизу справа

 

alexbmd
Offline
Зарегистрирован: 15.01.2016

b707 пишет:

Запись '1' - это один символ, а '\n' - это непонятно что, ни два ни полтора, ибо эскейп-последовательности работают только в двойных кавычках.

no comment

alexbmd
Offline
Зарегистрирован: 15.01.2016

вначале написал а потом проверил. всмысле что надо было наоборот. наэксперементировал так что забыл вернуть обратно. снял с ручника. поставил NL&CR. вопрос отпал.

но про полтора и в кавычках это шедевр :)

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

b707 пишет:

'\n' - это непонятно что, ни два ни полтора, ибо эскейп-последовательности работают только в двойных кавычках.

Чойта?  Я что-то пропустил, видимо? Всегда думал, что это вполне себе вменяемый char. '\r','\t' или вапще '\x20'  

b707
Offline
Зарегистрирован: 26.05.2017

alexbmd пишет:

b707 пишет:

Запись '1' - это один символ, а '\n' - это непонятно что, ни два ни полтора, ибо эскейп-последовательности работают только в двойных кавычках.

no comment

Хочешь поспорить? Или просто впервые услыхал?

Читай http://cppstudio.com/post/256/

Цитата:

Все управляющие символы, при использовании, обрамляются двойными кавычками,

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

b707 пишет:

Все управляющие символы, при использовании, обрамляются двойными кавычками,

О_О

alexbmd
Offline
Зарегистрирован: 15.01.2016

а самому проверить c == 10 и c == '\n' ?

пожалуйста https://onlinegdb.com/HktuO1yP_

b707
Offline
Зарегистрирован: 26.05.2017

DetSimen пишет:

b707 пишет:

Все управляющие символы, при использовании, обрамляются двойными кавычками,

О_О

ну не знаю :) меня так учили, что последовательность "\r" - это 0х0d, а '\r' - это просто  '\' + 'r'

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Петрович придёт, расскажет, что неправильно или меня или тебя учили. 

b707
Offline
Зарегистрирован: 26.05.2017

alexbmd пишет:

а самому проверить c == 10 и c == '\n' ?

пожалуйста https://onlinegdb.com/HktuO1yP_

Я с дедсименом разговариваю, а ты не веселись - у тебя "шедевров" на 20 таких как я хватит

 

alexbmd
Offline
Зарегистрирован: 15.01.2016

b707 и что мне тебя тоже к мартышкам послать? все ошибаются . + это (№13) вопрос был.  на форуме о помощи.  чо бычить то сразу

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

b707 пишет:

Я с дедсименом разговариваю, а ты не веселись - у тебя "шедевров" на 20 таких как я хватит

Вопщем, если этот сайт не врёть, то сётаки тебя плохо учили. :) 

b707
Offline
Зарегистрирован: 26.05.2017

alexbmd пишет:

что мне тебя тоже к мартышкам послать? все ошибаются

так посылай. Когда заслуженно - я не обижаюсь.

Но мне хотелось бы, чтобы еще кто-то выступил по двойным кавычкам. Я ж не сейчас это придумал. я это знаю (или "знаю") много лет. да и ссылку вон с подтверждением - выше - нашел в гугле на раз. не один я так думаю. если это ошибка - то распространенная

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Нинаю, я с децтва использовал, допустим, '\t' и не знал, что так делать низя. :) 

b707
Offline
Зарегистрирован: 26.05.2017

DetSimen пишет:

Вопщем, если этот сайт не врёть, то сётаки тебя плохо учили. :) 

ок, поял :) Значит был неправ.

Но я бы все равно вот так

if (c == '\r') {...}

писать не стал бы, байт намного проще с 0x0D сравнивать - да и не ошибешься в типе кавычек

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

b707 пишет:

Но я бы все равно вот так

if (c == '\r') {...}

писать не стал бы, байт намного проще с 0x0D сравнивать - да и не ошибешься в типе кавычек

А я вот даже и не помню, чему соответствует '/n', 0x0D или 0x0А, всегда char именно так и сравнивал, как ты говоришь "не стал бы". 

b707
Offline
Зарегистрирован: 26.05.2017

DetSimen пишет:

А я вот даже и не помню, чему соответствует '/n', 0x0D или 0x0А, всегда char именно так и сравнивал, как ты говоришь "не стал бы". 

да я не настаиваю. У меня просто выбора не было :)

mixail844
Offline
Зарегистрирован: 30.04.2012
если вдаваться в формализм , кмк
char c = '\n';

то же самое что и 

char ch = 'a';
вполне себе правильно , 
a вот 
char ch ="\n";
выстрел , себе в ногу .так как там неявно окажется '\0' в конце , который "затрет" в памяти что бы там нибыло
alexbmd
Offline
Зарегистрирован: 15.01.2016

кстати заметил что некоторые терминалы/девайсы оканчивают строку \n\r а некоторые \r\n
вы как обычно отлавливаете конец строки/передачи ? проверяте оба случая?

т.е. если проверять только что конец это "\n\r" скетч глюканет на другом девайсе/терминале. или както по другому проверяете?

b707
Offline
Зарегистрирован: 26.05.2017

mixail844 пишет:

a вот 
char ch ="\n";
выстрел , себе в ногу

про такое никто и не говорит, тут слева Чар, справа строка - ничего хорошего из этого не выйдет

Ладно, проехали.

"Сколько можно напоминать! я уже принес свои извинения" (с) Покровские ворота :)

b707
Offline
Зарегистрирован: 26.05.2017

alexbmd пишет:

кстати заметил что некоторые терминалы/девайсы оканчивают строку \n\r а некоторые \r\n
вы как обычно отлавливаете конец строки/передачи ? проверяте оба случая?

\n\r - никогда такого не встречал, поэтому не отлавливаю.

 

alexbmd
Offline
Зарегистрирован: 15.01.2016

\r\n 1.8.10 (и ранее/  а выше не проверял) ардуино мне например так шлёт. какойто gsm модем тоже мне так слал... долго тогда еще тупил, тоже считал (до того момента) что может быть только \n\r

alexbmd
Offline
Зарегистрирован: 15.01.2016

mixail844 пишет:

char ch ="\n";

warning: initialization makes integer from pointer without a cast

b707
Offline
Зарегистрирован: 26.05.2017

alexbmd пишет:

\r\n 1.8.10 (и ранее/  а выше не проверял) ардуино мне например так шлёт. какойто gsm модем тоже мне так слал...

Вы опять все перепутали.  Оно и должно слать \r\n

 

Цитата:
долго тогда еще тупил, тоже считал (до того момента) что может быть только \n\r

никакого "тоже" нет, меня не примазывайте. Вы ожидали \n\r, тогда как у всех наоборот.

Есть примеры. чтобы кто-то слал \n\r ?

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

alexbmd пишет:

warning: initialization makes integer from pointer without a cast

Ну а чего вы хотели ? У вас переменная char , а пихаете вы в нее два байта...

Может стоит написать  char ch='\n' ?

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

b707 пишет:

никакого "тоже" нет, меня не примазывайте. Вы ожидали \n\r, тогда как у всех наоборот.

Есть примеры. чтобы кто-то слал \n\r ?

Вот тут кстати нет правил :( И ИМХО нужно писать так, что бы обрабатывалось три варианта 1- \n, 2-\n\r, 3-\r\n 

b707
Offline
Зарегистрирован: 26.05.2017

brokly пишет:

Ну а чего вы хотели ? У вас переменная char , а пихаете вы в нее два байта...

Может стоит написать  char ch='\n' ?

не, это они меня все троллят, что я написал что '\n' писать нельзя :)

Почему-то был уверен. что эскейп-последовательности компилятор обрабатывает только внутри двойных кавычек. Ну и, естесственно, что применять их можно только внутри многосимвольных строк.

 

b707
Offline
Зарегистрирован: 26.05.2017

brokly пишет:

Вот тут кстати нет правил :( И ИМХО нужно писать так, что бы обрабатывалось три варианта 1- \n, 2-\n\r, 3-\r\n 

а оно такое есть? - \n\r

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Аааа, понял :) Ну тогда ch=*(char*)&"\n" .

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

b707 пишет:

brokly пишет:

Вот тут кстати нет правил :( И ИМХО нужно писать так, что бы обрабатывалось три варианта 1- \n, 2-\n\r, 3-\r\n 

а оно такое есть? - \n\r

Конечно !  Еще как.  Даже в терминалке ИДЕ имеет место быть и это не с проста :)