一、SysTick
Sys-系统,Tick-滴答声,系统滴答滴答很形象地表示了它是一个系统节拍器。SysTick 是一个集成在Cortex内核里的24位的倒计数定时器,当计到0时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息。
SysTick的作用。
SysTick主要有以下几个作用:
1、产生操作系统的时钟节拍;
当RTOS以并行的架构处理任务,单一任务的崩溃并不会牵连到整个系统。这样用户出于可靠性的考虑可能就会基于RTOS来设计自己的应用程序。这样SYSTICK存在的意义就是提供必要的时钟节拍,为RTOS的任务调度提供一个有节奏的“心跳”。
2、便于不同处理器之间程序移植
因为所有的CM3芯片都带有这个定时器,软件在不同 CM3器件间的移植工作得以化简。
3、作为一个闹铃测量时间
可以用作闹钟,作为启动一个特定任务的时间依据。它作为一个闹铃,用于测量时间。要注意的是,当处理器在调试期间被喊停(halt)时,则SysTick定时器亦将暂停运作。
二、项目配置
该项目以https://blog.csdn.net/fanxp66/article/details/80227611为基础,对程序中的延时替换为使用SysTick来实现精准延时。
1、将库函数库中的"misc.h"头文件复制到项目的\Lib\inc文件夹下,将"misc.c"程序文件复制到\Lib\src文件夹下;
2、将"misc.c"文件添加到项目的"Lib"组中;
3、在项目文件夹下新建一个"Public"文件夹,在项目中添加"Public"组;
4、新建"SysTick.h"文件和"SysTick.c"文件,将"SysTick.c"文件添加到项目的"Public"组中;
5、修改项目配置,将路径"\Public"添加到"C/C++"的"Include Paths"中。
三、编程
在本程序中,利用SysTick进行精准1秒定时,系统时钟初始为72MHz,选择SYSCLK/8分频后得到的9MHz作为SysTick的输入计时时钟,当设置计数值为9000000时,实现1秒定时。
在使用SysTick时有查询式和中断方式两种,使用查询方式时,首先为SysTick选择时钟源和设置计数值并启动计数,然后查询计数完成状态位,状态位为1时表示计数完成;使用中断方式时要为15号异常设置中断服务程序处理。这里使用查询方式。
SysTick编程用到以下寄存器:
CTRL SysTick 控制和状态寄存器
LOAD SysTick 重装载值寄存器
VAL SysTick 当前值寄存器
CALIB SysTick 校准值寄存器
在"core_cm3.h"文件中定义了:
typedef struct { __IO uint32_t CTRL; /*地址偏移: 0x00 SysTick 控制和状态寄存器*/ __IO uint32_t LOAD; /*地址偏移: 0x04 SysTick 装载计数值寄存器*/ __IO uint32_t VAL; /*地址偏移: 0x08 SysTick当前计数值寄存器*/ __I uint32_t CALIB; /*地址偏移: 0x0C SysTick 校准值寄存器*/ } SysTick_Type; #define SysTick ((SysTick_Type *)SysTick_BASE) /*SysTick 配置结构体 */ |
以后就可以通过对SysTick结构体指针操作SysTick的寄存器。
1、SysTick编程步骤。
① 为SysTick设置时钟源
在STM32的库函数文件中有"misc.h"头文件和"misc.c"程序文件定义了相应的宏和库函数。
在"misc.h"头文件有定义:
#define SysTick_CLKSource_HCLK_Div8 ((uint32_t)0xFFFFFFFB) #define SysTick_CLKSource_HCLK ((uint32_t)0x00000004) |
在"misc.c"程序文件定义函数
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource) { assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource)); if (SysTick_CLKSource == SysTick_CLKSource_HCLK) { SysTick->CTRL |= SysTick_CLKSource_HCLK; /*将CTRL寄存器的位2设为1*/ } else { SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8; /*将CTRL寄存器的位2设为0*/ } } |
在本程序中使用8分频的系统时钟,所以调用函数如下:
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); |
② 为SysTick 装载计数值寄存器设置计数值;
③ 对SysTick当前计数值寄存器置0;
④ 通过对SysTick的CTRL寄存器的位0置位使能SysTick定时器。
2、编程实现
在程序中,为了方便使用,定义了"SysTick.h"头文件和"SysTick.c"程序文件(这两个文件已经在前面“项目配置”部分创建)。
"SysTick.h"头文件内容如下:
#ifndef __SysTick__H #define __SysTick__H #include "stm32f10x.h" void SysTick_Init(u8 SYSCLK); void delay_us(u32 nus); void delay_ms(u16 nms); |
"SysTick.c"程序文件内容如下:
#include "SysTick.h" #include "misc.h" u8 fac_us = 0; u16 fac_ms = 0;
void SysTick_Init(u8 SYSCLK) { SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); fac_us = SYSCLK / 8; fac_ms = (u16)fac_us*1000; }
void delay_us(u32 nus) { u32 temp; SysTick->LOAD = nus * fac_us; SysTick->VAL = 0; SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; do{ temp = SysTick->CTRL; }while((temp&0x01)&&(!(temp&(1<<16)))); SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; SysTick->VAL = 0; } void delay_ms(u16 nms) { u32 temp; SysTick->LOAD = nms * fac_ms; SysTick->VAL = 0; SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; do{ temp = SysTick->CTRL; }while((temp&0x01)&&(!(temp&(1<<16)))); SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; SysTick->VAL = 0; } |
3、在主函数中使用定时
#include "stm32f10x.h" #include "stm32f10x_rcc.h" #include "led.h" #include "SysTick.h"
int main() { u32 i,j; //共阳数码管'0'-'9'显示码 u32 LED[10] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; LED_Init(); SysTick_Init(72); //系统时钟72MHz while(1) { for(i=0;i<10;i++) { //根据LED[n]数组的值决定数码管各个段位的显示 for(j=0; j<8; j++) if( ~(LED[i]) & 0x1<<j ) PCout(j) = 0; else PCout(j) = 1; delay_ms(1000); } } } |