自己學習總結用,有些亂,勿怪
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)
可見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 的各位定義如圖
2、SysTick-> LOAD 的定義如圖
3、SysTick-> VAL 的定義如圖
3、32 位置位/復位暫存器 (BSRR),
接下來我們看看 32 位置位/復位暫存器 (BSRR),顧名思義,這個暫存器是用來置位或者復位 IO 口,該暫存器和 ODR 暫存器具有類似的作用,都可以用來設定 GPIO 埠的輸出位是1 還是 0。暫存器描述如下:
對於低 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 連線原理圖
圖中我們用到一個 NPN 三極體(S8050)來驅動蜂鳴器,R61 主要用於防止蜂鳴器的誤發聲。當 PF。8 輸出高電平的時候,蜂鳴器將發聲,當 PF。8 輸出低電平的時候,蜂鳴器停止發聲。
程式設計時,先設計為下拉即低電平有效,即初始狀態為靜音狀態。