COM порт и Serial.available()

dangol
Offline
Зарегистрирован: 12.06.2012

Всем привет! Проблема такая. Я знаю, что комп пошлет в ардуину данные. А когда - это вопрос, через 100мс или через 10-100 сек. И из-за этого в loop нужно втыкать Serial.available()??? Только так??? Мне нужна мгновенная реакция на событие, что начался прием данных, и тогда через 10-20 мс, я начну цикл Serial.available(). А так ерунда получается. А если у меня loop пол секунды идет, что тогда?. На строку типа ISR(USART0_RX_vect) { ... }; Arduino IDE ругается, что мол multiple definitions. И больше в интернете, ничего найти не смог. Serial.Event()-это вообще непонятка зачем написана...? Может кто знает как разрулить эту проблему? Заранее благодарен!
 

mixail844
Offline
Зарегистрирован: 30.04.2012

по вашему вопросу изначально не совсем ясно чего вы хотите добиться,и у понимающего человека возникает путанница чего вы хотите добиться,вот был бы код...Serial.available() реагирует тогда когда данные пришли на последовательный порт.практически это происхдит "мгновенно".как вы хотите что либо делать с данными которые еще не пришли?
 

напоминает антирекламму iphone 5 : "..мы изобрели особенный порт,который позволяет закачивать фильмы так быстро,что фильм появляеться у вас в сотовом еще до того как сценариты написали для него сценарий" )))

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

возможно вам поможет реализация последовательного порта другим способом : arduiniana.org/libraries/newsoftserial/

leshak
Offline
Зарегистрирован: 29.09.2011

 > А если у меня loop пол секунды идет, что тогда

Переписать его так что бы он шел не пол секунды (очевидно же :) ). Мой астрал говорил что у вас там куча delay(), pulseIn и т.п. подобного - их нужно изгнать как бесов.

P.S. "Потомсвенный целитель, изгоняет delay() из скетчей, не дорого, с гарантией" ;)

dangol
Offline
Зарегистрирован: 12.06.2012

