第二章 SysTick定时器
前言
以前学习STM32的时候,看到原子哥的教程使用的是SysTick定时器来做延时函数,这样做的好处是不占用中断,也不用定时器就可以做出比较准确的延时函数。那GD32如何使用SysTick来做延时呢,下面就跟我一起来研究研究吧。如果喜欢,帮忙点个赞,你的支持会让我有更多动力写下去,感谢!
一、SysTick
- 先看一下官方手册,搜索一下SysTick,可以看到它是一个24位的计数器,自动重装向下计数,同样可以产生中断。
- 下一步只要知道它的时钟是多少,就能确定时间了,那就找一下数据数据手册的时钟树,可以看到SysTick的时钟为系统时钟的8分频,其实也可以选择不分频。
二、软件编程
-
拿上一章的工程模版来改一下,在原来的基础上,增加新建两个文件delay.c和delay.h,保存到我们的SYSTEM文件夹下,并把delay.c文件添加到工程中。
-
delay.c代码如下,我们选择SysTick的时钟源为HCLK,这里我的系统时钟频率是84MHz,则每计数减1,就过了1/84000000s,1us就需要计数84次。如果要延时N个us,那就要延时84 * N个计数值,那我们就循环的去读取SysTick的计数值,如果计数值超过84 * N,那说明延时时间到了,这样在不影响SysTick的前提下,达到延时的目的。
#include "delay.h"
static uint8_t fac_us = 0;
void Delay_Init(void)
{
//SysTick时钟源选择
systick_clksource_set(SYSTICK_CLKSOURCE_HCLK);
//延时1us需要SysTick个时钟节拍
fac_us = SystemCoreClock/1000000;
//重装值
SysTick->LOAD = 0xFFF;
//开启计数
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
}
void Delay_us(uint32_t nus)
{
uint32_t old_cnt,now_cnt,cnt = 0;
//重装值
uint32_t reload = SysTick->LOAD;
//延时节拍
uint32_t ticks = nus * fac_us;
//记录节拍
old_cnt = SysTick->VAL;
while(1)
{
now_cnt = SysTick->VAL;
if(old_cnt != now_cnt)
{
if(now_cnt < old_cnt)
cnt += (old_cnt - now_cnt);
else
cnt += (reload + old_cnt - now_cnt);
old_cnt = now_cnt;
if(cnt >= ticks)
break;
}
}
}
void Delay_ms(uint16_t nms)
{
uint32_t i;
for(i = 0;i < nms;i++)
{
Delay_us(1000);
}
}
- delay.h代码如下:
#ifndef _DELAY_H_
#define _DELAY_H_
#include "gd32f3x0.h"
void Delay_Init(void);
void Delay_us(uint32_t nus);
void Delay_ms(uint16_t nms);
#endif
- mian.c代码如下,在使用前需要初始化一下,这里我们使用LED点灯来验证我们的程序是否正确。
#include "main.h"
int main(void)
{
//延时函数初始化
Delay_Init();
//LED GPIO初始化
LED_Init();
while(1)
{
//点亮LED
gpio_bit_reset(GPIOB,GPIO_PIN_0);
Delay_ms(1000);
//熄灭LED
gpio_bit_set(GPIOB,GPIO_PIN_0);
Delay_ms(1000);
}
}
- 这里我们的代码已经编写完毕,重新编译后烧录到我们单片机中,即可看到LED每秒闪烁一次。这里如果大家想用到操作系统上,可以参考原子哥的代码进行修改。
三、总结
本章主要介绍如何使用GD32的SysTick定时器来设计延时函数,不过实际项目中,我不喜欢使用延时函数,这样影响系统的实时性。但是总少不了需要延时的地方,那要怎么做呢?关注我,下一章教大家写高效的单片机程序框架。
SysTick定时器