+1 голос
Как в среде Arduino IDE остановить выполнение основной программы если пришел байт через аппаратный uart порт (принять его, обработать и вернуться в основную программу) ?
(234 баллов) 1 3 18
исправил

2 Ответы

+3 голосов
 
Лучший ответ

Как написал parovoZZ, можно использовать UART прерывания. В этом случае управление UART придется переделать с помощью регистров. 

#include <avr/interrupt.h> //библиотека прерываний
char c; //байт в который мы считываем данные из uart

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


void setup() {                
  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) 
{
  с = UDR0;//принимаем байт из uart
  if(c == '1'){
    digitalWrite(15, HIGH);
  }else{
    digitalWrite(15, LOW);
  }
}

void loop() {        
}

В данном примере, когда приходят данные вызывается функция ISR(USART0_RX_vect). Не забывайте, что прерывания должны выполняться быстро и не иметь в теле долгого кода.

Есть другой способ. Функция serialEvent(). Она вызывается каждый раз, как заканчивается очередной цикл loop(), если данные пришли. 

В ней также нельзя использовать delay(). Вот пример её использования:

String inputString = "";         // a String to hold incoming data
bool stringComplete = false;  // whether the string is complete

void setup() {
  // initialize serial:
  Serial.begin(9600);
  // reserve 200 bytes for the inputString:
  inputString.reserve(200);
}

void loop() {
  // print the string when a newline arrives:
  if (stringComplete) {
    Serial.println(inputString);
    // clear the string:
    inputString = "";
    stringComplete = false;
  }
}

/*
  SerialEvent occurs whenever a new data comes in the hardware serial RX. This
  routine is run between each time loop() runs, so using delay inside loop can
  delay response. Multiple bytes of data may be available.
*/
void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag so the main loop can
    // do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}

Также можно использовать функцию Serial.available(), которая говорит, есть ли данные в буфере или нет. Можно её использовать перед самыми ресурсозатратными задачами контроллера в loop().

назад (302 баллов) 10 34
выбран назад
0 голосов

Отказаться от ардуиновского класса Serial и всю работу с UART написать на уровне работы с регистрами. Выглядит оно примерно так:

void UART_Init (uint16_t ubrr)
{
    UBRR0H = (uint8_t) (ubrr >> 8);
    UBRR0L = (uint8_t) ubrr;

    UCSR0B = (0 << RXCIE0) | (0 << TXCIE0) | (0 << UDRIE0) | (1 << RXEN0) | (1 << TXEN0);

    UCSR0C = (3 << UCSZ00);        // 1-stop bit, 8 bit data
}

void UART_Transmit (uint8_t data)
{
    while (!(UCSR0A & (1 << UDRE0)))
    ;
    UDR0 = data;
}

uint8_t UART_Receive (void)
{
    while (!(UCSR0A & (1 << RXC0)))
    ;
    return UDR0;
}

(186 баллов) 1 12
исправил
Круто, но не отвечает на вопрос. Если понимаю правильно, вызов `UART_Receive` заблокирует программу пока не придёт байт. А автора интересует, как заниматься своими делами пока не придёт байт. И в этот момент хочется бросить всё, обработать байт, и продолжить выполнение.
Добро пожаловать на Бредборд! Сайт вопросов и ответов на тему Arduino, Raspberry Pi и хоббийной электроники в целом. Цель Бредборда — быть максимально полезным. Поэтому мы строго следим за соблюдением правил, боремся с холиворами и оффтопиком.
  1. issaom

    220 балл(ов)

  2. gokase

    171 балл(ов)

  3. parovoZZ

    120 балл(ов)

  4. a1000

    79 балл(ов)

  5. vasp

    58 балл(ов)

  6. sser

    48 балл(ов)

Награды месяца
1-е место: Raspberry Pi 4 Model B (4 GB RAM)
2-е место: Raspberry Pi 4 Model B (2 GB RAM)
3-е место: Raspberry Pi 4 Model B (1 GB RAM)

...