Serial.read в ардуино

akz
Offline
Зарегистрирован: 08.11.2011

 Serial.read - эта функция считывает числа с сериал монитора, но когда пишешь программу, чтобы она считывала бцквы компилятор выдает ошибку.Разве эта функция может считывать только числа?

вот код программы :


int a = 0 // задаю переменную
void setup(){
Serial.begin(9600);
pinMode(13,OUTPUT);
}
void loop(){
while(Serial.available() == 0){
}
int a = Serial.read() - '0';
if(a == 1){
digitalWrite(13,HIGH);
}
else if (a == low){ // если в сериал мониторе написать "LOW"
digitalWrite(13,LOW); // выключить диод на выводе 13
}
else {
Serial.println("I cannot understand";)
}
Serial.flush();
}
 

Подправил вид кода программы. Adessit

 

bakemono
bakemono аватар
Offline
Зарегистрирован: 11.08.2011

Скорее всего дело в том, что переменная "а" имеет неверный тип (int числовой) :)

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

akz пишет:

int a = 0 // задаю переменную

Где точка с запятой, завершающая оператор?

Цитата:

else if (a == low){ // если в сериал мониторе написать "LOW"
digitalWrite(13,LOW); // выключить диод на выводе 13
}

почему low в нижнем регистре?

Цитата:

else {
Serial.println("I cannot understand";)
}

где правая круглая скобка перед точкой с запятой?

и зачем правая круглая скобка после точки с запятой?

Ответив на эти вопросы вы, возможно и на свой основной вопрос найдете ответ ;)

 

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

bakemono пишет:
Скорее всего дело в том, что переменная "а" имеет неверный тип (int числовой) :)

Проверил эту версию первой. Как ни странно, IDE Arduino вполне благосклонно отнеслась к этому обстоятельству.

akz
Offline
Зарегистрирован: 08.11.2011

 

 

step962 пишет:

где правая круглая скобка перед точкой с запятой?

и зачем правая круглая скобка после точки с запятой?

Ответив на эти вопросы вы, возможно и на свой основной вопрос найдете ответ ;)

 

 Это получилось случайно

akz
Offline
Зарегистрирован: 08.11.2011

 написал вот так:

char* a = {"abc"}; // задаю переменную
void setup(){
Serial.begin(9600);
pinMode(13,OUTPUT);
}
void loop(){
while(Serial.available() == 0){
}
char a = {Serial.read()- '0'};
if(a == 1 ){
digitalWrite(13,HIGH);
Serial.println(1);
}
else if ("a == low"){ // если в сериал мониторе написать "LOW" я ее использую не, как константу
digitalWrite(13,LOW); // выключить диод на выводе 13
Serial.println("low");
}
else {
Serial.println("I cannot understand");
}
Serial.flush();
}

 

 Пишу 1 диод горит.Пишу low диод не горит.Пишу ерунду а в сериал мониторе вместо того чтобы писаться "I cannot understand" пешится "low" и диод не горит.
 

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

akz пишет:

 написал вот так:

1: char* a = {"abc"}; // задаю переменную

[...]
 

2: char a = {Serial.read()- '0'};
[...]

