滴答定时器:

定时器的本质就是计数器。我们设置一个定值,然后计数器开始计数,从我们给的定值开始往下一直数,当数到0时,就做相应的动作(也可以不做什么,当把它用作延时计时的时候)。

滴答定时器systick是一个内核外设(即:内核自带的)

所以在《STM32F10xxx参考手册中文版.pdf》手册中没有相关描述,我们需要参考内核手册
《STM32F10xxx20xxx21xxxL1xxxx Cortex-M3 programming manual.pdf》

Systick是一个24bit的系统定时器(stm32F407的寄存器名字与位数都与f103一样,但是有些芯片定时器位数不同),向下计数(从定值开始数到0),当计数到0时,在下一个时钟边沿,会重复计数。所以如果我们用完定时器后,不再继续使用它时,记得要将定时器关掉,否则它就一直在重复计数,增加了功耗。

Systick的作用
1.产生一个精准的定时
2.FreeRTOS时基由Systick提供

在说定时器前,我们先来看一看如何计数?

频率:f = 9Mhz = 9*10^6/s(即:需要计数9百万下,才能花费1s时间)

周期:T = 1/f = 1/9M = = 111.111ns(即:计数1下,需要花费111.111ns时间)

我们知道,需要计数1下,需要花费秒的时间。那么我们只计数9000下呢?需要花费多少秒?

即:   *  9000  =    秒 = 1ms(毫秒),所以,在频率为9Mhz时,如果我们要想1ms延时,就计数9000下。

那么我们只计数9下呢?需要花费多少秒?

 *  9  =   秒  =  1us(微秒),所以,在频率为9Mhz时,如果我们要想1us延时,就计数9下。

所以,不管计数器需要计数多少值,我们只需要记住,  =  1ms ,   =  1us。

配置滴答定时器:

红框中就是滴答定时器的时钟,我们可以看到分频系数为8,所以滴答定时器的频率为:72M/8 = 9Mhz

配置滴答定时器我们需要下面几个寄存器:

注意:第16位,是定时完成标志位,每当计数到0时,该标志位就会置1。

注意:由于定时器是24位的,所以给定时器装载的定值是有一个范围的,红框中就是范围,范围为0x000001 ~ 0xFFFFFF

即:1~     也就是:1 ~ 16,777,215,如果填入的定值不是在0x000001 ~ 0xFFFFFF这个范围,则无法定时计数。

编程

产生Nms定时编程步骤:
        1》配置时钟源---AHB8分频,并且关闭定时器-----初始化(while(1)之前)
        2》设置计数值---N*9000
        3》清除当前值寄存器----注意:清除当前值寄存器,STK_CTRL寄存器的第16位会自动清0
        4》打开定时器
        5》等待定时器结束
        6》关闭定时器

代码:

uint32_t fu_ms;  // 1ms需要计的次数
uint32_t fu_us;  // 1us需要计的次数

void Systick_Config(uint32_t Sysclk)        //Sysclk就是系统时钟频率72Mhz,但是这里用72表示72Mhz
{
    // 1》配置时钟源---AHB8分频,并且关闭定时器-----初始化(while(1)之前)
    SysTick->CTRL  &=~0x05;        //这里关闭定时器的原因是,有可能之前没有关闭,所以一开始先将其关闭,再进行配置

fu_us  =Sysclk/8;                // 72/8 = 9,即:表示9Mhz
    fu_ms  =fu_us*1000;        //9*1000 = 9000,由前面知道,在9Mhz下,计数9000次为1ms
}

// 定时Nms程序,ms级延时
void Systick_NmsDelay(uint32_t Nms)
{
    uint32_t temp;
    // 2》设置计数值---N*9000
    SysTick->LOAD =Nms * fu_ms;

// 3》清除当前值寄存器----因为清除当前值寄存器,STK_CTRL的第16位(定时完成标志位)就会自动清0
    SysTick->VAL =0;        //清除标志位

// 4》打开定时器
    SysTick->CTRL |=0x01;

// 5》等待定时器结束
    do{
        temp=SysTick->CTRL;        
    }while(!(temp&(1<<16)));        //判断CTRL寄存器第16位是否为1。如果为1,则说明计数数到0了,此时计数完成

// 6》关闭定时器
    SysTick->CTRL &=~0x01;
}

