你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32实例-红外遥控实验②-程序设计

[复制链接]
STMCU小助手 发布时间:2022-6-26 18:24
    本实验使用到硬件资源如下:
(1)D1 指示灯
(2)串口 1
(3)红外遥控器和红外接收头
    D1 指示灯、串口 1 电路在前面章节都介绍过,这里就不多说,红外遥控器属于外部器件,只有红外接收头集成在开发板上,其电路如下图所示:
微信图片_20220626182411.png

    从电路图中可以看到,红外接收头的数据输出管脚连接在 STM32F1 芯片的PG15管脚上,这里我们使用PG15 引脚内部上拉,所以可以省去一个上拉电阻,不会有影响,当然也可以接一个 10K 的上拉电阻。通过配置 PG15 引脚为外部中断功能,按照 NEC 协议进行解码。
    D1 指示灯用来提示系统运行状态,红外遥控器用来发射红外键值的编码信
号,通过红外接收头进行解码,并将解码后的数据通过串口 1 打印输出。
    本实例所要实现的功能是:使用外部中断功能将遥控器键值编码数据解码后通过串口打印输出,同时控制 D1指示灯闪烁,提示系统运行。程序框架如下:
(1)使能 PG15 端口及 AFIO 时钟,映射 PG15 至外部中断线上,初始化 EXTI等
(2)编写红外解码函数(在 EXTI 中断处理)
(3)编写主函数
    外部中断的配置在“外部中断实验”章节中都有介绍,不清楚的可以回过头
看下。下面我们打开“ 红外遥控实验”工程,在APP 工程组中添加 hwjs.c 文件(里面包含了红外解码驱动程序),在 StdPeriph_Driver 工程组中添加stm32f10x_exti.c 库文件。EXTI 操作的库函数都放在stm32f10x_exti.c和stm32f10x_exti.h文件中, 所以使用到EXTI就必须加入 stm32f10x_exti.c文件,同时还要包含对应的头文件路径。
    这里我们分析几个重要函数。

外部中断初始化函数
    我们知道红外接收头数据输出管脚是接在 PG15 上, 所以配置 PG15 为外部中断功能,初始化代码如下:
  1. /****************************************************************
  2. * 函 数 名 : Hwjs_Init
  3. * 函数功能 : 红外端口初始化函数 时钟端口及外部中断初始化
  4. * 输 入 : 无
  5. * 输 出 : 无
  6. *****************************************************************/
  7. void Hwjs_Init()
  8. {
  9. GPIO_InitTypeDef GPIO_InitStructure;
  10. EXTI_InitTypeDef EXTI_InitStructure;
  11. NVIC_InitTypeDef NVIC_InitStructure;
  12. /* 开启 GPIO 时钟及管脚复用时钟 */
  13. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG|RCC_APB2Periph_AFIO,ENABLE);
  14. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_15;//红外接收
  15. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
  16. GPIO_Init(GPIOG,&GPIO_InitStructure);
  17. GPIO_EXTILineConfig(GPIO_PortSourceGPIOG, GPIO_PinSource15); //选择 GPIO 管脚用作外部中断线路
  18. EXTI_ClearITPendingBit(EXTI_Line15);
  19. /* 设置外部中断的模式 */
  20. EXTI_InitStructure.EXTI_Line=EXTI_Line15;
  21. EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
  22. EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
  23. EXTI_InitStructure.EXTI_LineCmd=ENABLE;
  24. EXTI_Init(&EXTI_InitStructure);
  25. /* 设置 NVIC 参数 */
  26. NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //打开全局中断
  27. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级为 0
  28. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应优先级为1
  29. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能
  30. NVIC_Init(&NVIC_InitStructure);
  31. }
复制代码

    在Hwjs_Init()函数中,首先使能 GPIOG 端口和 AFIO 时钟,然后将PG15 映射到外部中断线 15 上, 并配置 PG15 为上拉输入模式, 最后初始化 EXTI 及NVIC,这里需要注意,PG15 的外部中断通道是 EXTI15_10_IRQn。

