STM32 CubeMX HAL库 之红外接收(NEC协议)定时器捕获
程序员文章站
2022-06-08 19:06:24
...
第一次自己写完整的硬件驱动,发上来给大家看看,顺便吸收些改进方案,希望各位能够不吝赐教,指出代码的不足之处。同时我也很高兴这代码能给你带来帮助。
工程使用CubeMX创建,使用VS Code编程,单片机为STM32F103VCT6。
首先配置时钟,下载方式,开启USART以方便调试,这里就不具体展示了。开启某个定时器的输入捕获【Input Capture direct mode】预分频系数设为(72-1),开启捕获中断【TIM1 capture compare interrupt】优先级最好高一些(默认为0),其他设置默认。
这里以定时器1的通道一为例:将红外接收模块的输出端接入PA8即可,由于STM32F103VCT6的最高主频为72MHz故预分频系数设为(72-1),这样可以使计数每1μs加一,方便计算时间,开启捕获中断:
生成代码。将IR.c及IR.h文件添加到工程中(这两个文件将会放在在文章的下面,有较全的注释)
在相应位置修改main.c:
/* USER CODE BEGIN Includes */
#include "IR.h"
/* USER CODE END Includes */
/* USER CODE BEGIN PV */
uint32_t temp = 0;//用于接收数据
/* USER CODE END PV */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if (IR_Scanf(&temp))
{
printf("%X\r\n", temp);//这里需要重定向至串口后使用
}
}
/* USER CODE END 3 */
/* USER CODE BEGIN 4 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//捕获回调函数
{
if (TIM1 == htim->Instance)
{
IR_CaptureCallback();
}
}
/* USER CODE END 4 */
修改完成后即可编译下载。打开串口助手就可以看到遥控器发来的信息了。
基本上换个遥控器只需修改IR.h文件的内容就可以了,包括使用的定时器及其通道、各种逻辑的持续时间(我这个遥控器就不完全是NEC编码所以会有些不同,还请自己测试后修改)、是否检查编码正确性等可以方便修改的地方。
下面就是所需要的文件:
IR.c:
//csdn_可谓不低
#include "IR.h"
#include "main.h"
#include "tim.h"
#define CHECK_TIME_LOGIC_0() (CaptureBuf >= IR_us_LOGIC_0 - IR_DEVIATION && CaptureBuf <= IR_us_LOGIC_0 + IR_DEVIATION)
#define CHECK_TIME_LOGIC_1() (CaptureBuf >= IR_us_LOGIC_1 - IR_DEVIATION && CaptureBuf <= IR_us_LOGIC_1 + IR_DEVIATION)
#define CHECK_TIME_START() (CaptureBuf >= IR_us_START - IR_DEVIATION && CaptureBuf <= IR_us_START + IR_DEVIATION)
#define CHECK_TIME_REPEAT_START() (CaptureBuf >= IR_us_REPEAT_START - IR_DEVIATION && CaptureBuf <= IR_us_REPEAT_START + IR_DEVIATION)
#define CHECK_TIME_REPEAT_END() (CaptureBuf >= IR_us_REPEAT_END - IR_DEVIATION && CaptureBuf <= IR_us_REPEAT_END + IR_DEVIATION)
uint16_t CaptureBuf = 0; //存放捕获缓存
uint8_t CaptureFlag = 1; //捕获标志位
uint8_t IRData[4] = {0};//存放数据
uint8_t IRFlag = 0;//红外接收状态
uint8_t IRReceiveFlag = 0;//完成接收标志
void IR_Init()
{
__HAL_TIM_SET_CAPTUREPOLARITY(&IR_TIM, IR_TIM_CHANNE, TIM_INPUTCHANNELPOLARITY_RISING); //改为上升沿
HAL_TIM_IC_Start_IT(&IR_TIM, IR_TIM_CHANNE); //启动输入捕获
}
void IR_CaptureCallback()
{
if (CaptureFlag)
{
__HAL_TIM_SET_COUNTER(&IR_TIM, 0);
__HAL_TIM_SET_CAPTUREPOLARITY(&IR_TIM, IR_TIM_CHANNE, TIM_ICPOLARITY_FALLING); //设置为下降沿捕获
CaptureFlag = 0; //状态标志位置0
}
else
{
CaptureBuf = HAL_TIM_ReadCapturedValue(&IR_TIM, IR_TIM_CHANNE); //获取当前的捕获值.
__HAL_TIM_SET_CAPTUREPOLARITY(&IR_TIM, IR_TIM_CHANNE, TIM_INPUTCHANNELPOLARITY_RISING); //改为上升沿
CaptureFlag = 1; //状态标志位置1
if (CHECK_TIME_START()) //接收到数据开始位
{
IRFlag = 1;
for (uint8_t i = 0; i < 4; i++)
{
IRData[i] = 0;//清空数据
}
return; //退出,等待接收数据
}
else if (CHECK_TIME_REPEAT_START()) //接收到循环开始位
{
IRFlag = 40; //重复码标记
return; //退出,等待循环第二位
}
if (IRFlag && IRFlag <= 32)//接收数据
{
if (CHECK_TIME_LOGIC_1()) //判断为逻辑1
{
IRData[(IRFlag - 1) / 8] |= (1 << (7 - (IRFlag - 1) % 8));
}
else if (!CHECK_TIME_LOGIC_0()) //判断不是逻辑0
{
IRFlag = 0; //直接退出接收
return;
}
IRFlag++;
if (IRFlag == 33)//接收32个,接收完成
{
if(IR_CHECK_ADDRESS && IRData[0] != (uint8_t)~IRData[1] || IR_CHECK_COMMAND && IRData[2] != (uint8_t)~IRData[3])//校验
{
return;
}
IRReceiveFlag = 1;
return;
}
}
if (IRFlag == 40)
{
if (CHECK_TIME_REPEAT_END())
{
IRReceiveFlag = IR_CHECK_REPEAT;
}
}
}
}
uint8_t IR_Scanf(uint32_t* data)
{
if(IRReceiveFlag)IRReceiveFlag=0;
else return 0;
*data=0;
for(uint8_t i=0;i<4;i++)
{
*data|=IRData[i]<<8*(3-i);
}
return 1;
}
IR.h:
//csdn_可谓不低
#ifndef __IR_H
#define __IR_H
#include "main.h"
#define IR_TIM htim1
#define IR_TIM_CHANNE TIM_CHANNEL_1
#define IR_us_LOGIC_0 560
#define IR_us_LOGIC_1 1640
#define IR_us_START 4480
#define IR_us_REPEAT_START 39350
#define IR_us_REPEAT_END 2220
#define IR_DEVIATION 100 //误差范围
#define IR_CHECK_ADDRESS 1 //1:检查地址位 0:取消
#define IR_CHECK_COMMAND 1 //1:检查数据位 0:取消
#define IR_CHECK_REPEAT 1 //1:检查重复 0:取消
void IR_Init(void);
void IR_CaptureCallback(void);
uint8_t IR_Scanf(uint32_t* data);
#endif
/***************************************
* 1 00FFA25D
* 2 00FF629D
* 3 00FFE21D
* 4 00FF22DD
* 5 00FF02FD
* 6 00FFC23D
* 7 00FFE01F
* 8 00FFA857
* 9 00FF906F
* * 00FF6897
* 0 00FF9867
* # 00FFB04F
* up 00FF18E7
* left 00FF10EF
* OK 00FF38C7
* right 00FF5AA5
* down 00FF4AB5
*****************************************/
/****************************************
* 放入捕获中断回调函数中使用,按需修改TIM1
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (TIM1 == htim->Instance)
{
IR_CaptureCallback();
}
}
******************************************/