文章目录
- 一、基础定时器介绍
- 二、功能描述
- (1) Buzzer 功能
- 三、示例代码(PWM)
一、基础定时器介绍
基础定时器 Base Timer 包含两个定时器 TIM10/11。TIM10/11 功能完全相同。TIM10/11 是同步定时/计数器,可以作为 16/32 位自动重装载功能的定时/计数器,也可以作为16/32 位无重载功能的定时/计数器。TIM10/11 可以对外部脉冲进行计数或者实现系统定时。
二、功能描述
- TIM10/11 每个定时/计数器都有独立的控制启动信号、外部输入时钟和门控信号。
当 TIM10/11 使用 EXT、GATE 来进行计数功能时,EXT 用于计数器的外部输入时钟信号,GATE 用于有效电平计数使能信号。 - 当门控功能使能后,当且仅当外部输入 GATE 电平有效时,计数器才会计数,否则计数器处于保持状态。
- 门控使能使用 TIMx_CR.GATE_EN 控制。默认门控功能关闭。
- 门控电平选择使用 TIMx_CR.GATE_P 控制。默认高电平为门控有效电平;设置 TIMx_CR.GATE_P 为 1后,门控低电平为有效电平。
- 当 TIM10/11 使用 PCLK,GATE 来进行定时功能时,PCLK 用于定时器的内部输入时钟信号,GATE可用于有效电平定时使能信号。
- 当门控功使能后,当且仅当外部输入 GATE 电平有效时,定时器才会计数,否则定时器处于定时计数器停止状态。
- 门控使能使用 TIMx_CR.GATE_EN 控制。默认门控功能关闭。
- 门控电平选择使用 TIMx_CR.GATE_P 控制。默认高电平为门控有效电平;设置为 1 后门控有效电平是低电平。定时功能可以配置预除频。TIMx_CR.TMR_PRE 控制分频比。
(1) Buzzer 功能
- 通过定时器的翻转输出功能可以实现驱动 Buzzer 的功能。TIMx_CR.TOG_EN 为 1 时,TOG、TOGN输出反向。
- 设置 TIMx_CR.TOG_EN 为 0 可以同时设置端口 TOG、TOGN 输出为 0。
- 在计数时钟为4M 情况下 Buzzer 输出不同频率的 Timer 重载模式配置如下(16 位 Max=0xFFFF):
三、示例代码(PWM)
/********************************************************************************
* @file bsp_tim.c
* @author jianqiang.xue
* @version V1.1.0
* @date 2023-02-26
* @brief 本文件不再初始化GPIO,由APP_IO完成引脚初始化和复用。
********************************************************************************/
/* Public Includes ------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "RTE_Components.h"
#include CMSIS_device_header
#include "bsp_gpio.h"
#include "bsp_tim.h"
#include "cx32l003_hal_basetim.h"
/* Private Includes ----------------------------------------------------------*/
#include "ls_gpio.h"
#include "ls_syscfg.h"
/* Private Define ------------------------------------------------------------*/
/* Private Typedef -----------------------------------------------------------*/
#if LS_TIM10_EN
BASETIM_HandleTypeDef *g_tim10_handle = NULL;
static uint8_t g_tim10_pwm_update_cnt = 0;
static bsp_base_tim_cfg_t *g_tim10_cfg = NULL;
#endif
/* Public function prototypes -----------------------------------------------*/
#if LS_TIM10_EN
#include "ls_gpio.h"
#include "ls_syscfg.h"
/**
* @brief TIM10初始化
* @param *cfg: 基础定时器配置
* @retval 0--成功
*/
uint8_t bsp_tim10_init(bsp_base_tim_cfg_t *cfg) {
if (g_tim10_handle) return 0; // 已经初始化过
if (cfg == NULL) return 3; // 配置为空
g_tim10_handle = malloc(sizeof(BASETIM_HandleTypeDef)); // 申请空间
if (!g_tim10_handle) return 1; // TIM结构体无法申请空间
memset(g_tim10_handle, 0, sizeof(BASETIM_HandleTypeDef));
// 结构体赋值
g_tim10_handle->Instance = TIM10;
g_tim10_handle->Init.CntTimSel = BASETIM_TIMER_SELECT; // CKD 时钟分频因子(Clock division)
g_tim10_handle->Init.MaxCntLevel = BASETIM_MAXCNTLEVEL_16BIT; // TimerSize=0:max count value=0xFFFF;
g_tim10_handle->Init.AutoReload = BASETIM_AUTORELOAD_ENABLE; // 模式2自动重装载计数器/定时器
g_tim10_handle->Init.OneShot = BASETIM_REPEAT_MODE; // 重复模式
g_tim10_handle->Init.Period = BASETIM_MAXCNTVALUE_16BIT - HAL_RCC_GetPCLKFreq()/cfg->period; // 重装载值 cfg->period
g_tim10_handle->Init.Prescaler = cfg->prescaler; // 预分频 cfg->prescaler
g_tim10_cfg = cfg;
__HAL_RCC_BASETIM_CLK_ENABLE();
HAL_BASETIM_Base_Init(g_tim10_handle);
HAL_NVIC_EnableIRQ(TIM10_IRQn);
return 0;
}
void bsp_tim10_set_pwm(uint8_t io, uint8_t val) {
if (g_tim10_cfg == NULL) return;
HAL_BASETIM_Base_Stop_IT(g_tim10_handle);
if (g_tim10_cfg->io != io) {
g_tim10_cfg->io = io;
}
if (g_tim10_cfg->cnt != val) {
g_tim10_cfg->cnt = val;
}
if (io != 0xff) {
HAL_BASETIM_Base_Start_IT(g_tim10_handle);
}
}
void TIM10_IRQHandler(void) {
/* TIM Update event */
if (__HAL_BASETIM_GET_FLAG(g_tim10_handle) != RESET) {
if (__HAL_BASETIM_GET_IT_SOURCE(g_tim10_handle) != RESET) {
__HAL_BASETIM_CLEAR_IT(g_tim10_handle);
if (g_tim10_cfg == NULL) return;
if (g_tim10_cfg->io == 0xFF) {
HAL_BASETIM_Base_Stop_IT(g_tim10_handle);
return;
}
if (g_tim10_pwm_update_cnt++ < g_tim10_cfg->cnt) {
bsp_gpio_set_pin(g_io_cfg[g_tim10_cfg->io].port, g_io_cfg[g_tim10_cfg->io].pin, BSP_GPIO_PIN_SET);
} else if (g_tim10_pwm_update_cnt < g_tim10_cfg->period - g_tim10_cfg->cnt) {
bsp_gpio_set_pin(g_io_cfg[g_tim10_cfg->io].port, g_io_cfg[g_tim10_cfg->io].pin, BSP_GPIO_PIN_RESET);
} else {
g_tim10_pwm_update_cnt = 0;
}
}
}
}
#endif
/********************************************************************************
* @file bsp_tim.c
* @author jianqiang.xue
* @version V1.1.0
* @date 2023-02-26
* @brief 本文件不再初始化GPIO,由APP_IO完成引脚初始化和复用。
********************************************************************************/
#ifndef __BSP_TIM_H
#define __BSP_TIM_H
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include "ls_syscfg.h"
/* Private Define ------------------------------------------------------------*/
typedef struct {
uint16_t prescaler; // 预分频器的值(Prescaler value) 计数器的时钟频率(CK_CNT)等于 fCK_PSC/(PSC[15:0]+1)。
uint16_t freq; // 单位hz,freq对应的period: 750--15 1000--20 1500--30 2000--40 3000--60 6000--120
uint16_t period; // 周期 作为PWM时,决定了PWM的分辨率
uint8_t level_logic; // 有效电平 0--低电平 1--高电平
uint8_t io; // IO_ID
uint16_t cnt; // 计数器的值(Counter value)--CNT
} bsp_base_tim_cfg_t; // 模拟PWM
/* Private Typedef -----------------------------------------------------------*/
/* Public Function Prototypes ------------------------------------------------*/
#if LS_TIM10_EN
uint8_t bsp_tim10_init(bsp_base_tim_cfg_t *cfg);
void bsp_tim10_set_pwm(uint8_t io, uint8_t val);
#endif
#endif
#if LS_TIM10_EN
bsp_base_tim_cfg_t g_tim10_cfg = {
.prescaler = LS_TIM10_PRESCALER,
.freq = LS_TIM10_FREQ,
.period = LS_TIM10_PERIOD,
.level_logic = LS_TIM10_LEVEL_LOGIC};
#endif
bsp_tim10_init(&g_tim10_cfg);
// 将LED0亮度设置50%
bsp_tim10_set_pwm(LED0, g_tim10_cfg.period/2);