OpenEdv-开源电子网

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

断断续续看了三天,终于把延时函数看懂了

[复制链接]

23

主题

127

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
389
金钱
389
注册时间
2012-5-6
在线时间
0 小时
发表于 2012-5-22 21:09:09 | 显示全部楼层 |阅读模式
很纠结的是一些C语言的知识居然忘记了,然后边查资料,边看代码,边记笔记……
最后把东西写到自己博客了,希望对于刚拿到这么板子,写第一册例子有疑问的同学有所帮助。
高手勿喷。
没有把文章转过来,直接移步去围观吧,欢迎纠正错误。。。




首先几个操作技巧,RVMDK中打开别人的项目文件,遇到自定义的函数或变量,可以通过右键里的goto the definition of ***或者reference查看定义变量的文件和代码位置(如图)。


代码跟踪

先上代码,后面解释

#include “sys.h”
#include “delay.h”
#include “usart.h”
int main(){
u8 t=0;
Stm32_Clock_Init(9);//72M
delay_init(72);// 延时初始化
uart_init(72,9600); // 设置串口1 波特率
while(1){
printf(“t:%d\n”,t);
delay_ms(500);
t++;
}
}

下面是部分子函数

void delay_init(u8 SYSCLK)
{
SysTick->CTRL&=0xfffffffb;//bit2清空,选择外部时钟 HCLK/8
fac_us=SYSCLK/8;//计数基数 systick主频 HCLK/8=72/8=9MHZ,每次计数1/9us,所以计数为9时正好1us 
fac_ms=(u16)fac_us*1000; //计时基数 1us*1000=1ms
}

