STM32学习笔记一一红外遥控
2019-08-15 来源:eefocus
1. 简述
红外遥控是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,低功耗,低成本。
红外遥控的编码方式目前广泛使用的是: PWM (脉冲宽度调制)的 NEC 协议和 Philips PPM(脉冲位置调制) 的 RC-5 协议的。
1.1 NEC 协议定义
NEC 码的位定义: 一个脉冲对应 560us 的连续载波,一个逻辑 1 传输需要2.25ms(560us 脉冲+1680us 低电平),一个逻辑 0 的传输需要1.125ms(560us 脉冲+560us 低电平)。而遥控接收头在收到脉冲的时候为低电平,在没有脉冲的时候为高电平,这样,我们在接收头端收到的信号为:逻辑 1 应该是 560us 低+1680us 高,逻辑 0 应该是 560us 低 + 560us 高。
发射端逻辑:
遥控接收头逻辑:
1.2 NEC 协议特点
(1) 8 位地址和 8 位指令长度;
(2)地址和命令 2 次传输(确保可靠性);
(3) PWM 脉冲位置调制,以发射红外载波的占空比代表“0”和“1”;
(4)载波频率为 38Khz;
(5)位时间为 1.125ms 或 2.25ms;
1.3 NEC 遥控指令的数据格式
采用反码是为了增加传输的可靠性。NEC 码规定的连发码(由 9ms 低电平+2.5m 高电平+0.56ms 低电平+97.94ms 高电平组成),如果在一帧数据发送完毕之后,按键仍然没有放开,则发射重复码,即连发码。
2. 软件实现
上面我们基本了解了 NEC 格式的红外发码和收码的格式,就可以根据通信的协议来完成对应的程序。
程序逻辑:
2.1 初始化
void Remote_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //下拉输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_1);
TIM_TimeBaseStructure.TIM_Period = 10000;//设定自动重装值,10ms溢出
TIM_TimeBaseStructure.TIM_Prescaler = (72-1);//预分频器,1MHz的计数频率,1us加一
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//时钟分割
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;//IC2映射到TI5
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//上升沿捕获
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//不分频
TIM_ICInitStructure.TIM_ICFilter = 0x03;//IC4F=0011,输入滤波器8个定时器时钟周期滤波
TIM_ICInit(TIM5,&TIM_ICInitStructure);//初始化定时器输入捕获通道
TIM_Cmd(TIM5,ENABLE);//使能定时器5
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;//TIM5中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//从优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC2,ENABLE);//允许更新中断,允许CC2IE捕获中断
}
2.2 中断捕获
u8 RmtSta=0;
u16 Dval;
u32 RmtRec=0;
u8 RmtCnt=0;
void TIM5_IRQHandler(void)
{
if(TIM_GetITStatus(TIM5,TIM_IT_Update)!= RESET)
{
if(RmtSta&0x80)//数据接收到标志位
{
RmtSta &= ~0x10;//取消上升沿捕获标记
if((RmtSta&0x0F)==0x00)
RmtSta |= 1<<6;
if((RmtSta&0x0F)<14)
RmtSta++;
else
{
RmtSta &= ~(1<<7);//清空引导标志位
RmtSta &= 0xF0;//清空计数器
}
}
}
if(TIM_GetITStatus(TIM5,TIM_IT_CC2)!=RESET)
{
if(RDATA)//上升沿已经捕获
{
TIM_OC2PolarityConfig(TIM5,TIM_ICPolarity_Falling);//CC1P=1,设置为下降沿捕获
TIM_SetCounter(TIM5,0);//清空定时器数值
RmtSta |= 0x10;//标记上升沿已经被捕获
}
else
{
Dval = TIM_GetCapture2(TIM5);//读取CCR1的值
TIM_OC2PolarityConfig(TIM5,TIM_ICPolarity_Rising);//设置为上升沿捕获
if(RmtSta&0x10)
{
if(RmtSta&0x80)//接收到引导码
{
if(Dval>300&&Dval<800)//高电平为560us
{
RmtRec <<= 1;
RmtRec |= 0;//接收到0码
}
else if(Dval>1400&&Dval<1800)//高电平为1680us
{
RmtRec <<= 1;
RmtRec |= 1;//接收到1码
}
else if(Dval>2200&&Dval<2600)//连发码判断
{
RmtCnt++;
RmtSta &= 0xF0;//清空计数器
}
}
else if(Dval>4200&&Dval<4700)
{
RmtSta |= 1<<7;//记录接收到引导码
RmtCnt = 0;
}
}
RmtSta &= ~(1<<4);
}
}
TIM_ClearFlag(TIM5,TIM_IT_Update|TIM_IT_CC2);
}
2.3 遥控键值扫描
u8 Remote_Scan(void)
{
u8 sta=0;
u8 t1,t2;
if(RmtSta&(1<<6))//得到一个按键的信息
{
t1 = RmtRec>>24;//地址码
t2 = (RmtRec>>16) & 0xFF;//地址反码
if((t1==(u8)~t2)&&t1==REMOTE_ID)//校验遥控识别码以及遥控接收地址
{
t1 = RmtRec >> 8;//控制码
t2 = RmtRec;//控制反码
if(t1==(u8)~t2)
sta = t1;
}
if((sta==0)||((RmtSta&0x80)==0))//接收错误或者按键没有按下
{
RmtSta &= ~(1<<6);//清除接收按键有效标志位
RmtCnt = 0;
}
}
return sta;
}