红外遥控器
前言
使用外部中断和定时器计数实现红外遥控接受信号的解码,本文采用的是NEC编码
一、红外接收信号的波形图
一个完整的红外接收信号,由地址码、地址反码、命令码、命令反码组成
二、STM32CubeMX设置
定时器配置
注意:时钟的晶振非常重要,我使用的是外部8M晶振,经过锁相环翻倍成72M频率,再72分频,即最终是1M频率。
RCC配置如上
中断配置
中断设置成下降沿触发
三、程序
红外c文件
uint32_t receive_Code1;
uint32_t receive_Flag1;
void delay_us(uint16_t us)
{
uint16_t differ = 0xffff-us-5;
__HAL_TIM_SET_COUNTER(&htim2,differ); //设定TIM2计数器起始值
HAL_TIM_Base_Start(&htim2); //启动定时器
while(differ < 0xffff-5) //判断
{
differ = __HAL_TIM_GET_COUNTER(&htim2); //查询计数器的计数值
}
HAL_TIM_Base_Stop(&htim2);
}
uint8_t IR_HighLevelPeriod(void) //高电平持续时间函数
{
uint8_t t=0;
while(HAL_GPIO_ReadPin(EXTI_GPIO_Port,EXTI_Pin)==1) //高电平
{
t++;
delay_us(20);
if(t>=250) return t; //超时溢出
}
return t;
}
//在中断回调函数中完成红外解码
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) //红外遥控外部中断回调函数 时钟问题很重要 用8M外部晶振经过锁相环调整到72M外部晶振 再72分频
{
uint8_t Tim=0,Ok=0,Data,Num=0;
while(1)
{
if(HAL_GPIO_ReadPin(EXTI_GPIO_Port,EXTI_Pin)==1)
{
Tim = IR_HighLevelPeriod(); //获得此次高电平时间
if(Tim>=250)
break; //无用的信号
if(Tim>=200 && Tim<250)
Ok=1; //收到起始信号
else if(Tim>=60 && Tim<90)
Data=1; //收到数据1
else if(Tim>=10 && Tim<50)
Data=0; //收到数据0
if(Ok==1)
{
receive_Code1 <<= 1;
receive_Code1 += Data;
if(Num>=32) //总共32位 每一次都是Data的数据给 receive_Code1的最后一位,然后receive_Code1左移一位给Data的下一次留缓存空间
{
receive_Flag1=1;
break;
}
}
Num++;
}
}
}
红外h文件
#include "stm32f1xx_hal.h"
#ifndef __IR__H_
#define __IR__H_
extern uint32_t receive_Code1;
extern uint32_t receive_Flag1;
#endif
main.c文件
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
// if(IR_GetDataFlag() || IR_GetRepeatFlag()) //如果收到数据帧或者收到连发帧
// {
// Address=IR_GetAddress(); //获取遥控器地址码
// Command=IR_GetCommand(); //获取遥控器命令码
//
// OLED_ShowHexNum(2,1,Address,2); //显示遥控器地址码
// OLED_ShowHexNum(2,7,Command,2); //显示遥控器命令码
if(receive_Flag1 == 1)
{
receive_Flag1 = 0;
OLED_ShowHexNum(1, 1, receive_Code1, 6);
}
}
总结
需要注意的就是定时器的晶振频率