Serial теоретический вопрос

Тема в разделе "Проводная и беспроводная связь", создана пользователем issaom, 29 сен 2017.

  1. issaom

    issaom Гуру

    В умных домах этот код конечно вряд-ли кому пригодится - а р/у поделках может быть очень даже:
    Код (C++):
    void setup()
    {
      Serial.begin(9600);
      Serial.setTimeout(1000)
    }

    void loop()
    {
      Serial.readBytes(buffer, length)
      Serial.write(buf, len)
    }
    аналог написанный на прерываниях:
    Arduino ждет поступления пакета информации в течении 1 секунды - случае приема полного пакета
    сразу отвечает и при этом "как бы" может заниматься чем угодно в основном скетче.

    Код (C++):
    // Написано по материалам статьи
    // http://microsin.net/programming/avr/atmega2560-working-with-uart.html

    #include <avr/interrupt.h> //библиотека прерываний
    #include <LiquidCrystal.h> //библиотека дисплея
    LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

    volatile uint8_t IncomArr[4];   //Входящий массив
    volatile uint8_t SendArr[4];    //Отправляемый массив
    volatile uint8_t CountArr;      //Счетчик принятых байтов
    volatile uint16_t TimePipec = 62500;    //Время после которого считаем что связь пропала (mls) 1mls = 62.5 тика

    uint32_t test =0;

    void setup() {
      noInterrupts();           // disable all interrupts
       
      // открываем последовательный порт 0, задаем скорость передачи данных 9600 бод
      UBRR0H = 0;
      UBRR0L = 103; // число 103 соответствует baudrate 9600 при 16MHz. смотреть datasheet нa ATMega 2560
      // UCSR0B.RXCIE0 - обработчик прерывания по наличию в буфере приема данных 1
      // UCSR0B.RXEN0 - разрешение работы приемника, сюда нужно записать 1
      // UCSR0B.TXEN0 - разрешение работы передатчика, сюда нужно записать 1
      UCSR0B = (1 << RXCIE0) | (1 << RXEN0) | (1 << TXEN0);
      UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); //размер слова 8 разрядов

      // (1/16000000)/256 = 62500 (прескалер настроен на коэффициент деления 256)
      // initialize timer5
      TCCR5A = 0;               // сброс битов WGM51, WGM50
      TCCR5B = 0;
      TCNT5  = 0;               // сброс регистр счета тиков
      OCR5A = TimePipec;        // на этом значении счетчика он будет автоматически очищаться (CTC)
      TCCR5B |= (1 << WGM52);   // CTC mode
      TCCR5B |= (1 << CS52);    // 256 prescaler
      TIMSK5 |= (1 << OCIE5A);  // Разрешить прерывание для TIMER5_COMPA_vect

      //прочая хрень
      lcd.begin(20, 4);         //инициализируем дисплей
      pinMode(13, OUTPUT);
     
      interrupts();              // enable all interrupts
    }

    ISR(USART0_RX_vect)                   //Обрабатываем прерывание по поступлению байта
    {
      IncomArr[CountArr] = UDR0;          //принимаем байт во "Входящий массив"
      CountArr++;
      if (CountArr == sizeof(IncomArr)) { // если приняли 4 байта
        TCNT5 = 0;                        // все ОК = сброс таймера
        CountArr = 0;                     // сброс счетчика входящих байт
        PORTB |= _BV(PB7);                // зажигаем светодиод на 13 пине (связь есть)
        int i;                            // отправляем исходящий массив в цикле
        for (i = 0; i < sizeof(SendArr); i++) {
          while ( !( UCSR0A & (1 << UDRE0)) );       // ждем опустошения буфера
          UDR0 = (SendArr[i]);                       // отправляем байт через UART
        }                                            // конец цикла отправки
      }
    }

    ISR(TIMER5_COMPA_vect)          // прошло более чем TimePipec
    {
    PORTB &= ~ _BV(PB7);            // гасим светодиод на 13 пине (связи нет)
    CountArr = 0;                            // ждем новый пакет с первого байта
    }

    void loop() {

      delay(1000);
      test++;
      lcd.setCursor(8, 0);
      lcd.print(test);
      delay(1000);
      test++;
      lcd.setCursor(8, 0);
      lcd.print(test);
      lcd.setCursor(0, 8);
      SendArr[0] = 97; //присваиваем значения элементам массива который хотим отправить
      SendArr[1] = 98;
      SendArr[2] = 99;
      SendArr[3] = 100;
      lcd.setCursor(0, 0);    //печатаем на экране значения которые получили
      lcd.print(char(IncomArr[0]));
      lcd.setCursor(0, 1);
      lcd.print(char(IncomArr[1]));
      lcd.setCursor(0, 2);
      lcd.print(char(IncomArr[2]));
      lcd.setCursor(0, 3);
      lcd.print(char(IncomArr[3]));
    }
     
    ИгорьК нравится это.