Работа двух ардуин

lexaez
Offline
Зарегистрирован: 23.01.2016

Добрый день всем! Вопрос слеующий: имеются две платы ардуино, к одной подключен датчик bmp180 который снимает показания температур, записывает максимальное значение, постоянно его обновляет если следующее больше предыдущего (это в программе отработано). К другой плате подключен oled i2c (система включена, показывает ноль). Потом при подключении к первой плате (включенной плате) экран должен показывать эту максимальную температуру. Как запрограммировать вторую плату, чтобы при подключении к первой плате вся информация выводилась на экран?

Понимаю что в коде должно быть что-то типо опроса пинов, и только чтение данных.
 

Jatixo
Offline
Зарегистрирован: 13.01.2016

А почему бы не приходить просто с экраном, а не со второй ардуиной?

lexaez
Offline
Зарегистрирован: 23.01.2016
Пробовал, если включать питание одновременно с платой (питание от платы), то показывает значения, а если подключать после включения платы, то экран как был черным, так и остался.

Вот скетч:

#include <Wire.h>
#include <Adafruit_BMP085.h>

Adafruit_BMP085 bmp;

float T_max=1;
float T;

#include <OLED_I2C.h>

OLED  myOLED(8, 9, 8); // Подключение дисплея, 8pin - SDA , 9pin - SCL
extern uint8_t MegaNumbers[];

void setup()
{

myOLED.begin();
bmp.begin();

}

void loop()
{

T=bmp.readTemperache();

if (T>25)
{
if (T>T_max)
{
  T_max=T;

}

}
myOLED.clrScr(); // 
myOLED.setFont(MegaNumbers);
myOLED.print(String(T_max , 1), CENTER, 10);
myOLED.update();

}
 

Штирлиц
Штирлиц аватар
Offline
Зарегистрирован: 13.06.2015

lexaez пишет:

Добрый день всем! Вопрос слеующий: имеются две платы ардуино, к одной подключен датчик bmp180 который снимает показания температур, записывает максимальное значение, постоянно его обновляет если следующее больше предыдущего (это в программе отработано). К другой плате подключен oled i2c (система включена, показывает ноль). Потом при подключении к первой плате (включенной плате) экран должен показывать эту максимальную температуру. Как запрограммировать вторую плату, чтобы при подключении к первой плате вся информация выводилась на экран?

Понимаю что в коде должно быть что-то типо опроса пинов, и только чтение данных.
 

Ну так , по-хорошему, нужно с первой ардуинки на вторую проводок один -другой подкинуть. И научить ардуинки общаться между собой по какому-нибудь протоклу(типа I2C, virtualWire? UART? SPI ? USB? WINIFINI) или объеденить в одну нейроную сеть .

Клапауций 322
Offline
Зарегистрирован: 31.12.2015

Штирлиц пишет:

или объеденить в одну нейроную сеть .

или сходить в церковь и помолиться своему Богу, что бы тот попросил Диавола, что бы тот послал Чертей переместить электроны с одной Дуино в другую.

*православненько нужно... православненько.

Logik
Offline
Зарегистрирован: 05.08.2014

Штирлиц пишет:

Ну так , по-хорошему, нужно с первой ардуинки на вторую проводок один -другой подкинуть. 

Не мелочится! Сразу три провода: общий, туды и сюды.

Штирлиц пишет:

 И научить ардуинки общаться между собой по какому-нибудь протоклу(типа I2C, virtualWire? UART? SPI ? USB? WINIFINI) или объеденить в одну нейроную сеть .

I2C, SPI внутриплатные коммуникации, если расстояния промеж ардуинками более пары футов будет, то не оно.  virtualWire для прожженых мазохистов. Сети нейтронные ;) туда же. USB хорош да сложен шибко и быстр не по контроллеру. Остается UART. На пару метров при скорости умеренной вполне годится, а если мало - апгрейдить до RS или токовой петли. 

