打印
[MM32软件]

MM32F0140 TIM 学习笔记

[复制链接]
4631|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 MindMotion 于 2024-4-18 11:13 编辑

本篇笔记主要探讨 MM32F0140 定时器模块的框图结构、定时器提供的计数定时等功能以及配置定时器的流程,并以 pokt-f0140 开发板作为实际演示平台,使用开发板上 32 位定时器 TIM2 进行 pwm 波输出实验。

TIM 功能描述

MM32F0140 TIM 最基本的功能为计数定时,此功能依靠定时器内部的预分频器 PSC 、计数器 CNT 和 自动预装载寄存器 ARR 合作完成。此外,定时器如有输入输出通道,则还能提供输入捕获、比较输出和从模式输入等功能。在此之上,对于拥有额外刹车输入通道的高级定时器而言,还可提供刹车和死区设置。

1)TIM 框图

下图1 为 MM32F0140 高级定时器的结构框图,各部分支持不同的功能。其中:

  • 红框支持最基本的计数定时功能。计数器、预分频器和自动预装载器也被称为定时器的时基单元。预分频器 PSC 将输入的时钟信号进行分频,计数器 CNT 对分频信号进行计数。计数器值和自动预装载寄存器 ARR 值进行比较,发生上溢或下溢时,则表明完成一次周期计数,周期值为 ARR 寄存器写入值,频率为输入时钟源经过 PSC 预分频器分频后频率。
  • 灰框支持从模式输入功能。除内部时钟外,定时器模块可以通过配置从模式,选择来自外部输入引脚 TI1 或 TI2 的输入信号或 ETR 引脚信号或其他定时器的 ITRx 信号作为时钟输入源。
  • 绿框支持输入捕获功能。当通道 x 配置为输入捕获模式时,通道 x 的输入信号依次经过滤波、边沿检测以及分频,触发通道 x 捕获事件。定时器模块会将当前计数器计数值写入对应通道的捕获/比较寄存器 CCRx 中。
  • 蓝框支持比较输出功能。当通道 x 配置为比较输出模式时,定时器将当前计数器值与通道 x 捕获/比较寄存器 CCRx 中值进行比较,相等时定时器将改变通道 x 的参考输出电压 REF。
  • 黑框支持刹车功能,当 BKIN 通道有指定刹车信号出现时,各路输出通道将输出预设的空闲输出电压。


图1. MM32F0140 高级定时器框图

下文将详细叙述定时器的计数定时、输入捕获和比较输出这三个主要功能。

2)计数定时

计数定时即计数器使能后,在一定计数频率下进行计数。根据设置的计数方向,计数器完成周期次计数后,定时器触发更新中断。

计数器频率计算

设定时器输入频率为 clk_frq,预分频器分频值为 psc,则计数器频率 cnt_frq 为

计数器计数方向

MM32F0140 定时器中 TIM14、TIM16 和 TIM17 仅提供向上计数。其余定时器可以提供以下三种可选计数方向:

  • 向上计数,计数器从 0 开始向上计数,递增到 ARR 自动预装载寄存器值后,计数器产生上溢事件。定时器产生一个更新事件,计数器又从 0 开始计数。
  • 向下计数,计数器从 ARR 自动预装载寄存器值开始向下计数,递减到 0 后,计数器产生下溢事件。定时器产生一个更新事件,计数器又从 ARR 自动预装载寄存器值开始计数。
  • 先向上计数再向下计数。计数器从 0 开始向上计数,递增到 ARR 自动预装载寄存器值后,计数器产生上溢事件。定时器产生一个更新事件。然后计数器从 ARR 自动预装载寄存器值开始向下计数,递减到 0 后,计数器产生下溢事件。定时器再产生一个更新事件。


图2 定时器向上计数

如图2 所示,定时器输入时钟即分频器时钟 CK_PSC,预分频器 PSC 值为 1 ,即定时器频率为 CK_PSC 的二分频频率。定时器自动装载值 ARR 为 5,从图中可见计数器 CNT 达到 5 时,产生一个更新事件 UEV。

定时器周期长度

ARR 自动预装载寄存器的值为定时器周期长度,决定定时器计数多少次后产生一个更新事件。

3)比较输出

如图3 所示,定时器比较输出功能通过计数器、通道 x 的捕获/比较寄存器 CCRx 以及输出控制电路实现。定时器将计数器和捕获/比较寄存器 CCRx 值实时比较,当二值相等时会改变通道 x 的参考输出电压 REF,参考输出电压 REF 和输出控制电路共同决定通道 x 的实际电压值。


图3 MM32F0140 定时器输出通道1示意图

比较输出匹配值

输出通道x 对应的 CCRx 寄存器值为比较输出匹配值,定时器将在计数器值和通道 x 的匹配值相等时,根据比较输出模式,改变通道 x 的参考输出电压REF。

比较输出模式选择