解析:

1.我们先来看程序,定时器程序为什么被分成  Systick_Config(uint32_t Sysclk)  、Systick_NmsDelay(uint32_t Nms)两部分来写?

因为,Systick_Config(uint32_t Sysclk) 中的配置,在整个程序中只需要被初始化一次就行了,而Systick_NmsDelay(uint32_t Nms)是延时函数,它会被多次使用。如果将Systick_Config(uint32_t Sysclk)与Systick_NmsDelay(uint32_t Nms)写在一起的话,那么多次调用该函数时,原本只需要被初始化一次的语句,就会被多次执行,浪费CPU资源。

2.为什么程序中的这部分需要用do.....while而不用while()?

这里需要用do....while而不用while,是因为需要先执行temp = SysTick->CTRL; 将SysTick->CTRL寄存器中的值赋值给变量temp,然后再对temp进行真假判断,即:!(temp&(1<<16))。temp&(1<<16)为读取SysTick->CTRL中的第16位是1还是0,如果第16位是1,则为真,但是由于非 "!" 的存在,所以 ! (temp & (1<<16))就为假,所以此时do.....while循环不再循环下去。如果第16位是0,则为假,但是由于非 "!" 的存在,所以 ! (temp & (1<<16))为真,所以此时do.....while循环将继续循环下去。等到第16位变为1,也就是定时完成标志位置1时,如上所述,while循环将不再循环下去,此时计数器计数完成。

3.  由上面知滴答定时器的计数器是24位的,其计数范围为 0x000001 ~ 0xFFFFFF ,即:1 ~ 16,777,215,那么如果我需要计的数超过了这个范围呢?我该怎么办?

由前面知,计数9000下,延时1ms。所以,16,777,215可以延时1864ms,即:  =  1864 。也就是说,在9Mhz频率下,将计数器计满,可以实现延时1864ms。

的确,如果我想要延时2000ms,那么由于超过计数器的计数范围,那么滴答定时器就不会正常工作了。

所以,我们改下一下程序:

// 定时Nms程序
void Systick_NmsDelay(uint32_t Nms)
{
    uint8_t  systick_flag=0;
    uint32_t temp;

while(0==systick_flag){

if(Nms>1864){
            SysTick->LOAD =1864 * fu_ms;
            Nms =Nms -1864;
        }else{
            // 2》设置计数值---N*9000
            SysTick->LOAD =Nms * fu_ms;
            systick_flag=1;
         }

// 3》清除当前值寄存器----因为清除当前值寄存器,STK_CTRL的第16位会清0
        SysTick->VAL =0;

// 4》打开定时器
        SysTick->CTRL |=0x01;

// 5》等待定时器结束
        do{
            temp=SysTick->CTRL;
        }while(!(temp&(1<<16)));

// 6》关闭定时器
        SysTick->CTRL &=~0x01;

}

}

这样的话,就解决了1864问题了。

4.us级的延时程序是什么?

// 定时Nus程序
void Systick_NusDelay(uint32_t Nus)
{
    uint32_t temp;
    // 2》设置计数值---N*9
    SysTick->LOAD =Nus * fu_us;        //us与ms的程序就只有这里改变了

// 3》清除当前值寄存器----因为清除当前值寄存器,STK_CTRL的第16位会清0
    SysTick->VAL =0;

// 4》打开定时器
    SysTick->CTRL |=0x01;

// 5》等待定时器结束
    do{
        temp=SysTick->CTRL;
    }while(!(temp&(1<<16)));

// 6》关闭定时器
    SysTick->CTRL &=~0x01;
}

注意:

在FreeRTOS操作系统中,不能使用我们自己设置的Systick来进行延时,因为FreeRTOS时基是由Systick提供(裸机的时基是由晶振提供的)。这是什么意思?

