對於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不可能實現。