3: else if ("a == low"){ // если в сериал мониторе написать "LOW" я ее использую не, как константу
[...]

Пишу 1 диод горит.Пишу low диод не горит.Пишу ерунду а в сериал мониторе вместо того чтобы писаться "I cannot understand" пешится "low" и диод не горит.
 

Пункт 1: тут вами определена строковая переменная переменная длиной 4 байта (3 символа и завершающий "\0")

Пункт 2: в функции loop() определена новая строковая переменная непонятной длины, область видимости которой - функция loop(). Т.е. везде, кроме loop(), данные записываются/считываются в глобальную переменную a длиной 4 байта, определенную в первой строке программы (пункт 1), а внутри loop() эта глобальная переменная "заслоняется" локальной с тем же именем - весьма плохой стиль программирования чреватый самыми разнообразными проблемами в дальнейшем.

Пункт 3: Вообще-то, правильнее было бы написать else if(a=="low"), так как в текущем варианте в этой ветви сравнения стоит выражение, не равное нулю, а стало быть, ИСТИНА. И поэтому данная ветвь будет ВСЕГДА выполняться, за исключением варианта a=="1".

Но даже если вы и напишете if(a=="low"), то чуда не произойдет, и эта ветвь не будет срабатывать в нужный вам момент (ввод слова "low"). Потому что чуть раньше - в момент присвоения переменной a значения, пришедшего по последовательному каналу, вы вычли из него '0'. Зачем??? Бездумно скопировали из какого-то кода? Ну что же, получили вполне ожидаемый результат - неработающую логику.

Так что:

Избавьтесь от двойного определения одноименных переменных

Применяйте к переменным только операции, соответствующие их типу - ну не должна переменная работать то как целое, то как строка. Замучаетесь потом отлавливать ошибки.

Учите матчасть (синтаксис языка, описание микроконтроллера, ...)

akz
Offline
Зарегистрирован: 08.11.2011

 Спасибо буду пробывать.

 

 

akz
Offline
Зарегистрирован: 08.11.2011

step962 пишет:

Потому что чуть раньше - в момент присвоения переменной a значения, пришедшего по последовательному каналу, вы вычли из него '0'. Зачем???

  пОТОМУ ЧТО ИЗНАЧАЛЬНО Я ХОТЕЛ ВЫВОДИТЬ ЭТУ ПЕРЕМЕННУЮ В СЕРИАЛ МОНИТОРЕ,.А если бы я не вычел ноль у меня место 1 выходило бы 49 и т.д.

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

Для этого не надо было вычитать из полученного произвольного символа код символа '0'. Достаточно лишь определить переменную как char.

А '0' вычитают обычно для того, чтобы оперировать цифрами 0...9 вместо поступающих по каналу связи символов '0'...'9', то есть с прямо противоположной целью.

akz
Offline
Зарегистрирован: 08.11.2011

 Можете пожалуйста ввести исправления в мой код.Пишу ерунду  в сериал мониторе вместо того чтобы писаться "I cannot understand" пишится "low" вот в чем моя проблема.
 

char* a; // задаю переменную
void setup(){
Serial.begin(9600);
pinMode(13,OUTPUT);
}
void loop(){
while(Serial.available() == 0){
}
char a = {Serial.read()- '0'};
if(a == 1 ){
digitalWrite(13,HIGH);
Serial.println(1);
}
else if ("a == low"){ // если в сериал мониторе написать "LOW" я ее использую не, как константу
digitalWrite(13,LOW); // выключить диод на выводе 13
Serial.println("low");
}
  else {
Serial.println("I cannot understand");
}
Serial.flush();
}
 

akz
Offline
Зарегистрирован: 08.11.2011

почему не работает вот эта часть кода:else {
Serial.println("I cannot understand");
}
 

 

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

akz пишет:

 Можете пожалуйста ввести исправления в мой код.Пишу ерунду  в сериал мониторе вместо того чтобы писаться "I cannot understand" пишится "low" вот в чем моя проблема.
 

1: char* a; // задаю переменную

2: char a = {Serial.read()- '0'};
3: if(a == 1 ){
digitalWrite(13,HIGH);
Serial.println(1);
}
4: else if ("a == low"){ // если в сериал мониторе написать "LOW" я ее использую не, как константу
}
 

1: Тут все более-менее нормально, хотя едва ли оптимально в условиях куцей оперативной памяти ATMega. Лучше написать что-нибудь вроде char a[]="xxx"; // декларация с одновременным выделением необходимого для корректной работы объема памяти

2: Вместо char a={serial.read()-'0'} напишите просто a=serial.read();

Во-первых, объявление локальной переменной здесь ничем не оправдано.

Во-вторых фигурные скобки совершенно излишни.

В-третьих вычитания кода символа '0' не требуется. Все равно дальше вы практически не оперируете целыми числами.

3: Вместо if(a==1) пишите if(a=='1') (или если компилятор заругается - if(a=="1")), ведь переменная а объявлена типа char.

4. вместо else if("a==low")... напишите else if(a=="low") . Сейчас здесь просто бессмыслица стоит

akz
Offline
Зарегистрирован: 08.11.2011

Теперь когда пишишь low в сериал мониторе пишится "I cannot understand"

char* a ="{aaa}"; // задаю переменную
void setup(){
Serial.begin(9600);
pinMode(13,OUTPUT);
}
void loop(){
while(Serial.available() == 0){
}
char a = Serial.read();
if(a == '1' ){
digitalWrite(13,HIGH);
Serial.println(1);
}
else if (a == 'low'){ // если в сериал мониторе написать "LOW" я ее использую не, как константу
digitalWrite(13,LOW); // выключить диод на выводе 13
Serial.println("low");
}
  else{
Serial.println("I cannot understand");
}
Serial.flush();
}
 

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

Сразу после

char a = Serial.read();

поставьте

Serial.println(a);

(кстати после этого можете выкинуть три оператора вывода констант в ветвях конструкции if-else)

И будете видеть, с какой же информацией работает ваша программа.

А дальше - читайте, как правильно принимать потоки данных по последовательному интерфейсу.

 

 

akz
Offline
Зарегистрирован: 08.11.2011

 Я знаю что исправлять ошибки сложнее чем писать программу заново.Значит вот рабочая часть программы :

char* a ="{aaa}"; // задаю переменную
void setup(){
Serial.begin(9600);
pinMode(13,OUTPUT);
}
void loop(){
while(Serial.available() == 0){
}
char a = Serial.read();
if(a == '1' ){
digitalWrite(13,HIGH);
Serial.println(a);
}
else if ('a == low'){ // если в сериал мониторе написать "LOW" я ее использую не, как константу
digitalWrite(13,LOW); // выключить диод на выводе 13
Serial.println("low");
}

Serial.flush();
}

 

 Значит я хочу чтобы когда я писал ерунду в сериал мониторе появлялась надпись "I cannot understand".Пожалуйста помогите правильно написать программу.Мои предыдущие попытки привели к не правильной работе программы.Заранее благодарен.

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

akz пишет:

 Значит я хочу чтобы когда я писал ерунду в сериал мониторе появлялась надпись "I cannot understand".

Введите, как я предлагал в своем последнем посте, инструкцию Serial.println(a); после char a=Serial.read();

И, запустив программу, введите low.

И увидев, что же получает контроллер, вы, может быть,поймете, в каком направлении надо копать.

Как вы сами сказали "Исправлять ошибки сложнее, чем писать программу" - поэтому учитесь находить и исправлять их. Конечно, можно помочь вам "правильно написать программу". Но уверяю вас - программа, написанная и отлаженная самостоятельно (ну, естественно, помощь в отладке вы получите - от меня или кого нибудь другого) даст вам гораздо больше, чем готовое решение.

А пока подсказка (вы это увидите сами, подставив вышеуказанную инструкцию): проблема в том, что ваш алгоритм способен принимать отдельные байты, но не их последовательности.

akz
Offline
Зарегистрирован: 08.11.2011

 Сам я разобраться не могу(новичок в программировании).Я сделал как вы сказали step962 теперь когда пишешь слово пишется только первая буква.Пожалуйста помогите.

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

Ну слава богу - теперь вы хоть понимаете, что проблема в том, что не получается принять всю строку.

Как же это сделать?

Возьмем кусок из начала функции loop()

  while(Serial.available() == 0){
  }
  char a = Serial.read();

и перепишем его:

  while(Serial.available() == 0){
  }
  delay(100);
  int i=0;
  while(Serial.available()) {
    a[i] = Serial.read(); i++;
  }
  Serial.println(a);

Что мы тут делаем?

while(Serial.available() == 0){
  }

Ожидаем появления на входе последовательного канала первого передаваемого символа.

  delay(100);
  int i=0;

Даем пакету данных шанс прийти полностью. Одновременно готовимся к приему последовательности символов.

  while(Serial.available()) {
    a[i] = Serial.read(); i++;
  }

Переписываем все, что есть в буфере UART в нашу строковую переменную. Здесь можно было бы и указателями побаловаться, но эффективность и быстрота кода нам не нужна - мы должны помнить о том, что символы по UART-каналу поступают достаточно медленно и всегда есть опасность достичь конца принятой (в настоящий момент) строки до конца передачи всего пакета данных. Поэтому здесь можно даже небольшой delay дополнительно воткнуть, если вдруг на последующем отладочном выводе вы начнете получать не всю набранную строку.

  Serial.println(a);

А это и есть наш отладочный вывод.

Дальше должны стоять ваши конструкции If, хотя здесь больше подошел бы switch.

Думаю, что после этого вам удастся увидеть чуть больше одного символа в COM-мониторе.

Хотя желаемого результата вы еще не получите. Почему? Почитайте о представлении строк в Си - может быть, разберетесь сами. Нет - ждите продолжения...

 

akz
Offline
Зарегистрирован: 08.11.2011

 Спасибо работает.Правда иногда в сериал мониторе пишется то, что я пишу, а иногда появляются дополнительные символы, но с этим я сам разберусь.

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

akz пишет:

 Спасибо работает.Правда иногда в сериал мониторе пишется то, что я пишу, а иногда появляются дополнительные символы, но с этим я сам разберусь.

Как я писал в предыдущем посте,

Цитата:

... желаемого результата вы еще не получите. Почему? Почитайте о представлении строк в Си ...

Adessit
Adessit аватар
Offline
Зарегистрирован: 12.04.2011

На будущее, господин akz  при вставке кода в форум, есть специальная кнопка "Code"сверху поля ввода.

12sd
Offline
Зарегистрирован: 04.08.2011

 int a = (int) kakaya_to_stroka;

Это называется "явное приведение типов".

Можно еще atoi () функцию использовать, но для этого сторонние серъёзные либы нужны - она лучше работает. 

akz
Offline
Зарегистрирован: 08.11.2011

Adessit пишет:

На будущее, господин akz  при вставке кода в форум, есть специальная кнопка "Code"сверху поля ввода.

 Буду знать.

serenya
Offline
Зарегистрирован: 17.02.2012

Добились ли Вы каких либо результатов? У меня аналогичная задача, а о представлении строк в Си понятия не имею и не понял ничего в этом. Код который привел step962 работает но не полностью, буфер не очищается и если послать сначала 5 символов а затем 3, возвращается сначала те же 5 символов, а потом 3 отправленные плюс 2 последних из первой посылки. как это побороть я не знаю.  Подскажите пожалуйста.

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

Цитата:

 и перепишем его:

while(Serial.available() == 0){}
delay(100);
int i=0;
while(Serial.available()) {
  a[i] = Serial.read(); i++;
}

Serial.println(a);

Что мы ту

и перепишем его еще раз:

while(Serial.available() == 0){}
delay(100);
int i=0;
while(Serial.available()) {
  a[i] = Serial.read(); i++;
}
a[i] = '\0';
Serial.println(a);

Что мы тут делаем? Да то же самое, что и раньше. Только дополнительно - после считывания принятых символов - ставим в конец строки символ конца строки (уж извините за тавтологию).

serenya
Offline
Зарегистрирован: 17.02.2012

Спасибо, вечером попробую

Хотя если я правильно понимаю, то массив будет заполняться всем содержимым буфера, и если я пошлю 3 символа, то serial.read() вернетвсе равно 5 символов и к ним мы добавим символ конца строки. Может мне поможет команда Serial.flush(), если я правильно понял она очищает буфер.

akz
Offline
Зарегистрирован: 08.11.2011

 Если честно у меня тогда ничего не получилось и я забросил и даже забыл об этом(потому что товарищ step962 никогда не выкладывет код до конца).Сейчас под рукой нет ардуино, как только будет я проверю код.

serenya
Offline
Зарегистрирован: 17.02.2012

Попробовал код step962, кажется работает как надо, хотя механизм я так и не понял.

serenya
Offline
Зарегистрирован: 17.02.2012

http://www.faludi.com/itp_coursework/meshnetworking/XBee/XBee_program_Ar...

Здесь реализовано то что нужно, у меня заработало по полной.

bababababa
Offline
Зарегистрирован: 28.10.2011

 Помогите улучшить код. В ходе экспериментов, понял, что сериалу нужно время для принятия всей строки.

Сделал задержку 5 милисек (1 милисек на 1 символ), всё работает хорошо, но мне нужна высокая производительность, если кто подскажет как оптимизировать этот алгоритм, буду благодарен. Вообще по сериалу отсылается строка цифр известной длины. Как с наименьшими потерями перевести эту строку в цифры?

И попутно вопрос, как записывать данные на компе? В эксель или блокнот.  Скачал программу  www.mikmo.dk/gobetwino.html пока не разбирался, подскажите направление работы.

 

 

  void loop()
  { 
  while (Serial.available()==0) {
  }
  
  delay(5);
  n1=Serial.available();
  
  while (n1>0)  {
  sim=Serial.read()-'0';
  data=data+sim;
  n1=n1-1;
  }
  
    Serial.println(data);
    data="";
    sim="";
    Serial.flush();
}

 

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

bababababa пишет:

 Помогите улучшить код. В ходе экспериментов, понял, что сериалу нужно время для принятия всей строки.

Это вы правильно заметили. Может быть вы еще не заметили, но в функции setup() обычно стоит строка

Serial.begin(9600);

Так вот, если прочитать об этой функции, то можно узнать, что передаваемый ей единственный параметр - это скорость, на которой будет осуществляться обмен данными по UART со стороны мк. Эти скорости стандартизованы. Кроме 9600 (9600 бит в секунду, по 9 битов на передаваемый байт - получаем около 1000 символов в секунду, то есть по миллисекунде на символ) имеются еще скорости 14400, 19200, и т.д., в качестве максимальной приводят обычно 115200, но есть и еще более высокие - почитайте даташит на мк.

Цитата:

Сделал задержку 5 милисек (1 милисек на 1 символ), всё работает хорошо, но мне нужна высокая производительность, если кто подскажет как оптимизировать этот алгоритм, буду благодарен. Вообще по сериалу отсылается строка цифр известной длины. Как с наименьшими потерями перевести эту строку в цифры?

Как "оптимизировать", вы теперь, может быть, догадаетесь, почитав рекомендованные вещи. Символ 'цифра' преобразовать в цифру просто - из символа необходимо вычесть код символьного представления нуля. Проще всего это сделать так:

v = c-'0';

Для '0' получим 0, для '1' -1 и так далее до '9' (для этого сивола получится, естественно, 9).

Ну, а как собрать из отдельных цифирей число - это, надеюсь, вы помните из школьного курса?

Цитата:

И попутно вопрос, как записывать данные на компе? В эксель или блокнот.  Скачал программу  www.mikmo.dk/gobetwino.html пока не разбирался, подскажите направление работы.

 

Это пусть кто-нибудь другой подсказывает.

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

 ну если "строка цифр известной длины", то гораздо лучше вычитывать из Serail именно такое количество символов. По одному.

Ведь если, с компа, эту строку будет слать человек, а не софт (например вы в отладочных целях), то за 5 милесекунд он может и не успеть ее набрать. Сделайте счетки типа readedCounter и

Как-то так


int readed=0;

while (readed<5)  { // читаем строку длиной 4 символа
   
     if(Serial.available()){
        sim=Serial.read()-'0'
        // обрабатываем наш символ
        readed++;
      }
  }

Дальше, нужно там где "обрабатываем символ" собрать эти поступающие по очереди цифры в одно число.

Думаю вы сможете это сделать, если решите следующую алгебраическую задачу. Дано два числа a=2 и b=5. Вопрос какие арефметические операции (не строковые) нужно выполнить над этими числами, что-бы получить число 25?

Вот в дальнейшем "a" это будет ваш "накопитель" в котором вы собираете число, а "b" новый символ который нужно обработать.

bababababa
Offline
Зарегистрирован: 28.10.2011

спасибо за ответы. про сериал, да я как то забыл)

