AS32系列MCU芯片TIM模块的捕获和比较

一、引言

AS32系列MCU芯片集成4个高级定时器,每个定时器包含一个32位自动重载计数器,该计数器由可编程预分频器驱动,支持递增、递减、中心计数、编码器模式等计数方式。

高级定时器具有6个独立通道,可实现测量输入信号的脉冲宽度、可编程PWM输出、带死区插入的互补PWM等功能。

二、PWM简介

PWM,全称脉冲宽度调制。它是一种用数字信号来模拟模拟电压的技术。简单来说,就是快速地在"开"(高电平)和"关"(低电平)之间切换,通过改变一个周期内"开"的时间比例,来控制平均电压。

2.1 输出比较模式

定时器被配置为PWM模式时,会用到比较寄存器。

周期: 由自动重载寄存器决定。计数器从0计数到这个值,然后归零,这个过程就是一个PWM周期。

占空比: 由比较寄存器决定。它设定了电平翻转的阈值。

工作流程:

1.计数器从0开始向上计数。

2.当计数器的值 小于 比较寄存器的值时,输出高电平(例如)。

3.当计数器的值 达到或超过 比较寄存器的值时,输出翻转为低电平。

4.计数器到达自动重载值后归零,输出重新变为高电平,开始下一个周期。

通过修改比较寄存器 的值,就改变了高电平在一个周期内持续的时间,从而改变了占空比

输出比较可用于:

控制 LED 亮度: 占空比越大,LED越亮。

驱动舵机: 舵机的角度由PWM脉冲的宽度精确控制。

控制电机速度: 通过改变平均电压来调节直流电机转速。

音频输出: 通过极高频率的PWM,经过滤波后可以生成简单的音频信号。

2. 2 输入捕获

输入捕获功能就像一个"高速抓拍机"。当外部引脚上发生一个特定事件(如上升沿)时,它立刻"抓拍"下当前计数器的值,并保存起来。通过分析两次"抓拍"的值,我们就能计算出这个事件的时间参

定时器配置为输入捕获模式时,会用到捕获寄存器

工作流程:

1.定时器的计数器一直在自由运行。

2.当输入引脚上出现第一个上升沿 时,硬件会立即将计数器当前的值 复制到捕获寄存器中,并产生一个中断。

3.在中断服务程序里,程序读取这个捕获值(记为t1),并同时将捕获边沿设置为下降沿

4.当引脚出现下降沿时,硬件再次将计数器的当前值捕获(记为t2)。

5.程序计算 t2 - t1,这个差值就是高电平期间计数器计数的次数,再乘以计数周期,就得到了高电平脉冲的精确宽度。

6.同理,可以再捕获下一个上升沿,计算出整个信号的周期。

输入捕获可用于:

测量脉冲宽度和频率: 例如解码红外遥控信号(NEC协议)、测量超声波测距模块返回的脉冲宽度。

解码编码器信号: 读取旋转编码器的位置和速度。

测量数字信号的占空比。

三、软件设计

本文同时启用定时器HTIM1与HTIM5的通道1与通道2。其中,两个定时器的通道1均配置为PWM输出模式,以生成PWM信号;相应的通道2则工作在输入捕获模式,并采用中断驱动方式,以精确测量PWM信号的频率与占空比。最终,测量数据将通过串口打印输出。引脚连线如下:PD4->PH9, PC9->PD5

3.1软件分析

HTIM1初始化函数: void User_TIM1_Config(uint32_t arr, uint32_t psc, uint32_t rcr);

硬件使能与准备

复制代码
1.GPIOD_CLK_ENABLE();      // 使能GPIOD时钟  
2.HTIM1_CLK_ENABLE();      // 使能HTIM1时钟  

定时器时基配置

复制代码
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数

TIM_TimeBaseInitStructure.TIM_Period = arr; // 设定周期

TIM_TimeBaseInitStructure.TIM_Prescaler = psc; // 设定预分频

TIM_TimeBaseInitStructure.TIM_RepetitionCounter = rcr; // 重复计数

