STM32F1入门3-Timer




  • Hunto STM32培训系列
    文档及源码Github地址:hunto/learning_STM32


    STM32F1入门3 - Timer


    一、 Systick定时器

    1. 简介

    Cortex‐M3处理器内部包含了一个简单的定时器。因为所有的CM3芯片都带有这个定时器,软件在不同CM3器件间的移植工作得以化简。该定时器的时钟源可以是内部时钟,或者是外部时钟。不过,STCLK的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同,你需要查找芯片的器件手册来决定选择什么作为时钟源。Cortex-M3的内核中包含一个 SysTick 时钟。SysTick 为一个 24 位递减计数器,SysTick 设定初值并使能后,每经过 1 个系统时钟周期,计数值就减 1。计数到 0 时,SysTick 计数器自动重装初值并继续计数,同时内部的 COUNTFLAG 标志会置位,触发中断 (如果中断使能情况下)。


    2. Systick中寄存器

    名称 地址 类型
    STK_CTRL 0xE000E010 控制寄存器
    STK_LOAD 0xE000E014 重载寄存器
    STK_VAL 0xE000E018 当前值寄存器
    STK_CALRB 0xE000E01C 校准值寄存器

    2.1 STK_CTRL控制寄存器

    0_1530943461109_af9a7ba6-7650-4d25-9b92-9a0b8876b8a3-image.png

    • 第0位:ENABLE,Systick 使能位
      0:关闭Systick功能; 1:开启Systick功能
    • 第1位:TICKINT,Systick 中断使能位
      0:关闭Systick中断;1:开启Systick中断
    • 第2位:CLKSOURCE,Systick时钟源选择
      0:使用HCLK/8 作为Systick时钟;
      1:使用HCLK作为Systick时钟
    • 第16位:COUNTFLAG,Systick计数比较标志,如果在上次读取本寄存器后,SysTick 已经数到了0,则该位为1。如果读取该位,该位将自动清零

    2.2 STK_LOAD重载寄存器

    0_1530943504020_3a7a787c-6c10-423b-97b4-ec17d1cb67ff-image.png
    Systick是一个递减的定时器,当定时器递减至0时,重载寄存器中的值就会被重装载,继续开始递减。STK_LOAD 重载寄存器是个24位的寄存器最大计数0xFFFFFF。

    2.3 STK_VAL当前值寄存器

    0_1530943532243_11d292c8-cda3-4124-86fa-1616752dd92a-image.png
    也是个24位的寄存器,读取时返回当前倒计数的值,写它则使之清零,同时还会清除在SysTick 控制及状态寄存器中的COUNTFLAG 标志。


    3. 使用Systick实现延时功能

    • Systick初始化
      u32 fac_us;  // 延时1ns需要的滴答次数
      u16 fac_ms;  // 延时1ms需要的滴答次数
      void delay_init()
      {
          /* 选择外部时钟  HCLK/8 */
          SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);	
          /* 外部时钟为系统时钟的1/8 (8M晶振,CPU频率72M) */
          fac_us = SystemCoreClock / 8000000;	
          fac_ms = (u16)fac_us*1000;
      }	
      

    • 延时函数
      void delay_us(u32 nus)
      {		
          u32 temp;	    	 
          SysTick->LOAD = nus*fac_us; // 加载计数	  		 
          SysTick->VAL = 0x00; // 清空计数器
          SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk ; // 开始倒数
          do
          {
              temp = SysTick->CTRL;
          }while((temp & 0x01) && 
                 !(temp & (1 << 16)));	// 等待时间到达 
          SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;	// 关闭计数器
          SysTick->VAL = 0X00;  // 清空计数器	 
      }
      

    void delay_ms(u16 nms)
    {	 		  	  
        u32 temp;		   
        SysTick->LOAD=(u32)nms*fac_ms;				
        SysTick->VAL =0x00;						
        SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;
        do
        {
            temp=SysTick->CTRL;
        }while((temp&0x01)&&!(temp&(1<<16)));		  
        SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	
        SysTick->VAL =0X00;       				 	    
    } 
    

    二、 STM32定时器

    STM32中一共有11个定时器,其中2个高级控制定时器,4个通用定时器和2个基本定时器,以及2个看门狗定时器和1个系统嘀嗒定时器。其中系统嘀嗒定时器是前文中所描述的SysTick。


    定时器 计数器分辨率 计数器类型 预分频系数 产生DMA请求 捕获/比较通道 互补输出
    TIM1 16位 向上、向下、向上/向下 1-65536之间的任意数 可以 4
    TIM2<br>TIM3<br>TIM4<br>TIM5 16位 向上、向下、向上/向下 1-65536之间的任意数 可以 4 没有
    TIM6<br>TIM7 16位 向上 1-65536之间的任意数 可以 0 没有

    1. 通用定时器主要功能

    • 16位向上、向下、向上/ 向下自动装载计数器
    • 16位可编程(可以实时修改)预分频器,计数器时钟频率的
      分频系数为1~65536之间的任意数值
    • 4个独立通道:
      • 输入捕获
      • 输出比较
      • PWM生成(边缘或中间对齐模式)
      • 单脉冲模式输出

    2. 时钟来源

    计数器时钟可以由下列时钟源提供

    • 内部时钟(CK_INT)
    • 外部时钟模式1: 外部输入脚(TIx)
    • 外部时钟模式2: 外部触发输入(ETR)
    • 内部触发输入(ITRx): 使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器TIM1作为另一个定时器TIM2的预分频器

    3. 计数器模式

    TIM2-TIM5可以由向上计数、向下计数、向上向下双向计数。向上计数模式中,计数器从0计数到自动加载值(TIMx_ARR计数器内容),然后重新从0开始计数并且产生一个计数器溢出事件。在向下模式中,计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。而中央对齐模式(向上/向下计数)是计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。


    4. 使用通用定时器实现延时功能

    • TIM初始化
    #define SYSTICKPERIOD 1e-6
    #define SYSTICKFREQUENCY (1/SYSTICKPERIOD)
    void delay_init()
    {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
        /* 寄存器重载值 */
        TIM_TimeBaseStructure.TIM_Period = 999;  
        /* 预分频: 计数器+1时间为:预分频/CPU主频 */
        TIM_TimeBaseStructure.TIM_Prescaler = 
        	        SystemCoreClock / SYSTICKFREQUENCY - 1;
        /* 向上计数 */
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
        /* 使能TIMx 在 ARR 上的预装载寄存器 */
        TIM_ARRPreloadConfig(TIM2, ENABLE);
        /* 设置更新请求源只在计数器上溢或下溢时产生中断 */
        TIM_UpdateRequestConfig(TIM2, TIM_UpdateSource_Global);
        TIM_ClearFlag(TIM2, TIM_FLAG_Update);
    }
    

    • 延时函数
    void delay_ms(u16 nms)
    {	 		  	  
        /* 清零计数器 */
        TIM2->CNT = 0;
        TIM_Cmd(TIM2, ENABLE);
    	
        for (int n = 0; n < nms; n++) {
            /* 等待一个延时单位结束 */
            while (TIM_GetFlagStatus(TIM2, TIM_FLAG_Update) != SET) ;
                TIM_ClearFlag(TIM2, TIM_FLAG_Update);
        } 
        TIM_Cmd(TIM2, DISABLE);
    } 
    

 

Copyright © 2018 bbs.dian.org.cn All rights reserved.

与 Dian 的连接断开,我们正在尝试重连,请耐心等待