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中断实现跑马灯

前言

写这篇博客之前,还在纠结,因为现在面对的所有项目都不用延时函数,而且延时函数的使用会对后期的调试造成很大的麻烦,所以本人对延时函数抱着消极的态度。不过出于完美主义心态,就写了写。这个延时函数之所以有上限,是因为函数传递的数最大为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()函数

STM32F103五分钟入门系列按键实验(库函数+寄存器)

STM32F103五分钟入门系列蜂鸣器实验(库函数+寄存器)

STM32F103(二十)DAC(贼详细)

STM32F103你学不会系列(十七)电容触摸按键实现

STM32F103(十八)ADC总结(贼详细)