MM32 F0140 的 TIM 模块一共有 7 种比较输出模式:

  • 匹配结果对于参考输出电压 REF 没有影响。
  • 匹配时将参考输出电压 REF 设为高电平。
  • 匹配时将参考输出电压 REF 设为低电平。
  • 匹配时翻转参考输出电压 REF。
  • 强制参考输出电压 REF为低电平。
  • 强制参考输出电压 REF为高电平。
  • PWM模式1:当计数值小于匹配值时,参考电压REF为高电平,否则为低电平。
  • PWM模式2:当计数值小于匹配值时,参考电压REF为低电平,否则为高电平。

参考输出电压和实际输出电压间关系

定时器 CCER[CCxP] 位决定了参考输出电压和实际输出电压间关系,具体可见表1。CCER[CCxP]值为0表示高电平有效,为1表示低电平有效。


表1 CCER[CCxP]值对实际输出电压的影响

如下图 4 所示,通道1的比较值为1,当计数器值小于1时,通道1的比较输出电压 OC1REF 为高;当计数器值等于1时,通道1 的比较输出电压 OC1REF 拉低,产生一个下降沿。OC1REF 将一直保持为低,直到定时器更新事件发生,计数器从 0 开始计数时,OC1REF 又被拉高。


图4 递增计数下PWM模式1时输出通道参考电压

4)输入捕获

如图5 所示,输入通道 x 的输入信号 TIx 经过滤波器、边沿检测、分频以后被定时器捕获,定时器将输入捕获时刻的计数器值写入相应通道的捕获/比较寄存器 CCRx 中。


图5 MM32F0140输入捕获框图

计数定时配置

1)时基配置

配置定时器工作模式

配置 CR1[OPM] 位可以设置定时器工作模式,其中值为 0 表示定时器将循环计时,值为 1 表示计时 1 次后就停止计数器。

配置是否预装载


配置 CR1[ARPE] 位可以配置定时器自动预装载寄存器 ARR 的实际更新方式,值为1则用户写入 ARR 寄存器的值会在下一次计数器更新时起效,否则立刻生效。

配置计数模式

配置 CR1[DIR] 位和 CR1[CMS] 位可以配置计数器计数模式。如果选择单向计数,CR1[CMS]需配置为 0,此时CR1[DIR] 配置为 0 时,向上计数,配置为 1 时向下计数。如果选择先向上计数再向下计数,则需要配置 CR1[CMS],CR1[DIR] 值保持为 0。

配置预分频值

由上述计数器频率计算小结可知,如果需要定时器频率为 cnt_frq, 定时器输入源频率为 clk_frq,定时器的预分频值 psc 应为


计算出的 psc 值写入 PSC 寄存器。

配置自动预装载寄存器 ARR

自动预装载寄存器 ARR 的值决定定时器周期计数次数。假如定时器向上计数,则计数器从 0 递增到 ARR 值,即 ARR 寄存器值为 arrv,则实际计数器一个周期内会做arrv+1 次计数,所以ARR 寄存器值应为需要的周期计数值减一。将此值写入 ARR 寄存器。

使能计数器

完成上述配置后,将 CR1[CEN] 置为 1 即可启动计数器计数。当不需要计数时,将此位设置为 0。

2)比较输出配置

配置通道输出模式

配置 CCMRy[CCxS] 位为 0,可以将通道 x 配置为输出模式。

配置是否预装载匹配值

配置 CCMRy[OCxPE] 位可以设置通道 x 的比较输出匹配值生效方式,为 0 则一旦写入立刻生效,否则匹配值将在下一次更新事件后生效。

配置比较输出模式

配置 CCMRy[OCxM] 字段可以选择不同的比较输出模式,具体字段值和比较输出模式间关系可见表3。


表3 CCMRy[OCxM] 与 比较输出模式间对应关系

配置有效输出电压

配置 CCER[CCxP] 位,可以设置通道 x 的有效输出电压。值为0,则参考电压的高电平为有效电平;值为1,则参考电压的低电平为有效电平。

使能通道输出

配置 CCER[CCxE] 位为1,使能通道输出功能;配置为 0,则关闭通道输出功能。

3)输入捕获配置

配置通道输入模式

配置 CCMRy[CCxS] 位为1,可将通道 x 配置为输入模式。

配置输入信号边沿选择

配置 CCER[CCxP] 和 CCER[CCxNP] 位,可以配置输入信号的有效边沿选择,具体对应关系如表4。


表4 输入模式下,CCER[CCxP]和CCER[CCxNP]对于输入边沿影响

配置采样和滤波

配置 CCMRy[ICxF] 字段,设置通道 x 的输入捕获滤波器。

配置预分频器

配置 CCMRy[IC1PSC] 字段,设置通道 x 输入信号的预分频值。

使能通道输入


配置 CCER[CCxE] 位为 1,使能通道输入捕获功能;配置为 0,则关闭通道输入捕获功能。

样例

——pokt-f0140 开发板 定时器实现TIM2通道1输出pwm波

