Прерывание по поступлению байта, 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 }

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

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