完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
Part.1 timer介绍 MM32系列MCU有三种定时器,分为基本定时器,通用定时器和高级定时器。 基本定时器TIM14、TIM16和TIM17是均为16位的只能递增计数的定时器,可以定时,有1个外部IO。 通用定时器TIM2是一个32位的可以递增、递减、递增/递减计数的定时器,可以定时,可以输出比较,可以输入捕捉,每个定时器有4个外部IO。通用定时器TIM3是一个16位的可以递增、递减、递增/递减数的定时器,可以定时,可以输出比较,可以输入捕捉,每个定时器有4个外部IO。 高级定时器TIM1/8是均为16位的可以递增、递减、递增/递减计数的定时器,可以定时,可以输出比较,可以输入捕捉,还可以有三相电机互补输出信号,每个定时器有4对外部IO。 1.1时钟源 定时器时钟TIMxCLK,即内部时钟CK_INT,经APB1/APB2预分频器后分频提供,如果APB1/APB2预分频系数等于1,则频率不变,否则频率乘以2,库函数中APB1预分频的系数是2,即PCLK1=24M,所以定时器时钟TIMxCLK=24*2=48M。 1.2 计数器时钟 定时器时钟经过PSC预分频器之后,即CK_CNT,用来驱动计数器计数。PSC是一个16位的预分频器,可以对定时器时钟TIMxCLK进行1~65536之间的任何一个数进行分频。 具体计算方式为:CK_CNT=TIMxCLK/(PSC+1) 1.3计数器 计数器CNT是一个16/32位的计数器,可以递增、递减、递增/递减计数,最大计数值为65535/(232-1)。当计数达到自动重装载寄存器的时候产生更新事件,并清零从头开始计数。 1.4自动重装载寄存器 自动重装载寄存器ARR是一个16位/32位的寄存器,这里面装着计数器能计数的最大数值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。 1.5定时时间的计算 定时器的定时时间等于计数器的中断周期乘以中断的次数。计数器在CK_CNT的驱动下,计一个数的时间则是CK_CLK的倒数,等于:1/(TIMxCLK/(PSC+1)),产生一次中断的时间则等于:1/(CK_CLK*ARR)。如果在中断服务程序里面设置一个变量time,用来记录中断的次数,那么就可以计算出我们需要的定时时间等于:1/CK_CLK*(ARR+1)*time。 AMetal平台提供了定时器初始化函数,可以实现基础定时、PWM输出和输入捕获等功能,用户对照MM32技术手册直接调用相关函数即可实现需要的功能,下面我们一起来熟悉AMetal平台提供的相关函数接口使用方法。 Part.2 定时器初始化 2.1定时器初始化 AMetal平台提供了定时器初始化函数,可以直接调用初始化函数。以定时器1初始化函数为例,函数原型为: am_timer_handle_t am_mm32l073_tim1_timing_inst_init(void); 该函数在user_config目录下的am_hwconf_mm32l073_tim_timing.c文件中定义,在am_mm32l073_inst_init.h中声明。因此使用定时器初始化函数时,需要包含头文件am_mm32l073_inst_init.h。 初始化定时器1,调用该函数时需要定义一个am_timer_handle_t类型的变量,用于保存获取的定时器1服务句柄,定时器初始化程序为: am_timer_handle_t tim1_timing_handle; tim1_timing_handle=am_mm32l073_tim1_timing_inst_init(); 2.2定时器PWM初始化 AMetal平台提供了定时器的PWM初始化函数,可以直接调用初始化函数。MM32L073核心板上的LED可通过跳线帽连接到PB1引脚,PB1可复用为TIM3_CH4。因此以定时器3 PWM初始化函数为例,函数原型为: am_pwm_handle_t am_mm32l073_tim3_pwm_inst_init(void); 该函数在user_config目录下的am_hwconf_mm32l073_tim_pwm.c文件中定义,在am_mm32l073_inst_init.h中声明。因此使用定时器3的PWM初始化函数时,需要包含头文件am_mm32l073_inst_init.h。 初始化定时器3PWM,调用该函数时需要定义一个am_pwm_handle_t类型的变量,用于保存获取的定时器3PWM服务句柄,定时器3PWM初始化程序为: am_pwm_handle_tpwm_handle; pwm_handle=am_mm32l073_tim3_pwm_inst_init(); 2.3输入捕获初始化 AMetal平台提供了定时器的输入捕获初始化函数,可以直接调用初始化函数。以定时器2的输入捕获初始化函数为例,函数原型为: am_cap_handle_t am_mm32l073_tim2_cap_inst_init(void); 该函数在user_config目录下的am_hwconf_mm32l073_tim_cap.c文件中定义,在am_mm32l073_inst_init.h中声明。因此使用定时器2的输入捕获初始化函数时,需要包含头文件am_mm32l073_inst_init.h。 初始化定时器2输入捕获,调用该函数时需要定义一个am_cap_handle_t类型的变量,用于保存获取的定时器2输入捕获的服务句柄,定时器2出入捕获初始化程序为: am_cap_handle_tcap_handle; cap_handle=am_mm32l073_tim2_cap_inst_init(); Part.3 接口函数 3.1定时器定时接口函数 定时器的定时时间与时钟频率、分频系数、计数器位数有关。为了准确配置定时器的定时时间,需要知道定时器的时钟频率、可配置的分频系数、计数器位数。AMetal平台已提供获取定时器时钟频率、信息的函数,在am_timer.h中以内联函数的形式定义,am_timer.h可在service目录下的am_timer.c包含的头文件中找到。 获取定时器信息,主要获取时钟频率、可配置的分频系数值、定时器位数。以定时器1为例,获取定时器1的时钟频率,函数原型为: int am_timer_clkin_freq_get(am_timer_handle_thandle,uint32_t*p_freq);
基于以上信息,获取时钟频率的程序为: uint32_tclkin_freq=0; am_timer_clkin_freq_get(tim1_timing_handle,&clkin_freq); 获取定时器信息的函数原型为: Const am_timer_info_t *am_timer_info_get(am_timer_handle_thandle);
基于以上信息,获取定时器1信息的程序为: constam_timer_info_t *p_tim1_timing_info; p_tim1_timing_info=am_timer_info_get(tim1_timing_handle); 获取的信息,可以通过调试或用串口打印看到,进而根据定时器时钟频率和信息配置定时器。以串口打印获取的信息为例,程序如下所示。通过串口信息,可以清楚的知道定时器的相关信息,为后面定时器的配置做了准备。 打印定时器信息: AM_DBG_INFO("clk_freq=%drn",clkin_freq); AM_DBG_INFO("width=%drn",p_tim1_timing_info->counter_width); AM_DBG_INFO("chan=%drn",p_tim1_timing_info->chan_num); AM_DBG_INFO("prescaler=%drn",p_tim1_timing_info->prescaler); 3.2定时器编写回调函数 当定时时间到,调用回调函数,定时执行回调函数。回调函数与普通函数一样,程序如下所示。 定时器1回调函数: void tim1_timing_callback(void*p_arg) { AM_DBG_INFO("Timingtime!rn"); am_gpio_toggle(PIOB_1); } 编写的定时回调函数需要与定时器关联起来,需要设置回调函数。设置回调函数原型为: int am_timer_callback_set ( am_timer_handle_t handle, uint8_t chan, void (*pfn_callback)(void *), void *p_arg);
基于以上信息,设置回调函数的程序为: am_timer_callback_set(tim1_timing_handle,0,tim1_timing_callback,NULL); 3.3定时器配置定时时间 通过获取定时器时钟频率、定时器信息,可知时钟频率为48MHz,计数器宽度为16位,最大计数值为65535,分频器最大值为65536。AMetal提供了定时器分频值设置函数、定时计数值设置函数,函数均定义在am_timer.h中。 分频值设置函数在原型为: int am_timer_prescale_set ( am_timer_handle_t handle, uint8_t chan, uint32_t prescale);
定时计数值设置函数原型为: intam_timer_enable(am_timer_handle_thandle,uint8_tchan,uint32_tcount);
基于以上信息,设置分频系数为48000,计数值为500,即定时时间为500ms,具体程序为: am_timer_prescale_set(tim1_timing_handle,0,48000); am_timer_enable(tim1_timing_handle,0,500); 3.4PWM输出接口函数 先进行PWM参数配置,PWM参数包括频率、占空比、通道。AMetal平台提供了PWM参数配置的函数,可以直接使用。该函数以内联函数的形式定义在am_pwm.h中,am_pwm.h可以在soc目录下am_zlg_tim_pwm.c包含的头文件中找到。其函数原型为: int am_pwm_config ( am_pwm_handle_t handle, int chan, unsigned long duty_ns, unsigned long period_ns);
根据以上信息,配置PWM周期为500ms,占空比为50%的程序为: am_pwm_config(pwm_handle,3,250000000,500000000); PWM初始化、配置参数、使能后即可从对应I/O引脚输出PWM波形。AMetal平台提高了PWM使能、禁能函数,函数定义am_pwm.h中。PWM使能函数原型为: int am_pwm_enable(am_pwm_handle_thandle,intchan);
基于以上信息,PWM使能程序为: am_pwm_enable(pwm_handle,3); 3.5CAP输入捕获接口函数 当捕获事件发生时,调用回调函数,执行用户任务程序。以测量输入脉冲的周期为例,编写的回调函数如下所示。其中形式参数count为计数器的值。 捕获事件回调函数: void cap_callback(void*p_arg,unsignedintcount) { staticuint8_ttimes=0;//标记事件发生次数 if(times==0) {//第一次上升沿事件 g_time_ns=count; times=1; } else//第二次上升沿事件 { if(count>g_time_ns) {//计数器没有溢出 g_time_ns=count-g_time_ns; } else {//计数器溢出 g_time_ns=count+(0xffffffff-g_time_ns); } times=0; g_cap_flag=1; } } 输入捕获可选择捕获通道、捕获事件的类型,可设置捕获事件回调函数。AMetal平台提供了输入捕获配置函数,该函数定义在am_cap.h中,am_cap.h包含在soc目录下的am_zlg_tim_cap.c的头文件。输入捕获配置函数原型为: int am_cap_config ( am_cap_handle_t handle, int chan, unsigned int options, am_cap_callback_t pfn_callback, void *p_arg);
基于以上信息,输入捕获配置程序为: am_cap_config(cap_handle,1,AM_CAP_TRIGGER_RISE,cap_callback,NULL); 配置完捕获通道、捕获事件类型、捕获回调函数,使能捕获通道后,当发生事件便会执行回调函数。使能捕获通道函数定义在am_cap.h中,函数原型为: int am_cap_enable(am_cap_handle_thandle,intchan);
基于以上信息,使能输入捕获的程序为: am_cap_enable(cap_handle,1); Part.4 应用实例 4.1定时示例程序 定时500ms,在回调函数中翻转LED,并通过串口打印信息,程序如下所示。 定时器定时范例程序: #include"ametal.h" #include"am_board.h" #include"am_vdebug.h" #include"am_delay.h" #include"am_led.h" #include"am_gpio.h" #include"mm32l073_pin.h" #include"am_mm32l073_inst_init.h" void tim1_timing_callback(void*p_arg) { AM_DBG_INFO("Timingtime!rn"); am_gpio_toggle(PIOB_1); } int am_main(void) { am_timer_handle_ttim1_timing_handle;//定时器服务句柄 constam_timer_info_t*p_tim1_timing_info;//定时器信息 uint32_tclkin_freq=0;//定时器时钟频率 AM_DBG_INFO("Startupsuccessful!rn"); //初始化LEDGPIO am_gpio_pin_cfg(PIOB_1,AM_GPIO_OUTPUT_INIT_HIGH); //初始化定时器 tim1_timing_handle=am_mm32l073_tim1_timing_inst_init(); //获取定时器时钟频率 am_timer_clkin_freq_get(tim1_timing_handle,&clkin_freq); AM_DBG_INFO("clk_freq=%drn",clkin_freq); //获取定时器信息 p_tim1_timing_info=am_timer_info_get(tim1_timing_handle); AM_DBG_INFO("width=%drn",p_tim1_timing_info->counter_width); AM_DBG_INFO("chan_num=%drn",p_tim1_timing_info->chan_num); AM_DBG_INFO("prescaler=%drn",p_tim1_timing_info->prescaler); //设置回调函数 am_timer_callback_set(tim1_timing_handle,0,tim1_timing_callback,NULL); //设置时钟分频系数 am_timer_prescale_set(tim1_timing_handle,0,48000); //设置定时中断频率为2Hz am_timer_enable(tim1_timing_handle,0,500); while(1) { } } 4.2PWM示例程序 以定时器3的PWM通道4为例,从PB1引脚输出周期为500ms、50%占空比的PWM,控制LED闪烁,程序如下所示。编译下载后,可以看到LED0不断闪烁。 PWM范例程序: #include"ametal.h" #include"am_board.h" #include"am_vdebug.h" #include"am_delay.h" #include"am_led.h" #include"am_mm32l073_inst_init.h" intam_main(void) { am_pwm_handle_tpwm_handle; AM_DBG_INFO("Startupsuccessful!rn"); pwm_handle=am_mm32l073_tim3_pwm_inst_init(); am_pwm_config(pwm_handle,3,250000000,500000000); am_pwm_enable(pwm_handle,3); while(1) { } } 4.3输入捕获示例程序 将PA1配置为定时器2的TIM2_CH2输入捕获,测量从PB1引脚输出定时器3的PWM的周期,范例程序如下所示。短接PA1、PB2引脚,可以看到测量脉冲周期与配置的PWM周期一致。 输入捕获范例程序: #include"ametal.h" #include"am_board.h" #include"am_vdebug.h" #include"am_delay.h" #include"am_mm32l073_inst_init.h" uint32_tg_time_ns=0; uint8_tg_cap_flag=0; voidcap_callback(void*p_arg,unsignedintcount) { static uint8_t times=0;//标记事件发生次数 if(times==0) {//第一次上升沿事件 g_time_ns=count; times=1; } else { //第二次上升沿事件 if(count>g_time_ns){//计数器没有溢出 g_time_ns=count-g_time_ns; } else {//计数器溢出 g_time_ns=count+(0xffffffff-g_time_ns); } times=0; g_cap_flag=1; } } int am_main(void) { am_pwm_handle_tpwm_handle; am_cap_handle_tcap_handle; AM_DBG_INFO("Startupsuccessful!rn"); pwm_handle=am_mm32l073_tim3_pwm_inst_init(); am_pwm_config(pwm_handle,3,5000000,10000000); am_pwm_enable(pwm_handle,3); cap_handle=am_mm32l073_tim2_cap_inst_init(); am_cap_config(cap_handle,1,AM_CAP_TRIGGER_RISE,cap_callback,NULL); am_cap_enable(cap_handle,1); while(1) { if(g_cap_flag) { g_cap_flag=0; //将计数值换算成时间 am_cap_count_to_time(cap_handle,1,0,g_time_ns,&g_time_ns); AM_DBG_INFO("PWM_period=%dnsrn",g_time_ns); } } } |
|
相关推荐
|
|
只有小组成员才能发言,加入小组>>
2252个成员聚集在这个小组
加入小组灵动微电子MM32全系列MCU产品应用手册,库函数和例程和选型表
11823 浏览 3 评论
【MM32 eMiniBoard试用连载】+基于OLED12864的GUI---U8G2
5976 浏览 1 评论
【MM32 eMiniBoard试用连载】移植RT-Thread至MM32L373PS
11116 浏览 0 评论
【MM32 eMiniBoard测评报告】+ 开箱 + 初探
4595 浏览 1 评论
灵动微课堂(第106讲) | MM32 USB功能学习笔记 —— WinUSB设备
4327 浏览 1 评论
[MM32软件] MM32F002使用内部flash存储数据怎么操作?
1284浏览 1评论
851浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-24 03:17 , Processed in 0.644480 second(s), Total 68, Slave 52 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号