红外遥控器
红外遥控原理
用户码或数据码中的每一个位可以是位‘1’,也可以是位‘0’。区分‘0’和‘1’是利用脉冲的时间间隔来区分,这种编码方式称为脉冲位置调制方式,英文简写PPM。
红外接收头的型号有很多HS0038 VS838等 功能大致相同,只是引脚封装不同。
红外接收有几种统一的编码方式,采样哪种编码方式取决于遥控器使用的芯片,接收头收到的都是一样的。
电视遥控器使用的是专用集成发射芯片来实现遥控码的发射,如东芝TC9012,飞利浦AA3010T等,通常彩电遥控信号的发射,就是将某个按键所对应的控制指令和系统码(由0和1组成的序列),调制在38KHz的载波上,然后经放大、驱动红外发射管将信号发射出去。不同公司的遥控芯片,采样的遥控码格式也不一样,较普遍的有两种,一种NEC标准,一种是PHILIPS标准。
NEC标准:遥控载波的频率为38KHz(占空比1:3)当某个键按下时,系统首先发射一个完整的全码,如果按键超过108ms仍未松开,接下来发射的代码(连发代码)将由起始码(9ms)和结束码(2.5ms)组成。
一个完整的全码 = 引导码 +用户码 +用户码 + 数据码 + 数据码 + 数据反码。
其中,引导码高电平9ms,低电平4.5ms;系统码8位,数据码8位,共32位;其中前16位为用户识别码,能区别不同的红外遥控设备,以防止不同的机种遥控码互相干扰。后16位为8位的操作码和8位的操作反码,用于核对数据是否接收准确。收端根据数据码做出应该执行上面动作的判断。
连发代码是在持续按键时发送的码。它告知接收端。某键是在被连续的按着。
NEC标准下的发射码表示
发射数据0时用”0.56ms高电平 + 0.565ms低电平 = 1.125ms”表示;
数据1用”高电平0.56ms + 1.69ms = 2.25ms”表示。
PHILIPS标准:
载波频率38KHz:没有筒,点按键时,控制码1和0之间切换,若持续按键,则控制码不变。
一个全码 = 起始码’11’ +控制码 + 用户码 + 用户码
数据0用“低电平1.778ms + 高电平1.778ms”表示;
数据1用“高电平1.778ms + 低电平1.778ms”表示。
连续码重复延时114ms。
此处使用NEC标准
NEC协议总结:
数据格式: 同步码头 + 地址码 +地址反码 + 按键码 + 按键反码 (LSB先行)
同步码头:9ms低电平 + 4.5ms高电平
连发码 : 9ms低电平 + 2.5ms高电平
逻辑1: 560us + 1680us
逻辑0: 560us + 560us
步骤
读取一个字节的码
char IR_code[4];
char IR_ReadByte(void)
{
char byte=0x00;
for(int i=0; i<8; ++i)
{
while(digitalRead(PIN_IR)==1);
while(digitalRead(PIN_IR)==0); //0.56ms
delayMicroseconds(600); //0.56~1.69ms
byte |= (digitalRead(PIN_IR)<<i); //低位在前
}
return byte;
}
进行读取操作
char IR_ReadData(void)
{
memset(IR_code,0,4*sizeof(char));
char byte={0};
while(digitalRead(PIN_IR)==1); //空闲状态为高电平
//引导码
while(digitalRead(PIN_IR)==0); //9ms
while(digitalRead(PIN_IR)==1); //4.5ms
//读取
for(int i=0; i<4; ++i){ //4字节:用户码*2,按键码*2
byte = IR_ReadByte();
memcpy(&IR_code[i],&byte,sizeof(char));
}
//验证
if((IR_code[0]^IR_code[1])==0xff && (IR_code[0]^IR_code[1])==0xff)
return 1;
else
return 0;
}
完整代码
/*
* IR.c
*
*
*/
#include <stdio.h>
#include <string.h>
#include <wiringPi.h>
#define PIN_IR 1
char IR_code[4];
void wiringPiStart(void)
{
wiringPiSetup();
pinMode(PIN_IR, INPUT);
}
char IR_ReadByte(void)
{
char byte=0x00;
for(int i=0; i<8; ++i)
{
while(digitalRead(PIN_IR)==1);
while(digitalRead(PIN_IR)==0); //0.56ms
delayMicroseconds(600); //0.56~1.69ms
byte |= (digitalRead(PIN_IR)<<i); //低位在前
}
return byte;
}
char IR_ReadData(void)
{
memset(IR_code,0,4*sizeof(char));
char byte={0};
while(digitalRead(PIN_IR)==1); //空闲状态为高电平
//引导码
while(digitalRead(PIN_IR)==0); //9ms
while(digitalRead(PIN_IR)==1); //4.5ms
for(int i=0; i<4; ++i){ //4字节:用户码*2,按键码*2
byte = IR_ReadByte();
memcpy(&IR_code[i],&byte,sizeof(char));
}
if((IR_code[0]^IR_code[1])==0xff && (IR_code[0]^IR_code[1])==0xff)
return 1;
else
return 0;
}
int main(int argc, char **argv)
{
wiringPiStart();
while(1){
if(IR_ReadData())
{
for(int i=0; i<4; ++i)
printf("0x%x ",IR_code[i]);
printf("\n");
}
delay(300);
}
return 0;
}
各个按键对应输出
0x0 0xff 0x45 0xba
0x0 0xff 0x46 0xb9
0x0 0xff 0x47 0xb8
0x0 0xff 0x44 0xbb
0x0 0xff 0x40 0xbf
0x0 0xff 0x43 0xbc
0x0 0xff 0x7 0xf8
0x0 0xff 0x15 0xea
0x0 0xff 0x9 0xf6
0x0 0xff 0x16 0xe9
0x0 0xff 0x19 0xe6
0x0 0xff 0xd 0xf2
0x0 0xff 0xc 0xf3
0x0 0xff 0x18 0xe7
0x0 0xff 0x5e 0xa1
0x0 0xff 0x8 0xf7
0x0 0xff 0x1c 0xe3
0x0 0xff 0x5a 0xa5
0x0 0xff 0x42 0xbd
0x0 0xff 0x52 0xad
0x0 0xff 0x4a 0xb5
控制LED灯
修改主函数
void wiringPiStart(void)
{
wiringPiSetup();
pinMode(PIN_IR, INPUT);
pinMode(PIN_LED,OUTPUT);
digitalWrite(PIN_LED,0);
}
int main(int argc, char **argv)
{
wiringPiStart();
while(1){
if(IR_ReadData())
{
for(int i=0; i<4; ++i)
printf("0x%x ",IR_code[i]);
printf("\n");
if((IR_code[2] ^ 0x45) ==0x00) digitalWrite(PIN_LED,1);
if((IR_code[2] ^ 0x46) ==0x00) digitalWrite(PIN_LED,0);
}
delay(500);
}
return 0;
}