hudi008 发表于 2024-2-20 20:00

MM32L013x——LPTIM的应用介绍

低功耗技术旨在减少设备电流消耗,延长电池寿命,可以有效的延长产品的使用寿命。这就需要合理分配运行时间和空闲时间,在空闲时可以通过使MCU进入低功耗模式降低系统的功耗,在需要MCU工作时唤醒MCU,低功耗定时器(LPTIM)有助于降低功耗,特别是当系统处于低功耗模式时(如 stop模式)可以在休眠模式下实现外部脉冲计数功能。通过外部输入的触发信号,能够实现低功耗超时唤醒。LPTIM 具有外部时钟计数,超时唤醒功能和 PWM 输出等多种用途。本文主要介绍 MM32 全新低功耗系列 MM32L013x 产品中的 LPTIM 外设模块,它允许系统执行简单的任务,同时功耗保持在绝对最小。1 LPTIM 简介LPTIM 由一个 16 位计数器组成,可以为用户提供便捷的计数和定时功能。LPTIM 运行在 CORE 电源域,可以工作在低功耗模式下,具有低功耗的特点,当然也可以被当做一个普通的 16 位基础定时器来使用。2 LPTIM 常见用途
[*]脉冲计数功能
[*]PWM 生成器
[*]周期性地超时唤醒sleep模式、stop模式
以上所有功能应用均为普通 TIM 所不能实现的,正是由于 LPTIM 的时钟源具有多样性,使得其能够在所有电源模式(standby模式除外)下保持运行状态。3 LPTIM 主要特性
[*]16 位递增计数器,相当于 LPT_CNT 值由模块时钟驱动加一递增最大到 65535,并且包括一个 16 位比较寄存器和目标值寄存器
[*]3 位异步时钟预分频器,可以将输入进模块的时钟进行多种系数的预分频,包括: 1/2/4/8/16/32/64/128 分频
[*]多种内部和外部的时钟源可选,包括:LSI/LSE/PCLK2
https://aijishu.com/img/bVbKcq
[*]可以选择不同边沿的脉冲极性用作触发计数,触发源包括:LPTIM1_TRIGGER 引脚输入触发、COMP OUT 事件触发
[*]可以设定不同的 LPT_CMP 和 LPT_TARGET 值从而通过 LPTIM1_OUT 引脚输出不同占空比的PWM 波形或者方波
[*]可以设定不同的 LPT_TARGET 值从而进行不同时长的低功耗唤醒
[*]可以开启不同的中断,包括:外部触发、比较匹配和计数器溢出中断,在唤醒 STOP 模式时,除了需要使能相应的中断外,还需配置 EXTI_Line23 并且使能相关的功能
4 LPTIM 功能框图LPTIM 的功能框图如下,主要包括了:触发源选择模块、时钟输入及分频模块、计数模块以及比较匹配输出单元等。https://aijishu.com/img/bVbKcs涉及到时钟选择的部分需要设置RCC_CFGR2,在 UM 手册中时钟配置寄存器2(RCC_CFGR2):https://aijishu.com/img/bVbKct使能LPTIM时钟需要设置RCC_APB2ENR位:
https://aijishu.com/img/bVbKcu
涉及到 LPTIM1_TRIGGER 和 LPTIM1_OUT 引脚的功能定义情况在 DS 手册中引脚复用及复用列表:
https://aijishu.com/img/bVbKcv5 LPTIM 寄存器表由于 MM32L013x 系列产品中只有一个 LPTIM 模块,所以在文档和程序中也习惯称作 LPTIM1,它的基地址为 0x40012800,所有寄存器设计为 16 位,预留出 16位保持 32 位对齐,寄存器占用情况如下:https://aijishu.com/img/bVbKcw其中 LPT_CFG 、 LPT_IE 、 LPT_CTRL 、LPT_CMP 、 LPT_TARGET 为可读可写操作的,LPT_IF 为可读并且写 1 清零操作的,LPT_CNT 为只读操作的,具体功能描述参见 UM 对应章节内容。6 LPTIM 功能实现6.1带溢出中断的普通定时器
[*]使能 APB2 总线上的 LPTIM 外设时钟,用于同步
[*]初始化配置 LPT_CFG 寄存器 MODE=0,计数器被触发后保持运行,直到被关闭为止
[*]初始化配置 LPT_CFG 寄存器 TMODE=00,选择普通计数器模式
[*]选择外部时钟或内部时钟作为计数器的时钟源
[*]配置 LPT_IE =1,使能 LPTIM 计数器溢出中断
[*]配置 LPT_CTRL 寄存器 LPTEN=1,使能 LPTIM 计数器
[*]计数器使能后有两个周期的同步过程,同步完成后,计数器开始工作,计数达到目标之后回到 0 重新开始计数,并产生溢出中断
按上述流程的代码配置如下:void LPTIM1_Init(u16 arr){    LPTIM_TimeBaseInit_TypeDefinit_struct;    RCC_APB2PeriphClockCmd(RCC_APB2ENR_LPTIM1, ENABLE);    LPTIM_TimeBaseStructInit(&init_struct);    init_struct.ClockSource            = LPTIM_PCLK_Source;    init_struct.CountMode            = LPTIM_CONTINUOUS_COUNT_Mode;    init_struct.OutputMode             = LPTIM_NORMAL_WAV_Mode;    init_struct.Waveform               = LPTIM_AdjustPwmOutput_Mode;    init_struct.Polarity               = LPTIM_Positive_Wave;    init_struct.ClockDivision          = LPTIM_CLK_DIV1;    if(init_struct.ClockSource == LPTIM_LSE_Source) {      RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWR | RCC_APB1ENR_BKP, ENABLE);      PWR_BackupAccessCmd(ENABLE);      RCC_LSEConfig(RCC_LSE_ON);      DELAY_Ms(5000);      while(!RCC_GetFlagStatus(RCC_FLAG_LSERDY));      LPTIM_CLKConfig(LPTIM1, LPTIM_LSE_Source);    }    else if(init_struct.ClockSource == LPTIM_LSI_Source) {      RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWR | RCC_APB1ENR_BKP, ENABLE);      PWR_BackupAccessCmd(ENABLE);      RCC_LSICmd(ENABLE);      DELAY_Ms(500);      while(!RCC_GetFlagStatus(RCC_FLAG_LSIRDY));      LPTIM_CLKConfig(LPTIM1, LPTIM_LSI_Source);    }    else { //(init_struct.ClockSource == LPTIM_PCLK_Source)      LPTIM_CLKConfig(LPTIM1, LPTIM_PCLK_Source);    }    LPTIM_TimeBaseInit(LPTIM1, &init_struct);    LPTIM_SetTarget(LPTIM1, arr);}void LPTIMER1_IRQHandler(void){    if(LPTIM_GetITStatus(LPTIM1, LPTIF_OVIF)) {      LPTIM_ClearITPendingBit(LPTIM1, LPTIF_OVIF);      LED3_TOGGLE();      LED4_TOGGLE();    }}void NVIC_Configuration(void){    NVIC_InitTypeDef NVIC_InitStruct;    NVIC_InitStruct.NVIC_IRQChannel = LPTIMER1_IRQn;    NVIC_InitStruct.NVIC_IRQChannelPriority = 2;    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;    NVIC_Init(&NVIC_InitStruct);}s32 main(void){    DELAY_Init();    LED_Init();    LPTIM1_Init(4000 - 1);    NVIC_Configuration();    LPTIM_ITConfig(LPTIM1, LPTIE_OVIE, ENABLE);    LPTIM_Cmd(LPTIM1, ENABLE);    while (1)    {      LED1_TOGGLE();      LED2_TOGGLE();      DELAY_Ms(1000);    }}6.2PWM 输出
[*]初始化中使用以上相同的步骤,需要额外配置 LPT_CFG 寄存器 PWM=1,选择 PWM 输出模式
[*]再配置 LPT_CMP 和 LPT_TARGET 寄存器,设定比较值和目标值,PWM 的占空比由比较值和目标值决定,输出在计数器值等于比较值翻转为 1,在等于目标值时翻转为 0
[*]另外需要配置一组 LPTIM1_OUT 引脚用于输出 PWM 波形,这里以 PB14 为例
代码配置如下:void LPTIM_GPIO_Init(void){    GPIO_InitTypeDef GPIO_InitStruct;    RCC_GPIO_ClockCmd(GPIOB, ENABLE);    //set PB14 as LPTIM1 Output Pin    GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_3);    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_14;    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;    GPIO_Init(GPIOB, &GPIO_InitStruct);}void LPTIM1_Init(u16 arr){    LPTIM_TimeBaseInit_TypeDefinit_struct;    RCC_APB2PeriphClockCmd(RCC_APB2ENR_LPTIM1, ENABLE);    LPTIM_TimeBaseStructInit(&init_struct);    init_struct.ClockSource            = LPTIM_PCLK_Source;    init_struct.CountMode            = LPTIM_CONTINUOUS_COUNT_Mode;    init_struct.OutputMode             = LPTIM_NORMAL_WAV_Mode;    init_struct.Waveform               = LPTIM_AdjustPwmOutput_Mode;    init_struct.Polarity               = LPTIM_Positive_Wave;    init_struct.ClockDivision          = LPTIM_CLK_DIV1;    if(init_struct.ClockSource == LPTIM_LSE_Source) {      RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWR | RCC_APB1ENR_BKP, ENABLE);      PWR_BackupAccessCmd(ENABLE);      RCC_LSEConfig(RCC_LSE_ON);      DELAY_Ms(5000);      while(!RCC_GetFlagStatus(RCC_FLAG_LSERDY));      LPTIM_CLKConfig(LPTIM1, LPTIM_LSE_Source);    }    else if(init_struct.ClockSource == LPTIM_LSI_Source) {      RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWR | RCC_APB1ENR_BKP, ENABLE);      PWR_BackupAccessCmd(ENABLE);      RCC_LSICmd(ENABLE);      DELAY_Ms(500);      while(!RCC_GetFlagStatus(RCC_FLAG_LSIRDY));      LPTIM_CLKConfig(LPTIM1, LPTIM_LSI_Source);    }    else { //(init_struct.ClockSource == LPTIM_PCLK_Source)      LPTIM_CLKConfig(LPTIM1, LPTIM_PCLK_Source);    }    LPTIM_TimeBaseInit(LPTIM1, &init_struct);}s32 main(void){    DELAY_Init();    LED_Init();    LPTIM1_Init(4000 - 1);    LPTIM_SetCompare(LPTIM1, 4000 / 2 - 1);    LPTIM_SetTarget(LPTIM1, 4000 );    LPTIM_GPIO_Init();    LPTIM_Cmd(LPTIM1, ENABLE);    while (1)    {      LED1_TOGGLE();      LED2_TOGGLE();      DELAY_Ms(1000);    }}6.3Trigger 脉冲触发计数
[*]初始化中使用以上相同的步骤,需要修改配置 LPT_CFG 寄存器 TMODE=01,选择 Trigger 脉冲触发计数模式
[*]配置 LPT_CFG 寄存器 TRIGSEL = 0,选择外部引脚触发计数
[*]配置 LPT_CFG 寄存器 TRIGCFG,选择外部触发信号的有效沿
[*]用户可以根据需求选择是否使能滤波器,配置LPT_CFG 寄存器
[*]根据需求是否使能外部触发中断位
[*]另外需要配置一组 LPTIM1_TRIGGER 引脚用于触发输入,这里以 PB13 为例
代码配置如下:void LPTIM_GPIO_Init(void){    GPIO_InitTypeDef GPIO_InitStruct;    RCC_GPIO_ClockCmd(GPIOB, ENABLE);    //set PB13 as LPTIM1 Trigger Pin    GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_3);    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_13;    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_FLOATING;    GPIO_Init(GPIOB, &GPIO_InitStruct);}void LPTIM1_Init(u16 arr){    LPTIM_TimeBaseInit_TypeDefinit_struct;    RCC_APB2PeriphClockCmd(RCC_APB2ENR_LPTIM1, ENABLE);    LPTIM_TimeBaseStructInit(&init_struct);    init_struct.ClockSource            = LPTIM_PCLK_Source;    init_struct.CountMode            = LPTIM_CONTINUOUS_COUNT_Mode;    init_struct.OutputMode             = LPTIM_PULSE_TRIG_Mode;    init_struct.Waveform               = LPTIM_AdjustPwmOutput_Mode;    init_struct.Polarity               = LPTIM_Positive_Wave;    init_struct.ClockDivision          = LPTIM_CLK_DIV1;    if(init_struct.ClockSource == LPTIM_LSE_Source) {      RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWR | RCC_APB1ENR_BKP, ENABLE);      PWR_BackupAccessCmd(ENABLE);      RCC_LSEConfig(RCC_LSE_ON);      DELAY_Ms(5000);      while(!RCC_GetFlagStatus(RCC_FLAG_LSERDY));      LPTIM_CLKConfig(LPTIM1, LPTIM_LSE_Source);    }    else if(init_struct.ClockSource == LPTIM_LSI_Source) {      RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWR | RCC_APB1ENR_BKP, ENABLE);      PWR_BackupAccessCmd(ENABLE);      RCC_LSICmd(ENABLE);      DELAY_Ms(500);      while(!RCC_GetFlagStatus(RCC_FLAG_LSIRDY));      LPTIM_CLKConfig(LPTIM1, LPTIM_LSI_Source);    }    else { //(init_struct.ClockSource == LPTIM_PCLK_Source)      LPTIM_CLKConfig(LPTIM1, LPTIM_PCLK_Source);    }    LPTIM_TimeBaseInit(LPTIM1, &init_struct);    LPTIM1->CFGR = LPTIM_ExInputUpEdge;    LPTIM1->CFGR = LPTIM_External_PIN_Trig;}


yangxiaor520 发表于 2024-2-20 20:39

低功耗定时器吧?
页: [1]
查看完整版本: MM32L013x——LPTIM的应用介绍