Основная работа - програмный протокол. Как логическое описание способа взаимодействия. Но в Вашем случае все просто, ардуинка с датчиком периодически передает показания датчика. А та что с экраном просто ждет и принимает.

ПС. Недавно писал  протокол для межардуинного обмена, тока там рядом с датчиком температуры еще сервомашинка и немного реле,  а рядом с экраном - джойстик для управления этим хозяйством. Ниче сложного. Делал токовую петлю, т.к. помехи ожидаются, одна ардуина возле ДВС.

 

Jatixo
Offline
Зарегистрирован: 13.01.2016

Я просто спросил про экран, на самом деле подключать на горячую нежелательно, наверное, может что-нибудь сгореть... А не работает, вероятно, потому что инициализация экрана в setup только, а после подключения экрана её уже не происходит в loop.

Ну а так, если без прерываний и проверок всяких, подключаем 2 проводами, если питание не нужно (3 если нужно) землю на землю, rx переносной к tx стационарных, на стационарных раз в 5 сек. допустим передаем через serial.println, а на переносной после подключения ждём показаний, вот и всё. А так можно и провод добавить и запрашивать показания, правда на тех постоянно проверять придётся нет ли данных запроса Serial.available...

Logik
Offline
Зарегистрирован: 05.08.2014

Jatixo пишет:
допустим передаем через serial.println, а на переносной после подключения ждём показаний, вот и всё.

В общем да. Только передача через Serial.write логичней. Не зачем конвертировать в строку в протоколе. У Вас простой случай, запросы не нужны. Просто один передает все время, второй принимает как/когда может и выводит на экран. "Горячее" подключение возникнет само собой, ничего не сгорит. Можете ещё контрольную сумму добавить для надежности.  Хотя опять же в таком простом случае логичней просто полагать что должны принять 2 раза одинаковые значения, значить верный обмен и без контрольной суммы.

allesanbr
Offline
Зарегистрирован: 31.01.2016

раз уж у тебя есть две ардуины проверь пожалуйста кристинку(библиотека с собственным протоколом передачи данных)

подробнее здесь: http://arduino.ru/forum/programmirovanie/arduino-rasshirennaya-peredacha...

Logik
Offline
Зарегистрирован: 05.08.2014

allesanbr пишет:

раз уж у тебя есть две ардуины проверь пожалуйста кристинку

Проверил (правда не понял зачем 2 ардуины, либа ориентирована на обмен ардуино-ПК судя по всему). Загрузил распаковал, попробовал собрать без изменений. IDE рабочее 100%. "Болеет" хрыстя. История болезни на картинке.

 

Если поправите и захотите  проверить на двух ардуино, то давайте и скетч на вторую (т.е на приемник).

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

allesanbr
Offline
Зарегистрирован: 31.01.2016

немного непонятно: скетч из примера тоже не компилируется?

allesanbr
Offline
Зарегистрирован: 31.01.2016

--->>>равда при этом возникает в общем случае вопрос - куда выводить принятые сообщения.

 

никуда. моргать диодами если условие верно либо ещё чем нибудь если есть чем. странно, что ошибка при компеляции, у меня всё норм.

Logik
Offline
Зарегистрирован: 05.08.2014

allesanbr пишет:

немного непонятно: скетч из примера тоже не компилируется?

Именно он. Ни буквы отсебятины.

allesanbr
Offline
Зарегистрирован: 31.01.2016

незнаю какое отношение к этому имеет ХР-шка, но попробуй в текстовом редакторе открыть файл christina.h и превратить это в одну строку: int Index[30]={10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39};//0-29

 

затем сохрани и перекомпилируй

надеюсь ты юзаешь notepad++

Logik
Offline
Зарегистрирован: 05.08.2014

allesanbr пишет:

незнаю какое отношение к этому имеет ХР-шка

никакого. это явно gcc ругается. И ранше замечал, что не допускает инициализацию полей класса. Вероятно версия не та. Попробую 1.6.5 щас.

allesanbr пишет:

но попробуй в текстовом редакторе открыть файл christina.h и превратить это в одну строку: int Index[30]={10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39};//0-29

 

