STM32F103五分钟入门系列延时函数(自己重写的底层)(上限:477218ms和477218588us)
Posted 自信且爱笑‘
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32F103五分钟入门系列延时函数(自己重写的底层)(上限:477218ms和477218588us)相关的知识,希望对你有一定的参考价值。
学习板:STM32F103ZET6
强推系列:
STM32F103五分钟入门系列(一)跑马灯(库函数+寄存器)+加编程模板+GPIO总结
STM32F103五分钟入门系列(二)GPIO的七大寄存器+GPIOx_LCKR作用和配置
STM32F103五分钟入门系列(三)GPIO的常用库函数使用方法总结+一个网络上的误区
参考:
STM32F103五分钟入门系列(六)时钟框图+相关寄存器总结+系统时钟来源代码(寄存器)
STM32F103五分钟入门系列(七)SystemInit()函数、SetSysClock()函数
STM32F103五分钟入门系列(八)SysTick滴答定时器+SysTick中断实现跑马灯
延时函数(自己重写的底层)(上限:477218ms和477218588us)
前言
写这篇博客之前,还在纠结,因为现在面对的所有项目都不用延时函数,而且延时函数的使用会对后期的调试造成很大的麻烦,所以本人对延时函数抱着消极的态度。不过出于完美主义心态,就写了写。这个延时函数之所以有上限,是因为函数传递的数最大为32位,如果stm32定义了64位的数,相信这个延时时长还能进一步加长,不过太长的延时没有意义。通过这个延时函数,许多朋友写跑马灯等实验时,就可以延时2s、3s… 相信会给大家带来很大的方便。
害怕复制粘贴出错的朋友,可以直接下载这个延时函数文件包,之后把.c和.h文件添加进工程就好。STMF1板子都是Cortex‐M3处理器,所以该延时函数适用于全部板子。
一、延时ms(上限477218ms)
之前博客中有朋友私聊我代码无法执行,原因是找不到文件,这次就再总结一下怎么添加文件。
(一)建立工程
在文件目录下新建一个DELAY文件夹
打开工程,新建两个text文件并分别改名为delay.c、delay.h,保存在刚刚新建的DELAY文件夹下。
点击工程名,将文件夹添加进工程:
将.c文件添加进来:
再将头文件添加进来:
找到刚刚存放.c和.h文件的文件夹,点击确定
之后编译一下就可以找到.h文件了
(二)delay.h头文件编写
头文件编写还是老规矩:
//delay.h
#ifndef _DELAY_
#define _DELAY_
#include "sys.h"
void delay_ms(u32 nms);
#endif
(三)delay.c文件编写
1、框架
固定代码:
//delay.c
#include "delay.h"
void delay_ms(u32 n)
{
}
2、选择时钟源
因为重装载值范围有限,所以为了得到更大的延时时间,需要时钟慢一点,故采用8分频,即SysTick时钟:SYSCLK/8=9MHZ(AHB默认状态为1分频)
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟源72MHZ/8=9MHZ
//SysTick->CTRL &=0xFFFFFFFB
3、清空计数器
SysTick->VAL=0;
4、重装载初值(+思路整理)
SysTick时钟为外部时钟源,为系统时钟的8分频,所以SysTick时钟为9MHZ,一个时钟周期计数一次(与51区分,51单片机12个时钟周期为一个机器周期,一个机器周期计数一次,51单片机做定时用12MHZ晶振,而有的51单片机用11.0592MHZ晶振是为了便于通信(波特率换算),之前51板块有过总结)
则:
1s 计数: 9000000次
1ms 计数:9000次
1us 计数:9次
delay_ms(u32 n)函数传递了n的时间,则共需要计时次数9000n次(形参n,过来是实参),而SysTick最大为0xffffff,即MAX=(2^24)-1。
当这个9000n<=MAX,此时这个n最大为1864(ms),此时只需装载初值一次就好,重装载值为9000n。
当这个9000n>MAX,此时对(2^ 24 -1 ) 求商a、求余b,重装载a次MAX,再重装载b,就可以完成延时,并且延时上限应该为(2^32-1)/9000ms≈477218ms=477s,完全适用于各类场合。(因为传递的实参为32位数,所以是2^32-1,当然传递过来的数的单位为s,则可延时477ks,此时函数体只需稍微修改,没有意义,就不写这个函数了)
无论9000n>MAX,还是9000n<=MAX,都对它取商、取余,小于时商为0,这样两种情况就可以合用一套代码了。
5、程序细节
传递过来n后,先求需要几次重装载MAX和最后重装载的那个小于MAX的数:
u32 a;//商
u32 b;//余数
a=(9000*n/0xffffff);//2^24 -1=16777215=0xffffff
b=(9000*n)%0xffffff;
接下来当a>0时,装载a次MAX:
while(a)//商大于0时
{
SysTick->LOAD=(u32)0xffffff; //装载最大可装载值
SysTick->VAL=0; //清空计数器
SysTick->CTRL|=1; //使能计数器,开始计数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(0x10000)));//while(计数器未使能&&(!CTRL计数器倒计数到0))
a--;
if(!a)//a为0,表示装载最大可装载值的次数用完
{
SysTick->CTRL&=0xfffffffe;//关闭计数器
}
}
接下来就是重装载那个余数b:
SysTick->LOAD=b;//装载余数
SysTick->VAL =0x00; //清空计数器
SysTick->CTRL|=1; //重新使能计数器,开始计数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(0x10000)));//while(计数器未使能&&(!CTRL计数器倒计数到0))
SysTick->CTRL&=0xfffffffe;//关闭计数器
SysTick->VAL =0X00; //清空计数器
6、完整代码
//delay.h
#ifndef _DELAY_
#define _DELAY_
#include "sys.h"
void delay_ms(u32 nms);
void delay_Init(void);
#endif
//delay.c
#include "delay.h"
void delay_Init(void)
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟源72MHZ/8=9MHZ
//SysTick->CTRL &=0xFFFFFFFB
SysTick->VAL=0; //清空计数器
}
void delay_ms(u32 n)
{
u32 a;//商
u32 b;//余数
u32 temp;
a=(9000*n/0xffffff);//2^24 -1=16777215=0xffffff
b=(9000*n)%0xffffff;
while(a)//商大于0时
{
SysTick->LOAD=(u32)0xffffff; //装载最大可装载值
SysTick->VAL=0; //清空计数器
SysTick->CTRL|=1; //使能计数器,开始计数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(0x10000)));//while(计数器未使能&&(!CTRL计数器倒计数到0))
a--;
if(!a)//a为0,表示装载最大可装载值的次数用完
{
SysTick->CTRL&=0xfffffffe;//关闭计数器
}
}
SysTick->LOAD=b;//装载余数
SysTick->VAL =0x00; //清空计数器
SysTick->CTRL|=1; //重新使能计数器,开始计数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(0x10000)));//while(计数器未使能&&(!CTRL计数器倒计数到0))
SysTick->CTRL&=0xfffffffe;//关闭计数器
SysTick->VAL =0X00; //清空计数器
}
二、延时us(上限477218588us)
1、思路
1s 计数: 9000000次
1ms 计数:9000次
1us 计数:9次
因为传递过来的数是32,所以延时上限为:(2^32 -1)/9=477218588us≈477Ks
与delay_ms(u32 n)相比,delay_us(u32 n)只需改动以下地方:
2、代码
//delay.h
#ifndef _DELAY_
#define _DELAY_
#include "sys.h"
void delay_ms(u32 nms);
void delay_us(u32 nms);
void delay_Init(void);
#endif
//delay.c
#include "delay.h"
void delay_Init(void)
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟源72MHZ/8=9MHZ
//SysTick->CTRL &=0xFFFFFFFB
SysTick->VAL=0; //清空计数器
}
void delay_us(u32 n)
{
u32 a;//商
u32 b;//余数
u32 temp;
a=(9*n/0xffffff);//2^24 -1=16777215=0xffffff
b=(9*n)%0xffffff;
while(a)//商大于0时
{
SysTick->LOAD=(u32)0xffffff; //装载最大可装载值
SysTick->VAL=0; //清空计数器
SysTick->CTRL|=1; //使能计数器,开始计数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(0x10000)));//while(计数器未使能&&(!CTRL计数器倒计数到0))
a--;
if(!a)//a为0,表示装载最大可装载值的次数用完
{
SysTick->CTRL&=0xfffffffe;//关闭计数器
}
}
SysTick->LOAD=b;//装载余数
SysTick->VAL =0x00; //清空计数器
SysTick->CTRL|=1; //重新使能计数器,开始计数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(0x10000)));//while(计数器未使能&&(!CTRL计数器倒计数到0))
SysTick->CTRL&=0xfffffffe;//关闭计数器
SysTick->VAL =0X00; //清空计数器
}
以上是关于STM32F103五分钟入门系列延时函数(自己重写的底层)(上限:477218ms和477218588us)的主要内容,如果未能解决你的问题,请参考以下文章
STM32F103五分钟入门系列SystemInit()函数SetSysClock()函数