SysTick_系统定时器实现流水灯

参考资料《 ARM Cortex™-M4F 技术参考手册》-4.5 章节 SysTick Timer(STK)

SysTick(系统滴答定时器),本质上就是一个内嵌在NVIC中的一个定时器,属于内核中的一个外设,是一个24位的向下递减的计数器,计数器每1/SYSCLK就减1,当寄存器的值减到0的时就会产生一次(硬件上的)中断,也有叫做滴答中断。主要的目的1、用来产生精确的延时。2、一般用于操作系统,用于产生时基,维持操作系统的心跳给操作系统提供一个单独的心跳(时钟)节拍。关于对于SyeTick的介绍我推荐看一下这位大神博客 https://blog.csdn.net/yx_l128125/article/details/7884423。

SysTick的寄存器总共有四个,在使用SysTick产生定时的时候,只需配置前三个寄存器,最后一个校准值寄存器不需要使用。

接下来对各个寄存器的描述

SysTick控制及状态寄存器CTRL主要用来读取当前数值寄存器里的值、选择时钟源、使能异常请求、使能定时器。

SysTick_系统定时器实现流水灯_第1张图片

SysTick重装载数值寄存器LOAD主要是用来存储计数的值,最大为2^{24}

SysTick当前数值寄存器VAL,每一个计数器每1/SYSCLK就减1,当减到0时,计数标志位置1,然后把重装载数值寄存器里的值写进当前数值寄存器,并清除计数标志位。

Sys校准数值寄存器CALIB

SysTick_系统定时器实现流水灯_第2张图片

以上就是关于SysTick的介绍,接下来就要操作一下了,

我们要用SysTick来定时1S使LED灯状态变化一次,所以

1、首先,应先线配置SysTick相关寄存器,来产生1s的延时

2、初始化LED灯

3、编写主函数

由于Systick是嵌入在内核中的所以在硬件电路中只需要有LED模块即可,想要用SysTick实现流水灯1s切换一次状态的操作,首先就是要配置SysTick,这里我们直接用STM32官方额库函数SysTick_Config(uint32_t  ticks),在内核头文件core_cm4.h中,这个函数的功能是配置系统定时器和中断,并且打开SysTick,使计数器处于自由计数模式来产生一个周期性的中断。在这个函数中形参ticks是用来设置重装载寄存器的值,最大不能超过重装载寄存器的值2^{24},当重装载寄存器的值减到0时,就会产生一个中断,然后重装载寄存器的值又写入当前计数器中重新往下递减计数,以此循环。接下来这个库函数是给该中断配置中断优先级(关于中断优先级可以查看STM32中断及NVIC概述),然后给当前数值寄存器赋初值,接下来配置时钟源,使能中断,开启定时器。当返回0时,说明函数功能已经实现,返回1则表示失败。这个初始化函数主要是配置了SysTick中的三个寄存器:LOAD、VAL、CTRL,还调用了NVIC_SetPriority()配置中断优先级函数。

SysTick_系统定时器实现流水灯_第3张图片

因为SysTick是内核中的外设,所以时钟选择为HCLK180MHz时钟

SysTick_系统定时器实现流水灯_第4张图片

由于官方没有 SysTick的初始化函数,只有配置函数Config所以,我们自己简单的编写一个SysTick_Init()函数

SysTick_系统定时器实现流水灯_第5张图片

因为HCLK为180MHz,所以当ticks=SystemFrequency/1000时(180 000 000/1000),每经过1/SystemFrequency一次,ticks的值就减1,所以计数时间为ticks/(1/SystemFrequency)=1ms,,所以我们配置的SysTick为10us进一次中断。

配置好SysTick后,我们只需要再定义一个变量来记录进入中断的次数N,N*SysTick就等于我们所要定时的时间。

SysTick_系统定时器实现流水灯_第6张图片

nTime就是我进入SysTick中断的次数,每进入一次中断服务函数,TimingDelay就减1,当TimingDelay不等于0时,延时结束。

中断服务函数如下

SysTick_系统定时器实现流水灯_第7张图片

关于SysTick配置已经描述完,接下来初始化LED灯。

关于LED的初始化我就不再做过多的描述,可以参考STM32固件库函数点亮LED灯,代码如下

#include "stm32f4xx_gpio.h"
 
