红外通信是利用950nm近红外波段的红外线作为传递信息的媒体,
即通信信道。 发送端采用脉时调制(PPM) 方式, 将二进制数字信号调制成某一频率的脉冲序列, 并驱动红外发射管以光脉冲的形式发送出去;
接收端将接收到的光脉转换成电信号, 再经过放大、 滤波等处理后送给解调电路进行解调, 还原为二进制数字信号后输出。 简而言之, 红外通信的实质就是对二进制数字信号进行调制与解调,
以便利用红外
信道进行传输, 红外通信接口就是针对红外信道的调制解调器。
载波:38KHz
红外发送头 + 红外接收头、红外接收管
红外接收头:滤除载波 – 二进制信号
红外接收管:接收载波
编码:NEC 、 RC5
1. 数字量
NEC
数据 0 :560us低电平 + 560us高电平
数据 1 :560us低电平 + 1690us高电平
2. 数据帧格式
引导码:9ms低电平
重复引导码:9ms低+2.25ms高 –110ms发送一次
如何解析红外编码?
1. 外部中断
–边沿检测 – 时间:定时器
2. 定时器的输入捕获
美的 | 解析 |
---|---|
14120 | |
4494 | 引导码 |
4420 | 引导码 |
588 | |
1604 | 1 |
575 | |
501 | 0 |
566 | |
5215 | 分割码 |
4498 | 引导码 |
4398 | 引导码 |
588 | |
1571 | |
589 |
引导码:不一样 2000 ~ 9500
数据码:有浮动 450 ~ 700
1500 ~ 1800
分割码 5000 ~ 5400
// A code block
#include "ir.h"
_IR ir={.count=0,.overflag=0};
int second=0;
void IR_Config(void)
{
TIM2_Config(72,20000); //20ms
TIM1_Config(72,26,13); //38KHz 50%
sFLASH_ReadBuffer((u8 *)&ir,0x60000,sizeof(ir));
if(*(uint8_t *)&ir!=0xff)
{
second=ir.frequency;
IR_Display();
}
}
void TIM2_Config(uint16_t psc,uint16_t arr)
{
//PB3
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_ICInitTypeDef TIM_ICInitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//关闭JATG,启用SWD
GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);//将TIM2_CH2映射到PB3
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_3;
GPIO_Init(GPIOB,&GPIO_InitStruct);
//定时器TIM2配置
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV2;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period=arr-1;
TIM_TimeBaseInitStruct.TIM_Prescaler=psc-1;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
//输入捕获
TIM_ICInitStruct.TIM_Channel=TIM_Channel_2;//通道2
TIM_ICInitStruct.TIM_ICFilter=0x00;//不使用滤波器
TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Falling;//下降沿捕获
TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;//不分频
TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;// IC2
TIM_ICInit(TIM2,&TIM_ICInitStruct);
TIM_ITConfig(TIM2,TIM_IT_CC2|TIM_IT_Update,ENABLE);
NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStruct);
TIM_Cmd(TIM2,ENABLE);
}
//PA8 -- TIM1_CH1
//38KHz载波 -- 分频 72 -- 1M --重装载值 -- 26
void TIM1_Config(u16 psc,u16 arr,u16 ccr)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_TIM1,ENABLE);
//配置PA8 为复用推挽输出
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
GPIO_Init(GPIOA,&GPIO_InitStruct); //GPIO初始化
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV2;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStruct.TIM_Period = arr-1;//重装载值
TIM_TimeBaseInitStruct.TIM_Prescaler = psc-1;//分频值
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStruct);
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCInitStruct.TIM_Pulse = ccr;//比较值
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM2;//PWM2模式
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; //极性:高
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;//比较输出使能
TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Set; //空闲为高,对极性反转起作用
TIM_OC1Init(TIM1,&TIM_OCInitStruct);
TIM_CtrlPWMOutputs(TIM1,ENABLE);//主输出使能
TIM_Cmd(TIM1,DISABLE);
}
uint16_t ir_buff[1024]; //存放捕获的计数器的值
uint16_t ir_count=0; //保存边沿的个数
void TIM2_IRQHandler(void)
{
uint16_t i=0;
static uint16_t count = 0;
if(TIM_GetITStatus(TIM2,TIM_IT_Update))//更新中断
{
TIM_ClearFlag(TIM2,TIM_FLAG_Update); //清中断
if(count>40)
{
// for(i=0;i
// {
// printf("%d\r\n",ir_buff[i]);
// }
ir_count=count;
irrun[1] = 2000; //启动时间点
count = 0;
ir.overflag = 1;
}
}
if(TIM_GetITStatus(TIM2,TIM_IT_CC2))//捕获中断
{
TIM_ClearFlag(TIM2,TIM_FLAG_CC2); //清中断
ir_buff[count++]=TIM_GetCapture2(TIM2);
TIM2->CCER ^= (1<<5); //极性反转,输入/捕获通道2输出极性
TIM_SetCounter(TIM2,0); //计数器清零
}
}
/*
比较函数封装
time1 -- 要检测的数据
time2 -- 标准数据
range1 -- 下限
range2 -- 上限
*/
uint32_t guide=0;
uint8_t sign=0;
uint8_t Time_Judge(uint16_t time1,uint16_t time2,uint16_t range1,uint16_t range2)
{
if(time1 > (time2-range1) && time1 < (time2+range2))
return 1;
else
return 0;
}
void IR_Bootcode(void)
{
sign=0;
for(++guide;guide<ir.count;guide++)
{
if(Time_Judge(ir_buff[guide],4500,2000,5000)) //2500~9500
{
ir.ir_boot.boot_time[second][ir.ir_boot.boot_len[second]]=ir_buff[guide];
ir.ir_boot.boot_len[second]++;
sign=1;
printf("%d\r\n",ir_buff[guide]);
}
else
{
break;
}
}
}
void IR_Datacode(void)
{
sign=0;
for(guide+=1;guide<ir.count;guide+=2)
{
if(Time_Judge(ir_buff[guide],560,200,200))
{
ir.irdata[second][ir.datalen[second]/8] &=~ (1<<(7-ir.datalen[second]%8));
ir.datalen[second]++;
sign=3;
}
else if(Time_Judge(ir_buff[guide],1690,200,200))
{
ir.irdata[second][ir.datalen[second]/8] |= (1<<(7-ir.datalen[second]%8));
ir.datalen[second]++;
sign=2;
}
else
{
break;
}
}
}
void IR_Cutcode(void)
{
if(Time_Judge(ir_buff[guide],5200,500,500))
{
ir.ir_boot.cut_time=ir_buff[guide];
second=1;
printf("%d\r\n",ir_buff[guide]);
}
}
void IR_empty(void)
{
memset(&ir,0,sizeof(ir));
second=0;
guide=0;
sign=0;
}
void IR_Transformation(uint8_t a)
{
guide=0;
second=0;
irrun[1] = 0xffffffff;
if((ir.overflag ==1)&&(a==1))
{
memset(&ir,0,sizeof(ir));
ir.count = ir_count;
for(u8 i=0;i<second+1;i++)
{
IR_Bootcode();
IR_Datacode();
IR_Cutcode();
if((sign==0)||(ir.datalen[i]/8!=6))
{
IR_empty();
return;
}
ir.frequency=second;
}
ir.count = 0;
ir.overflag = 0;
sign=0;
IR_Display();
sFLASH_EraseSector(0x060000);//擦除器擦除第6块
sFLASH_WriteBuffer((uint8_t *)&ir,0x060000,sizeof(ir));//写缓存区
}
IR_empty();
}
void IR_Display(void)
{
u32 i=0,j=0;
for(j=0;j<second+1;j++)
{
//打印引导码
printf("第%d次引导码\r\n",j+1);
for(i=0;i<ir.ir_boot.boot_len[j];i++)
{
printf("%d\t",ir.ir_boot.boot_time[j][i]);
}
printf("\r\n");
printf("第%d次数据\r\n",j+1);
for(i=0;i<ir.datalen[j]/8;i++)
{
printf("%d\t",ir.irdata[j][i]);
}
printf("\r\n");
if((second!=0)&&(sign==0))
{
printf("分割码\r\n");
printf("%d\r\n",ir.ir_boot.cut_time);
sign=1;
}
printf("\r\n");
}
}
void IR_Bootsend(void)
{
for(guide=0;guide<ir.ir_boot.boot_len[second];guide++)
{
IR_38KHz(sign);
sign=!sign;
Delay_nus(ir.ir_boot.boot_time[second][guide]);
}
for(guide=0;guide<ir.datalen[second]/8;guide++)
{
for(u32 i=0;i<8;i++)
{
IR_38KHz(sign);
sign=!sign;
Delay_nus(520);
IR_38KHz(sign);
sign=!sign;
if(ir.irdata[second][guide]&(1<<(7-i)))
{
Delay_nus(1500);
}
else
Delay_nus(520);
}
}
IR_38KHz(sign);
sign=!sign;
Delay_nus(520);
IR_38KHz(sign);
sign=!sign;
Delay_nus(ir.ir_boot.cut_time);
second=1;
}
void IR_Sendout(void)
{
sign=1;
second=0;
for(u32 i=0;i<second+1;i++)
{
IR_Bootsend();
}
printf("发送完成\r\n");
printf("\r\n");
}
注:
我这里用的是小米手机的手机红外遥控器里的美的空调测试的,用的是NEC协议。每一个产品数据码不一样,引导码分割码也不一样,所以具体情况需要自己测试