/*************delay.h*************************/
#ifndef __DELAY_H
#define __DELAY_H
#include
//////////////////////////////////////////////////////////////////////////////////
//ALIENTEK STM32開發(fā)板
//使用SysTick的普通計數(shù)模式對延遲進(jìn)行管理
//包括delay_us,delay_ms
//正點(diǎn)原子@ALIENTEK
//技術(shù)論壇:www.openedv.com
//修改日期:2012/9/2
//版本:V1.5
//版權(quán)所有,盜版必究。
//Copyright(C) 廣州市星翼電子科技有限公司 2009-2019
//All rights reserved
//********************************************************************************
//V1.2修改說明
//修正了中斷中調(diào)用出現(xiàn)死循環(huán)的錯誤
//防止延時不準(zhǔn)確,采用do while結(jié)構(gòu)!
//V1.3修改說明
//增加了對UCOSII延時的支持.
//如果使用ucosII,delay_init會自動設(shè)置SYSTICK的值,使之與ucos的TICKS_PER_SEC對應(yīng).
//delay_ms和delay_us也進(jìn)行了針對ucos的改造.
//delay_us可以在ucos下使用,而且準(zhǔn)確度很高,更重要的是沒有占用額外的定時器.
//delay_ms在ucos下,可以當(dāng)成OSTimeDly來用,在未啟動ucos時,它采用delay_us實(shí)現(xiàn),從而準(zhǔn)確延時
//可以用來初始化外設(shè),在啟動了ucos之后delay_ms根據(jù)延時的長短,選擇OSTimeDly實(shí)現(xiàn)或者delay_us實(shí)現(xiàn).
//V1.4修改說明 20110929
//修改了使用ucos,但是ucos未啟動的時候,delay_ms中中斷無法響應(yīng)的bug.
//V1.5修改說明 20120902
//在delay_us加入ucos上鎖,防止由于ucos打斷delay_us的執(zhí)行,可能導(dǎo)致的延時不準(zhǔn)。
//////////////////////////////////////////////////////////////////////////////////
void delay_init(u8 SYSCLK);
void delay_ms(u16 nms);
void delay_us(u32 nus);
#endif
/*************delay.c******************/
#include "delay.h"
#include "sys.h"
//////////////////////////////////////////////////////////////////////////////////
//如果使用ucos,則包括下面的頭文件即可.
#if SYSTEM_SUPPORT_UCOS
#include "includes.h" //ucos 使用
#endif
//////////////////////////////////////////////////////////////////////////////////
//本程序只供學(xué)習(xí)使用,未經(jīng)作者許可,不得用于其它任何用途
//ALIENTEK STM32開發(fā)板
//使用SysTick的普通計數(shù)模式對延遲進(jìn)行管理
//包括delay_us,delay_ms
//正點(diǎn)原子@ALIENTEK
//技術(shù)論壇:www.openedv.com
//修改日期:2012/9/2
//版本:V1.5
//版權(quán)所有,盜版必究。
//Copyright(C) 廣州市星翼電子科技有限公司 2009-2019
//All rights reserved
//********************************************************************************
//V1.2修改說明
//修正了中斷中調(diào)用出現(xiàn)死循環(huán)的錯誤
//防止延時不準(zhǔn)確,采用do while結(jié)構(gòu)!
//V1.3修改說明
//增加了對UCOSII延時的支持.
//如果使用ucosII,delay_init會自動設(shè)置SYSTICK的值,使之與ucos的TICKS_PER_SEC對應(yīng).
//delay_ms和delay_us也進(jìn)行了針對ucos的改造.
//delay_us可以在ucos下使用,而且準(zhǔn)確度很高,更重要的是沒有占用額外的定時器.
//delay_ms在ucos下,可以當(dāng)成OSTimeDly來用,在未啟動ucos時,它采用delay_us實(shí)現(xiàn),從而準(zhǔn)確延時
//可以用來初始化外設(shè),在啟動了ucos之后delay_ms根據(jù)延時的長短,選擇OSTimeDly實(shí)現(xiàn)或者delay_us實(shí)現(xiàn).
//V1.4修改說明 20110929
//修改了使用ucos,但是ucos未啟動的時候,delay_ms中中斷無法響應(yīng)的bug.
//V1.5修改說明 20120902
//在delay_us加入ucos上鎖,防止由于ucos打斷delay_us的執(zhí)行,可能導(dǎo)致的延時不準(zhǔn)。
//////////////////////////////////////////////////////////////////////////////////
static u8 fac_us=0;//us延時倍乘數(shù)
static u16 fac_ms=0;//ms延時倍乘數(shù),在ucos下,代表每個節(jié)拍的ms數(shù)
#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定義了,說明使用ucosII了.
//systick中斷服務(wù)函數(shù),使用ucos時用到
void SysTick_Handler(void)
{
OSIntEnter(); //進(jìn)入中斷
OSTimeTick(); //調(diào)用ucos的時鐘服務(wù)程序
OSIntExit(); //觸發(fā)任務(wù)切換軟中斷
}
#endif
//初始化延遲函數(shù)
//當(dāng)使用ucos的時候,此函數(shù)會初始化ucos的時鐘節(jié)拍
//SYSTICK的時鐘固定為HCLK時鐘的1/8
//SYSCLK:系統(tǒng)時鐘
void delay_init(u8 SYSCLK)
{
#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定義了,說明使用ucosII了.
u32 reload;
#endif
SysTick->CTRL&=~(1<<2);//SYSTICK使用外部時鐘源
fac_us=SYSCLK/8;//不論是否使用ucos,fac_us都需要使用
#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定義了,說明使用ucosII了.
reload=SYSCLK/8;//每秒鐘的計數(shù)次數(shù) 單位為K
reload*=1000000/OS_TICKS_PER_SEC;//根據(jù)OS_TICKS_PER_SEC設(shè)定溢出時間
//reload為24位寄存器,最大值:16777216,在72M下,約合1.86s左右
fac_ms=1000/OS_TICKS_PER_SEC;//代表ucos可以延時的最少單位
SysTick->CTRL|=1<<1; //開啟SYSTICK中斷
SysTick->LOAD=reload; //每1/OS_TICKS_PER_SEC秒中斷一次
SysTick->CTRL|=1<<0; //開啟SYSTICK
#else
fac_ms=(u16)fac_us*1000;//非ucos下,代表每個ms需要的systick時鐘數(shù)
#endif
}
#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定義了,說明使用ucosII了.
//延時nus
//nus為要延時的us數(shù).
void delay_us(u32 nus)
{
u32 ticks;
u32 told,tnow,tcnt=0;
u32 reload=SysTick->LOAD;//LOAD的值
ticks=nus*fac_us; //需要的節(jié)拍數(shù)
tcnt=0;
OSSchedLock();//阻止ucos調(diào)度,防止打斷us延時
told=SysTick->VAL; //剛進(jìn)入時的計數(shù)器值
while(1)
{
tnow=SysTick->VAL;
if(tnow!=told)
{
if(tnow else tcnt+=reload-tnow+told; told=tnow; if(tcnt>=ticks)break;//時間超過/等于要延遲的時間,則退出. } }; OSSchedUnlock();//開啟ucos調(diào)度 } //延時nms //nms:要延時的ms數(shù) void delay_ms(u16 nms) { if(OSRunning==TRUE)//如果os已經(jīng)在跑了 { if(nms>=fac_ms)//延時的時間大于ucos的最少時間周期 { OSTimeDly(nms/fac_ms);//ucos延時 } nms%=fac_ms; //ucos已經(jīng)無法提供這么小的延時了,采用普通方式延時 } delay_us((u32)(nms*1000));//普通方式延時 } #else//不用ucos時 //延時nus //nus為要延時的us數(shù). void delay_us(u32 nus) { u32 temp; SysTick->LOAD=nus*fac_us; //時間加載 SysTick->VAL=0x00; //清空計數(shù)器 SysTick->CTRL=0x01 ; //開始倒數(shù) do { temp=SysTick->CTRL; } while((temp&0x01)&&!(temp&(1<<16)));//等待時間到達(dá) SysTick->CTRL=0x00; //關(guān)閉計數(shù)器 SysTick->VAL =0X00; //清空計數(shù)器 } //延時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; //清空計數(shù)器 SysTick->CTRL=0x01 ; //開始倒數(shù) do { temp=SysTick->CTRL; } while((temp&0x01)&&!(temp&(1<<16)));//等待時間到達(dá) SysTick->CTRL=0x00; //關(guān)閉計數(shù)器 SysTick->VAL =0X00; //清空計數(shù)器 } #endif /*****************主程序 test.c**************/ #include "sys.h" #include "usart.h" #include "delay.h" #include "led.h" #include "includes.h" //ALIENTEK戰(zhàn)艦STM32開發(fā)板實(shí)驗(yàn)53 //UCOSII實(shí)驗(yàn)1-任務(wù)調(diào)度 //技術(shù)支持:www.openedv.com //廣州市星翼電子科技有限公司 /////////////////////////UCOSII任務(wù)設(shè)置/////////////////////////////////// //START 任務(wù) //設(shè)置任務(wù)優(yōu)先級 #define START_TASK_PRIO 10 //開始任務(wù)的優(yōu)先級設(shè)置為最低 //設(shè)置任務(wù)堆棧大小 #define START_STK_SIZE 64 //任務(wù)堆棧 OS_STK START_TASK_STK[START_STK_SIZE]; //任務(wù)函數(shù) void start_task(void *pdata); //LED0任務(wù) //設(shè)置任務(wù)優(yōu)先級 #define LED0_TASK_PRIO 7 //設(shè)置任務(wù)堆棧大小 #define LED0_STK_SIZE 64 //任務(wù)堆棧 OS_STK LED0_TASK_STK[LED0_STK_SIZE]; //任務(wù)函數(shù) void led0_task(void *pdata); //LED1任務(wù) //設(shè)置任務(wù)優(yōu)先級 #define LED1_TASK_PRIO 6 //設(shè)置任務(wù)堆棧大小 #define LED1_STK_SIZE 64 //任務(wù)堆棧 OS_STK LED1_TASK_STK[LED1_STK_SIZE]; //任務(wù)函數(shù) void led1_task(void *pdata); int main(void) { Stm32_Clock_Init(9); //系統(tǒng)時鐘設(shè)置 delay_init(72); //延時初始化 LED_Init(); LED_Init(); //初始化與LED連接的硬件接口 OSInit(); OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO );//創(chuàng)建起始任務(wù) OSStart(); } //開始任務(wù) void start_task(void *pdata) { OS_CPU_SR cpu_sr=0; pdata = pdata; OS_ENTER_CRITICAL();//進(jìn)入臨界區(qū)(無法被中斷打斷) OSTaskCreate(led0_task,(void *)0,(OS_STK*)&LED0_TASK_STK[LED0_STK_SIZE-1],LED0_TASK_PRIO); OSTaskCreate(led1_task,(void *)0,(OS_STK*)&LED1_TASK_STK[LED1_STK_SIZE-1],LED1_TASK_PRIO); OSTaskSuspend(START_TASK_PRIO);//掛起起始任務(wù). OS_EXIT_CRITICAL();//退出臨界區(qū)(可以被中斷打斷) } //LED0任務(wù) void led0_task(void *pdata) { while(1) { LED0=0; delay_ms(50); LED0=1; delay_ms(50); }; } //LED1任務(wù) void led1_task(void *pdata) { while(1) { LED1=0; delay_ms(300); LED1=1; delay_ms(300); }; } /*********相關(guān)講解*************/ 第五章 SYSTEM 文件夾介紹 上一章,我們介紹了如何在 MDK3.80A 下建立 STM32 工程,在這個新建的工程之中,我 們用到了一個 SYSTEM 文件夾里面的代碼,此文件夾里面的代碼由 ALIENTEK 提供,是 STM32F103 系列的底層核心驅(qū)動函數(shù),可以用在 STM32F103 系列的各個型號上面,方便大家快速構(gòu)建自己的工程。 SYSTEM 文件夾下包含了 delay、 sys、 usart 等三個文件夾。分別包含了 delay.c、 sys.c、 usart.c及其頭文件。通過這 3 個 c 文件,可以快速的給任何一款 STM32 構(gòu)建最基本的框架。使用起來是很方便的。 本章,我們將向大家介紹這些代碼,通過這章的學(xué)習(xí),大家將了解到這些代碼的由來,也 希望大家可以靈活使用 SYSTEM 文件夾提供的函數(shù),來快速構(gòu)建工程,并實(shí)際應(yīng)用到自己的項(xiàng)目中去。 本章包括如下 3 個小結(jié): 5.1,delay 文件夾代碼介紹; 5.2,sys 文件夾代碼介紹; 5.3,usart 文件夾代碼介紹; 5.1 delay 文件夾代碼介紹 delay 文件夾內(nèi)包含了 delay.c 和 delay.h 兩個文件,這兩個文件用來實(shí)現(xiàn)系統(tǒng)的延時功能,其中包含 3 個函數(shù)(這里我們不講 SysTick_Handler 函數(shù),該函數(shù)在講 ucos 的時候再介紹) : void delay_init(u8 SYSCLK); void delay_ms(u16 nms); void delay_us(u32 nus); 下面分別介紹這三個函數(shù),在介紹之前,我們先了解一下編程思想:CM3 內(nèi)核的處理器, 內(nèi)部包含了一個 SysTick 定時器,SysTick 是一個 24 位的倒計數(shù)定時器,當(dāng)計到 0 時,將從RELOAD 寄存器中自動重裝載定時初值。只要不把它在 SysTick 控制及狀態(tài)寄存器中的使能位清除,就永不停息。SysTick 在《STM32 的參考手冊》(這里是指 V10.0 版本,下同)里面介紹的很簡單,其詳細(xì)介紹,請參閱《Cortex-M3 權(quán)威指南》第 133 頁。我們就是利用 STM32 的內(nèi)部 SysTick 來實(shí)現(xiàn)延時的,這樣既不占用中斷,也不占用系統(tǒng)定時器。 這里我們將介紹的是 ALIENTEK 提供的最新版本的延時函數(shù),該版本的延時函數(shù)支持在 ucos 下面使用,它可以和 ucos 共用 systick 定時器。首先我們簡單介紹下 ucos 的時鐘:ucos 運(yùn)行需要一個系統(tǒng)時鐘節(jié)拍(類似 “心跳”),而這個節(jié)拍是固定的(由 OS_TICKS_PER_SEC 設(shè)置),比如 5ms(設(shè)置:OS_TICKS_PER_SEC=200 即可),在 STM32 下面,一般是由 systick來提供這個節(jié)拍,也就是 systick 要設(shè)置為 5ms 中斷一次,為 ucos 提供時鐘節(jié)拍,而且這個時鐘一般是不能被打斷的(否則就不準(zhǔn)了)。 因?yàn)樵?ucos 下 systick 不能再被隨意更改,如果我們還想利用 systick 來做 delay_us 或者delay_ms 的延時,就必須想點(diǎn)辦法了,這里我們利用的是時鐘摘取法。以 delay_us 為例,比如delay_us (50),在剛進(jìn)入 delay_us 的時候先計算好這段延時需要等待的 systick 計數(shù)次數(shù),這里為 50*9 (假設(shè)系統(tǒng)時鐘為 72Mhz,那么 systick 每增加 1,就是 1/9us) ,然后我們就一直統(tǒng)計 systick的計數(shù)變化,直到這個值變化了 50*9,一旦檢測到變化達(dá)到或者超過這個值,就說明延時 50us時間到了。 下面我們開始介紹這幾個函數(shù)。 ALIENTEK 戰(zhàn)艦STM32開發(fā)板 www.openedv.com 79 5.1.1 delay_init 函數(shù) 該函數(shù)用來初始化 2 個重要參數(shù):fac_us 以及 fac_ms;同時把 SysTick 的時鐘源選擇為外部時鐘,如果使用了 ucos,那么還會根據(jù) OS_TICKS_PER_SEC 的配置情況,來配置SysTick的中斷時間,并開啟 SysTick 中斷。具體代碼如下: //初始化延遲函數(shù) //當(dāng)使用 ucos 的時候,此函數(shù)會初始化 ucos 的時鐘節(jié)拍 //SYSTICK 的時鐘固定為 HCLK 時鐘的 1/8 //SYSCLK:系統(tǒng)時鐘 void delay_init(u8 SYSCLK) { #ifdef OS_CRITICAL_METHOD //如果 OS_CRITICAL_METHOD 定義了, 則使用了 ucosII. u32 reload; #endif SysTick->CTRL&=~(1<<2); //SYSTICK 使用外部時鐘源 fac_us=SYSCLK/8; //不論是否使用 ucos,fac_us 都需要使用 #ifdef OS_CRITICAL_METHOD//如果 OS_CRITICAL_METHOD 定義了,則使用了 ucosII. reload=SYSCLK/8; //每秒鐘的計數(shù)次數(shù) 單位為 K reload*=1000000/OS_TICKS_PER_SEC;//根據(jù) OS_TICKS_PER_SEC 設(shè)定溢出時間 //reload 為 24 位寄存器,最大值:16777216,在 72M 下,約合 1.86s 左右 fac_ms=1000/OS_TICKS_PER_SEC;//代表 ucos 可以延時的最少單位 SysTick->CTRL|=1<<1; //開啟 SYSTICK 中斷 SysTick->LOAD=reload; //每 1/OS_TICKS_PER_SEC 秒中斷一次 SysTick->CTRL|=1<<0; //開啟 SYSTICK #else fac_ms=(u16)fac_us*1000; //非 ucos 下,代表每個 ms 需要的 systick 時鐘數(shù) #endif } 可以看到,delay_init 函數(shù)使用了條件編譯,來選擇不同的初始化過程,如果不使用 ucos的時候,就和《不完全手冊》介紹的方法是一樣的,而如果使用 ucos 的時候,則會進(jìn)行一些不同的配置,這里的條件編譯是根據(jù) OS_CRITICAL_METHOD 這個宏來確定的,因?yàn)橹灰褂昧?ucos,就一定會定義 OS_CRITICAL_METHOD 這個宏。 SysTick-> CALIB 不常用,在這里我們也用不到,故不介紹了。
SysTick 是 MDK 定義了的一個結(jié)構(gòu)體(在 stm32f10x_map.h 里面),里面包含 CTRL、 LOAD、VAL、CALIB 等 4 個寄存器,
SysTick->CTRL 的各位定義如圖 5.1.1.1 所示:
SysTick->CTRL&=0xfffffffb;這一句把 SysTick 的時鐘選擇外部時鐘,這里需要注意的是:SysTick 的時鐘源自 HCLK 的 8 分頻,假設(shè)我們外部晶振為 8M,然后倍頻到 72M,那么 SysTick的時鐘即為 9Mhz,也就是 SysTick 的計數(shù)器 VAL 每減 1,就代表時間過了 1/9us。
在不使用 ucos 的時候:fac_us,為 us 延時的基數(shù),也就是延時 1us,SysTick->LOAD 所應(yīng)設(shè)置的值。 fac_ms 為 ms 延時的基數(shù),也就是延時 1ms, SysTick->LOAD 所應(yīng)設(shè)置的值。 fac_us為 8 位整形數(shù)據(jù), fac_ms 為 16 位整形數(shù)據(jù)。 Systick 的時鐘來自系統(tǒng)時鐘 8 分頻, 正因?yàn)槿绱?,系統(tǒng)時鐘如果不是 8 的倍數(shù)(不能被 8 整除),則會導(dǎo)致延時函數(shù)不準(zhǔn)確,這也是我們推薦外部時鐘選擇 8M 的原因。這點(diǎn)大家要特別留意。
當(dāng)使用 ucos 的時候, fac_us,還是 us 延時的基數(shù),不過這個值不會被寫到 SysTick->LOAD
寄存器來實(shí)現(xiàn)延時,而是通過時鐘摘取的辦法實(shí)現(xiàn)的(后面會介紹)。而 fac_ms 則代表 ucos 自帶的延時函數(shù)所能實(shí)現(xiàn)的最小延時時間(如 OS_TICKS_PER_SEC=200,那么 fac_ms 就是 5ms)。
5.1.2 delay_us 函數(shù)
該函數(shù)用來延時指定的 us,其參數(shù) nus 為要延時的微秒數(shù)。該函數(shù)有使用 ucos 和不使用ucos 兩個版本,這里我們分別介紹,首先是不使用 ucos 的時候,實(shí)現(xiàn)函數(shù)如下:
//延時 nus
//nus 為要延時的 us 數(shù).
void delay_us(u32 nus)
{
ALIENTEK 戰(zhàn)艦STM32開發(fā)板 www.openedv.com
81
u32 temp;
SysTick->LOAD=nus*fac_us; //時間加載
SysTick->VAL=0x00; //清空計數(shù)器
SysTick->CTRL=0x01 ; //開始倒數(shù)
do
{
temp=SysTick->CTRL;
}
while((temp&0x01)&&!(temp&(1<<16)));//等待時間到達(dá)
SysTick->CTRL=0x00; //關(guān)閉計數(shù)器
SysTick->VAL =0X00; //清空計數(shù)器
}
有了上面對 SysTick 寄存器的描述,這段代碼不難理解。其實(shí)就是先把要延時的 us 數(shù)換算成 SysTick 的時鐘數(shù),然后寫入 LOAD 寄存器。然后清空當(dāng)前寄存器 VAL 的內(nèi)容,再開啟倒數(shù)
功能。等到倒數(shù)結(jié)束,即延時了 nus。最后關(guān)閉 SysTick,清空 VAL 的值。實(shí)現(xiàn)一次延時 nus的操作,但是這里要注意 nus 的值,不能太大,必須保證 nus<=(2^24)/fac_us,否則將導(dǎo)致延時時間不準(zhǔn)確。這里特別說明一下:temp&0x01,這一句是用來判斷 systick 定時器是否還處于開啟狀態(tài),可以防止 systick 被意外關(guān)閉導(dǎo)致的死循環(huán)。
再來看看使用 ucos 的時候,delay_us 的實(shí)現(xiàn)函數(shù)如下:
//延時 nus
//nus 為要延時的 us 數(shù).
void delay_us(u32 nus)
{
u32 ticks;
u32 told,tnow,tcnt=0;
u32 reload=SysTick->LOAD; //LOAD 的值
ticks=nus*fac_us; //需要的節(jié)拍數(shù)
tcnt=0;
OSSchedLock(); //阻止 ucos 調(diào)度,防止打斷 us 延時
told=SysTick->VAL; //剛進(jìn)入時的計數(shù)器值
while(1)
{
tnow=SysTick->VAL;
if(tnow!=told)
{
if(tnow
told=tnow;
if(tcnt>=ticks)break;//時間超過/等于要延遲的時間,則退出.
}
};
OSSchedUnlock(); //開啟 ucos 調(diào)度
}
ALIENTEK 戰(zhàn)艦STM32開發(fā)板 www.openedv.com
82
這里就正是利用了我們前面提到的時鐘摘取法,ticks 是延時 nus 需要等待的 SysTick 計數(shù)次數(shù)(也就是延時時間),told 用于記錄最近一次的 SysTick->VAL 值,然后 tnow 則是當(dāng)前的SysTick->VAL 值,通過他們的對比累加,實(shí)現(xiàn) SysTick 計數(shù)次數(shù)的統(tǒng)計,統(tǒng)計值存放在 tcnt 里面,然后哦通過對比 tcnt 和 ticks,來判斷延時是否到達(dá),從而達(dá)到不修改 SysTick 實(shí)現(xiàn) nus 的延時,從而可以和 ucos 共用一個 SysTick。
上面的 OSSchedLock 和 OSSchedUnlock 是 ucos 提供的兩個函數(shù),用于調(diào)度上鎖和解鎖,這里為了防止 ucos 在 delay_us 的時候打斷延時,可能導(dǎo)致的延時不準(zhǔn),所以我們利用這兩個函數(shù)來實(shí)現(xiàn)免打斷,從而保證延時精度!同時,此時的 delay_us,可以實(shí)現(xiàn)最長 2^32us 的延時,大概是 4294 秒。
5.1.3 delay_ms 函數(shù)
該函數(shù)用來延時指定的 ms,其參數(shù) nms 為要延時的微秒數(shù)。該函數(shù)同樣有使用 ucos 和不使用 ucos 兩個版本,這里我們分別介紹,首先是不使用 ucos 的時候,實(shí)現(xiàn)函數(shù)如下:
//延時 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; //清空計數(shù)器
SysTick->CTRL=0x01 ; //開始倒數(shù)
do
{
temp=SysTick->CTRL;
}
while((temp&0x01)&&!(temp&(1<<16)));//等待時間到達(dá)
SysTick->CTRL=0x00; //關(guān)閉計數(shù)器
SysTick->VAL =0X00; //清空計數(shù)器
}
此部分代碼和 5.1.2 節(jié)的 delay_us(非 ucos 版本)大致一樣,但是要注意因?yàn)?LOAD 僅僅是一個 24bit 的寄存器,延時的 ms 數(shù)不能太長。否則超出了 LOAD 的范圍,高位會被舍去,導(dǎo)致延時不準(zhǔn)。最大延遲 ms 數(shù)可以通過公式:nms<=0xffffff*8*1000/SYSCLK 計算。SYSCLK單位為 Hz,nms 的單位為 ms。如果時鐘為 72M,那么 nms 的最大值為 1864ms。超過這個值,建議通過多次調(diào)用 delay_ms 實(shí)現(xiàn),否則就會導(dǎo)致延時不準(zhǔn)確。
再來看看使用 ucos 的時候,delay_ms 的實(shí)現(xiàn)函數(shù)如下:
//延時 nms
//nms:要延時的 ms 數(shù)
void delay_ms(u16 nms)
ALIENTEK 戰(zhàn)艦STM32開發(fā)板 www.openedv.com
83
{
if(OSRunning==TRUE)//如果 os 已經(jīng)在跑了
{
if(nms>=fac_ms)//延時的時間大于 ucos 的最少時間周期
{
OSTimeDly(nms/fac_ms);//ucos 延時
}
nms%=fac_ms;//ucos 已經(jīng)無法提供這么小的延時了,采用普通方式延時
}
delay_us((u32)(nms*1000)); //普通方式延時
}
該函數(shù)中,OSRunning 是 ucos 正在運(yùn)行的一個標(biāo)志,OSTimeDly 是 ucos 提供的一個基于ucos 時鐘節(jié)拍的延時函數(shù),其參數(shù)代表延時的時鐘節(jié)拍數(shù)(假設(shè)OS_TICKS_PER_SEC=200,
那么 OSTimeDly(1),就代表延時 5ms)。
當(dāng) ucos 還未運(yùn)行的時候,我們的 delay_ms 就是直接由 delay_us 實(shí)現(xiàn)的, ucos 下的 delay_us可以實(shí)現(xiàn)很長的延時而不溢出! ,所以放心的使用 delay_us 來實(shí)現(xiàn) delay_ms,不過由于 delay_us的時候,任務(wù)調(diào)度被上鎖了,所以還是建議不要用 delay_us 來延時很長的時間,否則影響整個系統(tǒng)的性能。
當(dāng) ucos 運(yùn)行的時候,我們的 delay_ms 函數(shù)將先判斷延時時長是否大于等于 1 個 ucos 時鐘節(jié)拍 (fac_ms) ,當(dāng)大于這個值的時候,我們就通過調(diào)用 ucos 的延時函數(shù)來實(shí)現(xiàn) (此時任務(wù)可以調(diào)度) ,不足 1 個時鐘節(jié)拍的時候,直接調(diào)用 delay_us 函數(shù)實(shí)現(xiàn)(此時任務(wù)無法調(diào)度) 。
上一篇:STM32系統(tǒng)學(xué)習(xí)——SysTick(系統(tǒng)定時器)
下一篇:STM32中,systick具體延時時間計算
推薦閱讀
史海拾趣
設(shè)計資源 培訓(xùn) 開發(fā)板 精華推薦
- 有獎電源小課堂 | PI 1250V高壓氮化鎵芯片
- 逛村田在線云展廳,了解通信、移動、工業(yè)+環(huán)境、健康四大領(lǐng)域的應(yīng)用干貨!
- 答題贏好禮 | TDK專題報道只等你來(第3期)
- 免費(fèi)申請 | SFH 4713B紅外LED樣片,體驗(yàn)革新性IR:6技術(shù)
- ST有獎直播 | 75V降壓控制器和隔離降壓方案
- 【搶樓贏禮】聊聊“我眼中的ADI實(shí)驗(yàn)室電路”
- ADI有獎下載活動之19:ADI可編程邏輯控制器(PLC)解決方案(更新版)
- 免費(fèi)申請測評 | Sipeed MAix BiT AIoT 開發(fā)套件,搭載K210、屏幕和攝像頭
- 有獎直播|ADI電機(jī)控制解決方案
- 智能零售機(jī)器人實(shí)現(xiàn)柔性生產(chǎn)和庫存高效去化
- 長城汽車開創(chuàng)出行機(jī)器人時代
- 國能與AutoX與達(dá)成戰(zhàn)略合作在歐洲部署大規(guī)模的機(jī)器人出租車
- 5G車載終端的特性及應(yīng)用
- 汽車的電子模組設(shè)計面臨哪些挑戰(zhàn)?
- 華為發(fā)文教用戶解決手機(jī)無線投屏失敗、卡頓現(xiàn)象
- 未來一年智能手機(jī)產(chǎn)業(yè)或會迎新一輪變局
- Galaxy Note 20拆解:散熱規(guī)格和后蓋材質(zhì)變化大
- 數(shù)碼論:一加前進(jìn)一小步,歐加一大步
- 徐州鑫晶半導(dǎo)體首批12英寸半導(dǎo)體大硅片成功下線了