вот ещё пример простейшего кода, на мой взгляд самое то, для приема сериал, и перевода в цифры.

while (Serial.available()==0){
}
//Задержка делается чтобы сериал мог полностью принять входящие данные
delay(100);

    while (Serial.available())
    {
     result = result * 10 + (Serial.read() - '0');
    }
    
    Serial.println(result);
    result=0;
    Serial.flush();    

Про Excel. www.mikmo.dk/gobetwino.html Эта программа позволяет легко и просто записывать данные из сериал порта в файл, текстовый, эксель и ещё какие то)) внутри инструкция, на английском но вообщем понятная, за полчасика освоил.

 

ntdfish
Offline
Зарегистрирован: 10.06.2012

Все это очень интересно но не могу понять зачем вы организуете циклы для записи данных из буфера?

Я налаживаю связь между ардуиной и матлабом через usb и у меня хорошо работает такой код:

#define LED 8      //LED_pin
char message;   // for incoming serial data

void setup()
{
  pinMode(LED,OUTPUT);
  Serial.begin(9600);
}

void loop() {
while(Serial.available() == 0){
digitalWrite(LED, LOW);
}
if (Serial.available() > 0) { // if there are bytes waiting on the serial port
  digitalWrite(LED, HIGH);  // indicate
  delay(100);  // wait beforereading
  message = Serial.read();
}
if (message == 'ABC') { // check message
  digitalWrite(LED, HIGH);  // indicate
  delay(1000);
}
delay(1000);
Serial.print(message);
message=0;
Serial.flush();
}

