1. 程式人生 > >STM32學習之普通定時器是否能定時1us?

STM32學習之普通定時器是否能定時1us?

對於STM32F10x系列使用普通定時器能否能定時1us,筆者一直抱有懷疑態度。

於是筆者做了下述實驗:

程式碼:

主函式:

int main(void)
{
SystemClock_Config();
LED_Init();//LED初始化
NVIC_Config();
Timer2_Config();
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
while(1)
{
}

}

GPIO設定

void LED_Init(void)
{
GPIO_InitTypeDef  GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD, ENABLE);

//使能PB,PE時鐘

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;            //埠PC0配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //配置推輓輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO速度50MHz
GPIO_Init(GPIOC, &GPIO_InitStructure);     //初始化GPIOC.0
GPIO_SetBits(GPIOC,GPIO_Pin_0);                      //PC.0輸出高


GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3;              //埠PD3配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //配置推輓輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO速度50MHz
GPIO_Init(GPIOD, &GPIO_InitStructure);     //初始化GPIOD.3
GPIO_SetBits(GPIOD,GPIO_Pin_3);                      //PD.3輸出高

}

NVIC設定:

void NVIC_Config(void)  
{  
NVIC_InitTypeDef NVIC_InitStructure;  

//選擇中斷分組0
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);  


//選擇TIM2的中斷通道  
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;       

//搶佔式中斷優先順序設定為0  
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  

//響應式中斷優先順序設定為0  
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  

//使能中斷  
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  

NVIC_Init(&NVIC_InitStructure);  

TIM2設定:

void Timer2_Config(void)  
{   
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;


RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);   

TIM_DeInit(TIM2);  

//定時公式:(TIM_Period + 1) * (TIM_Prescaler + 1) / TIM2 Clock,向上
//TIM2時鐘設定72MHz  
TIM_TimeBaseStructure.TIM_Period=10-1;  //自動重灌載暫存器的值  

TIM_TimeBaseStructure.TIM_Prescaler=(36-1);         //時鐘預分頻數  

TIM_TimeBaseStructure.TIM_ClockDivision=0;  //取樣分頻(捕獲)普通定時不需要這個設定 ,無論怎麼改變不影響輸出頻率

TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上計數模式  

TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);  

TIM_ClearFlag(TIM2,TIM_FLAG_Update);               //清除溢位中斷標誌  

TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);  //使能更新中斷

TIM_Cmd(TIM2,ENABLE);                              //開啟時鐘  

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , DISABLE); /*先關閉等待使用*/    
}   


中斷函式:

void TIM2_IRQHandler(void)   
{  
u8 i;
u8 ReadValue;  
if(TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET)    //檢測是否發生溢位更新事件  
{  
TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);//清除TIM2的中斷待處理位  

                /************************************************/

                /***********************重點********************/
/*
for(i=0;i<10;i++)
{
GPIO_ResetBits(GPIOD,GPIO_Pin_3);
}
 */

                /***********************重點********************/

                /*************************************************/
ReadValue = GPIO_ReadOutputDataBit(GPIOC,GPIO_Pin_0);  

if(ReadValue == 0)                   //若該埠當前為低電平,  
{  
GPIO_SetBits(GPIOC,GPIO_Pin_0);//將其改為高電平輸出 ;  
}      
else                            //若該埠當前為高電平,  
{  
GPIO_ResetBits(GPIOC,GPIO_Pin_0);   //將其改為低電平輸出;  
}  
}          
}  

上述程式碼下載到微控制器裡面,輸出100KHz的方波(5us定時),但是,筆者欲1us定時,簡單認為:

TIM_TimeBaseStructure.TIM_Period=2-1;  //自動重灌載暫存器的值  

TIM_TimeBaseStructure.TIM_Prescaler=(36-1);         //時鐘預分頻數  

後來發現,輸出方波最高頻率為250KHz,在網上查閱各類部落格,發現並不能解決問題。

當隨手在中斷函式中加了幾句話(Period,Prescaler值不變),發現波形改變,於是就開始懷疑1us定時暫存器那樣設定,是不是中斷函式還未執行完畢,又發生了中斷,導致一直在中斷函式中。

為驗證猜想,筆者做了一個實驗,在中斷函式中執行了10個:

for(i=0;i<10;i++)
{
GPIO_ResetBits(GPIOD,GPIO_Pin_3);
}

輸出波形是這樣的:


正常100KHz波形是這樣的(上面那個函式遮蔽):


10個多餘的週期會導致波形頻率差這麼多,欲定時1us(前提中斷函式比較複雜),採用普通定時器這樣的辦法是不可以的。

如果中斷函式程式碼時一句或者兩句,定時1us還有可能,普通定時器否則定時1us不可能實現。