затем сохрани и перекомпилируй

надеюсь ты юзаешь notepad++

все тоже.

allesanbr пишет:

надеюсь ты юзаешь notepad++

да.

Logik
Offline
Зарегистрирован: 05.08.2014

На IDE 1.6.5 собралось, наплевало в порт

0C 00 00 00 00 0A 02 00 03 00 0B 04 05 06 00 
0C 00 00 00 00 0A 08 00 03 00 0B 05 05 06 00 
0C 00 00 00 00 0A 00 00 03 00 0B 06 05 06 00 
0C 00 00 00 00 0A 09 09 02 00 0B 07 05 06 00 
0C 00 00 00 00 0A 08 00 03 00 0B 08 05 06 00 
0C 00 00 00 00 0A 02 00 03 00 0B 09 05 06 00 
0C 00 00 00 00 0A 09 09 02 00 0B 00 06 06 00 
0C 00 00 00 00 0A 06 00 03 00 0B 01 06 06 00 
0C 00 00 00 00 0A 05 00 03 00 0B 02 06 06 00 
0C 00 00 00 00 0A 08 09 02 00 0B 03 06 06 00 
0C 00 00 00 00 0A 05 00 03 00 0B 04 06 06 00 
0C 00 00 00 00 0A 07 00 03 00 0B 05 06 06 00 
0C 00 00 00 00 0A 09 09 02 00 0B 06 06 06 00 
0C 00 00 00 00 0A 02 00 03 00 0B 07 06 06 00 

и продолжило ... Наверно работает.

allesanbr
Offline
Зарегистрирован: 31.01.2016

Вот это всё плюёт в порт:

 

 if(check == 0)
    {
    christina.Send(data, 0);// 0 - number(index) PIN_SNOS (allow: from 0 to 29)
    }
  else if(check == 1)
    {
    christina.Send(pl, 1); //pl - data from simulation pin, 1 - nuber(index) PIN_1 (from 0 to 29)
    pl++;
    }
  else if(check == 2)//get data with Christina and send to back
    {
    christina.Get();
    ln = christina.block();
    arr[0] = *(ln+0);//присвоение элементов массива по указателю
    arr[1] = *(ln+1);
    christina.Send(arr[1], 2);
    }

На всякий случай объясню, что здесть происходит:

как можно заметить, каждая отправка данных(christina.Send(int,int);) зависит от значения переменной " check ", которое в свою очередь изменяется с каждой новой итерацией функции loop():

check++;
    if(check >= 30)//
      {
      check = 0;
      }

Поэтому время между этими отправками задаётся в вызове функции delay(x); где x это время в миллисекундах

поскольку максимальное значение check задано "30", то: если х = 1000, то мы будем отправлять данные каждые 30 секунд (с интервалом очерёдности в одну секунду).

 

И спасибо, за то, что указали версию.

у меня также стоИт 1.6.5 в которой всё собирается. 

А в какой не собиралось то?

 

и это... скетч на приёмник таки наверное нужно написать отдельно, более расширено, но фишка в том, что событие приёма присутствует в этом блоке кода:

 else if(check == 2)//get data with Christina and send to back
    {
    christina.Get();//инициализация приёма данных
    ln = christina.block();
    arr[0] = *(ln+0);//присвоение элементов массива по указателю/ первый элемент массива это индекс
    arr[1] = *(ln+1);//второй элемент - данные(значение)
    christina.Send(arr[1], 2);//отправка данных обратно на ком-порт- здесь наоборот: первое принимаемое значение - данные, второе: индекс
    }

Но ты прав: нужно сделать более широкий пример, в котором функция christina.Get(); должна быть вынесена из поля условных операторов под окрывающую скобку loop, похоже кроме этого добавить нечего. Протокол разрабатывался как для приёма, так и для передачи по com-интерфейсу. Попробуй с одной ардуины отправить пару значений(data,index) на другую, как бы с двух пинов, там их принять и обработать, и одновременно оттуда также послать пару значений и уже на этой плате также их обработать. Короче чтобы происходил постоянный обмен данными. Напоминаю: если скетч ориентирован на приём, то вызов "christina.Get();" - следует вынести в начало loop. В данном случае в обеих скетчах.

