打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

LiSun

打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

一、基础定时器介绍

基础定时器 Base Timer 包含两个定时器 TIM10/11。TIM10/11 功能完全相同。TIM10/11 是同步定时/计数器,可以作为 16/32 位自动重装载功能的定时/计数器,也可以作为16/32 位无重载功能的定时/计数器。TIM10/11 可以对外部脉冲进行计数或者实现系统定时。

在这里插入图片描述

二、功能描述

  1. TIM10/11 每个定时/计数器都有独立的控制启动信号、外部输入时钟和门控信号。
    当 TIM10/11 使用 EXT、GATE 来进行计数功能时,EXT 用于计数器的外部输入时钟信号,GATE 用于有效电平计数使能信号。
  2. 当门控功能使能后,当且仅当外部输入 GATE 电平有效时,计数器才会计数,否则计数器处于保持状态。
  3. 门控使能使用 TIMx_CR.GATE_EN 控制。默认门控功能关闭。
  4. 门控电平选择使用 TIMx_CR.GATE_P 控制。默认高电平为门控有效电平;设置 TIMx_CR.GATE_P 为 1后,门控低电平为有效电平。
  5. 当 TIM10/11 使用 PCLK,GATE 来进行定时功能时,PCLK 用于定时器的内部输入时钟信号,GATE可用于有效电平定时使能信号。
  6. 当门控功使能后,当且仅当外部输入 GATE 电平有效时,定时器才会计数,否则定时器处于定时计数器停止状态。
  7. 门控使能使用 TIMx_CR.GATE_EN 控制。默认门控功能关闭。
  8. 门控电平选择使用 TIMx_CR.GATE_P 控制。默认高电平为门控有效电平;设置为 1 后门控有效电平是低电平。定时功能可以配置预除频。TIMx_CR.TMR_PRE 控制分频比。

(1) Buzzer 功能

  1. 通过定时器的翻转输出功能可以实现驱动 Buzzer 的功能。TIMx_CR.TOG_EN 为 1 时,TOG、TOGN输出反向。
  2. 设置 TIMx_CR.TOG_EN 为 0 可以同时设置端口 TOG、TOGN 输出为 0。
  3. 在计数时钟为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);
posted on 2023-04-23 21:00  xuejianqiang  阅读(45)  评论(0编辑  收藏  举报  来源
打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033