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

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

  1. issaom

    issaom Гуру

    Есть 2 платы Arduino - связаны через Serial интерфейс. Одна ардуино раз в 0.5 секунды посылает 1 байт. Вторая все время чем-то занята (например печатает какой-нибудь текст на графическом дисплее опрашивает кнопки и.т.п.). В какую сторону смотреть если нужно, чтобы как только пришел байт 2-я ардуино все бросила, отослала 1 байт в ответ , а потом вернулась к своей основной деятельности.
     
  2. rkit

    rkit Гуру

    Прерывание на прием байта, Только надо не забывать, что стандартный класс уже использует его, и если переписать, то класс сломается.
     
  3. Airbus

    Airbus Радиохулиган Модератор

    "Основная деятельность" какая?Blink?
    а тут есть прерывание по приходу байта в USART?
     
  4. rkit

    rkit Гуру

    Есть-есть.
     
  5. issaom

    issaom Гуру

    Ну.... скажем так
    Нет возможности проверять что, пришли данные в основном цикле программы - ответ должен уйти максимально быстро. Нужно что-то типа аналога внешнего прерывания - если такое существует в природе и не требует уровня знаний rkit
    Код (C++):
    void loop()
    {
    //не катит
    if (Serial.available() > 0) {
    }
    }
     
  6. rkit

    rkit Гуру

    Да никаких особых познаний не надо. Сесть, помедитировать часок-другой внимательно над чужими исходниками и даташитом.
     
  7. Unixon

    Unixon Оракул Модератор

    Код секретный? Чем проц занят в основном?
     
  8. rkit

    rkit Гуру

    Не секретный. Все есть на гитхабе в репозитории ардуино. И в других местах тоже наверняка есть. Проц занят лупом, в случае ардуино.
     
  9. b707

    b707 Гуру

    Serial.Event()
     
  10. issaom

    issaom Гуру

    http://forum.amperka.ru/threads/serial-event.9444/
    Не катит - так как от if(Serial.available()>0) в основном цикле ничем не отличается.
     
  11. b707

    b707 Гуру

    Отличается.
    if(Serial.available()>0) в основном цикле сработает лишь тогда, когда до него дойдет очередь.
    Serial.Event() вызывается как только в порт поступают данные, по прерыванию, ПРЕРЫВАЯ основной цикл loop.
    Читайте первоисточник на сайте Arduino.cc. а не какие-то обсуждения
    https://www.arduino.cc/en/Tutorial/SerialEvent
     
  12. issaom

    issaom Гуру

    Его и читал:
    "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"
    А вы сами то читали ?
    Загрузите "блинк" и сами увидите какие там используются прерывания основного цикла - прежде чем давать подобные советы на форуме.
     
  13. b707

    b707 Гуру

    А ты в блинке delay() не используй - и все будет работать. Тебе, как я понял. нужно принимать 1 байт раз в 500мс. Основной цикл, "опрашивающий кнопки" - легко может оборачиваться за 3-5мс, если его правильно написать, конечно. Запас на реагирование огромный.
    С выводом на экран сложнее, но и там код можно разбить на части, не превышающие 30-50мс
     
  14. issaom

    issaom Гуру

    И зачем мне тогда SerialEvent ? Если почитать документацию и как вы сказали "какие-то осуждения" то данное событие насколько я понял наступает только когда программа дойдет до конца цикла void loop() (если по какой-то причине не доходит (есть переходы внутри цикла или бесконечные циклы) то и вообще может не наступить никогда. 50мс в моей задаче уже не приемлемо - мне же еще и пакет вернуть нужно - все это время второе устройство будет простаивать и ждать ответа.
     
  15. Limoney

    Limoney Гик

    SerialEvent вызывается по прерыванию, а в loop() проверяется готовность принятых данных
     
  16. b707

    b707 Гуру

    Если требуется быстрая реакция, цикл loop() должен быть простым и коротким, никаких переходов и уж тем более бесконечных циклов. Вся работа - только в коротких внешних процедурах, запускаемых по таймауту. Повторюсь, если нет жестко закодированных задержек в периферии, в самой сложной программе можно написать loop. который будет оборачиватся в несколько мс
    Хотя. в принципе, согласен, что это не ответ на вопрос. Чтобы обеспечить реально быстрый ответ по Serial. придется копать системные прерывания, а это не просто. Повесить прерывание на пин Rx не поможет, так как библиотека Serial сама использует прерывание и во внешнем прерывании работать не будет
     
    Последнее редактирование: 29 сен 2017
  17. b707

    b707 Гуру

    ИМХО, issaom прав - судя по описанию на arduino.cc. Serial.Event() - не более чем Serial.availiable(), запускаемый системой МЕЖДУ вызовами loop()
    Цитата: This routine is run between each time loop() runs, so using delay inside loop can delay response.
     
  18. Limoney

    Limoney Гик

    Тогда, да - прав
     
  19. rkit

    rkit Гуру

    Исходники ардуино открыты, еще раз замечу. И как вызывается serialEvent посмотреть совсем не сложно. Он вызывается после каждого завершения выполнения loop, если во входящем буфере есть данные.
     
  20. issaom

    issaom Гуру

    Хорошо что в интернете есть люди которые не только посылают в гугл, но и пишут посты на форумах что-бы было чего там искать )))
    Нашел рабочий пример для МЕГИ
    http://arduino.ru/forum/programmiro...niyu-baita-usart-preryvanie-arduino-mega-2560
    Дергаем 18 ножку, одновременно "блинкуя" на 13-й отправляя on и of через консоль :)

    Код (C++):
    #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(13, OUTPUT);
      pinMode(18, 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(18, HIGH);//зажигаем светодиод
          /* отправляем обратно  в порт команду "on" (типо все ок команда принята) */
            USART_Transmit('o');
            delay(1);
            USART_Transmit('n');
          }
       
         if (s[0] == 'o' and s[1] == 'f')//проверяем что приняли, если команду "of"
          {
            digitalWrite(18, LOW);//гасим светодиод
          /* отправляем обратно  в порт команду "of" (типо все ок команда принята) */
            USART_Transmit('o');
            delay(1);
            USART_Transmit('f');
          }
         // сбрасываем все
         i=0;
         s[0]='0';
         s[1]='0';
       }
    }

    // the loop function runs over and over again forever
    void loop() {
      digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
      delay(1000);              // wait for a second
      digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
      delay(1000);              // wait for a second
    }
    а если прочитать вот это:
    http://microsin.net/programming/avr/atmega2560-working-with-uart.html
    то можно понять как это все и работает )))
     
    DIYMan нравится это.