Что делать, кто виноват и почему оно не работает?
- Войдите на сайт для отправки комментариев
В России, как известно, два главных вопроса: "Кто виноват?" и "Что делать?". Наш форум добавляет к ним третий, не менее, а может и более сложный - "Почему оно не работает?". И вот я в этих трёх вопросах немного заблудился.
Вот, допустим, надо организовать работу с AT-командами из монитора порта. Ну, что, берём Uno, цепляем модуль с которым надо работать на софтверный сериал и пишем маленький скетч-прокси. Оно, понятно, что Uno здесь лишняя и никаких прокси не надо, но вот такая задача.
#include <SoftwareSerial.h> #define ssRX 8 #define ssTX 7 SoftwareSerial ss(ssRX, ssTX); void setup(void) { Serial.begin(115200); ss.begin(9600); } void loop(void) { if (Serial.available()) ss.write(Serial.read()); if (ss.available()) Serial.write(ss.read()); }
и оно не работает! Вернее, работает, но глючит безбожно.
Ну, вроде, "Почему оно не работает?" - понятно (если подумать немного). "Кто виноват?" - в общем-то тоже понятно (и это не коммунисты, не евреи и даже не криворукие китайцы!). А вот "Что делать?" ... вернее, как сделать софтверный сериал, чтобы таких глюков не было ... в общем это вопрос.
Вопрос, правда, философский, т.к. делать его я не собираюсь. Но потрындеть было бы интересно.
P.S.
В топике умышленно не разжёвано почему оно не работает. Тех, кто это понимает, приглашаю к дискуссии "как делать сфотсериал, чтобы такого не было". А тех, кто не понимает ... без обид, ребята, но Ваше мнение в этой дискуссии неинтересно.
А скорости умышленно в 12 раз отличаются ?
как сделать софтверный сериал, чтобы таких глюков не было .
дык напишите грамотно свою библиотеку чтоб работал только с парой пинов PCINT, а не всем МК atmega - как минимум половина интернет сообщества вам спасибо скажут.
В 12 - случайно. Достаточно в два. По идее, эти скорости друг на друга влиять не должны (но влияют). Ну, хочешь, поставь flush после каждого write
Дело не в пинах PCINT.
В этом легко убедиться. PCINT там используется только для чтения. Убери чтение из моего примера (строку 15) и гони данные только в одну сторону "сериал -> софтсериал". Всё равно будет глючить. Так что не в PCINT проблема.
Софтсериал - штука капризная в принципе. Если его использовать в сценариях сложнее, чем "послал и слушаешь во while()" и на высоких (>38400) скоростях, то предсказывать результат работы вообще сложновато. Он, мерзавец, внутре себя и прерывания отключает...
Хотя вот в данном случае всё, в принципе, работать должно - последние версии SoftwareSerial являются Interrupt driven и сам луп не нагружен.
Какие симптомы-то?
Какие симптомы-то?
так такие и есть - прерывания он закрывает на всё время отправки байта. Если скорость хардсериала стоит выше хотя бы вдвое, то за время отправки байта софтовым сериалом, в хардовый успевают прийти два (или больше) и все пришедшие, кроме последнего теряются. Вот и все симптомы.
Мой пример начинает нормально работать, если в софтсериале cli закомментировать. Но тогда, если кто другой прервёт и будет полчаса в прерывании сидеть, тайминги сломаются.
Вот и задумался я как его можно по уму-то сделать.
ну вот аналогичный старинный пример, аппаратный 115200, с модемом общение 9600
http://arduino.ru/forum/apparatnye-voprosy/vse-o-sim800l-i-vse-chto-s-ni...
если скорости поменять - все ломается и не работает.
Лечение вижу только такие - замена библиотеки (на что?), обработка данных off line (где ж столько памяти на хранение взять?), замена МК.
http://arduino.ru/forum/apparatnye-voprosy/vse-o-sim800l-i-vse-chto-s-nim-svyazano?page=1#comment-376729
чтения русских и / или длинных СМС
Неленивый, однако! Я почитал как оно там всё и решил, да ну его в жопу столько расписывать - нахрена мне читать русские/длинные смс-ки? Для управления чем-нибудь обойдусь DTMF или короткими на латинице :-)
ЗЫ ...поступающие в виде частых прерываний запросы на посимвольную обработку входящих данных стали большой проблемой, поэтому последовательные порты в IBM PS/2 стали реализовываться с использованием 16550(A) UART, имеющего FIFO-буфер ёмкостью 16 байт для хранения поступающих символов
вопрос только в его количестве я так понимаю?
http://arduino.ru/forum/apparatnye-voprosy/vse-o-sim800l-i-vse-chto-s-nim-svyazano?page=1#comment-376729
чтения русских и / или длинных СМС
Неленивый, однако! Я почитал как оно там всё и решил, да ну его в жопу столько расписывать - нахрена мне читать русские/длинные смс-ки? Для управления чем-нибудь обойдусь DTMF или короткими на латинице :-)
Я же только учусь :)
Хорошая практика парсинга online, жизни в ограниченных ресурсах МК и т.д.....
ЗЫ ...поступающие в виде частых прерываний запросы на посимвольную обработку входящих данных стали большой проблемой, поэтому последовательные порты в IBM PS/2 стали реализовываться с использованием 16550(A) UART, имеющего FIFO-буфер ёмкостью 16 байт для хранения поступающих символов
вопрос только в его количестве я так понимаю?
Как оказалось из практики (сейчас мучаю stm32) - буфер в несколько десятков байт вообще ни о чем, логика МК отрабатывает настолько быстро, что узкое место оказывается периферия, закинуть пару килобайт данных в какой нибудь SIM7500E занимает микросекунды, а отправляется гораздо медленнее, поэтому алгоритмы работы программ и выходят на первое место, распараллеливание потоков и т д.
Как оказалось из практики (сейчас мучаю stm32) - буфер в несколько десятков байт вообще ни о чем ... поэтому алгоритмы работы программ и выходят на первое место, распараллеливание потоков и т д.
Ну, насчет распараллеливания в рамках МК - это как-то совсем уж круто, но над алгоритмами задумываться приходится.
Сейчас в работе проект, где МК отправляет наружу (на внешний синтезатор) MIDI-файл. Естественно, делается это все строго по времени и поэтому в прерывании. Но вот ведь зараза! Оказалось, в MIDI файле можно встретить одновременно более 30 команд. В реальности сделать такое абсолютно невозможно. Но вот настучать мышкой в MIDI-редакторе - запросто.
Т.е. из прерывания происходит попытка отправки порядка 100 байтов. Естественно, на 65-м байте функция записи начинает тормозить прерывание до освобождения буфера передачи. Ну и прерывания наползают друг на друга, в результате чего МК виснет.
Тоже думал, что делать, увеличить размер буфера порта (с одной стороны, для stm32 его увеличение в 2/4/8 раз - не проблема, но останавливает то, что это изменение нельзя сделать локально, в отдельно взятом проекте), но в результате решил бороться именно алгоритмически, - прогнозируя заполнение порта и при необходимости перенося команды в следующее прерывание.
При отправке отказался от прерываний, сделал в цикле каждого прохода проверку флагов аппаратного uart, не уверен что правильное решение. При выкладывании байта в fifo буфер приходилось запрещать прерывания т к в этот же момент могло сработать прерывание отправки и байт терялся. Учитывая что один такт МК примерно 14 наносекунд, while ожидания флага готовности отправки занимает непозволительное время, мне это не понравилось. Пока логика работает, посмотрим что дальше будет при усложнение программы. Возможно все будет меняться.
Вот и задумался я как его можно по уму-то сделать.
Я бы выбрал 328PB в качестве затычки. Создавать генерализованное решение для ардуины - а это, видимо, занять один таймер и дёргаться по нему для отправки байта - слишком расточительно по ресурсу и затратам времени.
Кто, например ? Если у вас несколько процессов настолько критичных по времени, то проблемы неизбежны, возьмите ардуину пожирнее и не парьтесь.
На самом деле сама идея "генерализованного решения" порочна. Он исходит и предпосылок, сформировавшихся при программировании больших машин.
Вот смотрите - типичное рассуждение о таких идеях: «Ну, да, если взять таймер под это дело, то не будет необходимости закрывать прерывания и я никому не нагажу. Но, стоит кому-нибудь закрыть прерывания, как он нагадит мне – сломает тайминги»
Здесь изначально неверный посыл в слове «кому-нибудь». Кому именно? Это что, мультипользовательская система, где кроме меня ещё 10+ юзеров свои задачи гоняют? Или мультизадачная и в ней есть какие-то демоны, которых я не запускал?
Никаких «кому-нибудь» здесь нет! Здесь есть я и только я! Если я сам себе не нагажу, то никто мне не нагадит.
Потому, надо просто признать, что никаких универсальных, на все случаи жизни, библиотек не бывает в природе. Пихать в код чужие библиотеки, которые ты сам не знаешь построчно, категорически нельзя – только своё или такое, что ты буквально покомандно разобрал и целиком знаешь.
Тогда можно делать то, что нужно под конкретную задачу (закрывать прерывания или сидеть в обработчиках по часу) и точно знать, что никто тебе не нагадит и ты никому не нагадишь по очень простой причине – кроме тебя там никого нет.
А чтобы делать более или менее универсальные решения с такой философией, явно не хватает продвинутого препроцессора – просто ещё одного прохода перед компиляцией, где можно было бы полноценно генерировать и разворачивать код. По крайней мере мне этого точно не хватает. Вот этим бы заняться и в тулчейн его встроить – цены б не было.
На самом деле сама идея "генерализованного решения" порочна. Он исходит и предпосылок, сформировавшихся при программировании больших машин.
Вот смотрите - типичное рассуждение о таких идеях: «Ну, да, если взять таймер под это дело, то не будет необходимости закрывать прерывания и я никому не нагажу. Но, стоит кому-нибудь закрыть прерывания, как он нагадит мне – сломает тайминги»
Согласен по всем пунктам. Всё, что не имеет возможности исполняться автономно, не завися от основного процессора, является потенциальным местом появления "багов". Переход на таймер в данном случае - только способ увеличения количества девяток после запятой в надёжности системы, а не панацея.
А по другому не сделаешь. Я делал так. Таймер щелкает в 4 раза чаще длительности бита. Если прием не ведется, в каждом вызове прерывания контролируем RX и при обнаружении старта переходим в режим приема, отсчитываем 5 вызовов и принимаем первый бит, затем каждые 4 вызова очередной. С передачей проще, там просто каждые 4 такта плюем бит. Просится вроде перенастраивать длительность таймера, но нельзя т.к. если во время передачи начнется прием то ошибка будет. Ну и понятно что другие прерывания должны отрабатывать не дольше периода таймера. С учетом системных часов ардуины выходит ограничение скорости порядка 2400бод.
Спасибо, мужики! Разговор пошёл именно в том русле, на которое я расчитывал.
Так что, все считают, что универсальных решений не бывает?
А кто согласен, что пригодился бы дополнительный проход в тулчейне, чтобы гибко код генерировать?
Возможно. Я так глубоко копаю редко и тинек хитрым кодом не насилую )