Как отправлять второй байт с данными в зависимости от первого байта, который был отправлен раньше?

sergiu920
Offline
Зарегистрирован: 27.12.2014

Приветствую дорогие форумчани! У меня к вам такой вопрос: Как отправлять второй байт с данными в зависимости от первого байта, который был отправлен раньше?

Описание проекта, над которым я работаю:

В общем, мне надо сделать один проект который состоит из базы(плата FPGA) и пару плат arduino, соединены последовательно через UART. Этот проект я делаю вместе с коллегой, он занимается базой(плата FPGA), а я с платами arduino. К каждой плате arduino будет соединен один светодиод и один потенциометр. 

С базы FPGA мне отправит пакет с данными, который состоит из 2 байта. В одном байте будет номер платы arduino с которой хотим общаться, а во втором байте будет 3 команды. 2 для светодиода (Включить/Выключить) и одна команда для потенциометра (Считать данные). Ну и обратно я должен послать также 2 байта, один байт будет содержать номер платы с которой общались, а другой байт будет содержать либо текущее значение потенциометра либо нули(светодиод выключен) либо единицы (светодиод включен).

Коллега пока что не закончил работу над базой FPGA, поэтому я пытаюсь вместо FPGA использовать компьютер пока база не будет готова. 

На всех ардуинок должен быть один и тот же скетч.

На данный момент на платах ардуино соединены только потенциометры. Я написал простой скетч который выполняет следующею задачу: Из Serial Monitor я отправляю номер платы ардуино с которой я хочу получать данные( с потенциометра ) и обратно я получаю текущее значение потенциометра. Например я отправляю цифру 1 обратно я получаю текущее значение потенциометра который подключен к первой ардуинки, отправляю цифру 2 обратно я получаю текущее значение потенциометра который подключен к второй ардуинки.

Вот код моего скетча:

#include <SoftwareSerial.h>

SoftwareSerial Serial_1 = SoftwareSerial(2,3); //Rx , Tx

int incoming = 0;
int incoming1 = 0;
int analogValue = 0;
int count_device = 0;
int val;

void setup()
{
  Serial.begin(9600);  //Begin Serial to talk to the Serial Monitor   
  Serial_1.begin(9600); //Begin Serial to talk to the Rx Arduino
  Serial.print("Количество подключенных плат: ");
  Serial.println(count_device);
}

void loop()
{
  analogValue = analogRead(0); //Считаем данные с потенциометра
  
/*  Через Serial Monitor отправляем число которая означает номер платы с которой хотим получить данные.
Например у меня подключено 3 платы. К каждой плате подключен один потенциометр к аналоговуму входу 0. Через Serial Monitor 
я отправляю например число 2. Это означает что я хочу получить данные с потенциометра который подключен ко второй плате. 
*/ 
 incoming = Serial.available(); 
  
  while (incoming != 0)           
  {
    nr_device_out = Serial.parseInt(); // В начале в переменную nr_device_out попадает число 2. 
    
    nr_device_out--; // Декрементируем. 2 - 1 = 1
    if (nr_device_out == 0) // Число 1 не равна нулю, значит через SoftwareSerial передаем число 1 к второй плате. 
    {
    /*
    Получаем данные с потенциометра который подключен к ардуино с номером которого послали через Serial Monitor, в нашом случае со второй платы.
    */
     Serial.println(analogValue); 
    }
    else{
       Serial_1.print(nr_device_out); // передаем число 1 к второй плате через SoftwareSerial. 
    }
    incoming = Serial.available();
  }

  //     From the Rx Arduino
  incoming1 = Serial_1.available();  // Получаем данные со второй платы
  
  while(incoming1 != 0)           //While there is something to be read
  {
    
    Serial.write(Serial_1.read()); // Выводим значение потенциометра, который подключен к второй платы.
    incoming1 = Serial_1.available();
  }
}

Описание вопроса:

Так я из Serial Monitor отправлю цифру 2. Предположим, что это первый байт, который означает номер ардуинки, с которой  хочу общаться.

Первая плата получает данный номер платы и декрементирует его на 1, если результат равен нулю,  значит, этот номер отправлен ей, в противном случае она должна его отправить дальше к следующей плате arduino, но уже с декрементированным номером.  Считаем 2 – 1 = 1. Видим, что результат декрементирования является число 1, а не 0. Значит, берем это число 1  и через softwareserial отправляем к следующей плате arduino. Вторая плата получает номер 1 и декрементирует его. 1 – 1 = 0. Результат декрементирования равен нулю,  значит, что номер отправлен именно для второй платы.

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

