教你手寫滴答定時器(看完這篇你就會手動寫啦,保姆級講解)---- 2020.3.25

先上完整滴答定時器部分代碼!!!

EXTI.c部分

#include "ext.h"

#define SYSTICK_E	9

/**
  * @brief  用於SysTick初始化
  * @param  None
  * @retval None
  */
void TICK_Init(void)
{
	//1.設置SysTick的時鐘頻率
	SysTick->CTRL&=~(1<<2);	//選擇當前時鐘爲AHB/8,在72MHz情況下,SysTick就是9MHz
}

/**
  * @brief  ms級別延遲,最大值在達到1864的情況下,會出現時間不精確
  * @param  u32 count:ms級別延遲時間數
  * @retval None
  */
void sleep_ms(u32 count)
{
	if(count<=0)return;
	
	u8 n=count/1000;
	u16 last=count%1000;
	if(n>=1){
		//循環n次1000ms
		u8 i=0;
		for(i=0;i<n;i++){
			sleep_us(1000*1000);
		}
	}
	
	if(last!=0){
		//在等待最後剩餘的時間
		sleep_us(last*1000);
	}
}

/**
  * @brief  us級別延遲
  * @param  u32 count:us級別延遲時間數
  * @retval None
  */
void sleep_us(u32 count)
{
	if(count<=0)return;
	
	//1.先設置LOAD寄存器
	SysTick->LOAD=SYSTICK_E*count;
	//2.清零
	SysTick->VAL=0;
	//3.使能(開啓SysTick)
	SysTick->CTRL=0x01;
	while(!(SysTick->CTRL&0x10000));
	//關閉SysTick
	SysTick->CTRL&=~(1<<0);
}

EXTI.h部分

void TICK_Init(void);		//用於SysTick初始化
void sleep_ms(u32 count);	//ms級別延遲
void sleep_us(u32 count);	//us級別延遲

好!按照老樣子,接下來開始詳細講解每行代碼的用處,以及爲什麼這樣寫!

滴答定時器初始化部分

//1.設置SysTick的時鐘頻率
SysTick->CTRL&=~(1<<2);	//選擇當前時鐘爲AHB/8,在72MHz情況下,SysTick就是9MHz

//
在這裏插入圖片描述//由上圖可以得知滴答定時器爲24位,自動裝載值也是24位,並且計數器計數的方式是從當前給定的load裝載值一直減少到0。
在這裏插入圖片描述//有上一篇文章我們得知,HCLK爲72MHz,那麼systick就是9MHz。
//
在這裏插入圖片描述//
在這裏插入圖片描述//由上圖我們可以得知,設置CLKSOURCE爲0,則代表當前時鐘頻率是9MHz。
//所以左移兩位,並且取反。

滴答定時器延時us部分

if(count<=0)return;

//這裏就是爲了防止輸入該函數的參數是0,那麼如果不加這個操作的話,這個函數毫無意義,最終返回。

//1.先設置LOAD寄存器
SysTick->LOAD=SYSTICK_E*count;

//在上main我們已經得知,該時鐘頻率爲9MHz,那麼就相當於爲1/9us,也就是每滴答一次就是1/9us,但是我們想要延時1us,是以1us爲基準單位的,那麼這裏就需要我們人爲擴大9倍。

//2.清零
SysTick->VAL=0;

//這裏就是在賦值的時候先清零,以防止之前寄存器裏面有值。

//3.使能(開啓SysTick)
SysTick->CTRL=0x01;
while(!(SysTick->CTRL&0x10000));
//關閉SysTick
SysTick->CTRL&=~(1<<0);

//在這裏插入圖片描述//當第0位爲0時,不使能滴答定時器,反之當第0位爲1時,則使能滴答定時器。並且再次清零。
//在這裏插入圖片描述//同時由上圖得知,當裝載值減少到0時,則該位返回1。
//那麼我們就需要通過判斷該位是否爲1來得知延時是否完成。
//由於COUNTFLAG爲第17位。
//
在這裏插入圖片描述
//最後關閉使能,取反即可。

滴答定時器延時ms部分

if(count<=0)return;

//同樣的道理,不再贅述。

u8 n=count/1000;
u16 last=count%1000;
if(n>=1){
	//循環n次1000ms
	u8 i=0;
	for(i=0;i<n;i++){
		sleep_us(1000*1000);
	}
}

//正常來說該裝載值寄存器是24位的,那麼通過計算器可知爲16777216。這時是以秒爲單位的那麼折算成ms,則需要除以1000。然後再除以9,得到如下所示。

在這裏插入圖片描述//
在這裏插入圖片描述//相當於最終算出來ms函數的輸入參數最大是1864,不能超過1864。那麼我們如果輸入的參數大於1864呢?那我們該怎麼辦?
//所以我們爲了解決這個問題,這時需要知道此時輸入的參數裏面到底有多少個1000,也就是有多少個1s。
//
在這裏插入圖片描述//如上圖所示,我們通過除運算,得知有多少個1000ms,通過%運算,得知還剩多少ms。
//如果n>=1代表肯定比1000多,那麼就需要先循環延時n次1000ms。

if(last!=0){
	//在等待最後剩餘的時間
	sleep_us(last*1000);
}

//如果最終執行完n次1000ms之後還有剩餘一部分時間(ms)(小於1000ms),那麼就在執行last ms即可。這就完美解決問題了!!!滴答定時器如此簡單!!!

結束語

如果覺得這篇文章還不錯的話,記得點贊 ,支持下!!!

以後我會繼續推出關於嵌入式(stm32)的協議方面的講解,下一講會推出DMA部分的文章!敬請期待!!!

**我先休息去了~~╭(╯^╰)╮

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