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重裝載數值寄存器LOAD主要是用來存儲計數的值,最大爲2^{24}

SysTick當前數值寄存器VAL,每一個計數器每1/SYSCLK就減1,當減到0時,計數標誌位置1,然後把重裝載數值寄存器裏的值寫進當前數值寄存器,並清除計數標誌位。

Sys校準數值寄存器CALIB

以上就是關於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是內核中的外設,所以時鐘選擇爲HCLK180MHz時鐘

由於官方沒有 SysTick的初始化函數,只有配置函數Config所以,我們自己簡單的編寫一個SysTick_Init()函數

因爲HCLK爲180MHz,所以當ticks=SystemFrequency/1000時(180 000 000/1000),每經過1/SystemFrequency一次,ticks的值就減1,所以計數時間爲ticks/(1/SystemFrequency)=1ms,,所以我們配置的SysTick爲10us進一次中斷。

配置好SysTick後,我們只需要再定義一個變量來記錄進入中斷的次數N,N*SysTick就等於我們所要定時的時間。

nTime就是我進入SysTick中斷的次數,每進入一次中斷服務函數,TimingDelay就減1,當TimingDelay不等於0時,延時結束。

中斷服務函數如下

關於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


	}   
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章