1. 程式人生 > >【STM32小案例 07 】STM32完美可用的延時程式,自用延時程式庫,直接呼叫

【STM32小案例 07 】STM32完美可用的延時程式,自用延時程式庫,直接呼叫

前面的案例中有很多的小夥伴都私信我關於delay_other.c和delay_other.h標頭檔案的原始碼。

在這裡就直接分享出來。

-------------------------------------------------------------------------------------------


主要就是這四個檔案。

-------------------------------------------------------------------------------------------

1. sys_other.c

#include "sys_other.h"

void NVIC_Configuration(void)
{

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	//設定NVIC中斷分組2:2位搶佔優先順序,2位響應優先順序

}

2. sys_other.h
#ifndef __SYS_H
#define __SYS_H	
#include "stm32f10x.h"


//0,不支援ucos
//1,支援ucos
#define SYSTEM_SUPPORT_UCOS		0		//定義系統資料夾是否支援UCOS
																	    
	 
//位帶操作,實現51類似的GPIO控制功能
//具體實現思想,參考<<CM3權威指南>>第五章(87頁~92頁).
//IO口操作巨集定義
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址對映
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 
 
//IO口操作,只對單一的IO口!
//確保n的值小於16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //輸出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //輸入 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //輸出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //輸入 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //輸出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //輸入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //輸出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //輸入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //輸出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //輸入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //輸出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //輸入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //輸出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //輸入



void NVIC_Configuration(void);



#endif

3.delay_other.c
#include "delay_other.h"
#include "sys_other.h"

static u8  fac_us=0;//us延時倍乘數
static u16 fac_ms=0;//ms延時倍乘數
#ifdef OS_CRITICAL_METHOD 	//如果OS_CRITICAL_METHOD定義了,說明使用ucosII了.
//systick中斷服務函式,使用ucos時用到
void SysTick_Handler(void)
{				   
	OSIntEnter();		//進入中斷
    OSTimeTick();       //呼叫ucos的時鐘服務程式               
    OSIntExit();        //觸發任務切換軟中斷
}
#endif

//初始化延遲函式
//當使用ucos的時候,此函式會初始化ucos的時鐘節拍
//SYSTICK的時鐘固定為HCLK時鐘的1/8
//SYSCLK:系統時鐘
void delay_init()	 
{

#ifdef OS_CRITICAL_METHOD 	//如果OS_CRITICAL_METHOD定義了,說明使用ucosII了.
	u32 reload;
#endif
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);	//選擇外部時鐘  HCLK/8
	fac_us=SystemCoreClock/8000000;	//為系統時鐘的1/8  
	 
#ifdef OS_CRITICAL_METHOD 	//如果OS_CRITICAL_METHOD定義了,說明使用ucosII了.
	reload=SystemCoreClock/8000000;		//每秒鐘的計數次數 單位為K	   
	reload*=1000000/OS_TICKS_PER_SEC;//根據OS_TICKS_PER_SEC設定溢位時間
							//reload為24位暫存器,最大值:16777216,在72M下,約合1.86s左右	
	fac_ms=1000/OS_TICKS_PER_SEC;//代表ucos可以延時的最少單位	   
	SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;   	//開啟SYSTICK中斷
	SysTick->LOAD=reload; 	//每1/OS_TICKS_PER_SEC秒中斷一次	
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;   	//開啟SYSTICK    
#else
	fac_ms=(u16)fac_us*1000;//非ucos下,代表每個ms需要的systick時鐘數   
#endif
}								    

#ifdef OS_CRITICAL_METHOD	//使用了ucos
//延時nus
//nus為要延時的us數.		    								   
void delay_us(u32 nus)
{		
	u32 ticks;
	u32 told,tnow,tcnt=0;
	u32 reload=SysTick->LOAD;	//LOAD的值	    	 
	ticks=nus*fac_us; 			//需要的節拍數	  		 
	tcnt=0;
	told=SysTick->VAL;        	//剛進入時的計數器值
	while(1)
	{
		tnow=SysTick->VAL;	
		if(tnow!=told)
		{	    
			if(tnow<told)tcnt+=told-tnow;//這裡注意一下SYSTICK是一個遞減的計數器就可以了.
			else tcnt+=reload-tnow+told;	    
			told=tnow;
			if(tcnt>=ticks)break;//時間超過/等於要延遲的時間,則退出.
		}  
	}; 									    
}
//延時nms
//nms:要延時的ms數
void delay_ms(u16 nms)
{	
	if(OSRunning==TRUE)//如果os已經在跑了	    
	{		  
		if(nms>=fac_ms)//延時的時間大於ucos的最少時間週期 
		{
   			OSTimeDly(nms/fac_ms);//ucos延時
		}
		nms%=fac_ms;				//ucos已經無法提供這麼小的延時了,採用普通方式延時    
	}
	delay_us((u32)(nms*1000));	//普通方式延時,此時ucos無法啟動排程.
}
#else//不用ucos時
//延時nus
//nus為要延時的us數.		    								   
void delay_us(u32 nus)
{		
	u32 temp;	    	 
	SysTick->LOAD=nus*fac_us; //時間載入	  		 
	SysTick->VAL=0x00;        //清空計數器
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;          //開始倒數	 
	do
	{
		temp=SysTick->CTRL;
	}
	while(temp&0x01&&!(temp&(1<<16)));//等待時間到達   
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;       //關閉計數器
	SysTick->VAL =0X00;       //清空計數器	 
}
//延時nms
//注意nms的範圍
//SysTick->LOAD為24位暫存器,所以,最大延時為:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK單位為Hz,nms單位為ms
//對72M條件下,nms<=1864 
void delay_ms(u16 nms)
{	 		  	  
	u32 temp;		   
	SysTick->LOAD=(u32)nms*fac_ms;//時間載入(SysTick->LOAD為24bit)
	SysTick->VAL =0x00;           //清空計數器
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;          //開始倒數  
	do
	{
		temp=SysTick->CTRL;
	}
	while(temp&0x01&&!(temp&(1<<16)));//等待時間到達   
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;       //關閉計數器
	SysTick->VAL =0X00;       //清空計數器	  	    
} 
#endif

4.delay_other.h
#ifndef __DELAY_H
#define __DELAY_H 			   
#include "sys_other.h"

void delay_init(void); //宣告C函式
void delay_ms(u16 nms);
void delay_us(u32 nus);

#endif

----------------------------------------------------------------

這四個檔案程式碼已經給出,如果要使用直接在檔案頭部呼叫 #include 標頭檔案即可。

至於為什麼我要加上一個other是因為這兩個程式都不是我自己的自寫程式,所以我加上了識別符號方便我自己區分。

你們也可以更改成自己的名稱,但是注意要在程式內也更改相印的名稱。