Искажение данных при чтении из Serial
- Войдите на сайт для отправки комментариев
Ср, 12/10/2016 - 14:27
Решил на MEGA2560 сделать чтение из Serial1 с использованием прерывания. Для контроля результат вывожу в Serial. Скетч работает, количество считываемых байт равно количеству отправленных, НО они искажены. Причем всегда одинаково. Для проверки делал без использования прерывания - все читается верно.
Вот пример посылки и результата отображения:
Используемый скетч:
// тест чтения порта Serial1 с помощью прерывания // ------------------------------------------------------------------------------ #define INTERRUPT_PIN 19 // pin Rx для Serial1 const byte MAX_WaitingCount = 50; // макс кол-во циклов ожидания данных //-------------------------------------------------------------------------------- void setup() { Serial.begin(9600); delay(100); Serial.println("BEGIN"); attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), f_Serial1_ISR, RISING); // определяем функцию по прерыванию } // end of setup() //-------------------------------------------------------------------------------- String Serial1_string; // результат чтения(строка) byte Serail1_byte[255]; // результат чтения(строка) int WaitingCount = 0; // время ожидания данных, мс int Serial_amount = 0; // кол-во прочитанных байт volatile boolean flag_Serial1 = false; //-------------------------------------------------------------------------------- // обработка прерывания для Serial1 void f_Serial1_ISR() { if (!flag_Serial1) flag_Serial1 = true; }// end of f_Serial1_ISR() //-------------------------------------------------------------------------------- // чтение данных из Serial1 void f_Serial1_Handler() { if (Serial_amount) // данные не обработаны, выход return; detachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN)); // отключаем прерывание Serial1.begin(9600,SERIAL_8N1); // активируем Serial1 Serial1_string = ""; WaitingCount = 0; /* while (!Serial1.available() and (WaitingCount< MAX_WaitingCount)) // ожидание данных в Serial1 { WaitingCount++; delay(1); } */ delay(500); // ожидание в явном виде if(Serial1.available()) // данные обнаружены { // delay(500); // ожидаем получения всего сообщения while (Serial1.available()>0) // читаем данные и формируем строку { int ci = Serial1.read(); if (ci>=0) { char c = (char)ci; Serail1_byte[Serial_amount] = (byte)ci; Serial1_string += c; Serial_amount++; } else // признак ошибки чтения { Serial_amount = 1; Serail1_byte[0] = 0; } } // end of while } // end of if(Serial1.available()) Serial1.end(); // закрываем Serial1 //delay(300); attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), f_Serial1_ISR, RISING); // активируем прерывание } // end of f_Serial1_Handler() //-------------------------------------------------------------------------------- // основной цикл void loop() { if (flag_Serial1) f_Serial1_Handler(); // чтение данных из Serial1 if(Serial_amount) { Serial.print("WaitingCount : "); // тестовый вывод Serial.print(WaitingCount); Serial.print(" Serial_amount : "); Serial.print(Serial_amount); Serial.print(" string :"); Serial.println(Serial1_string); for(byte k=0;k<Serial_amount;k++) { Serial.print(Serail1_byte[k],HEX); Serial.print(" "); } Serial.println(""); Serial_amount = 0; WaitingCount = 0; flag_Serial1 = false; // снимаем флаг для ISR delay(300); } } //--------------------------------------------------------------------------------
Прошу подсказать, где ошибка?
Замечание по использованию
Внутри функции обработки прерывания не работает delay(), значения возвращаемые millis() не изменяются. Возможна потеря данный передаваемых по последовательному соединению (Serial data) в момент выполнения функциии обработки прерывания. Переменные, изменяемые в функции, должным быть объявлены как volatile.
Отсюда : http://arduino.ru/Reference/AttachInterrupt
Скриншот и скетч вставились криво, поэтому повторяю:
Скетч:
Так внутри обработчика delay() нет - все вынесено в основной цикл ((
Так внутри обработчика delay() нет - все вынесено в основной цикл ((
А, ну да (я не delay() имел в виду в цитате). Ещё мысль навскидку - может быть стоит попробовать Serial1.begin(9600,SERIAL_8N1); вынести в setup() ?
Так внутри обработчика delay() нет - все вынесено в основной цикл ((
А, ну да (я не delay() имел в виду в цитате). Ещё мысль навскидку - может быть стоит попробовать Serial1.begin(9600,SERIAL_8N1); вынести в setup() ?
Спасибо, помогло.
Подчищу скетч и выложу сюда.
Выкладываю работающий скетч.
Задержка 1 мсек между чтением байт сделана вынужденно для заполнения буфера для длинных пакетов(более 10 байт).
ИМХО: преимуществом такой реализации является разгрузка основного цикла, в котором постоянно проводится только проверка одного флага.