您好,欢迎来到钮旅网。
搜索
您的当前位置:首页S.D.Lu的STM32学习笔记(4)用SysTick定时器实现延时

S.D.Lu的STM32学习笔记(4)用SysTick定时器实现延时

来源:钮旅网
S.D.Lu的STM32学习笔记(4) 用SysTick定时器实现延时

概述:

本篇将介绍如何使用CM3核内置的SysTick定时器实现较精确的延时。 由于3.5.0版的固件函数库并没有提供完整的SysTick定时器操作函数,所以我们将通过对寄存器的操作完成SysTick定时器相关设置,借此机会学习一下STM32的寄存器操作方法。

SysTick 定时器是一个包含在CM3 内核的处理器内部的24位倒计数定时器。SysTick定时器的介绍请参考《Cortex-M3权威指南》第8章以及《CM3技术参考手册》第8章与SysTick相关的内容。

说明:

本篇通过一个实例,解决一个问题,然后分析解决的方法。 本实验是在前一篇的基础上进行的,参考了网络上的程序资源。 利用定时器,使用查询的方式实现延时的基本流程是:

清空标志位; 填充初值; 打开定时器;

查询标志位,直到其置1; 关闭定时器; 清空标志位。

使用SysTick定时器实现延时的流程与之类似:

(使用SysTick前先设置其时钟源) 清空计数器及标志位; 填充重载寄存器; 打开定时器;

查询标志位,直到其置1; 关闭定时器;

清空计数器及标志位。

步骤1:修改main.c文件

在文件开始出添加一个宏定义:

#define MY_SYSCLK 32

//时钟频率MHz

删掉原来的延时函数,然后写两个函数:

//函数功能:设置SysTick时钟源===== void SysTick_Init(void) { }

- 1 -

SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);

//SysTick时钟 = AHB时钟/8

//函数功能:延时nms毫秒===== void Delay_ms(u32 nms) {

u32 temp;

temp = (u32)MY_SYSCLK*1000/8*nms; //计算初值 SysTick->LOAD = temp; //填充初值

SysTick->VAL=0x00; //清空计数器及标志位 SysTick->CTRL=0x01 ; //打开定时器 do { temp=SysTick->CTRL; }

while(temp&0x01&&!(temp&(1<<16)));// 查询标志位,直到其置1 SysTick->CTRL=0x00; //关闭定时器

SysTick->VAL =0X00; //清空计数器及标志位 }

主函数改成如下内容:

int main(void) //函数功能:主函数 {

RCC_Configuration(); //初始化外设时钟 PORT_Init(); //初始化I/O端口 SysTick_Init(); //设置SysTick时钟源 while(1) {

GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_SET); //PA8 = 1 Delay_ms(500); //延时500毫秒

GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_RESET); //PA8 = 0 Delay_ms(500); //延时500毫秒 } }

步骤2:编译,下载

将工程进行编译,下载到芯片上,即可看到LED在闪烁,周期为1秒钟。 至此实验完成。

代码分析:

所增加的SysTick_Init()函数只调用了一个库函数:SysTick_CLKSourceConfig(); 该函数的功能是选择SysTick定时器的时钟。

这是3.5.0库提供的唯一一个SysTick定时器操作函数。

《STM32固件库使用手册》中文版(UM0427)翻译自英文版UM0427 Oct. 2007 Rev 2。该版本是ST公司2007年10月发布的1.0版固件库使用手册,也就是最早的版本。后期的版本,特别是3.0之后的版本改动较大,但很多函数都保留了原来的接口,所以可以按照1.0版的使用手册进行调用。如果有改动,也可以根据固件库中的函数定义处的注释知道其使用方法。有些函数被废弃了,如对SysTick定时器的操作,3.5.0版的函数库只提供了一个可用的SysTick_CLKSourceConfig()。这样,用户只能通过直接操作寄存器完成其他相应的设置。

增加的另一个函数是:Delay_ms();

其功能是实现n毫秒延时。但应注意的是,该函数的输入应确保MY_SYSCLK*1000/8*nms <= 0x00FFFFF。其中MY_SYSCLK是文件开头定义的宏,标识使用的系统时钟频率,单位:MHz。本程序沿用了上一篇的RCC_Configuration()函数,所以MY_SYSCLK定义为32。根据上述要求,输入的nms应小于等于4194。

- 2 -

先看第一个对寄存器操作的语句

SysTick->LOAD = temp; //填充初值

从C语言的角度分析,这是对一个结构体的成员赋值。而从单片机内部结构的角度分析,这是对一个寄存器的操作。

那么,SysTick是一个什么样的结构体呢?

在SysTick->LOAD = temp;语句的SysTick上右键定位,在core_cm3.h找到其定义处:

这是一个宏定义,将SysTick定义为一个指向SysTick_Type型的指针,该指针的值为SysTick_BASE。

再右键定位,找到SysTick_Type的定义:

这是一个结构体类型,其中的4个成员与SysTick相关的4个寄存器一一对应,LOAD是其中之一。可以用右键对SysTick_BASE跟踪定位,找到:

0718行后面的注释意思是:SysTick的基地址,即首地址。

由此可见, SysTick是一个指向SysTick_Type结构体的指针,该结构体的地址是0xE000E010(正是SysTick控制及状态寄存器的地址)。

ST做了大量的工作对STM32的内核和外设寄存器进行整理,以结构体的形式提供操作接口,使得用户可以非常方便地操作相关寄存器。MDK的根目录下就包含了相应的头文件stm32f10x_map.h,路径是Keil\\ARM\\INC\\ST\\STM32F10x。该头文件首先对各个外设相关寄存器进行了结构体定义,之后对各个结构体的基地址进行了宏定义。 ST在设计芯片时就将某个外设的相关寄存器设计在连续的地址上(其实其他的芯片设计厂商也是这么做的)。这样做带来的好处就是,只要给出外设的第一个寄存器的地址,就可以访问该外设所有相关的寄存器,而结构体的特性正是如此。所以只要定义一个指向结构体的指针常量,且指向的地址是一个相关寄存器组的首地址,就可以通过该指针常量访问该寄存器组的所有寄存器。stm32f10x_map.h就是这么做的,stm32f10x.h也做了相类似的工作。所以我们只要在程序的开始出包含了相关的头文件,就可以像下面语句一样方便的操作各个寄存器了。

do……while(temp&0x01&&!(temp&(1<<16)));语句的功能是等待SysTick->CTRL寄存器的bit16置位。其中增加了bit0位的检测,这是确保SysTick定时器是在打开的状态。

如果将temp = (u32)MY_SYSCLK*1000/8*nms;语句中右边的表达式改为(u32)MY_SYSCLK/8*nms则可得到一个微妙级的延时函数。 作者:S.D.Lu 深圳 2013-1-30

- 3 -

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- niushuan.com 版权所有 赣ICP备2024042780号-2

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务