摩登3测试路线_最全!华大HC32F460定时器介绍


出品
 21ic论坛  binoo7


网站:bbs.21ic.com



这次和大家一起分享一下华大HC32F460的定时器。
首先说一下定时器的分类,一共有四种定时器分别是:

  • 高级控制定时器(Timer6)有3个;
  • 通用控制定时器(Timer4)有3个;
  • 通用定时器(TimerA)有6个;
  • 通用定时器(Timer0)有2个;




再次说一下这几个定时器有什么区别:
看名字就知道高级控制定时器肯定是功能最全的

  • 高级控制定时器 6(Timer6)是一个 16 位计数宽度的高性能定时器,可用于计数产生




不同形式的时钟波形,输出以供外部使用。

  • 该定时器支持三角波和锯齿波两种波形模式,可生成各种 PWM 波形;
  • 单元间可实现软件同步计数和硬件同步计数;
  • 各基准值寄存器支持缓存功能;
  • 支持 2 相正交编码和 3 相正交编码;
  • 支持 EMB 控制。


主要看一下基本框图




看框图能看,Timer6 的计数时钟可以有以下几种选择:
a) PCLK0 及 PCLK0 的 4、16、64、256、1024 分频(GCONR.CKDIV[2:0]设定)
b) 内部触发事件触发输入(HCUPR[17:16]或 HCDOR[17:16]设定)
c) TIM6_TRIGA-B 的端口输入(HCUPR[11:8]或 HCDOR[11:8]设定)
d) TIM6_ _PWMA 和 TIM6_ _PWMB 的 正交编码 输入( HCUPR[7:0] 或HCDOR[7:0]设定)
计数时钟源选择 a 时为软件计数模式,计数时钟源选择 b、c、d 时为硬件计数模式。
上述描述可以看到,b、c、d 时钟互相独立,可分别设定有效或无效,并且当选择 b、c、d 时钟时,a 时钟自动无效。
定时器6的时钟不能按照任意的分频系数进行分频,只能按照特定的频率进行分频,实话实说这一点就不如STM32方便了


计数方式有两种,一个是锯齿波,一个是三角波,两种波形的方式进行计数,当达到设定值后会清零或向下计数

自动重装载值这里叫做通用周期基准值寄存器,官方给的解释是设定每轮计数的计数周期值及对应缓存值 ,说实话这个官方的解释我看了一天也没搞懂是啥意思,很容易和STM32的周期计数混淆,大家要多注意了。


看寄存器的配置就能知道这是一个16位的定时器。

定时器可以产生的中断中官方给的解释如下:

  • 通用比较基准值寄存器(GCMAR-GCMFR)共计 6 个,可分别与计数值比较产生比较匹配。
  • 计数比较匹配时,状态标志寄存器(STFLR)中的 STFLR.CMAF~STFLR.CMFF位分别会被置为 1。
  • 此时若设定中断控制寄存器(ICONR)的 INTENA~INTENF 中相应位为 1 使能中断,则对应的中断请(TMR6_U _GCMA~F)也会被触发。
  • 在硬件捕获事件选择寄存器(HCPAR、HCPBR)选择的捕获输入有效条件产生时,捕获输入动作发生。
  • 此时若设置中断控制寄存器(ICONR)的 INTENA 或 INTENB 位为1 使能中断,则对应的中断请求(TMR6_U _GCMA~B)被触发。
  • 2 个专用比较基准值寄存器(SCMAR-SCMBR)也可分别与计数值比较产生比较匹配。
  • 计数比较匹配时,状态标志寄存器(STFLR)中的 STFLR.CMSPAF~CMSPBF 位分别会被置为 1。此时若设定中断控制寄存器(ICONR)的 INTENSAU 或 INTENSBU 中相应位为 1 使能中断,则对应的中断请求(TMR6_U _SCMA~B)也会被触发。


看上面的解释可能会云里雾里看不懂啥意思,还不如直接看中断控制寄存器,有多少中断都在中断控制器里写的明明白白,这样的话我们就能很容易的来根据需要配置中断的功能了,具体配置如下图所示



这里面比较值的设置就是根据两个比较基准寄存器的值来进行判断的,这两个寄存器分别是通用比较基准值寄存器,专用比较基准寄存器,其实还有一个是死区时间基准值寄存器




下面直接看代码,看看高级控制定时器的用法




官方给的例程挺多的,有耐心的小伙伴可以仔细分析一下MCU的TIMER6的PWM的锯齿波模式、无缓存输出功能,
看看比较输出的功能是怎么配置的