Все хорошо принимается и отсылается  назад. Плюс ардуина распознает ключ "ABC".

А вот если я начинаю организовывать циклы типа упоминавшихся ранее:

a[i] = Serial.read(); i++;

или

result = result * 10 + (Serial.read() - '0');

то начинает твориться что-то непонятное.

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

Подзодреваю что просто ошибаетесь когда думаете  "ардуина распознает ключ".

Переменная message имеет размер один байт. Строка 'ABC' - имеет размер три байта (плюс символ конца строки). Один байт никогда не будет равен трем байтам.

В строке 20-ть, сделайте, вместо диода, Serial.println("Key detected"); Откройте сериал монитор, пошлите в него ABC и услышите в ответ "тишина", а не "Key detected".

А "непонятное" творится потому что вы, скорее всего, не проверяете что принятый символ находит в диапазоне от 48 до 57. И пытаетесь декодить буквы и служебные символы (перевод строки и т.п.) . Для которых выражение Serial.read() - '0' , естесвенно не имеет смысла.

Ну и задачи перевести в строку в число в вашем коде решить не возможно. Можете например послать в сериал строку '357', принять ее ардуиной, прибавить к нему три, умножить на два и вернуть результат в serial (должно вернутся 720) ?  Без конвертации принятой строки в число - это не выйдет. А для этого нужен массив или вот этот result = result * 10 + ...

