嵌入式學習總結11,

自己學習總結用,有些亂,勿怪

1、SysTick定時器應用之一——用於延時函式

SysTick為簡單的向下計數的24位計時器,可以使用處理器時鐘或外部參考時鐘(通常是片上時鐘源)。當不使用OS時,SysTick定時器可以用作簡單的定時器外設,用以產生週期性中斷、延時或者時間測量。

SysTick定時器操作存在4個暫存器

SysTick->CTRL,SysTick->LOAD,SysTick->VAL,其中SysTick->CALIB 校準值暫存器,為軟體提供了校準資訊。CMSIS1。2後就不用這個暫存器了。於是查了一下CMSIS的版本號,位於core_cm4。h中。

因此主要就關注3個暫存器

SysTick->CTRL

SysTick->LOAD

SysTick->VAL

首先看delay_init函式

void delay_init(u8 SYSCLK)

{

SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);

fac_us=SYSCLK/8; //不論是否使用OS,fac_us都需要使用

fac_ms=(u16)fac_us*1000; //非OS下,代表每個ms需要的systick時鐘數

}

第一個函式SysTick_CLKSourceConfig

void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)

{

/* Check the parameters */

assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));

if (SysTick_CLKSource == SysTick_CLKSource_HCLK)

{

SysTick->CTRL |= SysTick_CLKSource_HCLK;

}

else

{

SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;

}

}

就是配置SysTick->CTRL暫存器

#define SysTick_CLKSource_HCLK_Div8 ((uint32_t)0xFFFFFFFB)

嵌入式學習總結11,

可見SysTick->CTRL暫存器第2位置0,即使用外部參考時鐘。

delay_init(168); //初始化延時函式

則fac_us == 168 / 8== 21,即1us內要有21個節拍,

fac_ms ==168 / 8 * 1000 ==21000,即1ms內要有21000個節拍

再看delay_us函式

//延時nus

//nus為要延時的us數。

//注意:nus的值,不要大於798915us(最大值即2^24/fac_us@fac_us=21)

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; //清空計數器

}

delay_xms函式

//延時nms

//注意nms的範圍

//SysTick->LOAD為24位暫存器,所以,最大延時為:

//nms<=0xffffff*8*1000/SYSCLK

//SYSCLK單位為Hz,nms單位為ms

//對168M條件下,nms<=798ms

void delay_xms(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; //清空計數器

}

delay_ms函式

//延時nms

//nms:0~65535

void delay_ms(u16 nms)

{

u8 repeat=nms/540; //這裡用540,是考慮到某些客戶可能超頻使用,

//比如超頻到248M的時候,delay_xms最大隻能延時541ms左右了

[當超頻使用時,是M4是248MHZ,根據delay_int分頻可知8分頻,然後,可知248/8=31次每us,然後,reload=31*1000000/200=155000,下面3的定時器時間,即最好系統時間單元是5ms,而105000/31us=5000us=5ms,reload最大值=16777216,在248M下是24位暫存器的理論值,它的延時是16777216/31us=541200.516us=0.5412s]

u16 remain=nms%540;

while(repeat)

{

delay_xms(540);

//這裡相當於一個完整delay_xms()週期,即540ms,有多少個repeat完整的重複週期,

repeat——;

}

if(remain)delay_xms(remain);

//remain是沒有滿一個delay_xms時,可知在一個delay_xms內小於540ms時的延時多少時間.

}

2、SysTick 是 MDK 定義了的一個結構體(在 core_m4.h 裡面),裡面包含 CTRL、LOAD、VAL、CALIB 等 4 個暫存器,

1、SysTick->CTRL 的各位定義如圖

嵌入式學習總結11,

2、SysTick-> LOAD 的定義如圖

嵌入式學習總結11,

3、SysTick-> VAL 的定義如圖

嵌入式學習總結11,

3、32 位置位/復位暫存器 (BSRR),

接下來我們看看 32 位置位/復位暫存器 (BSRR),顧名思義,這個暫存器是用來置位或者復位 IO 口,該暫存器和 ODR 暫存器具有類似的作用,都可以用來設定 GPIO 埠的輸出位是1 還是 0。暫存器描述如下:

嵌入式學習總結11,

對於低 16 位(0-15),我們往相應的位寫 1,那麼對應的 IO 口會輸出高電平,往相應的位寫 0,對 IO 口沒有任何影響。高 16 位(16-31)作用剛好相反,對相應的位寫 1 會輸出低電平,寫 0沒有任何影響。也就是說,對於 BSRR 暫存器,你寫 0 的話,對 IO 口電平是沒有任何影響的。我們要設定某個 IO 口電平,只需要為相關位設定為 1 即可。而 ODR 暫存器,我們要設定某個IO 口電平,我們首先需要讀出來 ODR 暫存器的值,然後對整個 ODR 暫存器重新賦值來打到設定某個或者某些 IO 口的目的,而 BSRR 暫存器,我們就不需要先讀,而是直接設定。BSRR 暫存器使用方法如下

GPIOA->BSRR=1<<1; //設定 GPIOA。1 為高電平

GPIOA->BSRR=1<<(16+1)//設定 GPIOA。1 為低電平

庫函式操作 BSRR 暫存器來設定 IO 電平的函式為

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

函式 GPIO_SetBits 用來設定一組 IO 口中的一個或者多個 IO 口為高電平。GPIO_ResetBits 用來設定一組 IO 口中一個或者多個 IO 口為低電平。比如我們要設定 GPIOB。5 輸出高,方法為:

GPIO_SetBits(GPIOB,GPIO_Pin_5);//GPIOB。5 輸出高

設定 GPIOB。5 輸出低電平,方法為:

GPIO_ResetBits(GPIOB,GPIO_Pin_5);//GPIOB。5 輸出低

4、

蜂鳴器與 STM32F4 連線原理圖

嵌入式學習總結11,

圖中我們用到一個 NPN 三極體(S8050)來驅動蜂鳴器,R61 主要用於防止蜂鳴器的誤發聲。當 PF。8 輸出高電平的時候,蜂鳴器將發聲,當 PF。8 輸出低電平的時候,蜂鳴器停止發聲。

程式設計時,先設計為下拉即低電平有效,即初始狀態為靜音狀態。