А что касается кристинки под Processing, то это просто экстраполяция данного протокола на Java. Короче не обращай внимания если это не используешь.

Logik
Offline
Зарегистрирован: 05.08.2014

allesanbr пишет:

А в какой не собиралось то?

На 1.0.6. Там на скрине, в названии окна IDE видно.

allesanbr пишет:

Но ты прав: нужно сделать более широкий пример, в котором функция christina.Get(); должна быть вынесена из поля условных операторов под окрывающую скобку loop, похоже кроме этого добавить нечего. Протокол разрабатывался как для приёма, так и для передачи по com-интерфейсу. Попробуй с одной ардуины отправить пару значений(data,index) на другую, как бы с двух пинов, там их принять и обработать, и одновременно оттуда также послать пару значений и уже на этой плате также их обработать. Короче чтобы происходил постоянный обмен данными. Напоминаю: если скетч ориентирован на приём, то вызов "christina.Get();" - следует вынести в начало loop. В данном случае в обеих скетчах.

А что касается кристинки под Processing, то это просто экстраполяция данного протокола на Java. Короче не обращай внимания если это не используешь.

Т.е. в либке есть и реализация приемника? Думаю это уже сможет заинтерисовать многих. Тут часто всплывают темы про обмен между ардуинами. А что он и под Processing это плюс, совместимость с чем-то всегда плюс. Мне протокол не нужен, своих хватает с доп плюшками - передача блоков данных, обнаружение и обработка ошибок, диспетчер приоритета передачи и т.д. Потестить ещё могу конечно, только я так и не понял как, Christina_Ex.ino залить в обе штоли? Или надо чего допилить?(Ну кроме вывода на экран, как я писал это докину сам) На счет примера - делайте их проще, тогда "люди к Вам потянутся". По крайней мере самый первый пример. Т.к. ардуиной занимаются много не профи, для них 10 строк кода в примере уже повод поискать чего попроще.

allesanbr
Offline
Зарегистрирован: 31.01.2016

Реализация приёмника есть, но для каждой платы, нужно написать немного различный код, нужно будет изменить loop для одной из ардуин в условии 

else if(check == 2)

и добавить кое чего по мелочи:

void loop() {
  // put your main code here, to run repeatedly:
  data =  analogRead(PIN_SNOS); //real data from pin A0 with reostate
  christina.Get();
  if(check == 0)
    {
    christina.Send(data, 0);// 0 - number(index) PIN_SNOS (allow: from 0 to 29)
    }
  else if(check == 1)
    {
    christina.Send(pl, 1); //pl - data from simulation pin, 1 - nuber(index) PIN_1 (from 0 to 29)
    pl++;
    }
  else if(check == 2)//get data with Christina and send to back
    {
    //christina.Get();
    //ln = christina.block();
    //arr[0] = *(ln+0);//присвоение элементов массива по указателю
    //arr[1] = *(ln+1);
    christina.Send(228, 2);//проверять нужно 228
    }

    check++;
    if(check >= 30)
      {
      check = 0;
      }

Indexation();
}
//и добавить переменную и функцию

int checkSend;

void Indexation()

{

    ln = christina.block();
    arr[0] = *(ln+0);//присвоение элементов массива по указателю
    arr[1] = *(ln+1);
   

if(arr[0] == 2)//проверяем индекс(например пина), и если это то, что нам нужно..

 {

checkSend = arr[1];//...обрабатываем прилетевшее значение

 }
 }

если всё прошло нормально, то, checkSend вернёт 228, а куда её выводить - это уже сам смотри

Gres
Gres аватар
Offline
Зарегистрирован: 26.03.2013