/******************************************************************************** Include files******************************************************************************/#include "hc32_ddl.h"
/******************************************************************************** Local type definitions ('typedef')******************************************************************************/
/******************************************************************************** Local pre-processor symbols/macros ('#define')******************************************************************************//* KEY0 (SW2)*/#define SW2_PORT (PortD)#define SW2_PIN (Pin03)/* KEY1 (SW4)*/#define SW4_PORT (PortD)#define SW4_PIN (Pin04)/* KEY2 (SW3)*/#define SW3_PORT (PortD)#define SW3_PIN (Pin05)/* KEY3 (SW5)*/#define SW5_PORT (PortD)#define SW5_PIN (Pin06)
/* LED0 Port/Pin definition */#define LED0_PORT (PortE)#define LED0_PIN (Pin06)
/* LED1 Port/Pin definition */#define LED1_PORT (PortD)#define LED1_PIN (Pin07)
/* LED2 Port/Pin definition */#define LED2_PORT (PortB)#define LED2_PIN (Pin05)
/* LED3 Port/Pin definition */#define LED3_PORT (PortB)#define LED3_PIN (Pin09)
/* LED0~1 toggle definition */#define LED0_TOGGLE() (PORT_Toggle(LED0_PORT, LED0_PIN))#define LED1_TOGGLE() (PORT_Toggle(LED1_PORT, LED1_PIN))#define LED2_TOGGLE() (PORT_Toggle(LED2_PORT, LED2_PIN))#define LED3_TOGGLE() (PORT_Toggle(LED3_PORT, LED3_PIN))
/******************************************************************************** Global variable definitions (declared in header file with 'extern')******************************************************************************/
/******************************************************************************** Local function prototypes ('static')******************************************************************************/
/******************************************************************************** Local variable definitions ('static')******************************************************************************/