Вообщем-то, не помню с какой версии arduinoIDE для этого, у Serial есть вспомогательный метод Serial.parseInt(), который может взять на себя эту черновую работу (но внутри у него - все тоже самое), но его не всегда можно применить (напрмер когда данные идут очень медленно и паралельно с приемом нужно еще что-то делать).

maksim
Offline
Зарегистрирован: 12.02.2012

Во первых, 'одинарные ковычки' применяются для обозначения одного символа, а не строки, строка обозначается "двойными ковычками" так что что у вас на самом деле получается при объявлении 'ABC' не известно. 

Во вторых, назад ваш код отсылает только первый символ принятого "ключа", в вашем случае это буква А.

Ну а в третих, весь ваш код можно заменить на код ниже, работать будет точно также.

#define LED 8      //LED_pin
char message;   // for incoming serial data

void setup(){
  pinMode(LED,OUTPUT);
  Serial.begin(9600);
}

void loop(){
  if(Serial.available()) { // if there are bytes waiting on the serial port
    digitalWrite(LED, HIGH);  // indicate
    delay(1000);
    digitalWrite(LED, LOW);
    message = Serial.read();
    Serial.print(message);    
    Serial.flush();
  }
}

 

ntdfish
Offline
Зарегистрирован: 10.06.2012

