Последовательный порт и преобразование данных.

XinoXano
XinoXano аватар
Offline
Зарегистрирован: 29.04.2011

Здравствуйте.

Помогите пожалуйста решить такую задачку:

Через последовательный порт вводится число от 1 до 9, нужно мигнуть светодиодом на 13 пине соответствующее количество раз, от 1 до 9.

 

Вроде бы элементарщина, но никак не могу разобраться с типами данных. Как можно полученный через последовательный порт символ использовать далее в программе в качестве переменной типа int?

набросал вот такой скетч:

int x=0;
void setup()
{
Serial.begin(9600);
pinMode(13, OUTPUT);
}
void loop()
{
if (Serial.available() > 0)
{
x = Serial.read();

//Serial.println(x); - если выводить обратно полученный символ - видно что это его десятичный ASCII код 
//Serial.println(x, BYTE); - если вывести в виде байта - вроде бы то, что нам нужно...

//x=byte(x);


}
if (x>9) x=9;
if (x<1) x=1;
for (int i = 0; i<=(x-1); i++)
{
digitalWrite(13, HIGH);
delay(200);
digitalWrite(13,LOW);
delay(200);
}
delay(1000);
}

в общем пробовал далее использовать конструкции типа x=byte(x) или x=int(byte(x)) - все равно в переменной остается десятичный код или что-то такое - светодиод при попытке ввода в любом случае будет мигать 9 раз, значит в переменной x находится что то явно больше 9;

Что же нужно сделать, чтобы введенная через порт цифра попала в переменную именно в том виде в котором это позволило бы выполнить условие задачи?

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

 

 

Во первых как поступают данные на ардуино? Тоесть передаётся например цифра 9 один раз или постоянно, перерывы?
Дальше я в коде заметил только если х меньше 1 то х=1, если х больше 9 то равно х=9
А где же тогда проверка сколько раз моргаь? Получается только 9 или 1 раз может моргать.
Нужно вводить задержки или в считывании или в передаче данных в ардуино.
Почему бы не поставить в цикле i=0, i==x,i++
 

XinoXano
XinoXano аватар
Offline
Зарегистрирован: 29.04.2011

Во первых как поступают данные на ардуино? Тоесть передаётся например цифра 9 один раз или постоянно, перерывы?

На этот счет в условии ничего не сказано, следовательно цифры от 1 до 9 вводятся n раз с произвольными промежутками времени между попытками ввода.


Дальше я в коде заметил только если х меньше 1 то х=1, если х больше 9 то равно х=9
А где же тогда проверка сколько раз моргаь? Получается только 9 или 1 раз может моргать.

если 1<x<9 то в переменной x сохранится ее значение. Следовательно x может принимать любые значения от 1 до 9. 
Нужно вводить задержки или в считывании или в передаче данных в ардуино.

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

Почему бы не поставить в цикле i=0, i==x,i++

в моем скетче цикл "мигания" выглядит как for (int i = 0; i<=(x-1); i++){...} это означает, что он выполнится x раз. Ну, если бы мне удалось успешно записать в x какую либо цифру из порта. Если перед циклом произвести присваивание переменной x некоего значения вручную и сделать перезаливку скетча - все работает как надо.

Ваш пример цикла неработоспособен, поскольку  результат операции сравниения i==x вернет истину только в случае если x==0. В этом случае цикл выполнится 1 раз. В случае если ((x>0) ||  (x<0)) цикл вообще не выполнится ни разу.

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

Про задержки которые delay().

Например если перевести данные с ком порта в обычный цифровой вид и ограничить диапазон переменной Х от 0 до 255

Далее внести это значение в analogWrite(LED,X) То Светодиод подсоединённый к порту LED будет гореть постоянно, ввиду того что данные поступают очень быстро, и просто вместо разных значений яркости мы не увидим мерцаний(конечно если данные поступают разные и хаотично). Но если после каждого считывания ставить паузу хотябы 30 мс то уже будут заметны изменения данных на светодиоде. 

Может конечно я в конец недели торможу, но вот эта проверка не подходит

if (x>9) x=9;
if (x<1) x=1;

Должно быть так

if (x>0) {

if(x<=9){

делаем что-то

}

}

Получается что если х больше 0 и если меньше либо равно 9 то делаем что-то

 

а вообще можно и так попробовать if(1<x<9) - IDE не ругается

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

На крайний случай кстате можно выводить среднее число за определенный промежуток времени, и дальше уже играться 

XinoXano
XinoXano аватар
Offline
Зарегистрирован: 29.04.2011

 Про задержки которые delay().Например если перевести данные с ком порта в обычный цифровой вид и ограничить диапазон переменной Х от 0 до 255

Далее внести это значение в analogWrite(LED,X) То Светодиод подсоединённый к порту LED будет гореть постоянно, ввиду того что данные поступают очень быстро, и просто вместо разных значений яркости мы не увидим мерцаний(конечно если данные поступают разные и хаотично). Но если после каждого считывания ставить паузу хотябы 30 мс то уже будут заметны изменения данных на светодиоде.

