华大单片机HC32L136定时器时间如何计算
介绍定时器是现代单片机的标配,顾名思义它的最基本作用就是定时。华大单片机HC32L136这颗芯片中包含了多个可以用来实现定时功能的外设,分别是通用定时器(TIM0/1/2/3)、低功耗定时器(LPTIM)、可编程计数阵列(PCA)、高级定时器(TIM4/5/6)、实时时钟(RTC)、看门狗定时器(WDT)和时钟校准模块(CLKTRIM)。由上可知HC32L136实现定时功能是非常灵活的,工程师们可以根据自己的项目实际使用到的模块而决定采用哪种方式来定时。下面先讲解下最最基本的定时方式–通用定时器(TIM0/1/2/3)模式0的定时功能。
定时器的时钟
使用 PCLK 做为 Timer 定时器时钟时,可以使用预分频。预分频设置如下:
预分频器没有预装载缓存,因此对预分频进行更改,预分频将会立刻生效。
模式 0 计数定时器功能
定时功能用于产生间隔定时。在定时功能中,定时器有预除频,定时器在每个预除频的一个时钟累加一次,计数到最大值会溢出并且产生中断。中断标志需要软件清除。这种模式下,计数器向上计数。计数器支持两种计数模式,16位重载模式与32位自由计数模式,计数到最大值溢出产生中断。16位重载模式计数范围从 ARR 向上计数到 0xFFFF 溢出,然后从 ARR 再开始计数,计数周期为 0Xffff-ARR+1,16位重载模式的框图与波形如下图所示:
32位自由计数模式从设置计数值计数到 0xFFFFFFFF 后溢出,溢出后计数值从 0x0 重新开始计数。其框图与波形如下图所示:
门控功能
定时器可用通过外部门控功能控制定时器是否计数。控制关系如下
与定时器0模式0有关的寄存器及相应位
定时器时间计算
毋庸置疑使用定时器功能都是希望实现定时功能。这个定时定多长时间是由用户自己来设定的。现在就介绍下如何来设定定时值。
其实定时器是个很简单的外设模块。它的原理就是每执行一个定时器的机器周期,定时器的计数值TIMx_CNT和TIMx_CNT32就会加1,直到加到定时器计数器最大值(16位模式时为0XFFFF,32位模式时为0XFFFFFFFF),之后再执行一个定时器周期则定时器计数值会溢出,溢出时会产生举出中断标志位TIMx_IFR寄存器中的UIF置1。如果设置为重载模式,定时器溢出后会把TIMx_ARR值装入TIMx_CNT寄存器,继续计数。如果是32位计数模式,溢出后TIMx_CNT和TIMx_CNT32的值都会变为0,继续进行计数。
下面以16位重载计数模式来说明,具体如何计算,32位自由计数模式原理一样,大家可以自行理解 。
定时器的机器频率就是通过TIMx_M0CR寄存器中PRS的设定完成对PCLK时钟的分频。假如系统时钟为4M(系统上电时候默认的时钟),HCLK和PCLK的分频系数为1,则PCLK的时钟频率同样为4M。TIMx_M0CR中的PRS设置为111,即对PCLK进行256分频,此种设置情况下定时器的频率为 4M / 256 = 15625 Hz,定时器计数器执行一个加1周期的需要的时间为 1 / 15625 = 0.000064秒。如果定时器想要实现0.6秒的定时需要执行的周期数为 0.6/ 0.000064 = 9375。是不是直接把9375写到TIMx_CNT和TIMx_ARR的寄存器中就可以了实现定时0.6秒呢?当然不是。因为定时器是加到溢出才会产生中断,所以写入到寄存器中的值应该是溢出的值减出我们计算出来的值(0X10000 - 9375)。
计算的原理就是这些,大家写程序的时候也可以根据自己的使用习惯进行相关数据的封装。
配置流程重载定时器设置
[*]设置定时器模式 M0CR.MODE=0
[*]设置装载值 ARR
[*]设置计数器初值 CNT
[*]清除中断标志
[*]使能中断 M0CR.UIE=1
[*]使能重载模式 M0CR.MD=1
[*]开启定时器 M0CR.CTEN=1
定时器0配置初始化代码
void App_Timer0Cfg(uint16_t u16Period)
{
uint16_t u16ArrValue;
uint16_t u16CntValue;
stc_bt_mode0_cfg_t stcBtBaseCfg;
DDL_ZERO_STRUCT(stcBtBaseCfg);
Sysctrl_SetPeripheralGate(SysctrlPeripheralBaseTim, TRUE); //Base Timer外设时钟使能
stcBtBaseCfg.enWorkMode = BtWorkMode0; //定时器模式
stcBtBaseCfg.enCT = BtTimer; //定时器功能,计数时钟为内部PCLK
stcBtBaseCfg.enPRS = BtPCLKDiv256; //PCLK/256
stcBtBaseCfg.enCntMode= Bt16bitArrMode; //自动重载16位计数器/定时器
stcBtBaseCfg.bEnTog = FALSE; //禁止翻转输出
stcBtBaseCfg.bEnGate = FALSE; //不使能门控
stcBtBaseCfg.enGateP = BtGatePositive;
Bt_Mode0_Init(TIM0, &stcBtBaseCfg); //TIM0 的模式0功能初始化
u16ArrValue = 0x10000 - u16Period;
Bt_M0_ARRSet(TIM0, u16ArrValue); //设置重载值(ARR = 0x10000 - 周期)
u16CntValue = 0x10000 - u16Period;
Bt_M0_Cnt16Set(TIM0, u16CntValue); //设置计数初值
Bt_ClearIntFlag(TIM0,BtUevIrq); //清中断标志
Bt_Mode0_EnableIrq(TIM0); //使能TIM0中断(模式0时只有一个中断)
EnableNvic(TIM0_IRQn, IrqLevel3, TRUE); //TIM0中断使能
}
定时器0中断服务函数
void Tim0_IRQHandler(void)
{
//Timer0 模式0 溢出中断
if(TRUE == Bt_GetIntFlag(TIM0, BtUevIrq))
{
//............
//用户程序
//............
Bt_ClearIntFlag(TIM0,BtUevIrq); //中断标志清零
}
}
主程序中调用调用定时器0并运行
App_Timer0Cfg(9375); //Timer0配置初始化(周期 = 9375*(1/4M)*256 = 0.6s)
//上电后系统初始时钟为4M
Bt_M0_Run(TIM0); //TIM0 运行。
简便计算
需要计数个数 = 目标时间 * 系统时钟 / HCLK分频 / PCLK分频 / 定时器分频
写入的CNT值 = 定时器溢出时间 - 需要计数个数
谢谢分享 有没有一个计算频率的工具呢
页:
[1]