Спасибо что ответили. Да все плохо :)

Подскажите где взять хорошее описание работы с serial? Стандартное описание из ardino совсем никуда не годится.

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

ntdfish пишет:

Спасибо что ответили. Да все плохо :)

Подскажите где взять хорошее описание работы с serial? Стандартное описание из ardino совсем никуда не годится.

Что значит "никуда не годится"? Вполне себе нормальная документация. Даже не плохая. Ну "не все переведено", тогда на "оригинал" смотреть http://arduino.cc/en/Reference/HomePage

А еще примеры всякие с arduinoIDE идут.

Оно может показаться "темным лесом" если вы пробуете "перепрыгнуть ступеньку". Не имея "програмерской базы" (четкого понимания что такое типы, переменные, фунции, операторы управления и т.п.) начали работать с "более комплексными примерами". Попробуйте начать чтение документации не с Serial а c боле базовых вещей. Какие-то книжки почитать, даже не обязательно "по ардуине", а просто по "какому-нибудь С подобному языку" (или просто по C/C++).

Можете погулить какие-то книги типа "Arduino cookbook" - сборники решений "типовых задач", но, опять-таки не имея базы понять-применить их будет не просто.

ntdfish
Offline
Зарегистрирован: 10.06.2012

 Может кто все таки поделится книжкой.

А пока я переписал код вот так:

void loop() {
if (Serial.available() > 0) { // if there are bytes waiting on the serial port
  delay(10);  // wait beforereading
  int len = 3; // expected string is 3 bytes long
  char message[len]; // declare string variable
  for (int i = 0; i < len; i++) {
    message[i] = Serial.read();
    delay(10);
  }
  delay(1000);
  Serial.print(message);
  if (String(message) == "ABC") { // check
  Serial.println("Key detected");
  }
}
Serial.flush();
}

В принципе назад в матлаб сообщения приходят, но во-первых, ардуина не расспознает команду ABC. Почему? А во-вторых, если длина сообщения больше 3, например 4, то оставшиеся символы сообщения заполняются кодом 255 плюс приходит одно лишнее сообщение. Вот пример ответа на "ABC1" в кодах ASCII:

65 66 67 49 255 255 211 4 3

От куда берется одно лишнее сообщение?

ntdfish
Offline
Зарегистрирован: 10.06.2012

Да вы правы, конкретно с Си опыта не хватает. Однако родное описание все таки не дотягивает...

Нашел какую-то книжку, там вроде есть более детальное описание раздела serial. Может тоже кому понядобится.

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

 >Может кто все таки поделится книжкой.

Гугл поделится.

И еще почитайте раздел сайта программирование. Особенно про string (который с маленькой буквы!).