FreeRTOS时基是由Systick提供,时基是需要保持不变的,所以Systick寄存器中的值必须是固定的,是不允许被修改的。但是,如果我们在FreeRTOS中用我们手动设置的Systick来进行延时,我们必定会去修改Systick寄存器中的值来得到我们需要的延时。所以,此时如果在FreeRTOS中使用我们手动设置的Systick去进行延时,那么就会卡死。解决办法:使用软件延时,delay()函数来代替Systick延时。代码如下:

//初始化延迟函数
//SYSTICK的时钟固定为AHB时钟,基础例程里面SYSTICK时钟频率为AHB/8
//这里为了兼容FreeRTOS,所以将SYSTICK的时钟频率改为AHB的频率!
//SYSCLK:系统时钟频率
void delay_init(u8 SYSCLK)
{
    u32 reload;
     SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); 
    fac_us=SYSCLK;                            //不论是否使用OS,fac_us都需要使用
    reload=SYSCLK;                            //每秒钟的计数次数 单位为M       
    reload*=1000000/configTICK_RATE_HZ;        //根据configTICK_RATE_HZ设定溢出时间
                                            //reload为24位寄存器,最大值:16777216,在168M下,约合0.0998s左右    
    fac_ms=1000/configTICK_RATE_HZ;            //代表OS可以延时的最少单位       
    SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;//开启SYSTICK中断
    SysTick->LOAD=reload;                     //每1/configTICK_RATE_HZ断一次    
    SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK     
}

//延时nus
//nus:要延时的us数.    
//nus:0~204522252(最大值即2^32/fac_us@fac_us=168)                                           
void delay_us(u32 nus)
{        
    u32 ticks;
    u32 told,tnow,tcnt=0;
    u32 reload=SysTick->LOAD;                //LOAD的值             
    ticks=nus*fac_us;                         //需要的节拍数 
    told=SysTick->VAL;                        //刚进入时的计数器值
    while(1)
    {
        tnow=SysTick->VAL;    
        if(tnow!=told)
        {        
            if(tnow<told)tcnt+=told-tnow;    //这里注意一下SYSTICK是一个递减的计数器就可以了.
            else tcnt+=reload-tnow+told;        
            told=tnow;
            if(tcnt>=ticks)break;            //时间超过/等于要延迟的时间,则退出.
        }  
    };                                            
}

//延时nms
//nms:要延时的ms数
//nms:0~65535
void delay_ms(u32 nms)
{    
    if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
    {        
        if(nms>=fac_ms)                        //延时的时间大于OS的最少时间周期 
        { 
               vTaskDelay(nms/fac_ms);             //FreeRTOS延时
        }
        nms%=fac_ms;                        //OS已经无法提供这么小的延时了,采用普通方式延时    
    }
    delay_us((u32)(nms*1000));                //普通方式延时
}

//延时nms,不会引起任务调度
//nms:要延时的ms数
void delay_xms(u32 nms)
{
    u32 i;
    for(i=0;i<nms;i++) delay_us(1000);
}

