STM32单片机:基本定时器应用:精确定时(STM32L4xx)

STM32单片机的基本定时器的功能比较简单,但提供精确的定时是其基本功能,这个是能轻松做到的。

应用程序中可以利用基本定时器为系统提供精确的定时,为某些需要定时完成的一些任务提供时间基准。

比如应用程序中需要每隔200ms刷新一下显示,每隔50ms刷新一下某个开关量输出,那么可以设计定时器的中断时间为10ms。再针对每个需要定时执行的任务设置一个计数器,比如针对刷新显示定义一个刷新显示计数器 ,针对开关量输出定义一个开关量输出计数器

当每次进中断时,刷新显示计数器+1,开关量输出计数器+1,当刷新显示计数器=20时(20*10ms = 200ms),置位**(刷新显示的标志)** ,当开关量输出计数器=5时(5*10ms = 50ms),置位(开关量输出的标志)

主程序循环检查这些标志位是否置位,如检测到标志置位则调用相关程序:如刷新显示,开关量输出,同时清除标志位,等待下次标志再次置位。从而完成这些定时执行的任务。


实例演示:TIM6每隔10ms产生一次中断,主程序每隔200ms刷新一次流水灯。


实施步骤:

1、打开TIM6的时钟使能:

参考本博主文章**《STM32单片机:外设时钟(STM32L4xx)》**

查阅芯片手册,TIM6的时钟由 APB1-PCLK1提供,所以将寄存器RCC_APB1ENR1.TIM6EN 置位即可使能TIM6的时钟:


2、设定合适的输入时钟频率:

本实验中TIM6的时钟源频率是36.864MHz,将其10分频**(TIM_PSC=9)**得到3.6864MHz,作为定时器的时钟频率,将定时器的溢出值设置为36864,溢出时间 = (36864 / 3.6864)us = 10000us = 10ms,当定时器计数到此值时溢出,产生中断。


实现的代码如下:

STM32L4xx_timer.h:定时器的寄存器定义

cpp 复制代码
#define TIM6             ((uint32_t)0x40001000)		// Basic timer 6
#define TIM7             ((uint32_t)0x40001400)		// Basic timer 7

#define TIM_CR1(timx)    REG32(timx + 0x00000000)   // TIMx control register 1
#define TIM_CR2(timx)    REG32(timx + 0x00000004)   // TIMx control register 2
#define TIM_DIER(timx)   REG32(timx + 0x0000000C)   // TIMx DMA/Interrupt enable register
#define TIM_SR(timx)     REG32(timx + 0x00000010)   // TIMx status register
#define TIM_EGR(timx)    REG32(timx + 0x00000014)   // TIMx event generation register
#define TIM_CNT(timx)    REG32(timx + 0x00000024)   // TIMx counter
#define TIM_PSC(timx)    REG32(timx + 0x00000028)   // TIMx prescaler
#define TIM_ARR(timx)    REG32(timx + 0x0000002C)   // TIMx auto-reload register

dev_tim6.c: 定时器TIM6初始化,以及TIM6中断服务程序

cpp 复制代码
uchar   uc_200ms_Flag;
uchar   uc_10ms_counter;

//---------------------------------------------------------------------------------------
// 初始化TIM6: 基本定时器(10ms中断一次)
//
// 时钟源:  APB1-PCLK1 = 18.432MHz【80 MHz Max】
//
// RCC_CFGR_PPRE1 的分频系数  = 1 时  CLK = APB1-PCLK1
// RCC_CFGR_PPRE1 的分频系数 != 1 时  CLK = APB1-PCLK1 * 2
// 因为: 本系统 RCC_CFGR_PPRE1 的分频系数 = RCC_CFGR_PPRE1_DIV4 , 不等于1
// 所以: CLK = APB1-PCLK1 * 2 = 18.432MHz * 2 = 36.864MHz
//---------------------------------------------------------------------------------------
void DEV_TIM6_Init(void)
{
    // 允许TIM6时钟
    RCC_APB1ENR1 |= RCC_APB1ENR1_TIM6EN;

    TIM_CR1(TIM6) = 0;

    // 定时器时钟 = 输入时钟 / (PSC+1) = 36.864MHz / 10 = 3.6864 MHz
    TIM_PSC(TIM6) = 9;

    // 定时10ms的计数值 = 10000 us * 3.6864 MHz = 36864
    TIM_ARR(TIM6) = 36864;

    // 清除更新中断标志
    TIM_SR(TIM6) = 0;

    // 允许更新中断
    TIM_DIER(TIM6) = 0;
    TIM_DIER(TIM6) |= TIM_DIER_UIE;

    // 启动TIM6计数器
    TIM_CR1(TIM6) |= TIM_CR1_CEN;

    // 开TIM6中断
    NVIC_EnableIRQ(TIM6_DAC_IRQn);
}

