OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7608|回复: 7

利用SysTick定时器写的延时函数

[复制链接]

0

主题

7

帖子

0

精华

新手上路

积分
38
金钱
38
注册时间
2020-3-13
在线时间
8 小时
发表于 2020-3-14 19:22:59 | 显示全部楼层 |阅读模式
本帖最后由 ypp庸 于 2020-3-14 19:25 编辑

菜鸟上路,看了原子哥21讲的视频来输出一下关于SysTick的用法





一、概述

SysTick定时器是系统滴答定时器,一个24位的倒计时计数定时器;

倒数到0时,将从RELOAD寄存器中自动重装载定时初值

只要不清除对应的使能位,定时器就永不停息,即使是在睡眠模式下也工作。


二、相关寄存器

SysTick有4个寄存器。CTRL、LOAD、VAL、CALIB;  (CALIB未用到)

2.1 Systick -> CTRL  状态和控制寄存器

图片1.png

位16: 当计数器倒数到0时,该位会自动置1。 【注:可用来判断计数器完成】

位2:时钟源选择位

            0=外部时钟源

            1=内部时钟源

位1:请求中断位

            0=SysTick倒数到0时无动作

            1=倒数到0时,产尘SysTick异常请求

位0:使能位


2.2 SysTick ->LOAD 重装载数值寄存器

图片2.png


2.3 SysTick ->VAL 当前值寄存器

图片3.png


三、频率选择

3.1、时钟的选择

本延时函数采用的是外部时钟源。所以该是时钟频率是系统时钟频率的八分之一,即72MHz / 8 =9 Mhz

3.2、如何延时1us

       时钟频率为9Mhz,即1秒计数9M次

即一次计数用了  1/9000000 s =  1/9000 ms = 1/9us

一次计数用了1/9us

所以1us 计数了9次

3.3、如何延时1ms

计数9000  即为延时1ms


四、编程思路

4.1 Delay初始化

选择时钟源

关闭定时器

4.2 延时函数

设置重装载值

计数器清0

使能SysTick

等待计数完毕

关闭定时器

计数器清0


五、示例代码

5.1 寄存器版

#include   "delay.h"

#define    val_us 9

#defne    val_ms 9000

Delay_Init(void)

{

   SysTick -> CTRL &=  ~(1<<2) ;                             //选择时钟源 把第二位设置为0

   SysTick -> ENABLE   &=  ~(1<<0);                             //关闭定时器

}


Delay_us(u32 num)

{

   u32 temp;

   SysTick -> LOAD = num * val_us ;                            //设置重装载值

   SysTick -> VAL = 0 ;                                                 //VAL清零

   SysTick -> CTRL |= (1<<0);                             //打开使能   第0位   设置为1

   do{

         temp =SysTick -> CTRL;

   }while(     (temp & 0x01)  &&!   (temp & (1<<16))  );                                                                 //等待计数完成  判断第16位是否为1  

   SysTick -> CTRL &=  &=  ~(1<<0);                             // 关闭使能   第第0位   设置为0

   SysTick -> VAL = 0;

}


Delay_ms(u16  num)

{

   u32 temp;

   SysTick -> LOAD = num * val_ms ;                            //设置重装载值

   SysTick -> VAL = 0 ;                                                 //VAL清零

   SysTick -> CTRL |= (1<<0);                             //打开使能   第第0位   设置为1

   do{

         temp =SysTick -> CTRL;

   }while(     (temp & 0x01)  &&!   (temp & (1<<16))  );                                                                 //等待计数完成  判断第16位是否为1  

   SysTick -> CTRL &=  &=  ~(1<<0);                             // 关闭使能   第第0位   设置为0

   SysTick -> VAL = 0;

}





5.2 库函数版

#include   "delay.h"

#define    val_us 9

#defne    val_ms 9000

Delay_Init(void)

{

   SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);

   SysTick->CTRL &=  ~SysTick_CTRL_ENABLE_Msk;        

}


Delay_us(u32 num)

{

           u32 temp;

        SysTick->LOAD = val_us * num,;                //设置重装载值

        SysTick->VAL = 0x00;                                //清空计数器

        SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;        //使能systick        开始倒计时

        do{

                temp = SysTick->CTRL;

        }while( (temp & 0x01)  &&! (temp & (1<<16)));        //等待计时完毕

        SysTick->VAL &= 0x00;

        SysTick->CTRL &=  ~SysTick_CTRL_ENABLE_Msk;        

}


Delay_ms(u16 num)

{

           u32 temp;

        SysTick->LOAD = val_ms * num,;                //设置重装载值

        SysTick->VAL = 0x00;                                //清空计数器

        SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;        //使能systick        开始倒计时

        do{

                temp = SysTick->CTRL;

        }while( (temp & 0x01)  &&! (temp & (1<<16)));        //等待计时完毕

        SysTick->VAL &= 0x00;

        SysTick->CTRL &=  ~SysTick_CTRL_ENABLE_Msk;        

}



}















正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

109

主题

5564

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
10561
金钱
10561
注册时间
2017-2-18
在线时间
1911 小时
发表于 2020-3-16 10:22:19 | 显示全部楼层
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
3
金钱
3
注册时间
2021-1-20
在线时间
1 小时
发表于 2021-1-20 09:59:53 | 显示全部楼层
写的非常不错,已经收藏
回复 支持 反对

使用道具 举报

10

主题

560

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1783
金钱
1783
注册时间
2014-6-27
在线时间
964 小时
发表于 2021-1-20 10:05:58 | 显示全部楼层
你应该写一个不用关滴答定时器的才比较实用。
回复 支持 反对

使用道具 举报

1

主题

3

帖子

0

精华

新手上路

积分
24
金钱
24
注册时间
2020-7-3
在线时间
4 小时
发表于 2021-4-5 21:14:12 | 显示全部楼层
在SysTick_Config函数中,SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;
在delay_us函数中,SysTick->LOAD=nus*fac_us;
请教一下,这里为什么一个没有减一,一个又减了一呢?
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
19
金钱
19
注册时间
2021-4-5
在线时间
4 小时
发表于 2021-4-6 11:15:35 | 显示全部楼层
这个延时函数中,有2个void delay_us(u32 nus),和void delay_ms(u16 nms)的定义,这样为什么没有出现重复定义啊
回复 支持 反对

使用道具 举报

1

主题

3

帖子

0

精华

新手上路

积分
24
金钱
24
注册时间
2020-7-3
在线时间
4 小时
发表于 2021-4-6 21:17:37 | 显示全部楼层
hikijinqiang 发表于 2021-4-6 11:15
这个延时函数中,有2个void delay_us(u32 nus),和void delay_ms(u16 nms)的定义,这样为什么没有出现重复 ...

因为有条件编译,而同名函数又处在不同分支,所以不可能同时编译两个同名函数的
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
13
金钱
13
注册时间
2022-7-22
在线时间
3 小时
发表于 2022-10-2 23:58:22 | 显示全部楼层
如果使用内部时钟呢。这个时钟应该怎么设置?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-26 01:30

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表