stm32f103——滴答定时器相关推荐

  1. [STM32F1]STM32F103滴答定时器定时不准?)

    STM32F103滴答定时器定时不准?       前几天调了1块F103ZET6的开发板,用了个系统定时器,感觉不准,最终找到原因是因为选错了时钟源. 今天来分享一下也算是给大家以后出现问题做个参考 ...

  2. STM32系统滴答定时器(systick)应用

    一:系统滴答定时器(systick) 1.systick介绍 Systick就是一个定时器而已,只是它放在了NVIC中,主要的目的是为了给操作系统提供一个硬件上的中断(号称滴答中断).滴答中断?这里来 ...

  3. stm32系统滴答定时器使用

     STM32菜鸟成长记录---系统滴答定时器(systick)应用 标签: delay任务测试reference编译器工作 2012-08-19 22:55 47395人阅读 评论(4) 收藏 举 ...

  4. stm32滴答计时器_stm32中的系统滴答定时器使用

    系统滴答定时器对于stm32的初学者来说还是非常重要的,因为随着你学习的深入编程过程中肯定会调用延时函数,比如我之前的一些gpio相关的实验中.那么延时函数的编写也是几种方法的,一般开始接触都是让系统 ...

  5. Systick滴答定时器寄存器、delay()延时函数、SysTick_Config函数

    SysTick定时器 SysTick定时器,是一个简单的定时器,对于CM3.CM4内核的芯片都有SysTick定时器.SysTick 是一个 24 位的倒计数定时器,当计数到 0 时,将从RELOAD ...

  6. STM32——系统滴答定时器

    STM32--系统滴答定时器 宗旨:技术的学习是有限的,分享的精神是无限的. 一.SysTick[内核中] [风格:先描述一下库对寄存器的封装,再举例实现某些功能] SysTick定时器被捆绑在NVI ...

  7. 滴答定时器的计数模式_【高手私藏】STM32学习笔记:SysTick滴答时钟

    今天我们来说说SysTick定时器.SysTick定时器在从参考手册中根本没有介绍.我费了九牛二虎之力才在一个犄角格拉里找到SysTick定时器的英文版的说明.在Cotex-M3有介绍,为什么要找ST ...

  8. STM32-Systick滴答定时器-延时函数

    1.STM32-Systick滴答定时器 Systick定时器,是一个简单的定时器,对于ST的CM3,CM4,CM7内核芯片,都有Systick定时器. Systick定时器常用来做延时,或者实时系统 ...

  9. 定时器开始时延时了十几秒_第六章--系统滴答定时器

    第六章--系统滴答定时器 简介:系统滴答定时器是内核(这里指M4)定时器使用的是内核时钟源168MZ或可以选择外部时钟源21MZ 应用场合: 为UCOS系统提供时钟节拍 作为简单的定时器延时使用 // ...

最新文章

  1. python软件代码示例-用Python写一个模拟qq聊天小程序的代码实例
  2. wxWidgets:wxMDIChildFrame类用法
  3. Python爬虫学习二
  4. 前端学习(685):循环的目的
  5. Jenkins 配置邮箱 530Authentication required ,535 uthentication failed 的解决方法
  6. [Common 17-39] ‘connect_bd_intf_net‘ failed due to earlier errors. 的解决办法
  7. 自己动手修改VB.NET支付宝接口
  8. javaee版eclipse导包出现未找到类问题
  9. Java知识梳理——可达性分析方法原理 finalize
  10. Go语言(golang)的错误(error)处理的推荐方案
  11. oracle 11203 ora32701,love wife love life —Roger的Oracle/MySQL数据恢复博客
  12. 关于svn(客户端)在安装完成过程中所遇到的一点问题
  13. 校验集装箱号合法性-php版
  14. (附源码)ssm基于WEB的房屋出租管理系统 毕业设计261620
  15. JSteg信息隐藏算法
  16. 申请实用新型专利的流程
  17. explain mysql using filesort:_Mysql之EXPLAIN显示using filesort
  18. 手机电视的概念及其发展状况
  19. QMetaObjectPrivate meta_constractors Q_INVOKABLE
  20. Google Earth Engine(GEE) 01-中输入提示快捷键Ctrl+space无法使用的问题

热门文章

  1. 阿里巴巴改变了什么?
  2. 分布式系统的“流言蜚语”
  3. 7-1 删除字符串中的子串 (20分)
  4. B1016 部分A+B
  5. 开源BI报表及OLAP多维分析平台OPENI(一)—DEMO演示
  6. 微信公众号服务器配置 --接口 nodejs实现方法
  7. xamarin android 报错 Could not load assembly 'Xamarin.Android.Support.v7.AppCompat
  8. 网易蜂巢(现已更名为网易云计算基础服务)用了什么技术?
  9. 陪你读书之《R语言实战》
  10. 半路出家: 如何转行成为软件开发者