Задача то в том, чтобы мигнуть несколько раз, а не в том, чтобы менять яркость свечения. Хотя если бы вы привели фрагмент кода, в котором данные из порта попадают в переменную, которая устанавливает яркость свечения - это тоже было бы решением проблемы, с которой я столкнулся. 

Кстати я еще даже еще незадумывался на вопросом, как считывать двух и трехзначные числа из порта в переменную... Декларировать строку длинной не менее буффера последовательного порта и посимвольно записывать туда считываемые символы? А затем преобразовывать строку в число? Надо будет попробовать.

Может конечно я в конец недели торможу, но вот эта проверка не подходит

if (x>9) x=9;
if (x<1) x=1;

Ну и почему же она не подходит? особенно если учесть, что результатом работы программы должна быть серия "мигов" - от 1 до 9?

Если уж вас так смущает эта часть, можно ее вообще выкинуть, это никак не повлияет на результат, за исключением того момента, что в переменной может находится значение, не обладающее свойством достоверности для данной задачи. Иначе говоря, вместо серии "мигов" от 1 до 9, может вообще не быть "мигов" - если в переменной оказалось нулевое или отрицательное значение или же серия "мигов" будет очень длинной - несколько сотен раз. Это непринципиально, поскольку в условии про контроль вводимых данных или отсеивание заведомо неправильных значений  ничего сказано не было. Поставил проверку чисто машинально наверное.

Должно быть так

if (x>0) {

if(x<=9){

делаем что-то

}

}

Получается что если х больше 0 и если меньше либо равно 9 то делаем что-то

 

а вообще можно и так попробовать if(1<x<9) - IDE не ругается

Если вас заинтриговала задача, может быть попробуете ее решить самостоятельно, благо даже переписать ее с нуля займет 5 минут времени и выложите сюда свой метод решения или скетч? Я бы с радостью на него посмотрел, потому что сам уже вроде бы перебрал все возможные варианты решения, но успеха так и не достиг.

XinoXano
XinoXano аватар
Offline
Зарегистрирован: 29.04.2011

Adessit пишет:

На крайний случай кстате можно выводить среднее число за определенный промежуток времени, и дальше уже играться 

Вводятся циферки все вручную. То есть мы же не работает с потоком цифр, которые выдает скажем какая то программа или датчик, нет необходимости ничего усреднять.

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

С удовольствием (люблю решать задачи), но плату ардуины забыл на работе. Могу лишь набить код но проверить не смогу( 

Для начала вот откройте в Arduino IDE - Examples - Comunication - Dimmer

Там простое присвоение про которое я говорил. НО ТАМ РАСЧИТАНО НА ПОДАЧУ СИГНАЛА ОТНОСИТЕЛЬНО ПОСТОЯННОГО, тоесть если он опять же сильно будет изменяться то на глаз просто будет не разглядеть изменений. Тоесть например посылаем триста раз например значение 100, и светодиод будет на половину яркости светится и это будет видно

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

Еще приведу пример. Из своего опыта:

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

Так и со светодиодом и резкими изменениями.

 

Если упростить задачу?

Например в течении 4х секунд подавать одно число (например 7), то ардуино считав его проморгает за 3 секунды семь раз и сделает перерыв еще на секунду, тоесть можно легко посчитать, количество морганий

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

Еще вариант 9 светодиодов, получится что то типа светодиодной линейки, и не надо мигать. Будет как уровень в магнитофонах) Но опять же надо ставить задержки8)

Меня уже совсем далеко унесло, верните меня;) Пошел прогуляться, я понял, у вас и так большие задержки под конец вашего кода, тоесть ардуино считывает значения с ком порта раз в 2 секунды грубо говоря

XinoXano
XinoXano аватар
Offline
Зарегистрирован: 29.04.2011

Рассмотрим следующий пример:

int x; char a='3';
Serial.println(a);  //тут все выводится правильно - символ '3'
for(x=0;x<int(a);x++); // по идее этот цикл должен выполнится ровно 3 раза, потому что функция int(a)  должна была преобразовать символ '3' в число 3 
Serial.println(x); //здесь по идее должно было бы быть выведено число 3, но вместо этого выводится десятичный код символа '3' - 52 

 

Вопрос то как раз в том - почему не работает преобразование типа в этом случае? в обучалке, да и на arduino.cc ни про какие ограничения не написано... А ведь вроде везде пишут, что "Язык программирования устройств Ардуино основан на C/C++"... 

Может быть я что-то не так понимаю?

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

Извините! пока умнее не придумал((((

int x=0;
int p=0;
void setup() 
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);
}

void loop() 
{
  if (Serial.available() > 0) 
  {
    x = Serial.read();
    if (x=='1')
    p=1;
    if (x=='2')
    p=2;
    if (x=='3')
    p=3;
    if (x=='4')
    p=4;
    if (x=='5')
    p=5;
    if (x=='6')
    p=6;
    if (x=='7')
    p=7;
    if (x=='8')
    p=8;
    if (x=='9')
    p=9;

  }
  for (int i = 1; i<=p; i++)
  {
    digitalWrite(13, HIGH);
    delay(100);
    digitalWrite(13,LOW);
    delay(100);   
  } 
p=0;
}


!!!!!!!!!!!!!!!!!!!!!!
ОООО уменьшил
!!!!!!!!!!!!!!!!!!
int p=0;
void setup() 
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);
}
void loop() 
{
  if (Serial.available() > 0) 
  {
   p = Serial.read()-48;
  }
  for (int i = 1; i<=p; i++)
  {
    digitalWrite(13, HIGH);
    delay(100);
    digitalWrite(13,LOW);
    delay(100);   
  }
p=0; 
}

 