在 SDK 中已有支持的 pokt-f0140 开发板上,在 tim_32b_0 样例工程中,通过 tim_32b_output_compare_pwm 可以使用定时器 TIM2 的通道 1 输出 pwm 波。

1)时钟初始化

TIM2 在 APB2 总线上,需要使能时钟。TIM2 的通道 1 复用 PA0 引脚,需要使能 GPIOA 时钟。

/* Enable TIM. */
RCC_EnableAPB1Periphs(RCC_APB1_PERIPH_TIM2, true);
RCC_ResetAPB1Periphs(RCC_APB1_PERIPH_TIM2);
/* Enable GPIOA for TIM2_CH1. */
RCC_EnableAHB1Periphs(RCC_AHB1_PERIPH_GPIOA, true);
RCC_ResetAHB1Periphs(RCC_AHB1_PERIPH_GPIOA);

2)初始化输出引脚

GPIO_Init_Type gpio_init;
gpio_init.Pins  = GPIO_PIN_0;
gpio_init.PinMode  = GPIO_PinMode_AF_PushPull;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio_init);
GPIO_PinAFConf(GPIOA, gpio_init.Pins, GPIO_AF_2);/* 根据data sheet, 配置复用模式2。 */

3)定时器时基配置
TIM_32B_Init_Type tim_init;
tim_init.ClockFreqHz = BOARD_TIM_32B_FREQ;/* 因为 TIM_32B 在APB2总线上,所以BOARD_TIM_32B_FREQ的值实际为APB2总线时钟频率。*/
tim_init.StepFreqHz = APP_TIM_UPDATE_PERIOD;  /* 定时器周期时长为定时器周期长度Period加1后除定时器频率StepFreqHz。*/
tim_init.Period = APP_TIM_UPDATE_PERIOD - 1u; /* 所以可得值为1,也即定时器周期时长为1s。 */
tim_init.EnablePreloadPeriod = false; /* 不采用预装载,修改ARR寄存器将立即生效。 */
tim_init.PeriodMode = TIM_32B_PeriodMode_Continuous;/* 循环计时。 */
tim_init.CountMode = TIM_32B_CountMode_Increase; /* 递增计数。 */
TIM_32B_Init(BOARD_TIM_32B_PORT, &tim_init);

4)配置输出通道
TIM_32B_OutputCompareConf_Type tim_outcomp_conf;
tim_outcomp_conf.ChannelValue = 0u;/* Compare value initialize with 0. */
tim_outcomp_conf.EnableFastOutput = false; /* Disable fast output. */
tim_outcomp_conf.EnablePreLoadChannelValue = false; /* Disable preload, put data immediately. */
tim_outcomp_conf.RefOutMode = TIM_32B_OutputCompareRefOut_FallingEdgeOnMatch;/*Generate a falling edge when matched.*/
tim_outcomp_conf.ClearRefOutOnExtTrigger = false; /* Ext signal won't clear output. */
tim_outcomp_conf.PinPolarity = TIM_32B_PinPolarity_Rising;/* High polarity is valid. */
TIM_32B_EnableOutputCompare(BOARD_TIM_32B_PORT, BOARD_TIM_32B_CHANNEL, &tim_outcomp_conf);

5)使能计数器
TIM_32B_Start(BOARD_TIM_32B_PORT);

6)main 函数

main 函数将轮询键入,并按设定的占空比数组循环输出不同的 PWM 波。

int main(void)
{
    BOARD_Init();
    printf("\r\ntim_32b_output_compare_pwm.\r\n");

    /* Setup the timer. */
    app_tim_32b_init();

    printf("press any key to change the pwm ...\r\n");

    while (1)
    {
        for (uint32_t i = 0; i < APP_TIM_32B_PWM_NUM; i++)
        {
            getchar();
            TIM_32B_PutChannelValue(BOARD_TIM_32B_PORT, BOARD_TIM_32B_CHANNEL, app_tim_32_pwm_val[i]);/* Change duty cycle. */
            printf("PWM value: %u\r\n", (unsigned)app_tim_32_pwm_val[i]);
        }
    }
}

7)实验结果

将 TIM2 通道1 所在引脚用杜邦线与小灯泡引脚相连,可以实现呼吸灯的效果。因为每次键入,都会改变 pwm 波的占空比,所以小灯泡的亮度在不断改变:




使用特权

评论回复
沙发
huquanz711| | 2024-4-19 20:23 | 只看该作者
可以出个系列视频教程

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:上海灵动微电子股份有限公司
简介:上海灵动微电子股份有限公司成立于 2011 年,是中国本土通用 32 位 MCU 产品及解决方案供应商。 灵动股份的 MCU 产品以 MM32 为标识,基于 Arm Cortex-M 系列内核,自主研发软硬件和生态系统。目前已量产近 300 多款型号,累计交付超 4 亿颗,在本土通用 32 位 MCU 公司中位居前列。

92

主题

110

帖子

5

粉丝