查看: 5626|回复: 8

STM32系列M3 的几种延时方法---基于MDK固件库--使用8MHZ晶振

[复制链接]
  • TA的每日心情
    奋斗
    2016-8-25 12:42
  • 签到天数: 692 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2012-11-3 10:25:36 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 fengye5340 于 2012-11-3 10:28 编辑

                        STM32系列M3的几种延时方法
    单片机编程过程中经常用到延时函数,最常用的莫过于微秒级延时delay_us( )和毫秒级delay_ms( )
    一、普通延时法
    这个比较简单,让单片机做一些无关紧要的工作来打发时间,经常用循环来实现,不过要做的比较精准还是要下一番功夫。下面的代码是在网上搜到的,经测试延时比较精准。
    //粗延时函数,微秒
    void delay_us(u16 time)
    {   
       u16 i=0;  
       while(time--)
       {
          i=10;  //自己定义
          while(i--) ;   
       }
    }
    //毫秒级的延时
    void delay_ms(u16 time)
    {   
       u16 i=0;  
       while(time--)
       {
          i=12000;  //自己定义
          while(i--) ;   
       }
    }
    SysTick 定时器延时
    CM3 内核的处理器,内部包含了一个SysTick 定时器,SysTick 是一个24 位的倒计数定时器,当计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息。SysTick STM32 的参考手册里面介绍的很简单,其详细介绍,请参阅《Cortex-M3 权威指南》。
    这里面也有两种方式实现
    二、中断方式
    如下,定义延时时间time_delaySysTick_Config()定义中断时间段,在中断中递减time_delay,从而实现延时。
    volatile unsigned long time_delay; // 延时时间,注意定义为全局变量
    //延时n_ms
    void delay_ms(volatile unsigned long nms)
    {
        //SYSTICK分频--1ms的系统时钟中断
        if (SysTick_Config(SystemFrequency/1000))
        {
       
            while (1);
        }
        time_delay=nms;//读取定时时间
        while(time_delay);
        SysTick->CTRL=0x00; //关闭计数器
        SysTick->VAL =0X00; //清空计数器
    }
    //延时nus
    void delay_us(volatile unsigned long nus)
    {
    //SYSTICK分频--1us的系统时钟中断
        if (SysTick_Config(SystemFrequency/1000000))
        {
       
            while (1);
        }
        time_delay=nus;//读取定时时间
        while(time_delay);
        SysTick->CTRL=0x00; //关闭计数器
        SysTick->VAL =0X00; //清空计数器
    }
        //在中断中将time_delay递减。实现延时
    void SysTick_Handler(void)
    {
        if(time_delay)
            time_delay--;
    }

    这里:SystemFrequency = 72MHZ/48MHZ(常用)
    三、非中断方式
    主要仿照原子的《STM32不完全手册》。SYSTICK 的时钟固定为HCLK 时钟的1/8,在这里我们选用内部时钟源72M,所以SYSTICK的时钟为9M,即SYSTICK定时器以9M的频率递减。SysTick 主要包含CTRLLOADVALCALIB 4 个寄存器,
    SysTick->CTRL
    位段
    名称
    类型
    复位值
    描述
    16
    COUNTFLAG
    R
    0
    如果在上次读本寄存器后systick已为0,则该位为1,若 读该位自动清零
    2
    CLKSOURCE
    RW
    0
    0:外部时钟源 1:内部时钟
    1
    TICKINT
    RW
    0
    0:减到0无动作;1:减到0产生systick异常请求
    0
    ENABLE
    RW
    0
    systick定时器使能位


    SysTick-> LOAD
    位段
    名称
    类型
    复位值
    描述
    23:0
    RELOAD
    RW
    0
    减到0时被重新装载的值
    SysTick-> VAL
    位段
    名称
    类型
    复位值
    描述
    23:0
    CURRENT
    RW
    0
    读取时返回当前倒计数的值,写则清零,同时还会清除在systick控制及状态寄存器中的COUNTFLAG 标志
    SysTick-> CALIB 不常用,在这里我们也用不到,故不介绍了。
    程序如下,相当于查询法。
    //仿原子延时,不进入systic中断
    void delay_us(u32 nus)
    {
    u32 temp;
    SysTick->LOAD = 9*nus;
    SysTick->VAL=0X00;//清空计数器
    SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
    do
    {
      temp=SysTick->CTRL;//读取当前倒计数值
    }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
         SysTick->CTRL=0x00; //关闭计数器
        SysTick->VAL =0X00; //清空计数器
    }
    void delay_ms(u16 nms)
    {
    u32 temp;
    SysTick->LOAD = 9000*nms;
    SysTick->VAL=0X00;//清空计数器
    SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
    do
    {
      temp=SysTick->CTRL;//读取当前倒计数值
    }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
        SysTick->CTRL=0x00; //关闭计数器
        SysTick->VAL =0X00; //清空计数器
    }
    三种方式各有利弊,第一种方式容易理解,但不太精准。第二种方式采用库函数,编写简单,由于中断的存在,不利于在其他中断中调用此延时函数。第三种方式直接操作寄存器,看起来比较繁琐,其实也不难,同时克服了以上两种方式的缺点,个人感觉比较好用。

    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2016-8-26 01:52
  • 签到天数: 120 天

    连续签到: 1 天

    [LV.7]常住居民III

    发表于 2012-11-3 11:44:11 | 显示全部楼层
    学习学习{:soso_e183:}{:soso_e113:}
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2016-8-25 12:42
  • 签到天数: 692 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2012-11-3 12:29:30 | 显示全部楼层
    Kite 发表于 2012-11-3 11:44
    学习学习

    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    2016-12-20 15:08
  • 签到天数: 510 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2012-11-3 23:51:22 | 显示全部楼层
    恩,第三种比较不错,要学习下
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2016-8-25 12:42
  • 签到天数: 692 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2012-11-4 08:14:02 | 显示全部楼层
    ming1006 发表于 2012-11-3 23:51
    恩,第三种比较不错,要学习下

    对STM32刚接触不久,还是要慢慢学的,有空多交流啊!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    2016-12-20 15:08
  • 签到天数: 510 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2012-11-4 10:06:26 | 显示全部楼层

    RE: STM32系列M3 的几种延时方法---基于MDK固件库--使用8MHZ晶振

    fengye5340 发表于 2012-11-4 08:14
    对STM32刚接触不久,还是要慢慢学的,有空多交流啊!

    我也是初学者
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2016-8-25 12:42
  • 签到天数: 692 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2012-11-4 12:39:11 | 显示全部楼层
    ming1006 发表于 2012-11-4 10:06
    我也是初学者

    那就好好交流,共同进步,呵呵
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    2016-12-20 15:08
  • 签到天数: 510 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2012-11-4 12:56:18 | 显示全部楼层
    fengye5340 发表于 2012-11-4 12:39
    那就好好交流,共同进步,呵呵

    恩,最近也在学习PSoC,因为试用期一个月,所以中心暂时会在PSoC上
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2012-11-9 23:45
  • 签到天数: 3 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    发表于 2012-11-6 00:33:14 | 显示全部楼层
    写得不错,学习了
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-5-15 18:58 , Processed in 0.184886 second(s), 31 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.