CH579M开发笔记09——红外遥控

专栏目录:CH579M开发笔记——目录


功能概述

在上一篇文章中,我们学习了如何使用CH579M的TIM0设定500ms定时,并在中断响应函数中控制蜂鸣器的电平状态。

本次实验的目的是初始化TIM0,实现50us的定时,实现对红外信号的解码、并通过串口打印收到的红外编码信息。

核心代码

定时器初始化

查看代码
void timer0_init(u16 us)

{

    TMR0_TimerInit(FREQ_SYS / (1000000 / us)); // 设置定时时间 100us

    TMR0_ITCfg(ENABLE, TMR0_3_IT_CYC_END); // 开启中断

    NVIC_EnableIRQ(TMR0_IRQn);

}

定时器中断响应函数

查看代码
void TMR0_IRQHandler(void) // TMR0 定时中断
{
    if (TMR0_GetITFlag(TMR0_3_IT_CYC_END)) {
        TMR0_ClearITFlag(TMR0_3_IT_CYC_END); // 清除中断标志
    }

    if ((++timer0_cnt) > 19999) {
        timer0_cnt = 0;
        cycle_1000ms = 1;
    }

    if (timer0_cnt % 1999 == 0) {
        cycle_100ms = 1;
    }

    if (timer0_cnt % 9999 == 0) {
        cycle_500ms = 1;
    }

    if (irda_sta > 0) {
        irda_time_cnt++;
    }
}

记录编码信息

查看代码
void irda_signal_scan(void)
{
    if (irda_time_cnt > 250) // frame head  13500us=13.5ms
    {
        irda_sta |= 0x4000;
    }

    // irda rx data
    if ((irda_sta & 0x4000) && (irda_time_cnt <= 50)) //2500us at most
    {
        irda_data <<= 1; //LSB
        if (irda_time_cnt >= 35) //1750us
        {
            irda_data |= (0x01 << 0);
        }
        if (((++irda_sta) & 0xFF) > 31) //32 rx data at most
        {
            irda_sta &= 0x1FFF; //irda rx finish
            irda_sta |= 0x2000;
        }
    }

    if (irda_sta & 0x2000) //irda generate data
    {
        irda_sta = 0;
        irda_temp[0] = (u8)((irda_data >> 0) & 0xff);
        irda_temp[1] = (u8)((irda_data >> 8) & 0xff);
        irda_temp[2] = (u8)((irda_data >> 16) & 0xff);
        irda_temp[3] = (u8)((irda_data >> 24) & 0xff);
        irda_data = 0;
        if (irda_temp[0] + irda_temp[1] == 0xFF) { //check correct
            irda_data_num = irda_cmd2num(irda_temp[0]);
            irda_data_cmd = irda_temp[0];
            printf("IRDA code is 0x%X", irda_temp[0]);
            irda_triger = 1;
            irda_sta = 0; //reset irda status
            irda_data_cmd = 0;
            irda_data_num = 0;
            irda_time_cnt = 0;
        }
    }
    irda_time_cnt = 0; //reset idata time cnt
}

解码红外数据

查看代码

u8 irda_cmd2num(u8 cmd)
{
    u8 ret = 0xFF;
    switch (cmd) {
    case 151: {
        ret = 0;
    } break;
    case 207: {
        ret = 1;
    } break;
    case 231: {
        ret = 2;
    } break;
    case 133: {
        ret = 3;
    } break;
    case 239: {
        ret = 4;
    } break;
    case 199: {
        ret = 5;
    } break;
    case 155: {
        ret = 6;
    } break;
    case 189: {
        ret = 7;
    } break;
    case 181: {
        ret = 8;
    } break;
    case 173: {
        ret = 9;
    } break;
    }
    return ret;
}

 

 

代码讲解

  • 红外信号格式(本例采用NEC编码)

 

NEC编码有如下特点:

    • 9ms的高电平+4.5ms的低电平,是红外信号的先导码
    • 有效信息是32个bit,4个8byte的16进制数据。前两个是用户码,第三个是键值(有效信息),最后一个是键值的反码,用来校验数据。
    • 逻辑判断:高电平0.56ms,低电平0.56ms则为逻辑0;高电平0.56ms,低电平1.685ms则为逻辑1;
  • 信号解析过程
    • 接收红外数据的引脚电平常高,仅当红外信号接收时状态变化,我们可以通过判断低电平时长的方式判断数据接收开始和解析红外编码信息。实际上红外接收的电平状态和上图的红外编码是相反的(信号常高,有红外信号时拉低9ms+拉高4.5ms作为先导码)
    • 初始化定时器,周期50us,作为计数时间基准,使用PB8作为红外输入引脚,下降沿触发。
    • 当红外信号被接收时,触发GPIOB的外部中断响应函数,将irda_sta标志值设为0x8000,意味着开始接收红外数据了。而在定时器的中断响应函数里,一旦irda_sta的状态值非零,即开始使用irda_time_cnt记录低电平时长。
    • 待GPIOB的外部中断响应函数第二次触发,正常情况下意味着先导码结束,数据传输开始。我们需要判断irda_time_cnt的大小来判断两次中断之间的时长是否是13.5ms。如果是,则将irda_sta标记为0x4000。
    • 通过判断低电平时长来确定信号是逻辑“0”或逻辑“1”;连续使用irda_data变量记录32次后,意味着一个完整的红外数据已经记录完成。将irda_sta状态位标记为0x2000。
    • 完成逻辑电平记录后,将32bit的逻辑电平转为4个byte的数据信息,解码完成。此时得到的编码是无规律的HEX数据,还需进一步解码才能与遥控器的数字相对应。

 

功能验证

使用烧录工具将编译后的hex文件写入开发板后,使用遥控器发送红外命令,开发板在成功解析红外命令后,蜂鸣器响一声,继而继电器状态翻转,同时串口可以看到开发板的打印信息。

 

注意事项

  • 本实验的关键是采用定时器获取红外编码的时长,如果改变了定时器的周期,则记录到的低电平时长也会相应改变。
  • 如果实测未达到预期效果,请检查遥控器是否故障。
posted @ 2022-02-08 14:17  realiot  阅读(331)  评论(0)    收藏  举报