【STM32小案例 07 】STM32完美可用的延時程式,自用延時程式庫,直接呼叫
阿新 • • 發佈:2019-01-04
前面的案例中有很多的小夥伴都私信我關於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
4.delay_other.h#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
#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是因為這兩個程式都不是我自己的自寫程式,所以我加上了識別符號方便我自己區分。
你們也可以更改成自己的名稱,但是注意要在程式內也更改相印的名稱。