/******************************************************************************** Function implementation - global ('extern') and local ('static')******************************************************************************//*********************************************************************************** \brief Callback function of external interrupt ch.0********************************************************************************/
void Timer6_OverFlow_CallBack(void){
}
/********************************************************************************** \brief Initialize the system clock for the sample**** \param None**** \return None******************************************************************************/static void SysClkIni(void){ en_clk_sys_source_t enSysClkSrc; stc_clk_sysclk_cfg_t stcSysClkCfg; stc_clk_mpll_cfg_t stcMpllCfg; stc_clk_output_cfg_t stcOutputClkCfg;

MEM_ZERO_STRUCT(enSysClkSrc); MEM_ZERO_STRUCT(stcSysClkCfg); MEM_ZERO_STRUCT(stcMpllCfg); MEM_ZERO_STRUCT(stcOutputClkCfg);
/* Set bus clk div. */ stcSysClkCfg.enHclkDiv = ClkSysclkDiv1; // 168MHz stcSysClkCfg.enExclkDiv = ClkSysclkDiv2; // 84MHz
stcSysClkCfg.enPclk0Div = ClkSysclkDiv1; // 168MHz (timer6 cnt) stcSysClkCfg.enPclk1Div = ClkSysclkDiv2; // 84MHz (timer6 logic) stcSysClkCfg.enPclk2Div = ClkSysclkDiv4; // 42MHz stcSysClkCfg.enPclk3Div = ClkSysclkDiv4; // 42MHz stcSysClkCfg.enPclk4Div = ClkSysclkDiv2; // 84MHz CLK_SysClkConfig(&stcSysClkCfg);
CLK_HrcCmd(Enable); //Enable HRC
/* MPLL config. */ stcMpllCfg.pllmDiv = 2ul; //HRC 16M / 2 stcMpllCfg.plln = 42ul; //8M*42 = 336M stcMpllCfg.PllpDiv = 2ul; //MLLP = 168M stcMpllCfg.PllqDiv = 2ul; //MLLQ = 168M stcMpllCfg.PllrDiv = 2ul; //MLLR = 168M CLK_SetPllSource(ClkPllSrcHRC); CLK_MpllConfig(&stcMpllCfg);
/* flash read wait cycle setting */ EFM_Unlock(); EFM_SetLatency(EFM_LATENCY_4); EFM_Lock();
/* Enable MPLL. */ CLK_MpllCmd(Enable);
/* Wait MPLL ready. */ while(Set != CLK_GetFlagStatus(ClkFlagMPLLRdy)) { ; }
/* Switch system clock source to MPLL. */ CLK_SetSysClkSource(CLKSysSrcMPLL);}
/*********************************************************************************** \brief Main function of project**** \param None**** \retval int32_t return value, if needed********************************************************************************/int32_t main(void){ uint16_t u16Period; uint16_t u16Compare; stc_timer6_basecnt_cfg_t stcTIM6BaseCntCfg; stc_timer6_port_output_cfg_t stcTIM6PWMxCfg; stc_timer6_gcmp_buf_cfg_t stcGCMPBufCfg; stc_port_init_t stcPortInit; stc_irq_regi_conf_t stcIrqRegiConf;
MEM_ZERO_STRUCT(stcTIM6BaseCntCfg); MEM_ZERO_STRUCT(stcTIM6PWMxCfg); MEM_ZERO_STRUCT(stcGCMPBufCfg); MEM_ZERO_STRUCT(stcPortInit); MEM_ZERO_STRUCT(stcIrqRegiConf);
SysClkIni();
PWC_Fcg2PeriphClockCmd(PWC_FCG2_PERIPH_TIM61, Enable);
PORT_SetFunc(PortE, Pin09, Func_Tim6, Disable); //Timer61 PWMA PORT_SetFunc(PortE, Pin08, Func_Tim6, Disable); //Timer61 PWMB
stcTIM6BaseCntCfg.enCntMode = Timer6CntSawtoothMode; //Sawtooth wave mode stcTIM6BaseCntCfg.enCntDir = Timer6CntDirUp; //Counter counting up stcTIM6BaseCntCfg.enCntClkDiv = Timer6PclkDiv1; //Count clock: pclk0 Timer6_Init(M4_TMR61, &stcTIM6BaseCntCfg); //timer6 PWM frequency, count mode and clk config
u16Period = 33600u; Timer6_SetPeriod(M4_TMR61, Timer6PeriodA, u16Period); //period set
u16Compare = 10000u; Timer6_SetGeneralCmpValue(M4_TMR61, Timer6GenCompareA, u16Compare); //Set General Compare RegisterA Value
u16Compare = 20000u; Timer6_SetGeneralCmpValue(M4_TMR61, Timer6GenCompareB, u16Compare); //Set General Compare RegisterB Value
stcTIM6PWMxCfg.enPortMode = Timer6ModeCompareOutput; //Compare output function stcTIM6PWMxCfg.bOutEn = true; //Output enable stcTIM6PWMxCfg.enPerc = Timer6PWMxCompareLow; //PWMA port output Low level when CNTER value match PERAR stcTIM6PWMxCfg.enCmpc = Timer6PWMxCompareHigh; //PWMA port output High level when CNTER value match with GCMAR stcTIM6PWMxCfg.enStaStp = Timer6PWMxStateSelSS; //PWMA output status is decide by STACA STPCA when CNTER start and stop stcTIM6PWMxCfg.enStaOut = Timer6PWMxPortOutLow; //PWMA port output set low level when CNTER start stcTIM6PWMxCfg.enStpOut = Timer6PWMxPortOutLow; //PWMA port output set low level when CNTER stop stcTIM6PWMxCfg.enDisVal = Timer6PWMxDisValLow; Timer6_PortOutputConfig(M4_TMR61, Timer6PWMA, &stcTIM6PWMxCfg);
stcTIM6PWMxCfg.enPortMode = Timer6ModeCompareOutput; //Compare output function stcTIM6PWMxCfg.bOutEn = true; //Output enable stcTIM6PWMxCfg.enPerc = Timer6PWMxCompareLow; //PWMB port output Low level when CNTER value match PERAR stcTIM6PWMxCfg.enCmpc = Timer6PWMxCompareHigh; //PWMB port output High level when CNTER value match with GCMBR stcTIM6PWMxCfg.enStaStp = Timer6PWMxStateSelSS; //PWMB output status is decide by STACB STPCB when CNTER start and stop stcTIM6PWMxCfg.enStaOut = Timer6PWMxPortOutLow; //PWMB port output set low level when CNTER start stcTIM6PWMxCfg.enStpOut = Timer6PWMxPortOutLow; //PWMB port output set low level when CNTER stop stcTIM6PWMxCfg.enDisVal = Timer6PWMxDisValLow; Timer6_PortOutputConfig(M4_TMR61, Timer6PWMB, &stcTIM6PWMxCfg);
/*config interrupt*/ /* Enable timer61 GOVF interrupt */ Timer6_ConfigIrq(M4_TMR61, Timer6INTENOVF, true);

stcIrqRegiConf.enIRQn = Int002_IRQn; //Register INT_TMR61_GOVF Int to Vect.No.002 stcIrqRegiConf.enIntSrc = INT_TMR61_GOVF; //Select Event interrupt of timer61 stcIrqRegiConf.pfnCallback = &Timer6_OverFlow_CallBack; //Callback function enIrqRegistration(&stcIrqRegiConf); //Registration IRQ
NVIC_ClearPendingIRQ(stcIrqRegiConf.enIRQn); //Clear Pending NVIC_SetPriority(stcIrqRegiConf.enIRQn, DDL_IRQ_PRIORITY_15);//Set priority NVIC_EnableIRQ(stcIrqRegiConf.enIRQn); //Enable NVIC

/*start timer6*/ Timer6_StartCount(M4_TMR61);
while(1) { ; }
}