String с большой, тут можно было и не использовать. обойтись массивами. только message тогда нужно было-бы сделать в 4-ре байта. и, после прочтения трех байт из сериал, в конце добалять message[3]=0;   (это признак конца строки, в C, все сишный функции "расчитывают" на его существование). Тогда, для сравнение, не нужно было-бы создавать новый объект String, а можно было-бы воспользоваться функций strcmp(message,"ABC")==0

Далее - совершенно не понятно желание везде натыкать delay() :)  

Предназначение его в строке 10 - для меня полная загадка. Разве что "терпение вырабатывать".

А в строке 08 - видимо "для того что-бы следующий байт успел прийти. Но "по феншую" это лучше так не делать (а если его дольше не будет? А если, наоборот будет быстрее - значит "тупим в пустую"). Феншуйно будет выкинуть delay из строки 08, и сделать так:

while(!Serial.avaliable()){} // ждем пока не появится чего-нибудь в serial
message[i] = Serial.read();

Тогда вы будете "тупить" ровно столько сколько нужно. До тех пор пока не прийдут данные. Ни больше, ни меньше (правда если они вообще не прийдут.... скетч будет стоять и ждать).

Далее. Все-таки почитайте про Serial в оригинале. Там есть такая функция как Serial.readBytes(). Которую и придумал что-бы сделать всю эту черновую работу за вас.

Она  вполне может заменить весь ваш цикл.  Serial.readBytes(message,3). Она сама озаботится и "подождать следующий байт" и "прерватся если вышел таймаут". Возвращает она сколько байт "удалось прочитать в буффер".

>но во-первых, ардуина не расспознает команду ABC. Почему?

ну вот скорее всего потому что вы забыли про необходимость нуля в конце строки. Вот оно и "поперло дальше" по памяти пока не наткнулось на какой-то ноль и поняло что "строка закончилас". Вот попробуте, из любопытсва, сделать вывести длину этого вашего String(message). Скорее всего там будет что-то больше 3 (вообщем пока случайно не попадется ноль).

Во вторых - отложите матлаб в сторону. Добейтесь "Key detected" посылая руками в Serial мониторе.

 

 

 

 

 

 

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

ntdfish пишет:

Нашел какую-то книжку, там вроде есть более детальное описание раздела serial. Может тоже кому понядобится.

Да подождите с Serial. У вас же не с ним проблема явно. А с непонимаем строк. Про стороки, массивы, указатели читайте, а потом про сериал.

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

ntdfish пишет:

А пока я переписал код вот так:

void loop() {
if (Serial.available() > 0) { // if there are bytes waiting on the serial port
  delay(10);  // wait beforereading
  int len = 3; // expected string is 3 bytes long
  char message[len]; // declare string variable
  for (int i = 0; i < len; i++) {
    message[i] = Serial.read();
    delay(10);
  }
  delay(1000);
  Serial.print(message);
  if (String(message) == "ABC") { // check
  Serial.println("Key detected");
  }
}
Serial.flush();
}

В принципе назад в матлаб сообщения приходят, но во-первых, ардуина не расспознает команду ABC. Почему?

Потому что строки в Си завершаются символом '\0'. У вас под трехсимвольную строку выделено три байта. Места под "правильный" завершающий нуль уже нет. Стало быть, проверка будет производиться наудачу - до встречи первой ячейки в памяти, которая - совершенно случайно - имеет значение 0. Хотите добиться правильного сравнения строк - прочитайте-таки о строках Си (хотя бы основы) и, вооружившись почерпнутыми там знаниями - записывайте в четвертый элемент массива message значение 0:

message[3]='\0'; // (после выхода из цикла, в котором вы принимаете поступающие по UART символы)

И - во избежание нежелательных побочных эффектов - не пользуйтесь при определении массивов переменными:

не char message[len]; (где len - переменная, определенная строкой выше)

а char message[LEN]; (где LEN - константа, определенная в заголовке программы: #define LEN 3)

 

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

 А вообще я не очень понимаю что вы хотите "читать про Serial". Что-бы работать с сериал, достаточно прочитать документацию на три функции begin, read,write . В редких случаях может потребоваться flush.

Все остальные функции Serial - это "помогайки-обертки" над этими базовыми. Используя пару  read/write можно принять что угодно и передать что угодно и как угодно.

ntdfish
Offline
Зарегистрирован: 10.06.2012

Спасибо СИнсеи :)

Конкретно про serial мне многое не понятно: размер буфера serial, как в буфере накапливаются символы, как буфер очищается и тп. Согласитесь в родном описании про это ни слова. Ладно почитаем.

