1.硬件接口
2.红外协议介绍
红外线是波长在750nm至1mm之间的电磁波,其频率高于微波而低于可见光,是一种人的眼睛看不到的光线。无线电波和微波已被广泛应用在长距离的无线通信中,但由于红外线的波长较短,对障碍物的衍射能力差,所以更适合应用在需要短距离无线通信场合点对点的直线数据传输。
在实际的通信领域,发出来的信号一般有较宽的频谱,而且都是在比较低的频率段分布大量的能量,所以称之为基带信号,这种信号是不适合直接在信道中传输的。为便于传输、提高抗干扰能力和有效的利用带宽,通常需要将信号调制到适合信道和噪声特性的频率范围内进行传输,这就叫做信号调制。我们平时用到的红外遥控器里的红外通信,通常是使用38KHz左右的载波进行调制的。
- 红外遥控协议组成:一般是引导码、用户码、按键码、重复码、按键反码、结束码等组成;
- 红外遥控载波频率:33K、36K、36.6K、38K、40K、56K。常用38K以37.916K最准确;
- 红外载波占空比:1/2、1/3;不常用的有1/4;
- 调制方式:脉宽调制和相位调制; 针对于接收方:
- 引导码:9ms的低电平 + 4.5ms高电平;
- 重复码:9ms的低电平 + 2.25ms高电平;
- 停止位:560us的低电平;
- 逻辑0:560us的低电平 + 560us的高电平;
- 逻辑1:560us的低电平 + 1680us的高电平
以下是我利用逻辑分析仪捕获的时序表:
一般来说可以采用外部中断加定时器的方式配合采集红外信号,也可以采用PWM的外部边沿捕获来达到效果,但是这里就介绍以下最近新学的单个使用定时器来达到效果的方法,若有不对之处请大佬指正。大概思路介绍,首先配置一个100us的定时器
然后配置对应的信号引脚为输入模式,然后记录这个引脚发生电平变化的时间(这边可以理解为次数),然后根据对应的引导码,用户码,按键码等的时间来判断高低电平的情况。代码如下:
/************* 红外接收程序变量声明 **************/
//sbit P_IR_RX = P3^5; //定义红外接收输入IO口
#define SysTick 10000 // 次/秒, 系统滴答频率, 在4000~16000之间
u8 IR_SampleCnt; //采样计数
u8 IR_BitCnt; //编码位数
u8 IR_UserH; //用户码(地址)高字节
u8 IR_UserL; //用户码(地址)低字节
u8 IR_data; //数据原码
u8 IR_DataShit; //数据移位
bit P_IR_RX_temp; //Last sample
bit B_IR_Sync; //已收到同步标志
bit B_IR_Press; //红外接收标志
u8 IR_code; //红外键码
u16 UserCode; //用户码.
u8 count=0;
/******************** 红外采样时间宏定义, 用户不要随意修改 *******************/
#define IR_SAMPLE_TIME (1000000UL/SysTick) //查询时间间隔, us, 红外接收要求在60us~250us之间
#if ((IR_SAMPLE_TIME <= 250) && (IR_SAMPLE_TIME >= 60))
#define D_IR_sample IR_SAMPLE_TIME //定义采样时间,在60us~250us之间
#endif
#define D_IR_SYNC_MAX (15000/D_IR_sample) //SYNC max time
#define D_IR_SYNC_MIN (9700 /D_IR_sample) //SYNC min time
#define D_IR_SYNC_DIVIDE (12375/D_IR_sample) //decide data 0 or 1
#define D_IR_DATA_MAX (3000 /D_IR_sample) //data max time
#define D_IR_DATA_MIN (600 /D_IR_sample) //data min time
#define D_IR_DATA_DIVIDE (1687 /D_IR_sample) //decide data 0 or 1
#define D_IR_BIT_NUMBER 32 //bit number
//*******************************************************************************************
//**************************** IR RECEIVE MODULE ********************************************
void IR_Int(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_PU;
GPIO_InitStructure.GPIO_AFType = GPIO_AFType_AF0;
GPIO_Init(GPIO_P1, &GPIO_InitStructure);
}
void IR_RX_NEC(void)
{
u8 SampleTime;
IR_SampleCnt++; //Sample + 1
F0 = P_IR_RX_temp; //Save Last sample status
P_IR_RX_temp = P_IR_RX; //Read current status
if(F0 && !P_IR_RX_temp) //Pre-sample is high,and current sample is low, so is fall edge
{
SampleTime = IR_SampleCnt; //get the sample time
IR_SampleCnt = 0; //Clear the sample counter
if(SampleTime > D_IR_SYNC_MAX) B_IR_Sync = 0; //large the Maxim SYNC time, then error
else if(SampleTime >= D_IR_SYNC_MIN) //SYNC
{
if(SampleTime >= D_IR_SYNC_DIVIDE)
{
B_IR_Sync = 1; //has received SYNC
IR_BitCnt = D_IR_BIT_NUMBER; //Load bit number
}
}
else if(B_IR_Sync) //has received SYNC
{
if(SampleTime > D_IR_DATA_MAX) B_IR_Sync=0; //data samlpe time too large
else
{
IR_DataShit >>= 1; //data shift right 1 bit
if(SampleTime >= D_IR_DATA_DIVIDE) IR_DataShit |= 0x80; //devide data 0 or 1
if(--IR_BitCnt == 0) //bit number is over?
{
B_IR_Sync = 0; //Clear SYNC
if(~IR_DataShit == IR_data) //判断数据正反码
{
UserCode = ((u16)IR_UserH << 8) + IR_UserL;
IR_code = IR_data;
B_IR_Press = 1; //数据有效
}
}
else if((IR_BitCnt & 7)== 0) //one byte receive
{
IR_UserL = IR_UserH; //Save the User code high byte
IR_UserH = IR_data; //Save the User code low byte
IR_data = IR_DataShit; //Save the IR data byte
}
}
}
}
}
最后利用B_IR_Press 这个标志位来判断是否有红外信号发生:
if(IR_code == 64 && B_IR_Press)//遥控器电源键 IR_code -- 对应的数据
{
B_IR_Press = 0;
//这里就可以写你需要在发生这个事件时要做的逻辑
}