我们直接分析主函数部分

第一步:先开启时钟 :PWC_Fcg2PeriphClockCmd(PWC_FCG2_PERIPH_TIM61, Enable);




直接看源程序,就能找到三个时钟分别是61 62 63
这次我们用的是61也就是第一个时钟

第二步:是配置引脚为TIMER61的输出引脚 也就是端口复用


第三步:配置定时器功能和预分频系数


定时器都有什么功能呢,看源代码能看到有三个




那我们再看一下这个功能是配置的哪个寄存器呢?




这个时候如果还是没看懂,那么我们回过头来看用户手册关于这个定时器是怎么说的




以后我们如果不知道代码中配置的是什么意思了,也可以这样来寻找答案。

第四步:设置通用周期基准值寄存器,也就是重装载值



u16Period = 33600u; Timer6_SetPeriod(M4_TMR61, Timer6PeriodA, u16Period); //period set

这里我们用的是A通道,timer6有三个通道,分别如下图所示

第五步:设置比较值



 u16Compare = 10000u; Timer6_SetGeneralCmpValue(M4_TMR61, Timer6GenCompareA, u16Compare); //Set General Compare RegisterA Value
u16Compare = 20000u; Timer6_SetGeneralCmpValue(M4_TMR61, Timer6GenCompareB, u16Compare); //Set General Compare RegisterB Value


看到这里我们来画个图说明一下




我们制定好波形,波形的频率就是根据预分频值算出来的,然后设置好重装载值和比较值,再设置中断类型,就可以产生响应的中断

第六步:设置输出功能



stcTIM6PWMxCfg.enPortMode = Timer6ModeCompareOutput; //Compare output function stcTIM6PWMxCfg.bOutEn = true; //Output enable stcTIM6PWMxCfg.enPerc = Timer6PWMxCompareLow; //PWMA port output Low level when CNTER value match PERAR stcTIM6PWMxCfg.enCmpc = Timer6PWMxCompareHigh; //PWMA port output High level when CNTER value match with GCMAR stcTIM6PWMxCfg.enStaStp = Timer6PWMxStateSelSS; //PWMA output status is decide by STACA STPCA when CNTER start and stop stcTIM6PWMxCfg.enStaOut = Timer6PWMxPortOutLow; //PWMA port output set low level when CNTER start stcTIM6PWMxCfg.enStpOut = Timer6PWMxPortOutLow; //PWMA port output set low level when CNTER stop stcTIM6PWMxCfg.enDisVal = Timer6PWMxDisValLow; Timer6_PortOutputConfig(M4_TMR61, Timer6PWMA, &stcTIM6PWMxCfg);


根据以上的代码我们就设置好了比较输出的功能,怎么算比较输出呢,就是当计数值经过比较值的时候输出引脚进行翻转,由高电平变为低电平,或者有低电平变为高电平

这样就产生了占空比可调的PWM波形输出了,看下面的图,大家就清楚了




每次遇到比较,就翻转输出,这样我们设置不同的比较值,就可以有不同占空比的PWM了,这样的控制方式对于步进电机控制上好处多多,我推荐大家可以看看硬石老师的电机开发例程和野火老师的例程,他们用的都是定时器的比较输出的功能来控制步进电机产生梯形加减速、S形加减速。

言归正传我们继续分析代码

第七步:配置中断功能



/*config interrupt*/ /* Enable timer61 GOVF interrupt */ Timer6_ConfigIrq(M4_TMR61, Timer6INTENOVF, true);

stcIrqRegiConf.enIRQn = Int002_IRQn; //Register INT_TMR61_GOVF Int to Vect.No.002 stcIrqRegiConf.enIntSrc = INT_TMR61_GOVF; //Select Event interrupt of timer61 stcIrqRegiConf.pfnCallback = &Timer6_OverFlow_CallBack; //Callback function enIrqRegistration(&stcIrqRegiConf); //Registration IRQ
NVIC_ClearPendingIRQ(stcIrqRegiConf.enIRQn); //Clear Pending NVIC_SetPriority(stcIrqRegiConf.enIRQn, DDL_IRQ_PRIORITY_15);//Set priority NVIC_EnableIRQ(stcIrqRegiConf.enIRQn); //Enable NVIC
复制代码





第八步:使能定时器



 /*start timer6*/ Timer6_StartCount(M4_TMR61);

这里我们讲解的是高级定时器的功能,剩下的定时器,就是在这个基础上进行简配得到的,所以就不再一一列举了,大家有时间可以看看手册和代码,关键的注意事项在上面都介绍了,大家应该配置没有问题,如果遇到问题了,可以在本帖留言,我看到后会及时回复 谢谢大家了




本文系21i
c论坛网友binoo7的回忆


免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!