А вы кстати не пользуетесь обычным компилятором Си для отладки? Просто с ардуины тяжело получить обратную связь. Этакий черный ящик. Я пока только по лампочкам могу определять отработку тех или иных блоков программы: зашел в условие - зажег лампу.

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

> Конкретно про serial мне многое не понятно:
>размер буфера serial,
достаточно в каталоге ArduinoIDE пройти в поддиректорию hardware/arduino/cores/arduino - здесь хранятся "родные" исходники Arduino - и открыть файл HardwareSerial.cpp. В нем, немного покопавшись, вы найдете ответ на этот вопрос: у камней с RAM<1K приемный буфер имеет длину 32 байта, у всех остальных - 128

#if (RAMEND < 1000)
  #define RX_BUFFER_SIZE 32
#else
  #define RX_BUFFER_SIZE 128
#endif

Кстати, о длине буфера сказано в описании метода Serial.available/

>как в буфере накапливаются символы,
Что вам даст ответ на этот вопрос? Вы хотите напрямую обращаться к буферу, не пользуясь имеющимися у класса методами?
Ну, а если для общего развития, то буфер организован в виде очереди: поступающие символы записываются в хвост очереди, вы - методом Serial.read считываете их из головы очереди. Два имеющиеся в составе класса указателя указывают (кто бы мог подумать?) на голову и хвост очереди. Хотите узнать побольше об организации очереди? Почитайте в Сети о классе Queue.

>как буфер очищается
метод Serial.flush 

>и тп. Согласитесь в родном описании про это ни слова.
Естественно, не соглашусь

>Ладно почитаем.
Вот это правильно.

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

ntdfish пишет:

А вы кстати не пользуетесь обычным компилятором Си для отладки? Просто с ардуины тяжело получить обратную связь. Этакий черный ящик. Я пока только по лампочкам могу определять отработку тех или иных блоков программы: зашел в условие - зажег лампу.

И кстати комплятор Си тут ничем не поможет. Задача компилятора переводить "человеческий язык" в машинные коды.

Отлаживать может - среда разработки. Но, для этого она должна иметь, в своем составе, либо эмулятор целевого процессора, либо сам процессор должен на железном уровне поддерживать отладку. Уметь останавливаться и по специальным интерфейсам (JTAG и и же с ними) сообщать компу "что там в нем происходит".

AMTEL-камни, на которых построенна ардуина - не имеют такой фичи. Остается "эмуляция". Насколько я знаю всякие WinAvr и т.п. - не содержат эмуляции. 

Эмуляция возможно программами типа http://www.virtualbreadboard.com/ , но "она денег стоит" и честно говоря я так, до конца и не понял по описанию и отзывам). А "честно эмулирует процессор" или, все-таки, запускает ардуиновкий код как java-программу (а значит отладка может сильно отличатся от реальности).

Еще дебажить можно в Proteus (гуглится как это делать). Пробовал - работает. Но "поигрался и положил". Когда идет "реальная работа" проще воткнуть Serial.println в интересующие место, чем заморачиватся с ним.

Вот тут еще есть список симуляторов:

http://www.arduino.com.au/Simulator-for-Arduino.html

Попробовал первый - вроде ниче так. Правда у него крайне кисло с эмуляцией внешнего оборудования, но за те деньги что он счас продается  - думаю взять сегодня/завтра. Авось пригодится. Остальные - честно говоря не смотрел особо. Если хотите - можете все перепробывать. Поделитесь впечатлениями.

Но вообщем мое IMHO что "нужен дебагер" - это привычка/стереотипы с "большого компа". На том уровне сложностей ардуиновских скетчей в 99% хватает диодов и Serial что-бы понять "что там происходит".

capt_smile
Offline
Зарегистрирован: 18.12.2012

или я устал или в конец отупел. но подскажите почему не очищается Serial.available:

void setup()
{
  Serial.begin(9600);
  Serial.println("Start");
}

void loop()
{
   Serial.println(Serial.available());  
   Serial.flush();
   delay(1000);
}

 

Alexander
Offline
Зарегистрирован: 25.04.2010

Я поправил описание Serial.flush() Начиная с версии Arduino 1.0 логика работы функции изменилась. Теперь она ожидает окончание отправки данных.

capt_smile
Offline
Зарегистрирован: 18.12.2012

а какая-же функция на самом деле будет очищать буфер?

ну или какой хитростью мне достигнуть результата? нужно считать символы из сериалМонитора в массив и вывести его