hello,大家好呀,下面咱们继续后面的课程。之前我们实现了小灯闪烁的代码,但是当时写的延时呢,属于软件延时(通过无意义的循环实现)。但是这种延时是不灵活的。假如我需要500ms的延时,那应该怎么去实现呢。
//粗略延时
void delay(uint32_t timers)
{
uint16_t i=0,j=0;
for(i = 0;i<timers;i++)
{
for(j =0;j<65535;j++);
}
}
下面的代码是精确延时的代码。
main.c
#include "stm32f10x.h"
#include "delay.h"
int main(void)
{
RCC->APB2ENR |= (uint32_t)0x00000010;//打开GPIOC时钟
GPIOC->CRH &= (uint32_t)0xFF0FFFFF;//使用前清零
GPIOC->CRH |= (uint32_t)0x00300000;//配置PC13为推挽输出,最大速度50MHz
Delay_Init();
while(1)
{
GPIOC->BSRR = (uint32_t)0x00002000;//PC13引脚输出高电平
Delay_ms(500); //延时500ms
GPIOC->BRR = (uint16_t)0x2000; //PC13引脚输出低电平
Delay_ms(500); //延时500ms
}
}
delay.c
//参考博客:https://blog.csdn.net/qq_38800089/article/details/75195600
//参考博客: https://blog.csdn.net/qq_38405680/article/details/82055729
#include "stm32f10x.h"
#include "delay.h"
static uint8_t D_us = 0; //微妙系数
static uint16_t D_ms = 0; //毫秒系数
void Delay_Init(void)
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//SysTick->CTRL &= (uint32_t)0xFFFFFFFB;
D_us = SystemCoreClock/8000000;
//SystemCoreClock/8:72000000 Hz/8 = 9000000 Hz
//SysTick一个计数时长为:1/(SystemCoreClock/8) s
//1us需要计数次数为10^(-6)÷[1/(SystemCoreClock/8)]=SystemCoreClock/8000000
D_ms = (uint16_t)D_us * 1000; //1ms需要计数次数
}
void Delay_us(uint32_t nus)
{
uint32_t temp = 0;
SysTick->CTRL = 0x00; //关闭SysTick定时器
SysTick->LOAD = nus*D_us; //延时重装载值
SysTick->VAL = 0x00; //清空计数器
SysTick->CTRL |= 0x01; //开启SysTick定时器
do
{
temp = SysTick->CTRL;
}while( (temp&0x01) &&!(temp&(1<<16))); //等待延时结束
SysTick->CTRL = 0x00; //关闭SysTick定时器
SysTick->VAL = 0x00; //清空计数器
}
void Delay_ms(uint32_t nms)
{
uint32_t temp = 0;
SysTick->CTRL = 0x00; //关闭SysTick定时器
SysTick->LOAD = nms*D_ms; //延时重装载值
SysTick->VAL = 0x00; //清空计数器
SysTick->CTRL |= 0x01; //开启SysTick定时器
do
{
temp = SysTick->CTRL;
}while( (temp&0x01) &&!(temp&(1<<16)));
SysTick->CTRL = 0x00; //关闭SysTick定时器
SysTick->VAL = 0x00; //清空计数器
}
delay.h
#ifndef __DELAY_H
#define __DELAY_H
#include "stm32f10x.h"
void Delay_Init(void);
void Delay_us(uint32_t nus);
void Delay_ms(uint32_t nms);
#endif
下面是适合逻辑分析仪抓取波形的程序。delay.c和delay.h文件同上。
main.c
#include "stm32f10x.h"
#include "delay.h"
int main(void)
{
RCC->APB2ENR |= (uint32_t)0x00000010;//打开GPIOC时钟
RCC->APB2ENR |= (uint32_t)0x00000008;//打开GPIOB时钟
GPIOB->CRH &= (uint32_t)0xFF0FFFFF;//使用前清零
GPIOB->CRH |= (uint32_t)0x00300000;//配置PB13为推挽输出,最大速度50MHz
GPIOC->CRH &= (uint32_t)0xFF0FFFFF;//使用前清零
GPIOC->CRH |= (uint32_t)0x00300000;//配置PC13为推挽输出,最大速度50MHz
Delay_Init();
while(1)
{
GPIOB->BSRR = (uint32_t)0x00002000;//PB13引脚输出高电平
GPIOC->BSRR = (uint32_t)0x00002000;//PC13引脚输出高电平
Delay_ms(500); //延时500ms
GPIOB->BRR = (uint16_t)0x2000; //PB13引脚输出低电平
GPIOC->BRR = (uint16_t)0x2000; //PC13引脚输出低电平
Delay_ms(500); //延时500ms
}
}
当高电平延时为500ms时候,PB13引脚的波形如下图所示。
当高电平延时为1s时候,PB13引脚的波形如下图所示。
当高电平延时为1.5s时候,PB13引脚的波形如下图所示。
当高电平延时为1.8s时候,PB13引脚的波形如下图所示。
但当高电延时为2s时候,PB13引脚的波形如下图所示。
可以看到此时实际延时和要求延时不符合。
造成这样的原因是,LOAD寄存器是一个24位的,它的取值为0-16777215。此时如果延时为2000ms的时候,经过计算存入LOAD寄存器的值为18000000,已经超过LOAD寄存器所能存储的极限了。因此会出现延时不正确的情况。