Что-то со считыванием из Serial...
- Войдите на сайт для отправки комментариев
И снова всем привет! Мужики, помогите мне разобраться с таким моментом: есть заинтересовавшая меня статья https://habrahabr.ru/post/167209/ в которой снизу есть такой код:
#include <Servo.h>
Servo myservo;
void setup() {
Serial.begin(9600);
}
String getParam(){
String re;
while (Serial.available()) {
re.concat(Serial.read()-48);
}
return re;
}
int getPin(String p){
return p.substring(0,2).toInt();
}
int getVal(String p){
return p.substring(2,6).toInt();
}
// Главный цикл
void loop() {
while (Serial.available()) {
char command = (char)Serial.read();
String param = getParam();
int pin = getPin(param);
int p;
switch (command) {
case '0': //Digital write
pinMode(pin,OUTPUT);
digitalWrite(pin, LOW);
break;
case '1': //Digital write
pinMode(pin,OUTPUT);
digitalWrite(pin, HIGH);
break;
case '2': //Servo
myservo.attach(pin);
p = getVal(param);
myservo.write(p);
break;
case '3': //Digital read
pinMode(pin,INPUT);
Serial.print(digitalRead(pin));
break;
case '4': { //Analog read
int aPin = A0;
switch (pin) {
case 1: aPin = A1; break;
case 2: aPin = A2; break;
case 3: aPin = A3; break;
case 4: aPin = A4; break;
case 5: aPin = A5; break;
}
Serial.print(analogRead(aPin));
}
break;
case '5': //Analog write
pinMode(pin,OUTPUT);
p = getVal(param);
analogWrite(pin, p);
break;
}
}
}
Исходя из статьи, если залить этот код в дуинку и отправить по Serial "113" должен включиться 13 пин...Если отправит 013 - выключиться (это написано в статье под самим кодом)... В итоге все работает на моих 2х китайских МЕГАх как то не так... Не буду вспоминать сколько я игрался с этим в часах, но заработал этот код только тогда, когда я скорость поменял на 115200 и после строки "char command = (char)Serial.read();" добавил еще 2:
Serial.print("command=");
Serial.println(command);
Как я понимаю, эти 2 строки всего лишь создали небольшую временную задержку, без них байтики начинают пропадать... Если вернуть скорость на 9600 и отправить команду "113" то все цифры попадают в эти две строчки и ответ приходит:
command=1 command=1 command=3
Получается, что функция getParam() не работает... Буду благодарен любой помощи.
Так поставьте вместо 12-ой строки три такие:
const char c = (char)(Serial.read()-48); Serial.print("c="); Serial.println(c); re.concat(с);"сразу прояснится на доске"
В приведённом коде отсутствует обработка ошибок, отсутствует проверка на то, что команда принята полностью. Это - как минимум, глубже не смотрел.
Я не раз повторял уже, повторю ещё раз: чтение "в лоб" по Serial.available - самая хадшая идея из тех, что могут возникнуть. Вот смотрите: вы попали в очередной вызов loop, проверили Serial.available - есть что-то там в порту, начали читать всё, что упало в буфер. И потом - начали выполнять свои действия в зависимости от того, что в буфере UART покладено/положено/зарыто.
НО! В буфер могли ещё не упасть все символы, переданные с той стороны, с чем вы, собственно, и столкнулись.
Как это решается при вдумчивом подходе? Обычно - вводят нечто вроде стоп-последовательности, при получении которой мы понимаем, что в буфере накопилась вся команда, переданная нам извне. Можно юзать хоть три 0xFF подряд (как делает дисплей Nextion), хоть символы новой строки (\r\n) - тут каждый пляшет, как умеет.
В итоге, псевдокод выглядит как-то так:
String buff; // буфер приёма очередной команды void GotCommand(const String& command) { // тут обрабатываем всю строку, которая пришла из порта } void loop() { // собираем команду до тех пор, пока не встретится символ новой строки \n while(Serial.available()) { char ch = Serial.read(); if(ch == '\r') continue; if(ch == '\n') { GotCommand(buff); buff = ""; } else buff += ch; } }В приведённом коде, кстати, тоже нет контроля максимальной длины пакета - можно засрать оперативу, посылая какие угодно символы, кроме \n ;) Но всё дописывается парой строчек.
Ещё раз убеждаюсь, что over9000 провентов примеров из статей в интернете - стоит рассматривать только как примеры. Как плохие примеры.
Так поставьте вместо 12-ой строки три такие:
const char c = (char)(Serial.read()-48); Serial.print("c="); Serial.println(c); re.concat(с);"сразу прояснится на доске"
Сделал так:
String getParam(){ String re; while (Serial.available()) { const char c = (char)(Serial.read()-48); Serial.print("c="); Serial.println(c); re.concat(с); } return re; }Ругается на re.concat(с); Говорит
Arduino: 1.6.5 (Windows 7), Плата"Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"
Ругается на re.concat(с); Говорит
Во ж блин, никогда не попадал на такие ошибки еще... Спасибо - буду знать... Итого результат отправки 113 на скорости 9600 ="1"... отправка 013 дает тот же результат...
Во ж блин, никогда не попадал на такие ошибки еще... Спасибо - буду знать... Итого результат отправки 113 на скорости 9600 ="1"... отправка 013 дает тот же результат...
Вы что-то невнятное написали. Лог скопипастите из сериал-монитора сюда.
DIYMan, спасибо за пояснение... Возможно, как раз это именно мой случай... Попробую провернуть нечто подобное сейчас. Спасибо!
ЕвгенийП, отправляю (кавычки не в счет) "113" а в монитор просто единица выскакивает одна-одинёшенька... Похоже очень на то, про что говорил DIYMan... Как я понял код, первая единица из "113" вылавливается и отправляется в блок свич-кейс, а все что за ней следует - в функцию getParam(),из которая потом сабстрингами вынимаются нужные циферки (поправьте если я не прав)... И в итоге данные еще не успели все сложиться в буфер, а дуинка их уже поперла обрабатывать... Это всего лишь мое предположение на основе многочасовой камасутры с этим кодом...
здесь #76 DigiUSB замени на Serial и юзай.
*не в первый раз наталкиваюсь на дурное пользование циклов - походу, какая-то эпидемия.
Клапауций 322, благодарю! Поразбираюсь что там и зачем... А может кто-нибудь посоветует статейку, в которой использую ту же связку ардуино-питон-веб страничка, в которой будет попонятнее объясняться вся эта схема? А то что-то в ссылке с первого поста все никак не запускается нифига то одно, то другое... Косяков там мелких дофига и догонять их времени вагон уходит. Интересует, чтобы дуинка общалась с веб-страничкой именно через УАРТ.