COM порт и Serial.available()
- Войдите на сайт для отправки комментариев
Ср, 26/09/2012 - 02:21
Всем привет! Проблема такая. Я знаю, что комп пошлет в ардуину данные. А когда - это вопрос, через 100мс или через 10-100 сек. И из-за этого в loop нужно втыкать Serial.available()??? Только так??? Мне нужна мгновенная реакция на событие, что начался прием данных, и тогда через 10-20 мс, я начну цикл Serial.available(). А так ерунда получается. А если у меня loop пол секунды идет, что тогда?. На строку типа ISR(USART0_RX_vect) { ... }; Arduino IDE ругается, что мол multiple definitions. И больше в интернете, ничего найти не смог. Serial.Event()-это вообще непонятка зачем написана...? Может кто знает как разрулить эту проблему? Заранее благодарен!
по вашему вопросу изначально не совсем ясно чего вы хотите добиться,и у понимающего человека возникает путанница чего вы хотите добиться,вот был бы код...Serial.available() реагирует тогда когда данные пришли на последовательный порт.практически это происхдит "мгновенно".как вы хотите что либо делать с данными которые еще не пришли?
напоминает антирекламму iphone 5 : "..мы изобрели особенный порт,который позволяет закачивать фильмы так быстро,что фильм появляеться у вас в сотовом еще до того как сценариты написали для него сценарий" )))
я так понимаю,у вас есть некий цикл в loop(),и вы хотите что бы обработка Serial.available() началась до того как до нее дойдет очередь в коде.а из за чего конкретно IDE у вас ругаеться,обитатели форума должны понять включив свои телепатические способности,уйти в астрал,считать ваш код на компьютере и дать ответ))
возможно вам поможет реализация последовательного порта другим способом : arduiniana.org/libraries/newsoftserial/
> А если у меня loop пол секунды идет, что тогда
Переписать его так что бы он шел не пол секунды (очевидно же :) ). Мой астрал говорил что у вас там куча delay(), pulseIn и т.п. подобного - их нужно изгнать как бесов.
P.S. "Потомсвенный целитель, изгоняет delay() из скетчей, не дорого, с гарантией" ;)
У меня кода пока НЕТ...) и предоставить в студию, пока нечего. Есть только идея, которую нужно реализовать. А идея такова. Ардуиновский (mega2560) 16 битный таймер, генерит ШИМ с частотой, например, 100 Гц. Мне нужно, чтобы после посылки команды с компа, счетчик перестроился на частоту, например, на 120 Гц, без каких либо пропусков. Если использовать стандартную схему, т.е. Serial.available в loop, то кто мне скажет, сколько пройдет 100 Гц импульсов, после того, как реально с компа уйдет команда на переключение в 120 Гц - 1, 2 или 7, тем более что время выполнения цикла loop, пока и вовсе неизвестно. Реализовать нужно, что-то вроде такого алгоритма... Loop, без Serial.available. Как только начинается "движуха" в порту, все бросаем, и Serial.availablом ждем появления данных из порта. Вроде все просто...) Нужно повесить свою функцию на прерывание типа USART0_RX_vect. Однако сделать это ПРОСТО и КРАСИВО не получается...( Вот я и обращаюсь к сообществу, может кто-то решал подобную задачу.
У меня кода пока НЕТ...) и предоставить в студию, пока нечего. Есть только идея, которую нужно реализовать. А идея такова. Ардуиновский (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 в таймерном прерывании не запрещен.
приходящие байты кладутся в кольцевой буфер, размер которого 64 байта или 512 бод
соответственно на скорости 9600 он заполнится за 50 микросекунд
все-таки - скорее 50 миллисекунд...
соответственно на скорости 9600 он заполнится за 50 микросекунд
ага , наврал
больше правда интересует не наврал ли я с Serial в таймерном прерывании
Привет всем еще раз! Чего удалось сделать... Описано для мега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. Я пока не анализировал код на предмет глюков, но символы приходят моментально и без глюков. По идее, пауза, от момента, после того как ардуино, аппаратно примет символ в буфер, до реального нашего считывания его из буфера, составляет около десятка машинных тактов, что очень круто... Ну вот и все, может кому пригодится.
Неплохо наверное, но думаю с таким же успехом можно в store_char вызывать Вашу функцию, не тратя прерывания ? Или я не прав.