小兴教你做平衡小车-stm32程序开发(精确延时)

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寄存器所能存储的极限了。因此会出现延时不正确的情况。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值