Здесь попробуем организовать прием данных с RF приемника RF433/315MHz китайского производства. В принципе все они работают по схожим принципам и переделать под любой другой не составляем проблемы.
Данный экземпляр приемника имеет 4 вывода:
- vcc
- data
- data
- gnd
Подаем на vcc 5V, землю на gnd, оба контакта data соеденены и с них снимаем данные.
Для работы с каким-либо пультом(передатчиком) необходимо снчала выяснить код посылаемый передатчиком. Для этого напишем скетч принимающий и выводящий в последовательный порт голые данные, для их последующего анализа.
Результатом работы скетча будет таблица с парами значений длительностей "0" и "1" для высокого и низкого уровня. Временные интервалы могут сильно отличаться для разных пультов. Далее необходимо провести анализ протокола и применить его во вотором скетче, который и будет заниматься определением кода нажатой клавиши. Делать будем без применения изысков в виде использования прерываний по входу, а "в лоб" записывая время изменения сигналов.
На выходе сканера получается табличка:
LOW | HIGH |
0 | 255 |
0 | 208 |
69 | 25 |
68 | 25 |
69 | 25 |
69 | 24 |
20 | 72 |
68 | 25 |
21 | 72 |
68 | 26 |
... | ... |
В таблице хорошо видно начало и конец пакета, постоянная часть пакета и данные. Снимать данные нужно для каждой кнопки и на разных мощностях передатчика(почему-то влияет на длительность).
Сканер
const int dataSize = 100; //количество записываемых пар длительностей(ограниченно свободной памятью Arduino)
byte storedDataH[dataSize]; //массив для значений времени HIGH
byte storedDataL[dataSize]; //Массив для значений времени LOW
int maxSignalLength = 255; //ограничение на максимальную длительность сигнала(записываем byte поэтому 255)
int dataCounter = 0;
//используемые для приемника пины
int RFgnd=10; // gnd
int RFvcc=13; // vcc
int RFdata=11;// data
void setup(){
Serial.begin(9600);
pinMode(RFgnd,OUTPUT); digitalWrite(RFgnd,LOW);
pinMode(RFvcc,OUTPUT); digitalWrite(RFvcc,HIGH);
// pinMode(RFdata+1,INPUT); digitalWrite(RFdata+1,LOW);
pinMode(RFdata,INPUT); digitalWrite(RFdata,LOW);
while(digitalRead(RFdata)==HIGH){
//Wait here until a LOW signal is received
}
cli();// запретим прерываения
//читаем данные с вывода data и длительности сохраняем в storedDataX
for(int i=0; i<dataSize; i=i+1){
//HIGH part
dataCounter=0;
while(digitalRead(RFdata)==HIGH && dataCounter<maxSignalLength){
dataCounter++;
}
storedDataH[i]=dataCounter;
//LOW part
dataCounter=0;//reset the counter
while(digitalRead(RFdata)==LOW && dataCounter<maxSignalLength){
dataCounter++;
}
storedDataL[i]=dataCounter;
}
sei();//разрешим прерывания
//Выводим все что приняли в Serial Monitor
Serial.println("=====================");
Serial.println("LOW, HIGH");
for(int i=0; i<dataSize; i=i+2){
Serial.print(storedDataL[i]);
Serial.print(",");
Serial.println(storedDataH[i]);
}
}
void loop(){
//Do nothing here
}
Второй частью будет написание скетча принимающего команды пульта(передатчика).
Функция listenForSignal считывает dataSize пар значений и собирает их в массиве storedData
Далее последовательно просматривая массив ищем начало пакета. Длительности нулей и единиц определяются эксперементально и определяются функциями getL и getH. Нужно заметить, что при отсутствии несущей частоты передатчика, приемник будет принимать дикий шум :), поэтому необходимо принять меры к четкому определению пакета данных. В данном случае я не анализирую весь пакет, т.к. особого смысла не имеет, а выделяю начало и несколько реперных точек. В моем случае сам пакет состоит из 27 бит. 19 бит постоянная часть, и 8 бит код кнопки.
Берем 8 бит данных кода кнопки, точнее её HIGH часть, и упаковываем в 1 байт. Получаем чистый код кнопки, который и обрабатываем в основном цикле.
const int dataSize = 100;
byte storedData[dataSize];
int maxSignalLength = 255;
int dataCounter = 0;
int pr = 20;
#define ERR 100
int RFgnd=10;
int RFvcc=13;
int RFdata=11;
int led = 13;
//////////////////////////////////////////////////////////////////
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(RFgnd,OUTPUT); digitalWrite(RFgnd,LOW);
pinMode(RFvcc,OUTPUT); digitalWrite(RFvcc,HIGH);
// pinMode(RFdata+1,INPUT); digitalWrite(RFdata+1,LOW);
pinMode(RFdata,INPUT); digitalWrite(RFdata,LOW);
}
void loop() {
const byte num[8]={63,207,15,243,51,195,3,252};
byte scode;
// put your main code here, to run repeatedly:
listenForSignal();
scode = GetCode();
if(scode != ERR)
{
// Serial.println(scode);
switch(scode){
case 15: Serial.println("[3]");
delay(10);
break;
case 243: Serial.println("[4]");
delay(10);
break;
case 51: Serial.println("[5]");
delay(10);
break;
case 195: Serial.println("[6]");
delay(10);
break;
case 63: Serial.println("[1]");
delay(10);
break;
case 207: Serial.println("[2]");
delay(10);
break;
case 3:
Serial.Serial.println("[7]");
delay(10);
break;
case 252: Serial.print("[8]");
delay(500);
break;
}
}
}
void listenForSignal(){
cli();
for(int i=0; i<dataSize; i=i+2){
//HIGH
dataCounter=0;
while(digitalRead(rfReceivePin)==HIGH && dataCounter<maxSignalLength){
dataCounter++;
}
storedData[i]=dataCounter;
//LOW part
dataCounter=0;
while(digitalRead(rfReceivePin)==LOW && dataCounter<maxSignalLength){
dataCounter++;
}
storedData[i+1]=dataCounter;
}
sei();
}
byte getL(byte n)
{
return (n==0)?0:((n>=10 && n<=25)?1:((n>=60 && n<=70)?2:ERR));
}
byte getH(byte n){
return (n>=20 && n<=40)?0:((n>=70 && n<=80)?1:((n>=200)?2:ERR));
}
byte GetCode(){
byte ret = 0,l,h;
int n=0;
while(n<dataSize){
if(storedData[n]==0 && storedData[n+1]>=200 && storedData[n+2]==0 && storedData[n+3]>=200) break;
n++;
}
if(n > dataSize-27*2-1) return ERR;
if(getL(storedData[n+26*2])!=1 || getH(storedData[n+26*2+1])!=2) return ERR;
n+=18*2;
for(int i=0;i<8;i++){
//Serial.print("n1=");Serial.print(storedData[n]);Serial.print(" n2=");Serial.println(storedData[n+1]);
l = getL(storedData[n]);
h = getH(storedData[n+1]);
// Serial.print("l=");Serial.print(l);Serial.print(" h=");Serial.println(h);
if(l==ERR || h==ERR) return ERR;
n+=2;
ret += h<<(7-i);
}
return ret;
}