//-----------------------------------------------------------------------------
// TIM6中断服务程序
//
// TIM6中断时间 = 36864 / 3.6864 MHz = 10ms
//-----------------------------------------------------------------------------
void TIM6_DAC_IRQHandler(void)
{
    // 清除更新中断标志
    TIM_SR(TIM6) = 0;

    // 每10ms, 计数器+1
    uc_10ms_counter++;

    // 计数值达到20, 即每200ms, 标志uc_200ms_Flag置位, 主程序里处理uc_200ms_Flag标志
    if (uc_10ms_counter >= 20)
    {
        uc_10ms_counter = 0;
        uc_200ms_Flag = 1;
    }
}

main.c: 主程序

cpp 复制代码
extern uchar uc_200ms_Flag;

//-------------------------------------------------------------------------------------
// 本工程实现功能:
//
// 1. 启动外部高频晶体HSE(24.576MHz)
//
// 2. HSE作为PLL的输入时钟, 启动PLL模块(主PLL模块, PLLSAI1模块, PLLSAI2模块)
//
// 3. 将PA8配置成MCO, 用于将主PLL模块的输出时钟PLLCLK/16通过此引脚输出, 
//    用于测试PLL时钟是否正常工作
//
// 4. 选择主PLL模块的输出时钟PLLCLK作为系统时钟SYSCLK
//
// 5. 基本定时器TIM6每10ms中断一次, 设置一个计数器, 每次中断+1, 
//    计数到20时(即200ms), 刷新一次流水灯输出
//
// 6. 将PC6, PC7, PC8, PC9配置成普通IO输出, 并分别连接LED发光二极管, 显示流水灯, 
//    指示程序正常运行
//
// 本工程运行环境:  IAR for ARM 8.32.1
//
// 本工程运行MCU:   STM32L431RCT6
//
// 注: 上电后程序从DEV_RCC_Init()这个函数开始运行, 然后再运行main()
//
//-------------------------------------------------------------------------------------
void main(void)
{
    ulong   ul_LedData;

    DEV_GPIO_Init();

    DEV_TIM6_Init();

    ul_LedData = BIT(6);
    GPIO_ODR(GPIOC) = ~ul_LedData;

    while(1)
    {
        if (uc_200ms_Flag)
        {
            uc_200ms_Flag = 0;

            GPIO_ODR(GPIOC) = ~ul_LedData;

            ul_LedData <<= 1;

            if (ul_LedData & BIT(10))   ul_LedData = BIT(6);
        }
    }
}
相关推荐
南棱笑笑生8 分钟前
20251107给荣品RD-RK3588-MID开发板跑Rockchip的原厂Android13系统时适配8寸屏的CTP【使用荣品的DTS】
单片机·嵌入式硬件·rockchip
辛河14 分钟前
单片机 小结
单片机·嵌入式硬件
d111111111d26 分钟前
STM32外设学习--USART串口外设--学习笔记。
笔记·stm32·单片机·嵌入式硬件·学习
LCMICRO-1331084774637 分钟前
长芯微LPS5820完全P2P替代NCP51820,LPS5820 是一款高速半桥驱动器,可用来驱动半 桥功率拓扑的 GaN 功率管。
stm32·单片机·嵌入式硬件·fpga开发·硬件工程
思茂信息1 小时前
CST电动车EMC仿真(二)——电机控制器MCU的EMC仿真
开发语言·javascript·单片机·嵌入式硬件·cst·电磁仿真
李boyang2 小时前
软件I2C
单片机·嵌入式硬件·软i2c
Industio_触觉智能2 小时前
RK3588应用分享之国产化系统-开源鸿蒙OpenHarmony
嵌入式硬件·rk3588·openharmony·开源鸿蒙·触觉智能·arm主板·xts认证
夜月yeyue3 小时前
Linux 中断处理机制详解:上下半部、内核线程与中断线程化
linux·运维·单片机·嵌入式硬件·uboot·bootloard
从零点5 小时前
STM32电机运动控制的设计
stm32·嵌入式硬件
听风说ml7 小时前
STM32 GPIO【深度理解】
stm32·单片机·嵌入式硬件