Зачем столько сложностей? Одна дуня постоянно плюет в трансмитер сообщения, другая все время принимает и выводит сообщение на дисплей. Два провода и никаких лишних протоколов. Длина линии конечно ограничена, хотите расстяний, перехрдите с UART на RS232 или RS485.

allesanbr
Offline
Зарегистрирован: 31.01.2016

Gres пишет:

Зачем столько сложностей? Одна дуня постоянно плюет в трансмитер сообщения, другая все время принимает и выводит сообщение на дисплей. Два провода и никаких лишних протоколов. Длина линии конечно ограничена, хотите расстяний, перехрдите с UART на RS232 или RS485.

да не было бы этих сложностей, если бы дуня спокойно передавала бы не 256 , а 1024 и/или 4096 значений одним пакетом.

Предваряя следующий вопрос: "256 мало что ли?"

Отвечаю: 256 значений критически мало, например для обработки углов, с аналогового входа.  так как полный угол равен 360, а если необходима точность в пол-градуса, то требуется вообще минимум 720 значений.

Logik
Offline
Зарегистрирован: 05.08.2014

Gres пишет:

Зачем столько сложностей? Одна дуня постоянно плюет в трансмитер сообщения, другая все время принимает и выводит сообщение на дисплей. Два провода и никаких лишних протоколов. Длина линии конечно ограничена, хотите расстяний, перехрдите с UART на RS232 или RS485.

.... а хотите надежность - делайте протокол. Напомню что UART/RS232/RS485 не относятся к надежным достаточно мощная помеха исказит передаваемый сигнал до неузнаваемости. При этом факт искажения может быть и не обнаружен. В результате, к примеру, вместо переданой команды 0x20- "погладь кота" будет принята и исполнена  0x30 -"уничтож цивилизацию".  Для защиты цивилизации в простейшем случае, если данные влазят в один байт достаточно их передавать 2 раза подряд а на приемнике принять два байта и сравнить. Не лишним будет настроить Serial на контроль четности, есть у него такой прибамбас немного повышающий надежность передачи. Однако ориентироватся на тот факт, что данные влезут в один байт не  благоразумно. Захочется большего - прийдется все переделывать с нуля.

Я использую такой двунаправленній протокол, опишу со стороны сервера, так проще: принимаем 3 байта, первый - идентификатор сообщения ID, второй - данные D, третий - контрольная сумма СRC. Проверяем CRC, если плохо, отправляем обратно сообщение (тоже 3 байта) с ID-спецкод ошибки приема, в поле D идентификация ошибки и CRC. Если ошибок не было, то анализируем принятый ID, возможны случаи: известнное однобайтовое сообшение, в D байт данных назначение которого так же определяется по ID, по немуже определяется необходимость отправки обратно подтверждения и его форма, как правило оно есть и тоже 3 байта, аналогичной структуры, ID как правило равно ID исходного в D результат исполнения или данные связанные с исполнением +CRC. Это минимальная форма.

При необходимости передачи данных более одного байта возможны 2 случая: сообщения фиксированной длины и переменной длины. Для первого случая есть специальное ID а в D при нем передается собственно ID этих данных которые неявно определяют их длинну+CRC как обычно, а за ним сами данные +их CRC.

Для переменной длины опять специальное ID (или их диапазон) в D - длинна передаваемых данных, разумеется CRC (оно вобще всегда 3 байт) за ним уже данные+CRC. В них может быть что угодно в т.ч. и расширения протокола.

При этом запрос и ответ может содержать разные формы. Например опрос состояния нескольких датчиков выглядит так: запрос, ID-запроса датчиков D-флаги уточня состава датчиков +CRC; ответ, ID-запроса датчиков D- длинна данных+CRC , сами данные +их CRC  (или ID-ошибки D-уточнение ошибки+CRC).

В общем имею надежный,простой и гибкий протокол. Стоит определить таблицу ID и получаем полное описание протокола. Для данных более 1 байта на принимающей стороне, в приложении, будет свич по ID принятого и реакциям на длинніе данные, например прямо пересылаем на экран, без буферизации, для экономии.

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

Гдето-так в общем.