#define GPIO_R_Pin  GPIO_Pin_10
#define GPIO_R_Port GPIOH
 
#define GPIO_G_Pin  GPIO_Pin_11
#define GPIO_G_Port GPIOH
 
#define GPIO_B_Pin  GPIO_Pin_12
#define GPIO_B_Port GPIOH
 
/************************控制LED灯亮灭的宏***************/
 
/*直接操作寄存器的方法控制IO*/
 
#define  LED_PORT_OUT_HI(p,i)				{ p->BSRRL = i ;}			//输出为高电平
#define  LED_PORT_OUT_LO(p,i)				{ p->BSRRH = i ;}			//输出为低电平
#define  LED_PORT_OUT_Toggle(p,i)		        { p->BSRRL ^= i ;}		       //输出为反状态
 
/*定义控制IO的宏*/
 
#define LED_R_Toggle		        LED_PORT_OUT_Toggle(GPIO_R_Port,GPIO_R_Pin)
#define LED_R_ON			LED_PORT_OUT_LO(GPIO_R_Port,GPIO_R_Pin)
#define LED_R_OFF			LED_PORT_OUT_HI(GPIO_R_Port,GPIO_R_Pin)
 
#define LED_G_Toggle		        LED_PORT_OUT_Toggle(GPIO_G_Port,GPIO_G_Pin)
#define LED_G_ON			LED_PORT_OUT_LO(GPIO_G_Port,GPIO_G_Pin)
#define LED_G_OFF			LED_PORT_OUT_HI(GPIO_G_Port,GPIO_G_Pin)
 
#define LED_B_Toggle		        LED_PORT_OUT_Toggle(GPIO_B_Port,GPIO_B_Pin)
#define LED_B_ON			LED_PORT_OUT_LO(GPIO_B_Port,GPIO_B_Pin)
#define LED_B_OFF			LED_PORT_OUT_HI(GPIO_B_Port,GPIO_B_Pin)
 
#define LED_RGBOFF   LED_R_OFF;\
										LED_G_OFF;\
										LED_B_OFF

void LED_GPIO_Config(void);
#include "bsp_led.h"
 
/**
  * @brief  初始化控制LED的IO
  * @param  无
  * @retval 无
  */
void LED_GPIO_Config(void)
{		
    /*定义一个GPIO_InitTypeDef类型的结构体*/
    GPIO_InitTypeDef GPIO_InitStructure;

    /*开启LED相关的GPIO外设时钟*/
    RCC_AHB1PeriphClockCmd ( LED1_GPIO_CLK|
	                     LED2_GPIO_CLK|
	                     LED3_GPIO_CLK, ENABLE); 

    /*选择要控制的GPIO引脚*/															   
    GPIO_InitStructure.GPIO_Pin = LED1_PIN;	

    /*设置引脚模式为输出模式*/
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;   
    
    /*设置引脚的输出类型为推挽输出*/
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    
    /*设置引脚为上拉模式*/
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

    /*设置引脚速率为2MHz */   
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; 

    /*调用库函数,使用上面配置的GPIO_InitStructure初始化GPIO*/
    GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure);	
    
    /*选择要控制的GPIO引脚*/															   
    GPIO_InitStructure.GPIO_Pin = LED2_PIN;	
    GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStructure);	
    
    /*选择要控制的GPIO引脚*/															   
    GPIO_InitStructure.GPIO_Pin = LED3_PIN;	
    GPIO_Init(LED3_GPIO_PORT, &GPIO_InitStructure);	
		
		/*关闭RGB灯*/
		LED_RGBOFF;		
}

配置好SysTick和LED后,接下来就开始写主函数

主函数如下

int main(void)
{
	/* LED 端口初始化 */
	LED_GPIO_Config();	 
 
        /* 配置SysTick 为10us中断一次,时间到后触发定时中断,
	*进入stm32fxx_it.c文件的SysTick_Handler处理,通过数中断次数计时
	*/
	SysTick_Init();
  
	while(1)
	{

	  LED_RED; 
	  Delay_us(100000);    	// 10000 * 10us = 1000ms
	  //延时1s
	  
	  LED_GREEN;
	  Delay_us(100000);		
          //延时1s
	
	  LED_BLUE;
	  Delay_us(100000);		
          //延时1s


	}   
}

 

你可能感兴趣的:(ARM)