红外解码函数
    初始化外部中断后,中断就已经开启了,当 PG15 引脚上来了一个下降沿,就会触发一次中断,在中断内我们可以计算高电平时间,通过高电平时间判断是否进入引导码及数据 0 和1。具体代码如下:
  1. void EXTI15_10_IRQHandler(void) //红外遥控外部中断
  2. {
  3. u8 Tim=0,Ok=0,Data,Num=0;
  4. while(1)
  5. {
  6. if(GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_15)==1)
  7. {
  8. Tim=HW_jssj();//获得此次高电平时间
  9. if(Tim>=250) break;//不是有用的信号
  10. if(Tim>=200 && Tim<250)
  11. {
  12. Ok=1;//收到起始信号
  13. }
  14. else if(Tim>=60 && Tim<90)
  15. {
  16. Data=1;//收到数据 1
  17. }
  18. else if(Tim>=10 && Tim<50)
  19. {
  20. Data=0;//收到数据 0
  21. }
  22. if(Ok==1)
  23. {
  24. hw_jsm<<=1;
  25. hw_jsm+=Data;
  26. if(Num>=32)
  27. {
  28. hw_jsbz=1;
  29. break;
  30. }
  31. }
  32. Num++;
  33. }
  34. }
  35. EXTI_ClearITPendingBit(EXTI_Line15);
  36. }
复制代码

    中断函数内调用了 HW_jssj函数获取高电平时间,此函数代码如下:
  1. /****************************************************************
  2. * 函 数 名 : HW_jssj
  3. * 函数功能 : 高电平持续时间,将记录的时间保存在t中返回,其中一次大约20us
  4. * 输 入 : 无
  5. * 输 出 : t
  6. *****************************************************************/
  7. u8 HW_jssj()
  8. {
  9. u8 t=0;
  10. while(GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_15)==1)//高电平
  11. {
  12. t++;
  13. delay_us(20);
  14. if(t>=250) return t;//超时溢出
  15. }
  16. return t;
  17. }
复制代码

    通过此函数返回值就可以计算高电平时间,t 累加一次积累的时间为20us。中断函数内,将此函数返回值保存在变量 Tim 中,通过 Tim 值就可以判断是否进入引导码,如果是引导码,就可以接着判断接收的数据是1 还是 0,然后将数据进行按低位在前高位在后顺序保存在 hw_jsm 内,当接收完 32 位数据后将hw_jsbz 标志位置 1,并退出解码函数。这里要注意,判断是否为引导码、数据1 和 0时,我们不要硬性的固定在高电平区分时间上,而应该给它一个在固定值旁的范围判断,以防止因为干扰而导致误操作。引导码及数据 0 和 1 的高电平区分时间在前面介绍 NEC 码已经讲解了,不清楚的可以回过头看下。

主函数
    编写好外部中断初始化和红外解码函数后,接下来就可以编写主函数了,代码如下:
  1. /****************************************************************
  2. * 函 数 名 : main
  3. * 函数功能 : 主函数
  4. * 输 入 : 无
  5. * 输 出 : 无
  6. *****************************************************************/
  7. int main()
  8. {
  9. u8 i=0;
  10. SysTick_Init(72);
  11. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2 组
  12. LED_Init();
  13. USART1_Init(9600);
  14. Hwjs_Init();
  15. while(1)
  16. {
  17. if(hw_jsbz==1) //如果红外接收到
  18. {
  19. hw_jsbz=0; //清零
  20. printf("红外接收码 %0.8X\r\n",hw_jsm); //打印
  21. hw_jsm=0; //接收码清零
  22. }
  23. i++;
  24. if(i%20==0)
  25. {
  26. led1=!led1;
  27. }
  28. delay_ms(10);
  29. }
  30. }
复制代码

    主函数实现的功能很简单,首先调用之前编写好的硬件初始化函数,包括
SysTick系统时钟, 中断分组, LED初始化等。然后调用我们前面编写的Hwjs_Init函数初始化 PG15 外部中断功能,最后进入 while 循环,通过 hw_jsbz 标志判断是否解码成功,如果成功将解码后的数据 hw_jsm 打印输出,同时控制 D1 指示灯闪烁,提示系统正常运行。

实验现象
    将工程程序编译后下载到开发板内,可以看到 D1 指示灯不断闪烁,表示程序正常运行。当按下红外遥控器键时,串口将打印输出解码后的数据(地址码+地址反码+控制码+控制反码)。如果想在串口调试助手上看到输出信息,可以打开 “串口调试助手” , 首先勾选下标号1 DTR框,然后再取消勾选。这是因为此串口助手启动时会把系统复位住,通过 DTR状态切换下即可。然后设置好波特率等参数后,串口助手上即会收到串口发送过来的信息。(串口助手上先勾选下标号 1 DTR 框,然后再取消勾选)如下图所示:
微信图片_20220626182401.png

    我们配的遥控器所有键的地址码与反码都是相同的,不同的是控制码和控制反码,其实知道了控制码就知道了控制反码,所以如果要使用红外遥控控制其他设备,可以通过区分控制码来实现。

收藏 评论0 发布时间:2022-6-26 18:24

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版