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

2019-07-20 23:50发布

很纠结的是一些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 ”,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安装目录KeilARMINCSTSTM32F10x下的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

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
22条回答
mredge
2019-07-21 23:07
回复【楼主位】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吗?(虽然知道说的不对,但不知道哪里错了)

一周热门 更多>