目录

1、普通延时

2、定时器中断

3、查询定时器

4、汇编指令


单片机编程过程中经常用到延时函数,最常用的莫过于微秒级延时delay_us()和毫秒级delay_ms()。本文基于STM32F207介绍4种不同方式实现的延时函数。

1、普通延时

这种延时方式应该是大家在51单片机时候,接触最早的延时函数。这个比较简单,让单片机做一些无关紧要的工作来打发时间,经常用循环来实现,在某些编译器下,代码会被优化,导致精度较低,用于一般的延时,对精度不敏感的应用场景中。

//微秒级的延时
void delay_us(uint32_t delay_us)
{    volatile unsigned int num;volatile unsigned int t;for (num = 0; num < delay_us; num++){t = 11;while (t != 0){t--;}}
}
//毫秒级的延时
void delay_ms(uint16_t delay_ms)
{    volatile unsigned int num;for (num = 0; num < delay_ms; num++){delay_us(1000);}
}

上述工程源码仓库:https://github.com/strongercjd/STM32F207VCT6/tree/master/02-Template

2、定时器中断

定时器具有很高的精度,我们可以配置定时器中断,比如配置1ms中断一次,然后间接判断进入中断的次数达到精确延时的目的。这种方式精度可以得到保证,但是系统一直在中断,不利于在其他中断中调用此延时函数,有些高精度的应用场景不适合,比如其他外设正在输出,不允许任何中断打断的情况。

STM32任何定时器都可以实现,下面我们以SysTick 定时器为例介绍:

初始化SysTick 定时器:

/* 配置SysTick为1ms */
RCC_GetClocksFreq(&RCC_Clocks);
SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000);

中断服务函数:

void SysTick_Handler(void)
{TimingDelay_Decrement();
}
void TimingDelay_Decrement(void)
{if (TimingDelay != 0x00){ TimingDelay--;}
}

延时函数:

void Delay(__IO uint32_t nTime)
{TimingDelay = nTime;while(TimingDelay != 0);
}

上述工程源码仓库:https://github.com/strongercjd/STM32F207VCT6/tree/master/02-Template

3、查询定时器

为了解决定时器频繁中断的问题,我们可以使用定时器,但是不使能中断,使用查询的方式去延时,这样既能解决频繁中断问题,又能保证精度。

STM32任何定时器都可以实现,下面我们以SysTick 定时器为例介绍。

STM32的CM3内核的处理器,内部包含了一个SysTick定时器,SysTick是一个24位的倒计数定时器,当计到0时,将从RELOAD寄存器中自动重装载定时初值。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。

SYSTICK的时钟固定为HCLK时钟的1/8,在这里我们选用内部时钟源120M,所以SYSTICK的时钟为(120/8)M,即SYSTICK定时器以(120/8)M的频率递减。SysTick 主要包含CTRL、LOAD、VAL、CALIB 等4 个寄存器。

                                       ▼CTRL:控制和状态寄存器

                                       ▼LOAD:自动重装载除值寄存器

                                        ▼VAL:当前值寄存器

                                 ▼CALIB:校准值寄存器

使用不到,不再介绍

示例代码

