STM下純軟件實現(xiàn)精確定時
#include "stm32f10x.h"
#include "core_cm3.h"
__asm int Dellayus(u32 usec)
{
loop
}
int main(void)
{
}
調(diào)試:
第一個100微妙延時函數(shù)運行前
第一個100微妙延時函數(shù)運行后
所花系統(tǒng)時鐘周期8579-1379=7200個系統(tǒng)時鐘,時間精確為0.00013293-0.0003293=0.0001秒,
也就是100微秒。延時函數(shù)通過軟件模擬以及硬件調(diào)試同樣精確,如果延時參數(shù)大于255微秒,調(diào)用
時會多耗兩個時鐘周期(0.028微秒)用于從代碼段加載常數(shù)??梢孕薷拇a修正誤差。最大定時不能
超過(232-1) ÷ 18 ≈ 238.6秒。
以上方法可以節(jié)約系統(tǒng)定時器資源,避免和其他代碼爭用定時器。通常用于微秒級延時。
版主的建議非常好,是該增加時鐘參數(shù)以適應(yīng)不同的時鐘頻率,改了一下代碼,目前軟件仿真測試沒問題,等晚上再用JLink
測試一下(理論上應(yīng)該沒問題,已經(jīng)考慮了閃存預(yù)取優(yōu)化)。
#include "stm32f10x.h"
#include "core_cm3.h"
__asm void Dellayus(u32 usec,u8 freq) //freq參數(shù)為系統(tǒng)時鐘頻率(SYSCLK),單位MHz,且必須能被4整除,且必須大 于等于16,常用的
{ //有24,36,48,56,72,如果一定要使用8MHz則必須滿足延時時間大于2微秒,但freq一定不要
loop
} //函數(shù)最低耗時11個時鐘周期,上面usec*(freq/4) - 2為循環(huán)代碼的耗時(此處減2是因為最后一次循環(huán)BNE沒有跳轉(zhuǎn),只消耗1個時鐘比跳轉(zhuǎn)的3個時鐘節(jié)約2個所以減去2才是最終循環(huán)的耗時),9就是其它代碼的耗時
//比如頻率為8MHz時延時2微秒所需延時周期數(shù)為2*8=16個時鐘,將值帶入上面的公式即為 2 * (8 / 4) - 2 + 9 =11 即為函數(shù)體耗時,再加上5個周期的調(diào)用開銷最終消耗16個時鐘周期,同時這也是最低延時周期數(shù)。
int main(void)
{
}
示例代碼見附件:
附件1: 軟件延時測試.rar (文件大小: 21 KB 下載次數(shù):218次)
附件2: 軟件延時測試增強版.rar (文件大小: 22 KB 下載次數(shù):309次)
1、頂,花了不少功夫!
不過在不同時鐘條件下,應(yīng)該就又要修改代碼了吧?
比如36M?8M?
所以 建議加入一個時鐘參數(shù),這樣比較通用一點.
不過在不同時鐘條件下,應(yīng)該就又要修改代碼了吧?
比如36M?8M?
所以
2、謝謝樓主!,我軟件測試延時的時候并沒有出現(xiàn)當(dāng)參數(shù)大于255微妙的時候會多消耗2個時鐘周期的情況,一樣很準(zhǔn)啊。還有我用J-LINK仿真SW模式,單步,那個SEC沒有變化,不知道是怎么回事。還有一個問題:為什么返回值要用int 不太懂匯編
3、需要將J-LINK設(shè)為JTAG模式才能讀出SEC值,另外返回值用int 當(dāng)時主要是想以后增加函數(shù)功能
4、這個建議非常好,馬上上個增強版
5、呵呵,還不如用C的
void Delay_us(unsigned int t)
{
int i;
for(i=0; i<144*t; i++){
;
}
}
比上面匯編的要準(zhǔn): 同時1000個循環(huán),
匯編用時為: 100.844ms
C及時: 100.139ms
void
{
}
比上面匯編的要準(zhǔn):
6、搞個-O2優(yōu)化試試,還準(zhǔn)不準(zhǔn).
另外換個時鐘頻率試試,還準(zhǔn)不準(zhǔn)?
另外換個時鐘頻率試試,還準(zhǔn)不準(zhǔn)?
7、
//加個編譯項就行了.
#define OSC (8) //定義為8M
#define OSC_D ((OSC*144)/8)
#pragma O3
void Delay_us(unsigned int t)
{
}
//測試
//運行時間為100.014ms
呵呵,純?yōu)橛螒蛑?在這種CPU,延時最好是用原子的方法了.8、用原子的戰(zhàn)艦開發(fā)板測試,用樓主這種方法,得到的延時總理理論時間的1.5倍,比如要延遲1秒,實際總是1.5秒。
懷疑CPU運行在48M,但是我設(shè)置的的確是72M,是不是哪里設(shè)置有問題?
懷疑CPU運行在48M,但是我設(shè)置的的確是72M,是不是哪里設(shè)置有問題?
9、要完全精確的話還得提前關(guān)掉中斷哦……
不過一般也不需要這么精確的延時,獻上我的,不占用定時器資源哦:
#define RT_TICK_PER_SECOND 100
void hw_tsc_init() // TSC-timestamp counter
{
unsigned int cnts;
cnts = (unsigned int)9000000 / RT_TICK_PER_SECOND;
SysTick->CTRL&=0xfffffffb;//bit2清空,選擇外部時鐘,也即HCLK/8
SysTick->LOAD=cnts-1;
SysTick->VAL = 0; // write to clean
SysTick->CTRL=0x01 ; //開始倒數(shù) 不產(chǎn)生中斷
}
void hw_tick_start()
{
unsigned int cnts;
cnts = (unsigned int)9000000 / RT_TICK_PER_SECOND;
SysTick->CTRL&=0xfffffffb;//bit2清空,選擇外部時鐘,也即HCLK/8
SysTick->LOAD=cnts-1;
SysTick->CTRL=0x01 ; //開始倒數(shù) 不產(chǎn)生中斷
SysTick->CTRL = 0x03; // 啟動systick并產(chǎn)生中斷
}
void hw_delay_us(unsigned int us)
{
unsigned int start ,target,cur;
while(us > 500) // 防止us超過systick周期。(假設(shè)systick周期超過500us)
{
hw_delay_us(500);
us -= 500;
}
start = SysTick->VAL;
target = (start-us*9);
if(start
{
target += (9000000 / RT_TICK_PER_SECOND);
do
{
cur = SysTick->VAL;
}while(cur<=start || cur>target); // target不能等于start,否則死循環(huán)。也即us不能等于systick周期
}
else // target <= start
{
do
{
cur = SysTick->VAL;
}while(target<=start); // 假設(shè)target為一個很小的值,則cur有可能在循環(huán)周期內(nèi)溢出而大于target,故須加上cur<=start的條件
}
}
void hw_delay_ms(unsigned int ms)
{
while(ms--)
{
hw_delay_us(500);
hw_delay_us(500);
}
}
不過一般也不需要這么精確的延時,獻上我的,不占用定時器資源哦:
#define
void
{
unsigned
cnts
SysTick->CTRL&=0xfffffffb;//bit2清空,選擇外部時鐘,也即HCLK/8
SysTick->LOAD=cnts-1;
SysTick->VAL
SysTick->CTRL=0x01
}
void
{
unsigned
cnts
SysTick->CTRL&=0xfffffffb;//bit2清空,選擇外部時鐘,也即HCLK/8
SysTick->LOAD=cnts-1;
SysTick->CTRL=0x01
SysTick->CTRL
}
void
{
unsigned
while(us
{
hw_delay_us(500);
us
}
start
target
if(start
{
target
do
{
cur
}while(cur<=start
}
else
{
do
{
cur
}while(target<=start);
}
}
void
{
while(ms--)
{
hw_delay_us(500);
hw_delay_us(500);
}
}
10、我不用軟件延時的...
我一直用systick延時。
11、樓主給力,不過不推薦用樓主這種笨辦法,樓主大可以移植ucos,移植成功后,你想定多久有多久,要多精確有多精確。
同時,我覺得用定時器實現(xiàn)精確延時比這個方法靠譜得多。
同時,我覺得用定時器實現(xiàn)精確延時比這個方法靠譜得多。
12、ucos的定時是以系統(tǒng)時基為單位的,比如OS_CFG_TICK_RATE_HZ設(shè)為100時就只能精確到10ms,也就是說高于10ms并且步進為10ms(50ms,500ms能較精確,但55ms就不精確了)可以比較精確定時,那我說延時10us如何用ucos的定時器定時呢?
13、你可以增大ucos的時鐘節(jié)拍數(shù),然后用OSTimeTick()來實現(xiàn)定時
14、STM32的定時器多的是,基本都用不完吧
評論