输入捕获配置(通道 2

  1. TIM_IC_InitStructure.TIM_Channel = TIM_Channel_2; // 使用通道2

  2. TIM_IC_InitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; // 上升沿捕获

  3. TIM_IC_InitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; // 直接输入

  4. TIM_IC_InitStructure.TIM_ICFilter = 0x0; // 无滤波器

  5. TIM_IC_InitStructure.TIM_ICPrescaler = 0x0; // 每个事件都捕获

中断与 PWM 输出配置

中断使能:

  1. TIM_IT_Update://定时器溢出更新中断

  2. TIM_IT_CC2://通道2捕获/比较中断

PWM 输出配置(通道 1 ):

  1. TIM_OC_InitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1

  2. TIM_OC_InitStructure.TIM_Pulse = arr/2; // 初始占空比50%

  3. TIM_OC_InitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 高电平有效

注:HTIM5配置除GPIO引脚外其余配置通HTIM1,此外HTIM5和HTIM1挂在不同总线下,读者使用时需自行计算外设时钟

在输入捕获模式下,当相应的 ICx 信号检测到跳变沿后,将使用捕获/比较寄存器(TIMx_CCRx)来锁存计数器的值。简单的说就是通过检测 TIMx_CHx 上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存(TIMx_CCRx)里面,完成一次捕获。

从上图可以看出,t1-t2 时间就是需要测量的高电平时间,假如定时器工作在向上计数模式,测量方法是:首先设置定时器通道 x 为上升沿捕获,这样在 t1 时刻,就会捕获到当前的 CNT 值,然后立即清零 CNT,并设置通道 x 为下降沿捕获,这样到 t2 时刻,又会发生捕获事件,得到此时的 CNT 值,记为 CCRx2。根据定时器的计数频率,就可以算出 t1-t2 的时间,从而得到高电平脉宽。在 t1-t2 时间内可能会出现 N 次定时器溢出,因此还需要对定时器溢出进行处理,防止因高电平时间过长发生溢出导致测量数据不准。CNT计数的次数等于:N*ARR+CCRx2,有了这个计数次数,再乘以 CNT 的计数周期,即可得到 t2-t1 的时间长度,即高电平持续时间。部分逻辑在中断函数中实现:

复制代码
void TIM1_IRQ_Handler()

{

static uint32_t TIM1_counter=0;

/* Get the value of TIM_CNT*/

if(TIM1_GetComplete==0)

{

if(TIM_GetITStatus(TIM1, TIM_IT_Update)!= RESET)

{

TIM1_Update_counter++;

TIM_ClearITPendingBit(TIM1, TIM_IT_Update);

}



if(TIM_GetITStatus(TIM1, TIM_IT_CC2)!= RESET)

{

TIM1_counter++;

if(TIM1_counter==1)

{

TIM1_Update_counter=0;

TIM1_Value1=TIM_GetCounter(TIM1);

}

if(TIM1_counter==2)

{

TIM1_Value2=TIM_GetCounter(TIM1);

TIM1_counter=0;

TIM1_GetComplete=1;

}

TIM_ClearITPendingBit(TIM1, TIM_IT_CC2);

}

}

else

{

TIM_ClearITPendingBit(TIM1, TIM_IT_Update | TIM_IT_CC2);

}

}

计算并输出PWM信号周期和频率的函数

复制代码
/* Calculate the input frequency and period */

TIM1_Input_Poriod=(10000*TIM1_Update_counter-TIM1_Value1+TIM1_Value2);

TIM1_Input_Poriod = TIM1_Input_Poriod/20;

Printf("TIM1 Input_Poriod: %d us\r\n", (uint32_t)TIM1_Input_Poriod);

Printf("TIM1 Frequence: %d hz\r\n", (uint32_t)(1000000/TIM1_Input_Poriod));

TIM1_Update_counter=0;

TIM1_GetComplete=0;

ClearCache();

其中第三行的20 为 HTIM1的时钟频率为20M。

四、开发板验证:

相关推荐
腾讯云开发者39 分钟前
共谈架构师 AI 进化论,腾讯云架构师技术沙龙圆满落幕
架构
C语言不精1 小时前
一种在 ESP32-S3 上取巧的清晰度检测方案
c语言·stm32·嵌入式硬件·学习
七宝大爷1 小时前
编码器-解码器架构:理解Transformer的两种基本模式
深度学习·架构·transformer
kk哥88991 小时前
高性能计算 FPGA 开发:Quartus Prime 18.0 下载安装教程 高带宽内存(HBM2)支持
fpga开发
j***49561 小时前
CentOS7安装Mysql5.7(ARM64架构)
adb·架构
DIY机器人工房1 小时前
简单理解:电源转换四大类型(AC/DC、DC/AC、DC/DC、boost、buck、LDO、AC/AC之间分别是什么关系?)
嵌入式硬件·boost·bms·buck·ldo·diy机器人工房·电源转换
nvd111 小时前
Agent架构升级:解决Gemini超大Prompt处理问题
架构·prompt
稚辉君.MCA_P8_Java1 小时前
DeepSeek Java 多线程打印的12种实现方法
java·linux·后端·架构·maven
JienDa2 小时前
JienDa聊PHP:电商系统实战架构深度解析与优化策略
开发语言·架构·php