void delay_us(uint32_t nus)
{uint32_t temp;SysTick->LOAD = RCC_Clocks.HCLK_Frequency/1000000/8*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(uint16_t nms)
{uint32_t temp;SysTick->LOAD = RCC_Clocks.HCLK_Frequency/1000/8*nms;SysTick->VAL=0X00;//清空计数器SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源do{temp=SysTick->CTRL;//读取当前倒计数值}while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达SysTick->CTRL=0x00; //关闭计数器SysTick->VAL =0X00; //清空计数器
}

上述工程源码仓库:https://github.com/strongercjd/STM32F207VCT6/tree/master/04-Delay

4、汇编指令

如果系统硬件资源紧张,或者没有额外的定时器提供,又不想方法1的普通延时,可以使用汇编指令的方式进行延时,不会被编译优化且延时准确。

STM32F207在IAR环境下

/*!*  @brief    软件延时 *  @param ulCount:延时时钟数*  @return none*  @note  ulCount每增加1,该函数增加3个时钟*/
void SysCtlDelay(unsigned long ulCount)
{__asm("    subs    r0, #1\n""    bne.n   SysCtlDelay\n""    bx      lr");
}

这3个时钟指的是CPU时钟,也就是系统时钟。120MHZ,也就是说1s有120M的时钟,一个时钟也就是1/120 us,也就是周期是1/120 us。3个时钟,因为执行了3条指令。

使用这种方式整理ms和us接口,在Keil和IAR环境下都测试通过。

/*120Mhz时钟时,当ulCount为1时,函数耗时3个时钟,延时=3*1/120us=1/40us*/
/*
SystemCoreClock=120000000us级延时,延时n微秒
SysCtlDelay(n*(SystemCoreClock/3000000));ms级延时,延时n毫秒
SysCtlDelay(n*(SystemCoreClock/3000));m级延时,延时n秒
SysCtlDelay(n*(SystemCoreClock/3));
*/#if defined   (__CC_ARM) /*!< ARM Compiler */
__asm void
SysCtlDelay(unsigned long ulCount)
{subs    r0, #1;bne     SysCtlDelay;bx      lr;
}
#elif defined ( __ICCARM__ ) /*!< IAR Compiler */
void
SysCtlDelay(unsigned long ulCount)
{__asm("    subs    r0, #1\n""    bne.n   SysCtlDelay\n""    bx      lr");
}#elif defined (__GNUC__) /*!< GNU Compiler */
void __attribute__((naked))
SysCtlDelay(unsigned long ulCount)
{__asm("    subs    r0, #1\n""    bne     SysCtlDelay\n""    bx      lr");
}#elif defined  (__TASKING__) /*!< TASKING Compiler */
/*无*/
#endif /* __CC_ARM */

上述工程源码仓库:https://github.com/strongercjd/STM32F207VCT6/tree/master/03-ASM

备注:

理论上:汇编方式的延时也是不准确的,有可能被其他中断打断,最好使用us和ms级别的延时,采用for循环延时的函数也是如此。采用定时器延时理论上也可能不准确的,定时器延时是准确的,但是可能在判断语句的时候,比如if语句,判断延时是否到了的时候,就在判断的时候,被中断打断执行其他代码,返回时已经过了一小段时间。不过汇编方式和定时器方式,只是理论上不准确,在实际项目中,这两种方式的精度已经足够高了。

点击查看本文所在的专辑,STM32F207教程

关注公众号,第一时间收到文章更新。评论区不能及时看到,需要交流可以到公众号沟通

STM32延时函数的四种方法相关推荐

  1. STM32延时函数的四种方法:普通延时(2种)、SysTick 定时器延时(2种)

    STM32延时函数的三种方法:普通延时.SysTick 定时器延时(1.中断方式:2.非中断方式) 单片机编程过程中经常用到延时函数,最常用的莫过于微秒级延时delay_us( )和毫秒级delay_ ...

  2. stm32延时us寄存器_STM32延时函数的四种方法

    关注.星标公众号,不错过精彩内容 单片机编程过程中经常用到延时函数,最常用的莫过于微秒级延时delay_us()和毫秒级delay_ms().本文基于STM32F207介绍4种不同方式实现的延时函数. ...

  3. iar stm32_STM32延时函数的四种方法

    关注.星标公众号,不错过精彩内容 单片机编程过程中经常用到延时函数,最常用的莫过于微秒级延时delay_us()和毫秒级delay_ms().本文基于STM32F207介绍4种不同方式实现的延时函数. ...

  4. Qt延时处理的四种方法

    Qt延时处理的四种方法 这里提供四种方法: 1. 多线程程序使用QThread::sleep()或者QThread::msleep()或QThread::usleep()或QThread::wait( ...

  5. java实现c语言的函数_C语言实现返回字符串函数的四种方法

    前言 C语言返回字符串函数共有四种方式,分别如下: 使用堆空间,返回申请的堆地址,注意释放 函数参数传递指针,返回该指针 返回函数内定义的静态变量(共享) 返回全局变量 下面来看看详细的介绍 其实就是 ...

  6. STM32按键控制led四种方法

    文章目录 回顾按键电路 按照之前文章方法在工程文件下加入Hardware中的key.c和key.h 打开固件库用户手册查询io读取相关的函数 第一种方式实现按键控制 第二种方式实现按键控制led 第三 ...

  7. 【嵌入式系统】STM32串口通信的四种方法(基于RTOS)

    目录 1.串行通信的基本参数 2.轮询方式代码效果 3.中断方式代码效果 4.中断加上时间戳方式代码及效果 5.DMA空闲中断方式接收数据 1.串行通信的基本参数 串行端口的通信方式是将字节拆分成一个 ...

  8. 实现Sleep函数的四种方法

    实现sleep函数,是一道考察候选人JS基本功的考题,让我们来一起探索这道题目吧~ 方式一:使用Promise + then 在Promise中通过setTimout来设置定时器,通过then来执行回 ...

  9. mysql 中split_在mysql中实现split函数的几种方法

    mysql 5.* 的版本现在没有split 函数,以下是几个自定义的split函数,供大家参考. 先设置:SET GLOBAL log_bin_trust_function_creators = 1 ...

最新文章

  1. 强化学习70年演进:从精确动态规划到基于模型
  2. 《统计学习方法》-李航、《机器学习-西瓜书》-周志华总结+Python代码连载(一)--模型选择+误差评估
  3. ubuntu10.04下安装windows7
  4. linux 查找tomcat目录,linux下通过tomcat访问某路径下的文件
  5. const修饰是指针和常量
  6. CentOS 系统盘迁移
  7. Myeclipse学习总结(17)——Java主流IDE优缺点分析
  8. 用wxDraw.js制作酷炫的小程序canvas动画『wxDraw 小程序界的zrender』
  9. 错误 ORA-01102: cannot mount database in EXCLUSIVE mode 的处理方法
  10. Oracle 11g RAC 自动应用PSU补丁简明版
  11. MATLAB卷积运算(conv)
  12. SSH框架之文件上传
  13. 然之协同 PHP,然之协同办公系统5.2开源版官方下载
  14. 「倍轻松」要上科创板,按摩器为什么总要和科技沾点边?
  15. 微信新动作!加好友解除5000上限,扫码进群开放至200人
  16. “世界很美好,值得你为之奋斗”我只同意后半句。
  17. mysql判断空_MySQL判断字段是否为null
  18. vue.使用popstate监听点击浏览器自带返回按钮
  19. 发票查验平台验证码识别
  20. 国外专家对于邮件标题的九大…

热门文章

  1. AutoCad 新建或打开对话框 经常变为命令提示行的解决办法!
  2. 实现ensp的单臂路由
  3. 数据结构(Java)-排序算法-选择排序
  4. 苹果6运行内存是多少_iPhone 12为什么不标注运行内存?安卓转苹果手机是入11还是入12呢?...
  5. 使用scrcpy开源进行电脑usb控制安卓手机,简单方便
  6. 中文版Ubuntu系统转为英文版Ubuntu
  7. netty--关于NIO和OIO
  8. win10安装虚拟机(Virtualbox + vagrant)
  9. Stroke:脑白质微结构完整性可预测脑卒中预后功能恢复情况
  10. [笔记]Pytorch框架下的入门应用:resnet34实现分类