STM32红外遥控(HAL库源码)

以 NEC协议为例,采用PWM脉冲宽度调制,利用脉冲宽度来表示 0 和 1 。

协议数据包组成:
同步码头、地址码、地址反码、控制码、控制反码
同步码由一个 9ms 的低电平和一个 4.5ms 的高电平组成
地址码、地址反码、控制码、控制反码均是 8 位数据格式(发送时低位在前 高位在后)
用反码是为了增加传输的可靠性

每一帧的数据为8*4=32位数据

以利用脉冲宽度表达逻辑上的0与1

一个脉冲对应 560us 的连续载波
一个逻辑 1 传输需要 2.25ms(560us 脉冲+1680us 低电平)
一个逻辑 0 的传输需要 1.125ms(560us 脉冲+560us 低电平)
遥控接收头在收到脉冲的时候为低电平 常态下为高电平 所以
在接收头端收到的信号为:
逻辑 1 应该是 560us 低+1680us 高,
逻辑 0 应该是 560us 低+560us 高。

同步头为 9ms 低电平加上 4.5ms 高电平,控制码为 8 个 0,控制反码为 8 个 1。

stm32输入捕获功能,可以获取脉冲宽度长度以及频率,刚好可以应用在这里

具体原理:
当你设置的捕获开始的时候,cpu会将计数寄存器的值复制到捕获比较寄存器中并开始计数,当再次捕捉到电平变化时,这是计数寄存器中的值减去刚才复制的值就是这段电平的持续时间,你可以设置上升沿捕获、下降沿捕获、或者上升沿下降沿都捕获,
STM32红外遥控(HAL库源码)_第1张图片

红外信号解析实验

实验目的:利用定时器输入捕获将红外信号解析到单片机中,通过串口发送给上位机验证。
实验原理:用定时器输入捕获检查同步码是否到来,当检测到同步头,开始记录 32 个数据的时间值。
实验步骤:

定时器配置及程序编写如下

1 设置输入捕获滤波器
STM32在很多功能中都提供了滤波器,滤波器的功能简单来说就是多次检测视为一次有效,达到滤波效果,
数字滤波器由一个事件计数器组成,假设我们是检测高电平,滤波N次,那么记录到N个事件后计数器会产生一个输出的跳变。也就是说连续N次采样检测,如果都是高电平,则说明这是一个有效的电平信号,这样便可以过滤掉那些因为某些而干扰产生的一些信号
输入捕获滤波器IC1F[3:0],这个用于设置采样频率和数字滤波器长度。其中:fCK_INT是定时器的输入频率,fDTS是根据TIMx_CR1的CKD[1:0]的设置来确定的。

2 设置输入捕获极性
3 设置具体为那种捕获事件
可以设置上升沿捕获、下降沿捕获、或者上升沿下降沿都捕获

4 设置输入捕获映射关系
STM32为了更好的优化使用,TIMx_CH1通道1捕捉到的信号可以传输到IC1,TIMx_CH1捕捉到的信号也可以连接到IC2,TIMx_CH2捕捉到的信号也可以连接到IC2,也可以连接到IC2

5 设置输入捕获分频器
设置每N个事件触发一次捕获,可以设置为1/2/4/8次检测到电平变化才触发捕获

脉冲时间计算过程

STM32红外遥控(HAL库源码)_第2张图片
t1时刻检测到低电平,发生中断,在中断里将计数值置0,开始记溢出次数N,

其中每计数0xFFFF次溢出一次,直到t2时刻跳变回高电平,

获取最后一次溢出时到t2时刻的计数值TIM5CH1_CAPTURE_VAL

则 低电平时间 = 溢出次数*65535+TIM5CH1_CAPTURE_VAL us ;根据定时器初始化时的频率即可计算出溢出总次数所占用的时间,即为低电平时间。

如果计数器值为 32 bit 那么最大为0xFFFFFFFF

低电平时间:
T * 0XFFFFFFFF + TIM5CH1_CAPTURE_VAL

CUBEMX配置过程设置RCC

设置高速外部时钟HSE 选择外部时钟
设置时钟 72M
设置TIM1定时器 开启时钟 点开input Capture
预分频系数为71 计数时钟频率就是 72MHz/(71+1) = 1MHz 此时1us计数一次
自动加载值设置为32bit最大值 0xFFFFFFFF
设置下降沿捕获
设置输入捕获分频器 不分频
设置滤波值为8

将会使用到的函数:

//设置捕获极性
__HAL_TIM_SET_CAPTUREPOLARITY(&htim1, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);

//启动输入捕获   在修改定时器某一通道的输入捕获极性时,一定要先清除该通道之前捕获极性
HAL_TIM_IC_Start_IT(&htim5, TIM_CHANNEL_1);	

//获取当前的捕获值
HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);

//停止捕获
HAL_TIM_IC_Stop_IT(&htim5,TIM_CHANNEL_1); 

重要:对应引脚设置上拉电阻,保证没有信号输入的时候电平稳定,因为红外接头常态下为高电平

代码:


uint32_t capture_Buf[3] = {
     0}; 
uint8_t  capture_Cnt = 0;    
uint32_t low_time=0;   

 while (1)
  {
     
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  switch (capture_Cnt)
	  {
     
	  	case 0:
	  	{
     	capture_Cnt++;
	  		//HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
	  		__HAL_TIM_SET_CAPTUREPOLARITY(&htim1, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING);
	  		HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_1);	//启动输入捕获       或�??: __HAL_TIM_ENABLE(&htim1);
	  	}break;
	  	case 3:
	  	{
     
	  		low_time = capture_Buf[1]- capture_Buf[0];    //高电平时�?
	  		printf("lowtime:%d\r\n",(int)low_time);
	  		HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
	  		HAL_Delay(1000);   //延时1S
	  		capture_Cnt = 0;  //清空标志�?
	  	}break;

	 }



  }

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
     

	if(TIM1 == htim->Instance)
	{
     

		switch(capture_Cnt){
     

			case 1:{
     
				capture_Buf[0] = HAL_TIM_ReadCapturedValue(&htim1,TIM_CHANNEL_1);						//获取当前的捕获值.
				__HAL_TIM_SET_CAPTUREPOLARITY(&htim1,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);    //设置为上升沿捕获
				capture_Cnt++;
			}break;

			case 2:{
     
				capture_Buf[1] = HAL_TIM_ReadCapturedValue(&htim1,TIM_CHANNEL_1);						//获取当前的捕获值.
				HAL_TIM_IC_Stop_IT(&htim1,TIM_CHANNEL_1); 												//停止捕获   或者: __HAL_TIM_DISABLE(&htim5);
				capture_Cnt++;
			};

			               }

	}

你可能感兴趣的:(个人笔记,stm32)