程序完成利用STM32F103C8T6 滴答時鍾 SysTick進行定時,每隔1秒輸出腳PC13的小燈閃爍一下。
注意,小燈每隔1秒閃爍只是轉換狀態,可以理解為定時或1個脈沖時間,但並不是頻率,頻率要2個
脈沖時間2秒,所以要測頻率的話是0.5Hz,即頻率=1/2秒= 0.5Hz 。
1 使用中斷的方法
修改stm32f10x_it.c文件,增加下面內容:
extern void LED_PC13 (); //外部引入函數聲明 加在文件首部
void SysTick_Handler(void) //中斷入口
{
LED_PC13 (); //亮燈取反滅燈函數
}
下面是main.c
#include "stm32f10x.h"
//**********************************************************************************
void GPIO_CFG() //亮燈引腳配置函數
{
GPIO_InitTypeDef GPIO_InitStructure; //聲明GPIO_InitStructure結構變量
// 原版創作,引用請指明出處 https://www.cnblogs.com/beiyhs/p/12438787.html 北有寒山
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); //使能AHB預分頻器到端口C的開關
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //指定腳13輸出
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //設置為推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //設定端口最快輸出50MHz
GPIO_Init(GPIOC, &GPIO_InitStructure); //按以上參數設置C口
GPIO_SetBits( GPIOC, GPIO_Pin_13); //置高GPIO_Pin_13,關閉LED
}
//*********************************************************************************
void LED_PC13(void) //亮燈取反滅燈函數
{
GPIO_WriteBit(GPIOC, GPIO_Pin_13, //指定修改PC13腳的位
(BitAction)((1-GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13)))); //讀PC狀態后取反
}
//*********************************************************************************
//*********************************************************************************
int main(void)
{
GPIO_CFG() ; //亮燈腳PC13的設置函數
SysTick_Config(9000000); //重裝值設9M,定時1秒
//SysTick_Config(9000); //重裝值設9K,定時1毫秒
//SysTick_Config(9); //重裝值設9,定時1微秒
//NVIC_SetPriority (SysTick_IRQn, 0); //設SysTick中斷優先級最高,不會在中斷時被別的中斷打斷
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //配置SysTick時鍾=HCLK時鍾/8
//即72M/8=9MHz 即記數9M次耗時1秒
//注意要放在SysTick_Config函數之后
//如果屏蔽此句,默認使用的時鍾是72M
//將上面9000000 改為72000000仍可得到
//1秒定時
while (1)
{ }
}
說明:
1.1 systick定時器的內部計數器是24位遞減的,最大重裝值0xFFFFFF,即16777215,設置時不能超此值。
1.2 使用systick定時器,只需調用SysTick_Config(uint32_t ticks)函數即可,該函數可以自動完成重裝載
值的裝載、時鍾源選擇、計數寄存器復位、中斷優先級的設置(默認最低)、開中斷、開始計數的工作。
一次搞定,是不是很爽。函數是在core_cm3.h頭文件中進行定義的。
1.3 要修改時鍾源,比如外部時鍾,可以修改SysTick_CLKSourceConfig函數內部,也可按照SysTick_Config
中默認設置FCLK不變。
1.4 要修改中斷優先級調用 NVIC_SetPriority函數,函數在core_cm3.h
1.5 systick是cortex_m3的標配,不是外設。故不需要在RCC寄存器組打開他的時鍾。
1.6 每次systick溢出后會置位計數標志位和中斷標志位,計數標志位在計數器重裝載后被清除,而中斷標志位
也會隨着中斷服務程序的響應被清除,所以這兩個標志位都不需要手動清除。
2 使用延時的方法
下面是下面是main.c
//*********************************************************************************
#include "stm32f10x.h"
//************************************************
void delay_ms(unsigned int ms) //把ms換成us,下面9000換成9,就改成了us定時函數
{
unsigned int tmp = 0;
SysTick->LOAD = ms * 9000; // 重裝寄存器 設置 72MHz/9000=9MHz
SysTick->VAL = 0x00; // 當前計數寄存器 清零
SysTick->CTRL = 0x01; // 控制寄存器 使能systick,禁止中斷,時鍾頻率AHB/8
do
{
tmp = SysTick->CTRL; // 讀取控制寄存器的值賦給tmp
}
while (!(tmp & (1<<16))); // 就是讀取tmp的第16位的值,這一位如果為0就表示計數器的值不是0(即
// 還在計數),如果是1就表示計數器已經自減到0了,計數結束。
//假設該值為0,還在計數,套上外面的!取反為1,繼續做do的內容。
SysTick->VAL = 0x00; // 當前計數寄存器 清零
SysTick->CTRL = 0x00; //失能systick
}
//*********************************************************************************
int main(void)
{
GPIO_CFG() ; //亮燈腳PC13 設置 參照上面同名函數,不再貼出
while(1)
{
Delay_ms(1000);
GPIO_SetBits(GPIOC,GPIO_Pin_13);
Delay_ms(1000);
GPIO_ResetBits(GPIOC,GPIO_Pin_13);
}
}
//*********************************************************************************************************
說明: 上面的定時函數如果用到us級別時,誤差還是不能忽視的,尤其是10us級別誤差很大的這是因為
程序指令的執行、跳轉都是要花費時間的,也是在us級別。如果是us級精確定時輸出控制的話,可以考
慮使用PWM方式,畢竟設定一次即可,后面全是硬件自己控制。