Предлагаю простой способ обмена данными между главным микроконтроллером и датчиками основанный на алгоритме микросхем SC2272/SC2262 и библиотеке RemoteSwitch.zip (троичный протокол) или RCswitch.zip (двоичный протокол) для Arduino IDE.В данный момент разработан беспроводной датчик влажности/температуры на основе этого протокола.
Обновление - добавлен двоичный протокол отправки.
Радиоканал основан на радиомодулях 433мгц/315мгц.Можно оргнанизовать и проводную сеть,но в этом случае у передатчиков после отправки данных необходимо вывод переводить в режим входа..
Библиотеки RemoteSwitch и RCswitch используется для управления устройствами ,основанными на микросхемах SC2272/SC2262 -соотвественно примеры кодов передатчиков,описаных ниже могут управлять данными устройствами.
Код передачи данных представляет из себя число:
Для троичного протокола на базе RemoteSwitch:от 0 до 531440. (312)
Для двоичного протокола на базе RCswitch:от 0 до1048576. ( 220.)
В зависимости от ваших требований вы должны определится какой протокол будет использоватся.Обмен данными между двумя устройствами с разными протоколами не возможен.
Алгоритмы отправки цифровых данных
Передаем температуру из переменной float с одним знаком после запятой:
Имеем переменную temp и для её передачи мы должны провести определенные математические операции:
1.Умножаем на 10,чтобы избавится от знаков после запятой.
2.Прибавляем 500 для того чтобы без проблем отправить отрицательную температуру.
Получаем: temp*10+500+код-идентификатор =число,которое можем передать по радиоэфиру через библиотеку RemoteSwitch.Получившиееся число должно быть в диапозоне от 0 до 531 440.
Алгоритм приема цифровых данных:
Принимаем число и проводим данные логические операции в обратном порядке.
if (key<=receivedCode && key+999>receivedCode) temp=(receivedCode-key1-500)/10;
Где receivedCode - это принятый код.
key - это константа код-идентификатор,которую мы задавали при передаче текущих данных.
temp - полученная температура с одним знаком после запятой.
Откуда взялось число 999 ? - это указание диапозона,в котором число будет воспринято как данная температура в даипозоне -49.9 до +49.9
Как передать другие более простые переменные ?
Для отправки НЕотрицательного значения мы можем упустить прибавления числа 500
Для отправки ЦЕЛОГО числа мы можем не умножать на 10 при передаче,а при приеме не делить на 10..
Пример отправки данных на ардуине (Передатчик)
#define period 400 // mcs период
// подпрограмма отправки данных void sendRC(unsigned long code) { code |= (unsigned long)period << 23; code |= 3L << 20; RemoteSwitch::sendTelegram(code,2); }
#include <RCSwitch.h> RCSwitch mySwitch = RCSwitch(); float tempout=-25.46; float tempin=30.64; #define key1 300000 #define key2 303000 void setup() { mySwitch.enableTransmit(10); // пин,на который подключен передатчик } void loop() { sendRC(tempout*10+key1+500); delay(1000); sendRC(tempin*10+key2+500); delay(1000); } // подпрограмма отправки данных void sendRC(unsigned long code) { mySwitch.send(code, 20); }
Пример подпрограммы для отправки данных на чистом Си (Передатчик)
#define RC_BIT 3 // пин
#define periodusec 400 // mcs период
void sendRC(unsigned long data) { // , unsigned short pin 531 440 max
DDRB |= _BV(RC_BIT);
data |= 3L << 20;
unsigned short repeats = 1 << (((unsigned long)data >> 20) & 7);
data = data & 0xfffff; //truncate to 20 bit
unsigned long dataBase4 = 0; uint8_t i;
for (i=0; i<12; i++) {
dataBase4<<=2;
dataBase4|=(data%3);
data/=3;
}
unsigned short int j;
for (j=0;j<repeats;j++) {
data=dataBase4; uint8_t i;
for (i=0; i<12; i++) { switch (data & 3) {
case 0:
PORTB |= _BV(RC_BIT);
_delay_us(periodusec);
PORTB &= ~_BV(RC_BIT);
_delay_us(periodusec*3);
PORTB |= _BV(RC_BIT);
_delay_us(periodusec);
PORTB &= ~_BV(RC_BIT);
_delay_us(periodusec*3);
break; case 1: PORTB |= _BV(RC_BIT);
_delay_us(periodusec*3);
PORTB &= ~_BV(RC_BIT);
_delay_us(periodusec);
PORTB |= _BV(RC_BIT);
_delay_us(periodusec*3);
PORTB &= ~_BV(RC_BIT);
_delay_us(periodusec);
break;
case 2:
PORTB |= _BV(RC_BIT);
_delay_us(periodusec);
PORTB &= ~_BV(RC_BIT);
_delay_us(periodusec*3);
PORTB |= _BV(RC_BIT);
_delay_us(periodusec*3);
PORTB &= ~_BV(RC_BIT);
_delay_us(periodusec);
break;
}
data>>=2;
}
PORTB |= _BV(RC_BIT);
_delay_us(periodusec);
PORTB &= ~_BV(RC_BIT);
_delay_us(periodusec*31);
} }
Пример проверен на м/к Atmega AVR.
Вызов отправки аналогично из примера Arduino: sendRC (temp*10+key2+500);
Код так же может использоватся на Arduino IDE (с небольшими правками).
На этом примере основан беспроводной датчик влажности/температуры.
Пример отправки данных на Raspberry PI (Передатчик)
Троичный протокол:
sendrc.c.zip Компиляция командой gcc -Wall -o sendrc -lbcm2835 ./sendrc.c
Пример запуска через командую строку: ./sendrc число-код GPIO_pin .
Пример приема данных на Arduino (Приёмник)
#include <RemoteReceiver.h> float tempout=0,tempin=0,Hr; void setup() { RemoteReceiver::init(0, 3, skey); // иницилизация.Используется вывод м/к с прерыванием под номером 0. } void loop() { // тут могут выводится данные tempout и tempin на лсд экран или отправлятся через езернет. } #define key1 300000 // датчик температуры #define key2 303000 // датчик температуры #define key3 305000 // датчик влажность void skey(unsigned long receivedCode, unsigned int period) { // тут можно ещё проверять переменную period if (key1<=receivedCode && key1+999>receivedCode) tempout=(float)(receivedCode-key1-500)/10; else if (key2<=receivedCode && key2+999>receivedCode) tempin=(float)(receivedCode-key2-500)/10; else if (key3<=receivedCode && key3+999>receivedCode) Hr=(float)(receivedCode-key3)/10;//пример для влажности // можно не делить на 10,если отправляем через езернет на компьютер- разделить можно там. }
#include <RCSwitch.h> RCSwitch mySwitch = RCSwitch(); float tempout=0,tempin=0,Hr=0; #define key1 300000 // датчик температуры #define key2 303000 // датчик температуры #define key3 305000 // датчик влажность void setup() { mySwitch.enableReceive(0); // Receiver on inerrupt 0 => that is pin #2 // иницилизация.Используется вывод м/к с прерыванием под номером 0. } void loop() { if (mySwitch.available()) { unsigned long receivedCode= mySwitch.getReceivedValue(); if (receivedCode == 0) { // обработка:не верный формат данных } else { if (key1<=receivedCode && key1+999>receivedCode) tempout=(float)(receivedCode-key1-500)/10; else if (key2<=receivedCode && key2+999>receivedCode) tempin=(float)(receivedCode-key2-500)/10; else if (key3<=receivedCode && key3+999>receivedCode) Hr=(float)(receivedCode-key3)/10;//пример для влажности // можно не делить на 10,если отправляем через езернет на компьютер- разделить можно там. } mySwitch.resetAvailable(); // сброс данных. } // end available // тут могут выводится данные tempout и tempin на лсд экран или отправлятся через езернет. }
Сервер-приемник использует прерывание,т.е. подключить модуль приемника можно только на определенные выводы м/к:
Arduino UNO / Duemilanove: 2 -прерывание 0 ,3 -прерывание 1.*
Arduino Mega: 2 -прерывание 0, 3 -прерывание 1, 18 -прерывание 5, 19 -прерывание 4, 20 -прерывание 3, и 21 -прерывание 2.*
Микроконтроллеры Attiny25,Attiny85,Attiny85: 7(PB2) -прерывание 0.**
*-У Arduino -нумерация по плате. **-У микроконтроллеров - нумерация корпуса микросхемы.