У меня кода пока НЕТ...) и предоставить в студию, пока нечего. Есть только идея, которую нужно реализовать. А идея такова. Ардуиновский (mega2560) 16 битный таймер, генерит ШИМ с частотой, например, 100 Гц. Мне нужно, чтобы после посылки команды с компа, счетчик перестроился на частоту, например, на 120 Гц, без каких либо пропусков. Если использовать стандартную схему, т.е. Serial.available в loop, то кто мне скажет, сколько пройдет  100 Гц импульсов, после того, как реально с компа уйдет команда на переключение в 120 Гц - 1, 2 или 7, тем более что время выполнения цикла loop, пока и вовсе неизвестно. Реализовать нужно, что-то вроде такого алгоритма... Loop, без Serial.available. Как только начинается "движуха" в порту, все бросаем, и Serial.availablом ждем появления данных из порта. Вроде все просто...) Нужно повесить свою функцию на прерывание типа USART0_RX_vect. Однако сделать это ПРОСТО и КРАСИВО не получается...( Вот я и обращаюсь к сообществу, может кто-то решал подобную задачу.

Borland
Offline
Зарегистрирован: 17.05.2012

dangol пишет:

У меня кода пока НЕТ...) и предоставить в студию, пока нечего. Есть только идея, которую нужно реализовать. А идея такова. Ардуиновский (mega2560) 16 битный таймер, генерит ШИМ с частотой, например, 100 Гц. Мне нужно, чтобы после посылки команды с компа, счетчик перестроился на частоту, например, на 120 Гц, без каких либо пропусков. Если использовать стандартную схему, т.е. Serial.available в loop, то кто мне скажет, сколько пройдет  100 Гц импульсов, после того, как реально с компа уйдет команда на переключение в 120 Гц - 1, 2 или 7, тем более что время выполнения цикла loop, пока и вовсе неизвестно. Реализовать нужно, что-то вроде такого алгоритма... Loop, без Serial.available. Как только начинается "движуха" в порту, все бросаем, и Serial.availablом ждем появления данных из порта. Вроде все просто...) Нужно повесить свою функцию на прерывание типа USART0_RX_vect. Однако сделать это ПРОСТО и КРАСИВО не получается...( Вот я и обращаюсь к сообществу, может кто-то решал подобную задачу.

Чтото не могу вставить коментарий

Насколько я понимаю для Hardware Serial какими являются serial Serial1 .... уже все обработчики прерывания написаны и висят, приходящие байты кладутся в кольцевой буфер, размер которого 64 байта или 512 бод

соответственно на скорости 9600 он заполнится за 50 микросекунд, так что больше 10 микросекунд я бы не рисковал

другое дело что по Avaluable можно читать сразу все что есть в бувере ReadBytes(), например

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

Старшие товарищи поправят, но вроде как Serial.Avaluable и Serial.read в таймерном прерывании не запрещен.

step962
Offline
Зарегистрирован: 23.05.2011

Borland пишет:

приходящие байты кладутся в кольцевой буфер, размер которого 64 байта или 512 бод

соответственно на скорости 9600 он заполнится за 50 микросекунд

все-таки - скорее 50 миллисекунд...

Borland
Offline
Зарегистрирован: 17.05.2012

step962 пишет:
Borland пишет:
приходящие байты кладутся в кольцевой буфер, размер которого 64 байта или 512 бод
соответственно на скорости 9600 он заполнится за 50 микросекунд
все-таки - скорее 50 миллисекунд...

ага , наврал

больше правда интересует не наврал ли я с Serial  в таймерном прерывании

dangol
Offline
Зарегистрирован: 12.06.2012

Привет всем еще раз! Чего удалось сделать... Описано для мега2560...

Итак, прерывание ISR(USART0_RX_vect), конечно работает в принципе, но если использовать Serial.begin(115200), то при попытке использовать это прерывание, компилятор выдает сообщение о запрете "повторного объявления", так как вообще-то, оно уже определено, и функция ему назначена. Итог... Либо писать полностью самому процедуру обработки COM порта - что очень влом, либо найти какое-нибудь изголение. Я выбрал второй вариант. А именно... Жертвуем DigitalPin21 (для Мега2560). Как известно, на нем возникает аппаратное прерывание, даже если сигнал меняется программным путем. В скетч вставляем строку attachInterrupt(2, func, RISING); Это значит, что прерывание возникнет, когда на 21 цифровой ножке, он же PORTD0, сигнал изменится с 0 на 1. В функцию func - втыкаем процедуру обработки COM порта. И самое главное, модифицируем файл HardwareSerial.cpp (он один в папке Arduino). Вот фрагмент этого файла:   

#if defined(USART_RX_vect)
  SIGNAL(USART_RX_vect)
#elif defined(SIG_USART0_RECV)
  SIGNAL(SIG_USART0_RECV)
#elif defined(SIG_UART0_RECV)
  SIGNAL(SIG_UART0_RECV)
#elif defined(USART0_RX_vect)
  SIGNAL(USART0_RX_vect)
#elif defined(SIG_UART_RECV)
  SIGNAL(SIG_UART_RECV)
#endif
  {
  #if defined(UDR0)
    unsigned char c  =  UDR0;
  #elif defined(UDR)
    unsigned char c  =  UDR;
  #else
    #error UDR not defined
  #endif
    store_char(c, &rx_buffer);

//=====================================
// Мой код             PD0 - 21 ножка Ардуино Мега 2560
   PORTD&=~(1<<0);  // сброс бита
   PORTD|=(1<<0);     // установка бита
//=====================================

  }
#endif
#endif

ИТОГ... Serial.available() в LOOP вообще не используем. Как только прием символа завершен, срабатывает код в HardwareSerial.cpp , возникает прерывание на 21 цифровой ножке и срабатывает приаттаченная функция. Вот и все. Жертвы - одно аппаратное прерывание и PORTD0. Я пока не анализировал код на предмет глюков, но символы приходят моментально и без глюков. По идее, пауза, от момента, после того как ардуино, аппаратно примет символ в буфер, до реального нашего считывания его из буфера, составляет около десятка машинных тактов, что очень круто... Ну вот и все, может кому пригодится.

 

Borland
Offline
Зарегистрирован: 17.05.2012

 Неплохо наверное, но думаю с таким же успехом можно в store_char  вызывать Вашу функцию, не тратя прерывания ? Или я не прав.