单片机学习小组
直播中

纯纯纯牛奶

11年用户 523经验值
私信 关注

红外接收的原理是什么?

红外接收的原理是什么?

回帖(1)

陈逸群

2022-2-15 11:08:14
废话不多,直接切入正题,根据需要自行选择标题内容


  • 红外接收原理
  • NEC通讯协议
  • demo编写

红外接收原理介绍
红外原理性的东西,就不在这进行介绍了,不懂的可自行百度,会百度也是一种学习能力。
直接介绍红外的两部分,发射和接收。也就是发射机接收器这两部分属于硬件的设计需要考虑的范围,如果只是单纯的想写好代码,那么就请略过本小节,直接吃透NEC通讯协议。但为了更多人考虑,还是需要介绍一下的。
发射机
通常是个带纽扣电池的手持装置。现在很多低功耗芯片用于红外发射的原因就是可以很灵活的使用,在没有遥控按钮操作时,发射机几乎不会消耗电量,当有按钮操作时会马上唤醒相应红外命令。而通常市面上的发射机都基本采用陶瓷晶振,通过对外红LED控制电流范围来实现控制距离的远近。当然对于这如何进行选择最优解还是需要根据实际情况来判断。
一个简单的晶体三极管放大威廉希尔官方网站 就可以驱动红外LED。

接收器
重点为调制频率和区域可行性。
红外信号由接收器的检波二极管接收,信号通过放大和限幅处理,使信号有稳定的脉冲电平。

不用担心不懂此处的威廉希尔官方网站 部分,因为厂家已经集成到一个接收模块中,此处可作为了解。
NEC通讯协议
这是***重点***内容
特征:
8bit地址码,8bit命令码
完整发射两次地址码和命令码
脉冲时间长短调制方式
38KHz载波频率
位时间1.12ms和2.25ms

NEC协议根据脉冲时间长短解码,每个脉冲为560us长的38KHz载波。逻辑“1”脉冲时间为2.25ms 逻辑“0”脉冲时间为1.12ms

0.56ms的低电平,1.68ms的高电平脉冲 为 1
0.56ms的低电平,0.56ms的高电平脉冲 为 0

完整的协议波形图如下

协议规定低位首先发送。每次发送信息首先是9ms的低电平脉冲,接着是4.5ms的高电平,然后就是地址码和命令码。地址码和命令码发送两次,第二次发送的是反码,用于验证接收信息的准确性。因为每位都发送一次它的反码,所以总体的发送时间是恒定的。
当然,也会有人一直按着一个按键不放,注意,一串信息只能发送一次。如果一直按着同一按键不放,发送的则是以110ms为中期的重复码。
Demo编写
先说明下思维,这种方式为计算脉冲高电平时间来判断是否为逻辑1或0.
通过采用接收器所在GPIO管脚映射到外部事件中断线上,下降沿触发中断
当然还有各种不同的写法,比如通过定时器做的,个人认为芯片外设是少而珍贵的,如果能用数学思维来解决问题是比较好,把外设留给更重要的事件使用。

具体的电器属性配置还需根据自身情况来设定


这是STM32F030芯片,根据公司的产品的威廉希尔官方网站 图所写
切不可直接 ctrl+c+v


    EXTI_InitTypeDef EXTI_InitStruct;
        NVIC_InitTypeDef NVIC_InitStruct;


        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);


        SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource6);


        EXTI_InitStruct.EXTI_Line=EXTI_Line6;
        EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
        EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;
        EXTI_InitStruct.EXTI_LineCmd=ENABLE;
        EXTI_Init(&EXTI_InitStruct);


        NVIC_InitStruct.NVIC_IRQChannel=EXTI4_15_IRQn;
        NVIC_InitStruct.NVIC_IRQChannelPriority=2;
        NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
        NVIC_Init(&NVIC_InitStruct);


计算高电平时间,有关函数中的延时,会出有关延时的各种写法的文章。此处的延时为精准的20us,不同的芯片所对应的晶振也会不同,导致延时时间不同,需要根据自身情况判断


u8 IR_High_time(void)
{
        u8 t=0;
        while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6)==1)
                {
                        t++;
                        delay_us(2);
                        if(t>=250)
                                {
                                        return t;  //超时溢出
                                }
                }
        return t;
}


解码函数,不严谨的地方在于,在中断中进行了处理,切记不可在中断中处理复杂的事情,另外一个处理版本,不可公布出来。


        u8 time=0,ok=0,data,Num=0;
        while(1)
                {
                        if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6)==1)
                                {
                                        time=IR_High_time();
                                        if(time>=250)
                                        {       
                                                break;
                                        }                                               
                                        if(time>=200&&time<250)
                                                {
                                                        ok=1;
                                                }
                                        else if(time>=60&&time<90)
                                                {                                                       
                                                        data=1;
                                                }
                                        else if(time>=10&&time<50)
                                                {                                                       
                                                        data=0;
                                                }
                                        if(ok==1)
                                                {                                                       
                                                        IR_Recive_data<<=1;
                                                        IR_Recive_data+=data;
                                                        if(Num>=32)
                                                                {
                                                                        IR_Recive_flag=1;
                                                                        break;
                                                                }
                                                }
                                        Num++;
                                }
                }




最后还有两个全局变量用于判读和接收


u32 IR_Recive_data;
u8 IR_Recive_flag;
主函数部分,就只展示最简单的通过串口输出已解码的字符


while ( 1 )
          {               
                        if(IR_Recive_flag==1)
                        {       
                                IR_Recive_flag=0;
                                printf("Recive_data: %xrn",(u16)IR_Recive_data);
                        }
          }
举报

更多回帖

发帖
×
20
完善资料,
赚取积分