Еще раз: Для начало я отправляю номер 2 (для второй ардуинки), потом я хочу отправить команду для потенциометра (предположим 3). Так вот эту цифру 3 (команда для потенциометра, считывать данные) нужно отправить сразу второй ардуинки, без декрементирования как в случае с первой цифры 2.

Надеюсь, вопрос поняли. Если что то не понятно, пишите.

У меня есть огромная просьба к Вам, напишите Ваши ответы/советы КАК МОЖНО ПДРОБНЕЕ, чтобы мне было четко ясно, что делать.

Спасибо Вам огромное и жду Ваших ответов!

Извиняюсь за мой русский!

KacmanAV
Offline
Зарегистрирован: 30.12.2014

Для начала не мешает почитать что нибудь про протоколы передачи данных.

Обычно устройства обмениваются между собой короткими пакетами данных.

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

Например: заводим переменную-счетчик, записываем туда 5  и каждую миллисекунду делаем ей декремент. Если придет байт по UART снова записываем в счетчик 5. Это нужно чтобы отследить паузу в канале связи. если счетчик обнулится, устанавливаем флаг, который означает, что нужно ждать начало пакета (например байт 0x7E). Если после паузы пришел байт не  0x7E начинаем все с начала т.е. ждем очередную паузу 5мс. Если же пришел  0x7E начинаем принимать пакет. Второй байт пакета есть адрес устройства которому предназначен пакет. Если совпадает с вашим, принимаем дальше, если нет все с начала. Следующий байт - адрес отправителя. Следующий байт - длина пакета, дальше данные, и в конце контрольная сумма. Как то так.

В принцепе можно не ждать паузу, а начало пакета искать по двум байтам, например 0х05, 0х64.

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Можно и в лоб решение. Отправляете первый байт как и отправляете с дикриментами всякими и т.д., та плата которой предназначен следующий байт по условию 1-1=0 взводит флаг типа "Жду 2й байт". Второй байт отправляете предварительно прибавив к нему нужное число, в Вашем примере 2. Первый получает, смотрит на флаг, видит что он ничего не ждет отнимает 1 и шлет дальше когда байт дойдет до нужного контроллера, того у которого флаг стоит, что он ждет второй байт сбрасываете флаг и имеете нужный второй байт.

sergiu920
Offline
Зарегистрирован: 27.12.2014

Penni пишет:

Можно и в лоб решение. Отправляете первый байт как и отправляете с дикриментами всякими и т.д., та плата которой предназначен следующий байт по условию 1-1=0 взводит флаг типа "Жду 2й байт". Второй байт отправляете предварительно прибавив к нему нужное число, в Вашем примере 2. Первый получает, смотрит на флаг, видит что он ничего не ждет отнимает 1 и шлет дальше когда байт дойдет до нужного контроллера, того у которого флаг стоит, что он ждет второй байт сбрасываете флаг и имеете нужный второй байт.

Спасибо за ответ! Подскажите пожалуйста как взводить флаг типа "Жду 2й байт" ?

KacmanAV
Offline
Зарегистрирован: 30.12.2014

Заведите счетчик принятых байт. И ветвитесь оператором switch в зависимости от состояния этого счетчика.

Еще можете добавить команду к устройству, которой будете прописывать его сетевой адрес.

По умолчанию адрес у всех устройств будет одинаковый, например 0хFF. 

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

sergiu920 пишет:

как взводить флаг типа "Жду 2й байт" ?

Обычная переменная типа boolean. Объявляете boolean NeedTwoByte = false; Потом в нужном месте "взводите" NeedTwoByte = true; Сбрасываете так же NeedTwoByte = false;

sergiu920
Offline
Зарегистрирован: 27.12.2014

Penni пишет:

sergiu920 пишет:

как взводить флаг типа "Жду 2й байт" ?

Обычная переменная типа boolean. Объявляете boolean NeedTwoByte = false; Потом в нужном месте "взводите" NeedTwoByte = true; Сбрасываете так же NeedTwoByte = false;

Понятно. Спасибо!