stm32对EV1527波形进行解码
最近学习了红外协议,用的是基于EV1527协议,对于从来没搞过红外协议的人来说,初次上手的确略显迷茫,网上的文章也是讲的一知半解,看完原理后,压根没有办法去编写代码,所以,我将整理网上的概述,用通俗易懂的语言进行讲解!若对你有帮助,那么最好不过,共勉!
首先:你得确保你用的协议是EV1527,因为市面上,还有NEC的红外协议,这两者的波形是有区分的。所以要先确保这一点
其次:你得有示波器或者逻辑分析仪,没有这个,你将无法捕获波形,分析波形,这样你是一头雾水的
最后:根据我的代码,一行一行的进行讲解!
正题开始
一开始,你总得有个IC手册吧,没手册,你怎么知道相关信息是什么呢,这里我就打开了EV1527的手册,可以去嘉立创商城下载,这个步骤我就不教了。
看到手册,我们知道
1.这个IC的封装长这样的
2.相关引脚功能是这样的
3.波形时序图编码规则是这样的
ok,了解到这些就足够了
下面就用示波器/逻辑分析仪捕获波形
这个就是整个波形的一个周期,里面就包含了,同步码+24BIT的数据位
分析这个波形之前,我们得测量这个波形高低电平的脉宽时间,这是写代码的关键,如果不知道这个,代码是没办法完成编写的
ok,这些时间都知道了,现在我就先说个编写代码的大概原理,读者可以先自行编写,若无果。则可参考笔者的,笔者的代码也是从网上参考借鉴,若有不对之处,有劳各位读者批评指正!
思路:根据这些波形,我们可以基于定时器100us中断产生一次中断,然后读取IO口电平高低所占的时间,来判断是否接收到了同步码→数据位
下面先解析我写的代码
//*******************************************************************
主函数:
int main(void)
{
RCC_GetClocksFreq(&RCC_Clocks);
EV1527_GPIO_Init();
Timer_Init();
LED_Init();
while(1)
{
if(decode_ok == 1) //解码成功
{
switch(rf_data[2])
{
case 0x91: //解码为0xf8,点亮LED
GPIO_ResetBits(GPIOC, GPIO_Pin_13);
break;
case 0x92: //解码为0xf2,熄灭LED
GPIO_ResetBits(GPIOC, GPIO_Pin_13);
break;
case 0x94: //解码为0xf8,点亮LED
GPIO_SetBits(GPIOC, GPIO_Pin_13);
break;
case 0x96: //解码为0xf2,熄灭LED
GPIO_SetBits(GPIOC, GPIO_Pin_13);
break;
}
}
}
}
//*******************************************************************
//*******************************************************************
Timer.c
void EV1527_GPIO_Init(void) //EV1527 IO口初始化
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // PB9 输入端
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
}
//*******************************************************************
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//50ms
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;//10000=1S
TIM_TimeBaseInitStructure.TIM_Prescaler =72-1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2, ENABLE);
}
uint8_t RF;
uint8_t decode_ok; //解码成功
uint8_t hh_w,ll_w; //高,低电平宽度
uint8_t ma_x; //接收到第几位编码了
uint8_t bma1,bma2,bma3,bma4; //用于接收过程存放遥控编码,编码比较两次,这是第一次
uint8_t mma1,mma2,mma3,mma4;
uint8_t mmb1,mmb2,mmb3,mmb4; // 用于接收过程存放遥控编码,第二次
//extern uint8_t mmb1,mmb2,mmb3,mmb4;
uint8_t rf_ok1,rf_ok2,rf_ok; //解码过程中的临时接收成功标志,接收到一个完整的遥控命令后置1,通知解码程序可以解码了
uint8_t old_rc5; //保存上一次查询到的电平状态
uint8_t tb_ok; //接收到同步的码时置1
uint8_t D0,D1,D2,D3 ;
uint16_t s ,s1;
uint8_t bt_auto; //自动设置遥控接收波特率标志
extern uint8_t rf_data[4];
void TIM2_IRQHandler(void)//100us产生一次中断
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
//接收数据的电平 PB9
RF = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_9);
if (!RF) // 检测到低电平 低电平时间加1
{
ll_w++;
// 保存上一次查询到的电平状态
old_rc5=0;
}
else // 检测到高电平
{
hh_w++;
if (!old_rc5) // 检测到从低到高的跳变,已检测, 到一个完整(高-低)电平周期
{
if (((hh_w>=2)&&(hh_w<=5))&&((ll_w>=100)&&(ll_w<=130))) //判同步码 2/5 100/130
{
tb_ok = 1 ;//接收到同步码标志位
ma_x = 0;
bma1=0; bma2=0; bma3=0; bma4=0;
}
else if ((tb_ok)&&((ll_w>=8)&&(ll_w<=13))) //8/13
{
ma_x++; //已经接收到同步码,判0
if(ma_x>23)
{
if(!rf_ok1) //rf_ok1临时接收成功
{ //将接收到的编码复制到解码寄存器中
mma1=bma1;
mma2=bma2;
mma3=bma3;
mma4=bma4;
// 通知解码子程序可以解码了
rf_ok1=1;
tb_ok=0;
s=1000;
}
else
{ //将接收到的编码复制到解码寄存器中
mmb1=bma1;
mmb2=bma2;
mmb3=bma3;
mmb4=bma4;
// 通知解码子程序可以解码了
rf_ok2=1;
tb_ok=0;
}
}
}
else if ((tb_ok)&&((ll_w>=2)&&(ll_w<=7))) // 2/7
{
switch (ma_x)
{ //遥控编码第1位
case 0 : bma1=bma1 | 0x80; break;
case 1 : bma1=bma1 | 0x40; break;
case 2 : bma1=bma1 | 0x20; break;
case 3 : bma1=bma1 | 0x10; break;
case 4 : bma1=bma1 | 0x08; break;
case 5 : bma1=bma1 | 0x04; break;
case 6 : bma1=bma1 | 0x02; break;
case 7 : bma1=bma1 | 0x01; break;
case 8 : bma2=bma2 | 0x80; break;
case 9 : bma2=bma2 | 0x40; break;
case 10: bma2=bma2 | 0x20; break;
case 11: bma2=bma2 | 0x10; break;
case 12: bma2=bma2 | 0x08; break;
case 13: bma2=bma2 | 0x04; break;
case 14: bma2=bma2 | 0x02; break;
case 15: bma2=bma2 | 0x01; break;
case 16: bma3=bma3 | 0x80; break;
case 17: bma3=bma3 | 0x40; break;
case 18: bma3=bma3 | 0x20; break;
case 19: bma3=bma3 | 0x10; break;
case 20: bma3=bma3 | 0x08; break; // 按键状态第1位
case 21: bma3=bma3 | 0x04; break;
case 22: bma3=bma3 | 0x02; break;
case 23:
bma3=bma3 | 0x01;
if(!rf_ok1)
{
mma1=bma1;
mma2=bma2;
mma3=bma3; // 将接收到的编码复制到解码寄存器中
rf_ok1=1; // 通知解码子程序可以解码了
tb_ok=0;
s=1000;
break;
}
else
{
mmb1=bma1;
mmb2=bma2;
mmb3=bma3; // 将再次接收到的编码复制到解码寄存器中,
rf_ok2=1; // 通知解码子程序可以解码了
tb_ok=0;
break;
}
}
}
ma_x++;
}
else
{
ma_x=0;
tb_ok=0;
bt_auto=0;
bma1=0;
bma2=0;
bma3=0;
hh_w=1;
ll_w=0;
}
//接收到不符合的高-低电平序列
ll_w=0;hh_w=1;
}
old_rc5=1; // 记录本次电平状态
}
if(rf_ok1) //规定时间内接受到2帧相同的编码数据才有效
{
s--;
if(!s) rf_ok1=0;
if(rf_ok2)
{
if((mma1==mmb1)&&(mma2==mmb2)&&(mma3==mmb3))
{
rf_ok=1;
rf_ok1=0;
rf_ok2=0;
}
else
{
rf_ok=0;
rf_ok1=0;
rf_ok2=0;
}
}
}
if((rf_ok)) //判断是否接收成功
{
TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);
rf_ok=0;
rf_data[0]=mma1;
rf_data[1]=mma2;
rf_data[2]=mma3;
decode_ok=1;
TIM_ITConfig(TIM2 , TIM_IT_Update, ENABLE);
}
}
如有不懂的,欢迎讨论!