XinoXano
XinoXano аватар
Offline
Зарегистрирован: 29.04.2011

LEVV2006 пишет:

!!!!!!!!!!!!!!!!!!!!!! ОООО уменьшил !!!!!!!!!!!!!!!!!!  { p = Serial.read()-48; } 

 

Спасибо, как раз то что нужно!

LEVV2006
LEVV2006 аватар
Offline
Зарегистрирован: 15.04.2011

 Всё основано на Таблица кодировки символов ASCII. По usb передается номер символа.

 

Таблица

В первом варианте как раз проверяется на символы.

XinoXano
XinoXano аватар
Offline
Зарегистрирован: 29.04.2011

LEVV2006 пишет:

 Всё основано на Таблица кодировки символов ASCII. По usb передается номер символа.

 

Таблица

В первом варианте как раз проверяется на символы.

Ну это все понятно, просто я почему то подумал, что для этого дела уже должна существовать готовая функция или что это можно сделать просто преобразовав тип =)

Каюсь, затупил.

LEVV2006
LEVV2006 аватар
Offline
Зарегистрирован: 15.04.2011

Я сам не гуру в программировании. Просто сам так делал. Возможно существуют и другие средства и методы для нормального преобразования типов. 

Holmaster
Offline
Зарегистрирован: 14.08.2013

Всем привет! Вопрос к спецам, мастерю ситему которая присматривает за домом: отопление, датчик газа, вентиляция и т.д. Прога вращается на штатном компьютере общаясь по USB с переферией через ATMEGу. Нужен надежный протокол общения, если можно то покажите примеры. 

BlackHarold
Offline
Зарегистрирован: 27.08.2015
int i=0;                                                          //цифра которую введем через СОМ
int x;                                                            //сколько раз повторим мигание диодом
int led = 5;                                                      //диод которым будем мигать
 
void setup()
{
Serial.begin (9600);
pinMode (led, OUTPUT);
}
 
void loop()
{
  if (Serial.available() != 0)
  {
    i=Serial.read()-48;
    /*Serial.println("New number: ");                             //для развлечения */
    Serial.println(i);                                            //печатает на экран введеное число
    x=i;                                                          //уравнивает X c I
   }
   while(x>0)                                                     //x больше нуля чтобы повторить то кол-во которое в порту.
   {
   
   x--;                                                           //уменьшает на 1 за каждый проход, чтобы совпало с нужным кол-вом
   Serial.println(x);                                             //печать в порт для самопроверки
   //digitalWrite(led,!digitalRead(led));                         //если использовать так, то считывает цикл чаще 1 раза за мигание)
   digitalWrite(led, HIGH);
   delay (1000);
   digitalWrite(led, LOW);
   delay (1000);
   }
}
andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Holmaster пишет:

Всем привет! Вопрос к спецам, мастерю ситему которая присматривает за домом: отопление, датчик газа, вентиляция и т.д. Прога вращается на штатном компьютере общаясь по USB с переферией через ATMEGу. Нужен надежный протокол общения, если можно то покажите примеры. 

Если через USB, то практически безальтернативно - эмуляция COM-порта. Стандартный объект Serial.

pomkka
Offline
Зарегистрирован: 18.08.2015

Подскажите, пожалуйста, можно ли как-то отбрасывать "паразитные" данные. Посылаю через com порт символ,  обратно возвращается его код, однако ардуино отрабатывает 3 раза (подключил 4 сдвиговых регистра и наблюдаю за перемещением сигнала по лампочкам). Опытным путем вычислил, что передаются символы с кодом: 80 и 176. Есть ли какие-то ограничения на прием данных? 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

XinoXano пишет:

Рассмотрим следующий пример:

int x; char a='3';
Serial.println(a);  //тут все выводится правильно - символ '3'
for(x=0;x<int(a);x++); // по идее этот цикл должен выполнится ровно 3 раза, потому что функция int(a)  должна была преобразовать символ '3' в число 3 
Serial.println(x); //здесь по идее должно было бы быть выведено число 3, но вместо этого выводится десятичный код символа '3' - 52 

 

Вопрос то как раз в том - почему не работает преобразование типа в этом случае? в обучалке, да и на arduino.cc ни про какие ограничения не написано... А ведь вроде везде пишут, что "Язык программирования устройств Ардуино основан на C/C++"... 

Может быть я что-то не так понимаю?

Совершенно верно - не так понимаете.

int('1') - вовсе не преобразование сивола 1 в число 1. Это преобразвание типа байт в тип int безо всекого изменения содержимого. Результатом будет целое число равное коду символьной единицы.