STM32 CubeMX HAL库 之红外接收(NEC协议)定时器捕获

第一次自己写完整的硬件驱动,发上来给大家看看,顺便吸收些改进方案,希望各位能够不吝赐教,指出代码的不足之处。同时我也很高兴这代码能给你带来帮助。
工程使用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();
	}
}
******************************************/

  • 13
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值