void delay_ms(u16 nms)
{
u32 temp;
SysTick->LOAD=(u32)nms*fac_ms;//时间加载(SysTick->LOAD为24bit)
SysTick->VAL =0×00; //清空计数器
SysTick->CTRL=0×01 ; //开始倒数
do
{
temp=SysTick->CTRL;
}
while(temp&0×01&&!(temp&(1<CTRL=0×00; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}

SYSTICK 是RVMDK里定义的一个结构体(准确说是一个指针,指向了结构体),具体代码部分见RVMDK安装目录Keil\ARM\INC\ST\STM32F10x下的stm32f10x_map.h,515行,下面又把它强制类型转换成了指针,以便使用”->”方式调用赋值,我的理解就是一大堆地址定义。



SysTick是MDK定义了的一个结构体(在stm32f10x_map. h里面),里面包含CTRL、LOAD 、

VA L 、CALIB等4 个寄存器,各位定义如所示:

下面介绍STM32中的systick,Systick 部分内容属于NVIC控制部分,一共有4个寄存器,名称和地址分别是:

STK_CSR,        0xE000E010  –  控制寄存器
STK_LOAD,     0xE000E014  –  重载寄存器
STK_VAL,        0xE000E018  –  当前值寄存器
STK_CALRB,   0xE000E01C  –   校准值寄存器

首先看STK_CSR控制寄存器:寄存器内有4个位t具有意义


第0位:ENABLE,Systick 使能位  (0:关闭Systick功能;1:开启Systick功能)
第1位:TICKINT,Systick 中断使能位    (0:关闭Systick中断;1:开启Systick中断)
第2位:CLKSOURCE,Systick时钟源选择  (0:使用HCLK/8 作为Systick时钟;1:使用HCLK作为Systick时钟)
第3位:COUNTFLAG,Systick计数比较标志,如果在上次读取本寄存器后,SysTick 已经数到了0,则该位为1。如果读取该位,该位将自动清零

STK_LOAD  重载寄存器:


Systick是一个递减的定时器,当定时器递减至0时,重载寄存器中的值就会被重装载,继续开始递减。STK_LOAD  重载寄存器是个24位的寄存器最大计数0xFFFFFF。

 

STK_VAL当前值寄存器:


也是个24位的寄存器,读取时返回当前倒计数的值,写它则使之清零,同时还会清除在SysTick 控制及状态寄存器中的COUNTFLAG 标志。

STK_CALRB  校准值寄存器:


这个寄存器好像目前的水平我还用不到,大体意思明白点,把英文说明放这吧:

位31 NOREF :1=没有外部参考时钟(STCLK 不可用)0=外部参考时钟可用

位30 SKEW:1=校准值不是准确的1ms 0=校准值是准确的1ms

位[23:0] :Calibration value

 

当然也可以参考这个


SYSTICK的时钟频率,这里我们使用了外部时钟源,即RCC通关AHB时钟(HCLK)8分频后作为Cortex的系统定时器(Systic)的外部时钟,通过对Systic状态寄存器的设置,SYSTICK->CTRL寄存器第2位(0:使用HCLK/8 作为Systick时钟;1:使用HCLK作为Systick时钟),通过SYSTICK->CTRL&=0xfffffffb设置第二位为0以选择HCLK/8为SYSTICK时钟频率。

然后我们在延时函数初始化SYSTICK,设置计时基数,得到最小单位时间为1us的计数单位,以便设置SYSTICK->RELOAD计数数值。



然后下面我们就是利用计数器延时的过程了,①、时间加载(SysTick->LOAD为24bit)②、清空计数器 ③、开始倒数④、循环查询SysTick->CTRL状态位是否计数完毕   ⑤、关闭计数器⑥、清空计数器  (对应的代码就是上文中delay_ms的子函数了)

因为之前学过51,所以感觉和51的计数器差不多,不过多了一个时钟频率的选择,当然,除了查询方式的延时函数外,还可以采用中断方式,学到的时候在写。



文章地址http://rmingwang.com/systick-delay-function-notes.html

我的博客,欢迎来访~
http://rmingwang.com
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2012-5-23 00:33:59 | 显示全部楼层
写的很不错,希望楼主直接发到我们论坛.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

23

主题

127

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
389
金钱
389
注册时间
2012-5-6
在线时间
0 小时
 楼主| 发表于 2012-5-23 10:45:20 | 显示全部楼层
回复【2楼】正点原子:
--------------------------------
额 直接复制过来了
我的博客,欢迎来访~
http://rmingwang.com
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2012-5-23 11:41:14 | 显示全部楼层
酷贴.
回复 支持 反对

使用道具 举报

7

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
59
金钱
59
注册时间
2012-5-18
在线时间
0 小时
发表于 2012-5-23 18:42:39 | 显示全部楼层
支持楼主的分享,顶一个
世界上最遥远的距离,是我在if里你在else里,似乎一直相伴又永远分离;世界上最痴心的等待,是我当case你是switch,或许永远都选不上自己;世界上最真情的相依,是你在try我在catch。无论你发神马脾气,我都默默承受,静静处理。到那时,再来期待我们的finally。
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2200
金钱
2200
注册时间
2012-2-8
在线时间
35 小时
发表于 2012-5-23 19:14:56 | 显示全部楼层
用SysTick或者定时器件延时的优点就是很精准,缺点就是不可重入。
https://github.com/roxma
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2012-5-23 21:28:13 | 显示全部楼层
回复【6楼】Pony279:
---------------------------------
可以写成可重入的,还可以写成和ucos的系统时钟共用!
豪华版发布的时候,我会发布这个代码.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

22

主题

61

帖子

0

精华

初级会员

Rank: 2

积分
178
金钱
178
注册时间
2012-5-15
在线时间
2 小时
发表于 2012-5-23 22:28:57 | 显示全部楼层
回复【楼主位】Rming:
---------------------------------
void delay_init(u8 SYSCLK) 

SysTick->CTRL&=0xfffffffb;//bit2清空,选择外部时钟 HCLK/8 
fac_us=SYSCLK/8;//计时基数 systick主频 HCLK/8=72/8=9MHZ,每次计数1/9us,所以计数为9时正好1us 
fac_ms=(u16)fac_us*1000; //计时基数 1us*1000=1ms 

其中的“fac_us=SYSCLK/8,每次计数1/9us,所以计数为9时正好1us ,“感觉基数为什么是1us,不应该按计数一次来算吗,不应该是1/9us吗?(虽然知道说的不对,但不知道哪里错了)
回复 支持 反对

使用道具 举报

23

主题

127

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
389
金钱
389
注册时间
2012-5-6
在线时间
0 小时
 楼主| 发表于 2012-5-24 10:45:08 | 显示全部楼层
回复【8楼】mredge:
---------------------------------
额  理解的方式不太一样  你的思维是 second=1,hour=60*60*second ;  我的是 second=1,minute=60*1,hour=60*minute;
定时器递减一次是1/9 us ,如果装入初值为9时,整个递减过程即1us
最小定时单位确实为1/9us,但是为了得到整数个us,ms,所以定义了计数基数为9,即定时1us(让我想起来了换元法- -|)
改改备注去
我的博客,欢迎来访~
http://rmingwang.com
回复 支持 反对

使用道具 举报

3

主题

123

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
364
金钱
364
注册时间
2012-4-30
在线时间
11 小时
发表于 2012-5-24 12:43:10 | 显示全部楼层
LZ还搞网页啊??
真的勇士,敢于直面惨淡的warning,敢于正视淋漓的error.
回复 支持 反对

使用道具 举报

19

主题

302

帖子

2

精华

高级会员

Rank: 4

积分
727
金钱
727
注册时间
2011-11-22
在线时间
10 小时
发表于 2012-5-24 14:23:17 | 显示全部楼层
LZ下功夫了,
世界如此美好,好好珍惜每一天吧!
回复 支持 反对

使用道具 举报

23

主题

127

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
389
金钱
389
注册时间
2012-5-6
在线时间
0 小时
 楼主| 发表于 2012-5-24 14:44:55 | 显示全部楼层
回复【10楼】Lkingz:
---------------------------------
额 之前做web的
我的博客,欢迎来访~
http://rmingwang.com
回复 支持 反对

使用道具 举报

46

主题

329

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1544
金钱
1544
注册时间
2012-4-9
在线时间
80 小时
发表于 2012-5-25 09:27:37 | 显示全部楼层
学习了
回复 支持 反对

使用道具 举报

0

主题

4

帖子

0

精华

初级会员

Rank: 2

积分
56
金钱
56
注册时间
2012-8-13
在线时间
10 小时
发表于 2012-8-13 16:12:28 | 显示全部楼层
 


有点不明白,那句while(temp&0x01&&!(temp&(1<<16)));//等待时间到达
我的理解是控制寄存器如果读回来的位16为1,那肯定时间到,然后执行下面的关闭清空计数器的操作。可是看了右看,temp&0x01这句话有起什么作用,因为之前
SysTick->CTRL=0x01 ; //开始倒数也就是使能了计数器,最低位为1了,temp&0x01肯定为真,去掉这句话也能达到延时的目的,不是么?望各位兄弟姐妹指教
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2012-8-13 18:16:22 | 显示全部楼层
回复【14楼】small_boy!:
---------------------------------
TEMP&0x01是确保SYSTICK处于开启状态.一旦systick非法关闭,而此时你又在延时的话,死循环就出现了...
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

0

主题

21

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2012-8-8
在线时间
1 小时
发表于 2012-8-15 20:59:19 | 显示全部楼层
不错,终于明白了。
回复 支持 反对

使用道具 举报

2

主题

5

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2012-9-17
在线时间
0 小时
发表于 2012-10-25 13:41:48 | 显示全部楼层
明白了
回复 支持 反对

使用道具 举报

11

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
110
金钱
110
注册时间
2012-10-12
在线时间
3 小时
发表于 2012-10-25 16:59:01 | 显示全部楼层
厉害!佩服!同时问一下,systick在就应该是最准的了吧?有没有更准的?
新人求指导~~~
回复 支持 反对

使用道具 举报

50

主题

201

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
423
金钱
423
注册时间
2013-4-9
在线时间
1 小时
发表于 2013-4-16 15:55:42 | 显示全部楼层
能提供个通用定时器的延时函数吗
回复 支持 反对

使用道具 举报

9

主题

147

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
376
金钱
376
注册时间
2012-11-7
在线时间
35 小时
发表于 2013-4-17 10:51:30 | 显示全部楼层
看看我做的多定时器http://www.openedv.com/posts/list/12126.htm
回复 支持 反对

使用道具 举报

0

主题

11

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
215
金钱
215
注册时间
2017-9-21
在线时间
37 小时
发表于 2017-10-3 16:39:28 | 显示全部楼层
。。。。。。。。。。。。。。。。
回复 支持 反对

使用道具 举报

7

主题

247

帖子

0

精华

高级会员

Rank: 4

积分
745
金钱
745
注册时间
2016-1-20
在线时间
78 小时
发表于 2017-10-20 16:08:44 | 显示全部楼层
收藏下,有用到的时候来看一下!
回复 支持 反对

使用道具 举报

0

主题

64

帖子

0

精华

高级会员

Rank: 4

积分
715
金钱
715
注册时间
2012-6-27
在线时间
69 小时
发表于 2019-6-13 13:28:37 | 显示全部楼层
谢谢分享
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-5-28 01:38

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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