完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1)实验平台:alientek 阿波罗 STM32F767 开发板
2)摘自《STM32F7 开发指南(HAL 库版)》关注官方微信号公众号,获取更多资料:正点原子 第三十七章 红外遥控实验 本章,我们将向大家介绍如何通过 STM32 来解码红外遥控器的信号。ALIENTK 阿波罗 STM32F767 开发板标配了红外接收头和一个很小巧的红外遥控器。在本章中,我们将利用 STM32F767 的输入捕获功能,解码开发板标配的这个红外遥控器的编码信号,并将解码后的键 值 LCD 模块上显示出来。本章分为如下几个部分: 37.1 红外遥控简介 37.2 硬件设计 37.3 软件设计 37.4 下载验证 37.1 红外遥控简介 红外遥控是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,功耗低,成 本低,易实现等显著优点,被诸多电子设备特别是家用电器广泛采用,并越来越多的应用到计 算机系统中。 由于红外线遥控不具有像无线电遥控那样穿过障碍物去控制被控对象的能力,所以,在设 计红外线遥控器时,不必要像无线电遥控器那样,每套(发射器和接收器)要有不同的遥控频率 或编码(否则,就会隔墙控制或干扰邻居的家用电器),所以同类产品的红外线遥控器,可以有 相同的遥控频率或编码,而不会出现遥控信号“串门”的情况。这对于大批量生产以及在家用 电器上普及红外线遥控提供了极大的方面。由于红外线为不可见光,因此对环境影响很小,再 由红外光波动波长远小于无线电波的波长,所以红外线遥控不会影响其他家用电器,也不会影 响临近的无线电设备。 红外遥控的编码目前广泛使用的是:NEC Protocol 的 PWM(脉冲宽度调制)和 Philips RC-5 Protocol 的 PPM(脉冲位置调制)。ALIENTEK 阿波罗 STM32F767 开发板配套的遥控 器使用的是 NEC 协议,其特征如下: 1、8 位地址和 8 位指令长度; 2、地址和命令 2 次传输(确保可靠性) 3、PWM 脉冲位置调制,以发射红外载波的占空比代表“0”和“1”; 4、载波频率为 38Khz; 5、位时间为 1.125ms 或 2.25ms; NEC 码的位定义:一个脉冲对应 560us 的连续载波,一个逻辑 1 传输需要 2.25ms(560us 脉冲+1680us 低电平),一个逻辑 0 的传输需要 1.125ms(560us 脉冲+560us 低电平)。而遥控 接收头在收到脉冲的时候为低电平,在没有脉冲的时候为高电平,这样,我们在接收头端收到 的信号为:逻辑 1 应该是 560us 低+1680us 高,逻辑 0 应该是 560us 低+560us 高。 NEC 遥控指令的数据格式为:同步码头、地址码、地址反码、控制码、控制反码。同步码 由一个 9ms 的低电平和一个 4.5ms 的高电平组成,地址码、地址反码、控制码、控制反码均是 8 位数据格式。按照低位在前,高位在后的顺序发送。采用反码是为了增加传输的可靠性(可 用于校验)。 我们遥控器的按键“▽”按下时,从红外接收头端收到的波形如图 37.1.1 所示: 图 37.1.1 按键“▽”所对应的红外波形 从图 37.1.1 中可以看到,其地址码为 0,控制码为 168。可以看到在 100ms 之后,我们还 收到了几个脉冲,这是 NEC 码规定的连发码(由 9ms 低电平+2.5m 高电平+0.56ms 低电平 +97.94ms 高电平组成),如果在一帧数据发送完毕之后,按键仍然没有放开,则发射重复码, 即连发码,可以通过统计连发码的次数来标记按键按下的长短/次数。 第十四章我们曾经介绍过利用输入捕获来测量高电平的脉宽,本章解码红外遥控信号,刚 好可以利用输入捕获的这个功能来实现遥控解码。关于输入捕获的介绍,请参考第十四章的内 容。 37.2 硬件设计 本实验采用定时器的输入捕获功能实现红外解码,本章实验功能简介:开机在 LCD 上显示 一些信息之后,即进入等待红外触发,如过接收到正确的红外信号,则解码,并在 LCD 上显示 键值和所代表的意义,以及按键次数等信息。同样我们也是用 LED0 来指示程序正在运行。 所要用到的硬件资源如下: 1) 指示灯 DS0 2) LCD 模块 3) 红外接收头 4) 红外遥控器 前两个,在之前的实例已经介绍过了,遥控器属于外部器件,遥控接收头在板子上,与 MCU 的连接原理图如 37.2.1 所示: 图 37.2.1 红外遥控接收头与 STM32 的连接电路图 红外遥控接收头连接在 STM32 的 PA8(tiM1_CH1)上。硬件上不需要变动,只要程序将 TIM1_CH1 设计为输入捕获,然后将收到的脉冲信号解码就可以了。不过需要注意: REMOTE_IN 和 DCMI_XCLK 共用了 PA8,所以他们不可以同时使用。 开发板配套的红外遥控器外观如图 37.2.2 所示: 图 37.2.2 红外遥控器 37.3 软件设计 打开我们光盘的红外遥控器实验工程,可以看到我们添加了remote.c和remote.h两个文件, 同时因为我们使用的是输入捕获,所以还用到定时器相关的库函数源文件 stm32f7xx_hal_tim.c 和头文件 stm32f7xx_hal_tim.h。 打开 remote.c 文件,代码如下: TIM_HandleTypeDef TIM1_Handler; //定时器 1 句柄 //红外遥控初始化 //设置 IO 以及 TIM1_CH1 的输入捕获 //TIM1 挂载 APB2 上 void Remote_Init(void) { TIM_IC_InitTypeDef TIM1_CH1Config; TIM1_Handler.Instance=TIM1; //通用定时器 1 TIM1_Handler.Init.Prescaler=215; //预分频器,1M 的计数频率,1us 加 1. TIM1_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; //向上计数器 TIM1_Handler.Init.Period=10000; //自动装载值 TIM1_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; HAL_TIM_IC_Init(&TIM1_Handler); //初始化 TIM1 输入捕获参数 TIM1_CH1Config.ICPolarity=TIM_ICPOLARITY_RISING; //上升沿捕获 TIM1_CH1Config.ICSelection=TIM_ICSELECTION_DIRECTTI;//映射到 TI1 上 TIM1_CH1Config.ICPrescaler=TIM_ICPSC_DIV1; //配置输入分频,不分频 TIM1_CH1Config.ICFilter=0x03; //IC1F=0003 8 个定时器时钟周期滤波 HAL_TIM_IC_ConfigChannel(&TIM1_Handler,&TIM1_CH1Config, TIM_CHANNEL_1);//配置 TIM1 通道 1 HAL_TIM_IC_Start_IT(&TIM1_Handler,TIM_CHANNEL_1); //开始捕获 TIM1 的通道 1 __HAL_TIM_ENABLE_IT(&TIM1_Handler,TIM_IT_UPDATE); //使能更新中断 } //定时器 1 底层驱动,时钟使能,引脚配置 //此函数会被 HAL_TIM_IC_Init()调用 //htim:定时器 1 句柄 void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim) { GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_TIM1_CLK_ENABLE(); //使能 TIM1 时钟 __HAL_RCC_GPIOA_CLK_ENABLE(); //开启 GPIOA 时钟 GPIO_Initure.Pin=GPIO_PIN_8; //PA8 GPIO_Initure.Mode=GPIO_MODE_AF_PP; //复用推挽输出 GPIO_Initure.Pull=GPIO_PULLUP; //上拉 GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速 GPIO_Initure.Alternate=GPIO_AF1_TIM1; //PA8 复用为 TIM1 通道 1 HAL_GPIO_Init(GPIOA,&GPIO_Initure); HAL_NVIC_SetPriority(TIM1_CC_IRQn,1,3); //设置抢占优先级 1,子优先级 3 HAL_NVIC_EnableIRQ(TIM1_CC_IRQn); //开启 ITM1 中断 HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn,1,2); //设置抢占优先级 1,子优先级 2 HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn); //开启 ITM1 中断 } //遥控器接收状态 //[7]:收到了引导码标志 //[6]:得到了一个按键的所有信息 //[5]:保留 //[4]:标记上升沿是否已经被捕获 //[3:0]:溢出计时器 u8 RmtSta=0; u16 Dval; //下降沿时计数器的值 u32 RmtRec=0; //红外接收到的数据 u8 RmtCnt=0; //按键按下的次数 //定时器 1 更新(溢出)中断 void TIM1_UP_TIM10_IRQHandler(void) { HAL_TIM_IRQHandler(&TIM1_Handler);//定时器共用处理函数 } //定时器 1 输入捕获中断服务程序 void TIM1_CC_IRQHandler(void) { HAL_TIM_IRQHandler(&TIM1_Handler);//定时器共用处理函数 } //定时器更新(溢出)中断回调函数 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim->Instance==TIM1){ if(RmtSta&0x80)//上次有数据被接收到了 { RmtSta&=~0X10; //取消上升沿已经被捕获标记 if((RmtSta&0X0F)==0X00)RmtSta|=1<<6; //标记已经完成一次按键的键值信息采集 if((RmtSta&0X0F)<14)RmtSta++; else { RmtSta&=~(1<<7);//清空引导标识 RmtSta&=0XF0; //清空计数器 } } } } //定时器输入捕获中断回调函数 void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//捕获中断发生时执行 { if(htim->Instance==TIM1) { if(RDATA)//上升沿捕获 { TIM_RESET_CAPTUREPOLARITY(&TIM1_Handler,TIM_CHANNEL_1); //一定要先清除原来的设置!! TIM_SET_CAPTUREPOLARITY(&TIM1_Handler,TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING);//CC1P=1 设置为下降沿捕获 __HAL_TIM_SET_COUNTER(&TIM1_Handler,0); //清空定时器值 RmtSta|=0X10; //标记上升沿已经被捕获 }else //下降沿捕获 { Dval=HAL_TIM_ReadCapturedValue(&TIM1_Handler,TIM_CHANNEL_1); //读取 CCR1 也可以清 CC1IF 标志位 TIM_RESET_CAPTUREPOLARITY(&TIM1_Handler,TIM_CHANNEL_1); //一定要先清除原来的设置!! TIM_SET_CAPTUREPOLARITY(&TIM1_Handler,TIM_CHANNEL_1, TIM_ICPOLARITY_RISING);//配置 TIM5 通道 1 上升沿捕获 if(RmtSta&0X10) //完成一次高电平捕获 { if(RmtSta&0X80)//接收到了引导码 { if(Dval>300&&Dval<800) //560 为标准值,560us { RmtRec<<=1; //左移一位. RmtRec|=0; //接收到 0 }else if(Dval>1400&&Dval<1800) //1680 为标准值,1680us { RmtRec<<=1; //左移一位. RmtRec|=1; //接收到 1 }else if(Dval>2200&&Dval<2600) //得到按键键值增加的信息 2500 为标准值 2.5ms { RmtCnt++; //按键次数增加 1 次 RmtSta&=0XF0; //清空计时器 } }else if(Dval>4200&&Dval<4700) //4500 为标准值 4.5ms { RmtSta|=1<<7; //标记成功接收到了引导码 RmtCnt=0; //清除按键次数计数器 } } RmtSta&=~(1<<4); } } } //处理红外键盘 //返回值: // 0,没有任何按键按下 //其他,按下的按键键值. 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)//检验遥控识别码(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; } 该部分代码包含 7 个函数,首先是 Remote_Init 函数,该函数和 MSP 回调函数 HAL_TIM_IC_MspInit 共同完成 TIM1 的时基参数初始化,TIM1_CH1 的 1 的输入捕获配置,IO 口初始化配置,IO 口复用映射配置以及 NVIC 配置。具体内容和输入捕获实验章节基本一致, 不同的是换了定时器而已。请参考输入捕获实验章节讲解。 由于 TIM1 是高级定时器,它有 2 个中断服务函数: TIM1_UP_TIM10_IRQHandler 中断服务函数用于处理 TIM1 的溢出(更新)事件, TIM1_CC_IRQHandler 中断服务函数用于处理 TIM1 的输入捕获事件。对于我们使用 HAL 库, 根据定时器中断实验讲解,会在中断服务函数中调用 HAL 库提供的公用中断处理函数 HAL_TIM_IRQHandler,该函数内部会对中断进行判断,然后调用相应的中断处理回调函数。 溢出(更新)中断回调函数为 HAL_TIM_PeriodElapsedCallback,在本例程里面,该函数用 来处理 TIM1 溢出,并标用于标记键值获取完成。每一次红外按键解码,都必须通过定时器溢 出事件来标记完成。输入捕获中断回调函数 HAL_TIM_IC_CaptureCallback, 在本例程里面, 该函数实现对红外信号的高电平脉冲的捕获,同时根据我们之前简介的协议内容来解码。这两 个中断处理回调函数用到几个全局变量,用于辅助解码,并存储解码结果。 这里简单介绍一下高电平捕获思路:首先输入捕获设置的是捕获上升沿,在上升沿捕获到 以后,立即设置输入捕获模式为捕获下降沿(以便捕获本次高电平),然后,清零定时器的计数 器值,并标记捕获到上升沿。当下降沿到来时,再次进入捕获中断服务函数,立即更改输入捕 获模式为捕获上升沿(以便捕获下一次高电平),然后处理此次捕获到的高电平。 最后是 Remote_Scan 函数,该函用来扫描解码结果,相当于我们的按键扫描。输入捕获解 码的红外数据,通过该函数传送给其他程序。 接下来我们打开 remote.h 文件,可以看到下面一行代码: #define REMOTE_ID 0 这里的 REMOTE_ID 就是我们开发板配套的遥控器的识别码,对于其他遥控器可能不一样, 只要修改这个为你所使用的遥控器的一致就可以了。remote.h 其他是一些函数的声明,我们不 做过多讲解,最后我们看看主函数代码如下: int main(void) { u8 key; u8 t=0; u8 *str=0; Cache_Enable(); //打开 L1-Cache HAL_Init(); //初始化 HAL 库 Stm32_Clock_Init(432,25,2,9); //设置时钟,216Mhz …//此处省略部分代码 Remote_Init(); //初始化 红外接收 while(1) { key=Remote_Scan(); if(key) { LCD_ShowNum(86,130,key,3,16); //显示键值 LCD_ShowNum(86,150,RmtCnt,3,16);//显示按键次数 switch(key) { case 0:str="ERROR";break; case 162:str="POWER";break; ..//此处省略部分代码 case 66:str="0";break; case 82:str="DELETE";break; } LCD_Fill(86,170,116+8*8,170+16,WHITE); //清楚之前的显示 LCD_ShowString(86,170,200,16,16,str); //显示 SYMBOL }else delay_ms(10); t++; if(t==20) { t=0; LED0_Toggle; } } } main 函数代码比较简单,主要是通过 Remote_Scan 函数获得红外遥控输入的数据(键值), 然后显示在 LCD 上面。 至此,我们的软件设计部分就结束了。 37.4 下载验证 在代码编译成功之后,我们通过下载代码到 ALIENTEK 阿波罗 STM32 开发板上,可以看 到 LCD 显示如图 37.4.1 所示的内容: 图 37.4.1 程序运行效果图 此时我们通过遥控器按下不同的按键,则可以看到 LCD 上显示了不同按键的键值以及按键次数和对应的遥控器上的符号。如图 37.4.2 所示: 图 37.4.2 解码成功 |
|
相关推荐
|
|
STM32进行DMA数据转运,为什么只有A组最后一位数据被转运到B组去?
1265 浏览 2 评论
1585 浏览 3 评论
1206 浏览 0 评论
嵌入式开发 Win11安装ST-Link 提示 设备描述符请求失败 怎么处理?
1339 浏览 0 评论
1632 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-8-18 06:20 , Processed in 0.587023 second(s), Total 61, Slave 48 queries .
Powered by 电子发烧友网
© 2015 www.ws-dc.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号