视频展示效果
红外解码视频演示
一、环境介绍
硬件设备:STM32F103C8T6、红外模块
软件环境:STM32CubeIDE
二、红外接收波形监测分析(重点)
我这里使用逻辑分析仪分析接收到的红外波形,截取了几种关键波形作分析
下图是我长按红外遥控按键“1”数秒后松手产生的波形
下图是起始信号波形(9ms的低电平,4ms的高电平,总共13ms)
下图是数据帧中的“0”信号(640us的低电平,500us的高电平,总共1.14ms)
下图是数据帧中的“1”信号(640us的低电平,1.6ms的高电平,总共2.25ms)
下图是结束信号(640us的脉冲)
下图是重复信号(9ms的低电平,2ms的高电平,总共11ms)
三、硬件资源分析
1.硬件资源与IO使用情况
接收红外信号:PB11,外部中断脚
串口2发送数据:PA2,PA3,串口收发脚
定时器:使用基础计时功能,任意一个即可(我这里使用TIM1)
2.实物连接
3.图形化配置初始化
- 时钟引脚配置(HSE和LSE均配置为无源晶振,LSE不配也行,这里没用到)
- 教大家一个方法判断板子上的晶振是有源晶振还是无源晶振,直接看他的原理图,如果晶振两端有接起振电容就是无源晶振,没有接就是有源晶振
- IO配置(LED参数默认,外部中断脚上拉,下降沿触发)
- 串口配置(异步通讯,其他参数默认)
- 定时器配置(时钟源选择内部时钟,预分频系数为72-1,因为时钟会配置为72M,这样计数值加1就是1us,默认向上计数,重载值65535)
- 时钟树配置(系统时钟72M)
四、基础功能调试
1.LED点灯,看看工程能不能跑,板子是否正常工作
可在用户代码区2给LED写入低电平(我这块板子低电平点亮)。
2.EXIT外部中断验证
代码可以像我这样写,验证可以用杜邦线一端接上PB11,另一端去碰GND,不灵敏是正常的,有反应即可。
3.串口发送验证
串口可以直接移植我封装好的模块,也可以自己写,在while(1)里能输出信息即可。
4.TIM计时是否准确
我这里使用官方的HAL_Delay()函数进行粗测。
提醒HAL_Delay()函数是ms级的,不适合做us的延时,而且这个函数延时会多1ms,传参要减一。
代码验证可以参考我的代码,串口发送看下来挺准的。
五、解码程序编写(重点)
先贴代码
- tim.c
/*
* tim.c
*
* Created on: 2024年4月11日
* Author: 废话文学创始人
*/
#include <tim.h>
//设置计数值
void set_tim1_cnt(uint32_t cnt)
{
htim1.Instance->CNT = cnt;
}
//清空计数值
void clear_tim1_cnt()
{
set_tim1_cnt(0);
}
//获得计数值
uint32_t get_tim1_cnt()
{
return htim1.Instance->CNT;
}
//定时器1开始计时
void count_time_start()
{
clear_tim1_cnt();
HAL_TIM_Base_Start(&htim1);
}
//定时器1停止计时
void count_time_stop()
{
HAL_TIM_Base_Stop(&htim1);
clear_tim1_cnt();
}
- tim.h
/*
* tim.h
*
* Created on: 2024年4月11日
* Author: 废话文学创始人
*/
#ifndef INC_TIM_H_
#define INC_TIM_H_
#include <stm32f1xx_hal.h>
#include <stm32f1xx_hal_tim.h>
extern TIM_HandleTypeDef htim1;
void set_tim1_cnt(uint32_t cnt);
void clear_tim1_cnt();
uint32_t get_tim1_cnt();
void count_time_start();
void count_time_stop();
#endif /* INC_TIM_H_ */
- it.c中一些相关变量和宏的定义
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define wait 0
#define start 1
#define data_rx 2
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
uint8_t state = 0;
uint8_t signal_repeat = 0;
uint8_t signal_data_rx_over = 0;
uint32_t count = 0;
uint8_t pdata = 0;
uint8_t ir_receive[4];
/* USER CODE END PV */
- 外部中断回调函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
//判断外部中断源是否为GPIO_PIN_11
if(GPIO_Pin == GPIO_PIN_11){
switch(state){
case wait://空闲状态
state = start;
//检测到下降沿开始计时
count_time_start();
break;
case start://起始信号和重复信息阶段
//读取间隔时间
count = get_tim1_cnt();
//停止计数
count_time_stop();
//判断是起始信号还是重复信号
if(count >= 13500 - 500 && count <= 13500 + 500){
//进入数据接收阶段
state = data_rx;
//为数据阶段计时
count_time_start();
}
else if(count >= 11250 - 500 && count <= 11250 + 500){
//反馈重复信号,重回空闲状态
signal_repeat = 1;
state = wait;
}
else state = wait;
break;
case data_rx://数据处理阶段
//读取间隔时间
count = get_tim1_cnt();
//停止计数
count_time_stop();
//数据处理
if((count >= 1140 - 500 && count <= 1140 + 500)){
//向pdata位写入0
ir_receive[pdata/8] &= ~(1 <<(pdata%8));
}
else if((count >= 2250 - 500 && count <= 2250 + 500)){
//向pdata位写入1
ir_receive[pdata/8] |= (1 <<(pdata%8));
}
//pdata位移向下一位
pdata++;
//继续接收下一位byte数据
state = data_rx;
//数据帧处理结束
if(pdata == 32){
//重置pdata为0
pdata = 0;
//利用数据协议的反码数据校验数据准确性
if((ir_receive[0]=~ir_receive[2])&&(ir_receive[1]=~ir_receive[3])){
//反馈数据处理完成信号
signal_data_rx_over = 1;
}
//重回空闲状态
state = wait;
}
//数据帧未结束,为下次下降沿计时
else count_time_start();
break;
}
}
}
- main函数
while (1)
{
//对数据接收完成信号进行处理
if(signal_data_rx_over == 1){
//发送地址码和命令码
Uart_Send_String(" address:%2x, command:%2x\n",ir_receive[0],ir_receive[2]);
//发送地址码和命令码的反码
Uart_Send_String("~address:%2x,~command:%2x\n",ir_receive[1],ir_receive[3]);
//标志清零
signal_data_rx_over = 0;
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
思路讲解:
对TIM的基本计时功能进行函数封装,可让代码思路更清晰。(前提是你函数命名没有偷懒)
解码部分参考了别人的状态机解码思路,将长时间的高电平时间段设为空闲阶段,将起始信号和重复信号时间段设为开始阶段,将数据帧信号时间端设为数据接收处理阶段。通过下降沿触发中断实现3种状态之间的迁移。
各个信号的下降沿间隔时间有明显区别,利用此特性,计时两次下降沿之间的时间,去判断是何种信号。
数据接收完进行数据校验,具体校验原理是因为他发的数据格式就是地址码-地址码反码-命令码-命令码反码。