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 小时前
基于单片机智能水产养殖系统设计(论文+源码)
单片机·嵌入式硬件·毕业设计·毕设
xiaomin201710 小时前
【STM32 HAL库】高级定时器TIM8输出PWM
stm32·单片机·嵌入式硬件
沐欣工作室_lvyiyi11 小时前
基于单片机的小型农业气象监测系统(论文+源码)
单片机·嵌入式硬件·物联网·毕业设计·气象监测
飞猿_SIR12 小时前
基于海思Hi3798MV200Android7.0聊聊HDMI色深模式和电视HDR
android·嵌入式硬件·音视频
范纹杉想快点毕业13 小时前
单片机开发中的队列数据结构详解,队列数据结构在单片机软件开发中的应用详解,C语言
c语言·数据库·stm32·单片机·嵌入式硬件·mongodb·fpga开发
三佛科技-1341638421213 小时前
鼻毛修剪器MCU方案开发设计
单片机·嵌入式硬件·智能家居·pcb工艺
btzhy15 小时前
STM32单片机:外设时钟(STM32L4xx)
stm32·单片机·嵌入式硬件·外设时钟
三佛科技-1341638421217 小时前
FT8430-LRT非隔离5V100MA电源芯片,满足小家电、智能照明、MCU供电需求,替代阻容降压(典型案例,电路图)
单片机·嵌入式硬件·智能家居
HPT_Lt18 小时前
ZCC5515_耐压9.5V ,超低静态功耗5uA,完全替代CS5515
嵌入式硬件