Оптимизация обмена данными между Arduino Due и Pro mini
- Войдите на сайт для отправки комментариев
Требуется помощь в оптимизации обмена данными между Arduino. Суть проблемы: Arduino Pro mini считывает положеник 12-ти кнопок и по uart (скорости пробовал от 800 до 230400) передает данные на Arduino Due, если пишу скетч чтобы Due только поморгал диодом, то все "Ок" реакция на нажатие просто мгновенная, если добавляю в Due монитор порта или вывод результата на LCD, то все печально - реакция на нажатие кнопки до нескольких секунд...
Код Arduino Pro mini (328, 3.3В, 8МГц) - формируется два байта, в каждом 1 бит синхронизации и информация о 6-ти кнопках, байты передаются поочередно каждый цикл
byte frame1; byte frame2; int x=0; void setup() { Serial.begin(800); pinMode(2, INPUT); digitalWrite(2, HIGH); // включить подтягивающий резистор pinMode(3, INPUT); digitalWrite(3, HIGH); // включить подтягивающий резистор pinMode(4, INPUT); digitalWrite(4, HIGH); // включить подтягивающий резистор pinMode(5, INPUT); digitalWrite(5, HIGH); // включить подтягивающий резистор pinMode(6, INPUT); digitalWrite(6, HIGH); // включить подтягивающий резистор pinMode(7, INPUT); digitalWrite(7, HIGH); // включить подтягивающий резистор pinMode(8, INPUT); digitalWrite(8, HIGH); // включить подтягивающий резистор pinMode(9, INPUT); digitalWrite(9, HIGH); // включить подтягивающий резистор pinMode(10, INPUT); digitalWrite(10, HIGH); // включить подтягивающий резистор pinMode(11, INPUT); digitalWrite(11, HIGH); // включить подтягивающий резистор pinMode(12, INPUT); digitalWrite(12, HIGH); // включить подтягивающий резистор pinMode(13, INPUT); digitalWrite(13, HIGH); // включить подтягивающий резистор } void loop() { // формирование первого пакета bitWrite(frame1, 7, 1); bitWrite(frame1, 6, 1); //бит синхронизации bitWrite(frame1, 5, digitalRead(7)); bitWrite(frame1, 4, digitalRead(6)); bitWrite(frame1, 3, digitalRead(5)); bitWrite(frame1, 2, digitalRead(4)); bitWrite(frame1, 1, digitalRead(3)); bitWrite(frame1, 0, digitalRead(2)); // формирование второго пакета bitWrite(frame2, 7, 1); bitWrite(frame2, 6, 0); //бит синхронизации bitWrite(frame2, 5, digitalRead(13)); bitWrite(frame2, 4, digitalRead(12)); bitWrite(frame2, 3, digitalRead(11)); bitWrite(frame2, 2, digitalRead(10)); bitWrite(frame2, 1, digitalRead(9)); bitWrite(frame2, 0, digitalRead(8)); if (x == 0) { Serial.write(frame1); x=1; } // передача первого пакета каждый нечетный цикл else { Serial.write(frame2); x=0; } // передача второго пакета каждый четный цикл }
Код Arduino Due - принимает пакет, по биту синхронизации определяет какой из них пришел и присваевает значение переменным кнопок
#include <Wire.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27,20,4); byte frame; byte frame1; byte frame2; int buttonPinUp; // pin for the Up button (Menu Up) int buttonPinDown; // pin for the Down button (Menu Down) int buttonPinLeft; // pin for the Left button (Menu Left) int buttonPinRight; // pin for the Right button (Menu Right) int buttonPinEnter; // pin for the Enter button (Menu Select - unlock) int buttonPinEsc; // pin for the Esc button (Menu Cancel - lock) int CameraPinUp; // Camera Up int CameraPinDown; // Camera Down int CameraPinLeft; // Camera Left int CameraPinRight; // Camera Right int RatesPinHigh; // Rates High int RatesPinLow; // Rates High void setup() { Serial1.begin(800); pinMode(13, OUTPUT); lcd.init(); // initialize the lcd lcd.backlight(); } void loop() { if (Serial1.available() >0){ frame = Serial1.read(); if (bitRead(frame, 6) == 1){frame1 = frame; } if (bitRead(frame, 6) == 0){frame2 = frame; }} buttonPinEnter = bitRead(frame1, 0); buttonPinEsc = bitRead(frame1, 1); RatesPinLow = bitRead(frame1, 2); RatesPinHigh = bitRead(frame1, 3); CameraPinRight = bitRead(frame1, 4); CameraPinUp = bitRead(frame1, 5); CameraPinLeft = bitRead(frame2, 0); CameraPinDown = bitRead(frame2, 1); buttonPinRight = bitRead(frame2, 2); buttonPinDown = bitRead(frame2, 3); buttonPinLeft = bitRead(frame2, 4); buttonPinUp = bitRead(frame2, 5); if (buttonPinEnter == 0) {digitalWrite(13, LOW); } else {digitalWrite(13, HIGH);} lcd.setCursor(0,0); lcd.print(frame1, BIN); lcd.setCursor(0,1); lcd.print(frame2, BIN); }
Когда поключал монитор порта Due заметил, что чем меньший объем информации передаю в монитор порта тем меньше тупит - соответственно пока передаются данные на LCD набивается буфер от Pro mini и потом это все медленно переваривается, может обновлять LCD раз 10 циклов?
Зачем Pro mini при каждом проходе loop() (то есть ну ооочень часто) шлёт повторяющиеся (в подавляющем большинстве случаев) байты ? Может быть есть смысл отправлять информацию только когда состояние пинов изменилось ?
Добавьте, например, некий флаг необходимости отправить пакет (boolean sendPacket = true;), выставляйте его в процессе опроса пинов :
if (digitalRead(7) != bitRead(frame1, 5)) { sendPacket = true; }
bitWrite(frame1, 5, digitalRead(7));
...и так для прочих пинов...
и отправляйте пакет, когда это действительно необходимо :
if ( sendPacket )
{
Serial.write(frame1);
Serial.write(frame2); // отчего бы и два байта за раз не отправить ? Только процедуру приёма измените чуть.
sendPacket = false;
}
Спасибо Модест, логично. Я догадывался об этом, но так как начинающий самоучка не знал как реализовать. Сейчас пойду гуглить. Алгоритм:
в Setup
1. присваиваю 12-ти значениям (значения кнопок) логическую "1" frame1=11111111, frame2=10111111 (кнопки отжаты)
в loop
2. опрашиваю все 12 входов и присваюиваю значения двум пакетам frame1d и frame2d
3. если frame1d != frame1 отправляю пакет на передачу и присваиваю frame1 = frame1d
если frame2d != frame2 отправляю пакет на передачу и присваиваю frame2 = frame2d
Как мне изменить процедуру приема? В данный момент я получаю пакет, по синхронизирующему биту смотрю, что за он и присваиваю значения переменным.
Алгоритм:
в Setup
1. присваиваю 12-ти значениям (значения кнопок) логическую "1" frame1=11111111, frame2=10111111 (кнопки отжаты)
в loop
2. опрашиваю все 12 входов и присваюиваю значения двум пакетам frame1d и frame2d
3. если frame1d != frame1 отправляю пакет на передачу и присваиваю frame1 = frame1d
если frame2d != frame2 отправляю пакет на передачу и присваиваю frame2 = frame2d
Я выше описал (IMHO) более простой алгоритм, да и Ваш неплох.
UPD: А, впрочем, Ваш алгоритм проще )).
Как мне изменить процедуру приема? В данный момент я получаю пакет, по синхронизирующему биту смотрю, что за он и присваиваю значения переменным.
Строку
if
(Serial1.available() >0){
замените на
while
(Serial1.available() >0){
Спасибо. Я еще приду к Вашему алгоритму, но позже, а пока воспользуюсь своим скромным багажом знаний.
немного оффтоп, подтяжку пинов можно записать как
Ну есть еще одно замечание. На Мега надо сразу создавать многопоточную систему. Один поток на прием данных. Ну а второй поток уже для назначение. Про мини уже должна проводить первичный отбор нажатых клавиш. То есть посылать код только что нажатой клавиши.И разумеется если нажато несколько ничего не посылать. Если эта клавиша регистр.
ПС: А может перестать хренью баловаться и заказать это.
http://ru.aliexpress.com/store/product/Button-Keypad-3x4-module/1950989_...
Спасиобо, попробую.
qwone, Ваш вариант рассматривался мной ранее, но он мне не подходит. Вот мой проект, который я совершенствую и у меня должны одновременно регистрироваться нажатия нескольких кнопок. Я исправил проект, так как советовал Araris и все работает замечательно, очень ему признателен. Мини и присылает код нажатой (нажатых) клавишы, только он кодируется и декодируется моим способом, который я считаю наиболее оптимальным.
P.S. по я образованию я инженер телекоммуникационных систем и очень хорошо знаком с различными способами кодирования и декодирования не по наслышке
если дальше развивать систему, то надо создать систему Сервер-Клиент.
Мега по условию Сервер. А Pro mini клиент.
Можно организовать протокол DCON.http://www.bookasutp.ru/Chapter2_10.aspx
Мега #АА , где АА адрес mini 00 - посылка #00
Pro mini >(дата) точнее >FF .
Так что меге можно отправлять запросы ну не чаще 0,2 сек и получать ответы. Таким образом можно разгрузить Мегу.
Там много лишнего для моего случая, единственное что можно организовать это примитивную проверку правильности принятого пакета (для этого у меня есть один не используемый бит) и отправку отчета от Due (у меня не Мега) к Мини, если пакет принят не правильно то посылка передается еще раз. В данный момент у меня посылаются посылки только если кнопки поменяли положение, так что Due по этому поводу не грузится.
Суть проверки правильности принятого пакета - "проверка четности":
1.проверочным битом я могу из любой посылки сделать в ней четное количество бит (принимает значение "0" или "1", чтобы количество бит было четным);
2. на приемном конце (Due) проверяю четное или нечетное количество бит в принятой посылке, если четное - посылка принята верно (отправляю отчет о правильном принятии посылки и выполняю алгоритм дальше, нечетное - отчет об ошибке и жду повторной передачи пакета)
Данный способ позволяет со 100% вероятность обнаружить одну ошибку в принятом пакете. Блин, Вы мне напомнили о помехоустойчивом кодировании, ща начну вспоминать сверточные коды, гонять полиномы и выполнять сложение по модулю два..
Вы опять меня не поняли. У вас там клавиатура. А клавиши надо опрашивать с частотой в 0,2 сек. Ну чаще человек не может стучать по кнопкам. Так что посылки идут в Мега с частотой 5 Гц. Причем когда надо и не надо. Чаще всего не надо. Но это буквально требует ресурсов. И надо этот поток обработать. Вдруг потом пригодится.
Проще когда созрела необходимость дать запрос и получить ответ о состоянии клавиш. Тем более Про Мини должна и отработать клавиши и дребезг их. То есть Про Мини регулярно опрашивает кнопки , гасит дребезг и готовит (обновляет) пакет для отправки. А вот при запросе его выкидывает в канал. Понятно что канал это две линии. Туда и обратно. Но за то такая организация экономит ресурсы памяти и процессорного времени.
ПС: Помехозащита. Так сделать 2 запрос-ответа. с побитной защитой. да хоть 4 байта посылка.
qwone, насчет дребезжания контактов согласен, я планировал это делать. А по поводу передачи состояния кнопок по запросу от Due не считаю это необходимым и пожалуй оставлю как есть. Состояние кнопок передаются только в момент изменения их положения и до следующего изменения не передается - что в этом плохого? Захочу заморочится сделаю проверку правильности принятого пакета как писал выше.
С передачей нормально. Но у вас 12 кнопок. А это значит минус 12 байт ОЗУ в минус. И плюс опереция перекодирующая посылку изменения в состояние. Но практика критерий истины. У меня хороший плюс. Это не моя проблема и не моя задача решать. Я обозначил "подводные камни".