STM32F103學(xué)習(xí)筆記 (九) 輸入捕獲實驗
這個實驗是用 TIM5 的通道 1( PA0) 來做輸入捕獲, 捕獲 PA0 上高電平的脈寬(用 WK_UP 按鍵輸入高電平),通過串口打印高電平脈寬時間。
初始化里邊先設(shè)置上升沿為輸入捕捉,進入捕捉中斷后,記錄TIM5_CNT的值,然后配置捕獲信號為下降沿捕獲,當(dāng)下降沿到來時,發(fā)生捕獲,并記錄此時的 TIM5_CNT 值。這樣,前后兩次 TIM5_CNT 之差,就是高電平的脈寬,
同時 TIM5 的計數(shù)頻率我們是知道的,從而可以計算出高電平脈寬的準(zhǔn)確時間。
相應(yīng)的配置步驟為:
(1)開啟TIM5時鐘和GPIO時鐘,設(shè)置PA0為下拉輸入
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);//使能TIM5時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能GPIOA時鐘
(2)初始化TIM5,設(shè)置TIM5的ARR和PSC。(3)設(shè)置TIM5的輸入比較參數(shù),開啟輸入捕獲。(4)使能捕獲和更新中斷(設(shè)置TIM5的DIER寄存器) (5)設(shè)置中斷分組,編寫中斷服務(wù)函數(shù) 。
if(TIM_GetITStatus(TIM5,TIM_IT_Update)!=RESET){}//判斷是否為更新中斷
if(TIM_GetITStatus(TIM5,TIM_IT_CC1)!=RESET){}//判斷是否發(fā)生捕獲事件
TIM_ClearITPendingBit(TIM5,TIM_IT_CC1|TIM_IT_Update);//清除中斷和捕獲標(biāo)志位
(6)使能定時器(設(shè)置TIM5的CR1寄存器)
TIM_Cmd(TIM5,ENABLE);//使能定時器5
timer.c中:
//定時器5通道1輸入捕獲配置
TIM_ICInitTypeDefTIM5_ICInitStructure;
voidTIM5_Cap_Init(u16arr,u16psc)
{
GPIO_InitTypeDefGPIO_InitStructure;
TIM_TimeBaseInitTypeDefTIM_TimeBaseStructure;
NVIC_InitTypeDefNVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);//①使能TIM5時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//①使能GPIOA時鐘
215
//初始化GPIOA.0①
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//PA0設(shè)置
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;//PA0輸入
GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化GPIOA.0
GPIO_ResetBits(GPIOA,GPIO_Pin_0);//PA0下拉
//②初始化TIM5參數(shù)
TIM_TimeBaseStructure.TIM_Period=arr;//設(shè)定計數(shù)器自動重裝值
TIM_TimeBaseStructure.TIM_Prescaler=psc;//預(yù)分頻器
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;//TDTS=Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//TIM向上計數(shù)模式
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);//初始化TIMx
//③初始化TIM5輸入捕獲通道1
TIM5_ICInitStructure.TIM_Channel=TIM_Channel_1;//選擇輸入端IC1映射到TI1上
TIM5_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//上升沿捕獲
TIM5_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//映射到TI1上
TIM5_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;//配置輸入分頻,不分頻
TIM5_ICInitStructure.TIM_ICFilter=0x00;//IC1F=0000配置輸入濾波器不濾波
TIM_ICInit(TIM5,&TIM5_ICInitStructure);//初始化TIM5輸入捕獲通道1
//⑤初始化NVIC中斷優(yōu)先級分組
NVIC_InitStructure.NVIC_IRQChannel=TIM5_IRQn;//TIM3中斷
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//先占優(yōu)先級2級
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;//從優(yōu)先級0級
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//IRQ通道被使能
NVIC_Init(&NVIC_InitStructure);//初始化NVIC
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//④允許更新中斷捕獲中斷
TIM_Cmd(TIM5,ENABLE);//⑥使能定時器5
}
u8TIM5CH1_CAPTURE_STA=0;//輸入捕獲狀態(tài)
u16TIM5CH1_CAPTURE_VAL;//輸入捕獲值
//⑤定時器5中斷服務(wù)程序
voidTIM5_IRQHandler(void)
{
if((TIM5CH1_CAPTURE_STA&0X80)==0)//還未成功捕獲
{
if(TIM_GetITStatus(TIM5,TIM_IT_Update)!=RESET)
{
216
if(TIM5CH1_CAPTURE_STA&0X40)//已經(jīng)捕獲到高電平了
{
if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高電平太長了
{
TIM5CH1_CAPTURE_STA|=0X80;//標(biāo)記成功捕獲了一次
TIM5CH1_CAPTURE_VAL=0XFFFF;
}elseTIM5CH1_CAPTURE_STA++;
}
}
if(TIM_GetITStatus(TIM5,TIM_IT_CC1)!=RESET)//捕獲1發(fā)生捕獲事件
{
if(TIM5CH1_CAPTURE_STA&0X40)//捕獲到一個下降沿
{
TIM5CH1_CAPTURE_STA|=0X80;//標(biāo)記成功捕獲到一次上升沿
TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising);//設(shè)置為上升沿捕獲
}else//還未開始,第一次捕獲上升沿
{
TIM5CH1_CAPTURE_STA=0;//清空
TIM5CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM5,0);
TIM5CH1_CAPTURE_STA|=0X40;//標(biāo)記捕獲到了上升沿
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);//設(shè)置為下降沿捕獲
}
}
}
TIM_ClearITPendingBit(TIM5,TIM_IT_CC1|TIM_IT_Update);//清除中斷標(biāo)志位
}
其中重要的是TIM5 的中斷服務(wù)函數(shù),TIM5CH1_CAPTURE_STA,是用來記錄捕獲狀態(tài):
設(shè)置 TIM5_CH1 捕獲上升沿,這在TIM5_Cap_Init 函數(shù)執(zhí)行的時候就設(shè)置好了,然后等待上升沿中斷到來, 當(dāng)捕獲到上升沿中斷,此時如果 TIM5CH1_CAPTURE_STA 的第 6 位為 0, 則表示還沒有捕獲到新的上升沿, 就先把TIM5CH1_CAPTURE_STA、 TIM5CH1_CAPTURE_VAL 和 TIM5->CNT 等清零,然后再設(shè)置TIM5CH1_CAPTURE_STA 的第 6 位為 1, 標(biāo)記捕獲到高電平, 最后設(shè)置為下降沿捕獲,等待下降沿到來。如果等待下降沿到來期間,定時器發(fā)生了溢出,就在 TIM5CH1_CAPTURE_STA里面對溢出次數(shù)進行計數(shù),當(dāng)最大溢出次數(shù)來到的時候,就強制標(biāo)記捕獲完成(雖然此時還沒有捕獲到下降沿)。當(dāng)下降沿到來的時候,先設(shè)置 TIM5CH1_CAPTURE_STA 的第 7 位為 1,標(biāo)記成功捕獲一次高電平,然后讀取此時的定時器值到 TIM5CH1_CAPTURE_VAL 里面,最后設(shè)置為上升沿捕獲,回到初始狀態(tài)。
main.c:
externu8TIM5CH1_CAPTURE_STA;//輸入捕獲狀態(tài)
externu16TIM5CH1_CAPTURE_VAL;//輸入捕獲值
intmain(void)
{
u32temp=0;
delay_init();//延時函數(shù)初始化
NVIC_Configuration();//設(shè)置NVIC中斷分組2
uart_init(9600);//串口初始化波特率為9600
LED_Init();//LED端口初始化
TIM3_PWM_Init(899,0);//不分頻。PWM頻率=72000/(899+1)=80Khz
TIM5_Cap_Init(0XFFFF,72-1);//以1Mhz的頻率計數(shù)
while(1)
{
delay_ms(10);
TIM_SetCompare2(TIM3,TIM_GetCapture2(TIM3)+1);
if(TIM_GetCapture2(TIM3)==300)
TIM_SetCompare2(TIM3,0);
if(TIM5CH1_CAPTURE_STA&0X80)//成功捕獲到了一次上升沿
{
temp=TIM5CH1_CAPTURE_STA&0X3F;
218
temp*=65536;//溢出時間總和
temp+=TIM5CH1_CAPTURE_VAL;//得到總的高電平時間
printf("HIGH:%dusrn",temp);//打印總的高點平時間
TIM5CH1_CAPTURE_STA=0;//開啟下一次捕獲
}
}
}
如果用杜邦線把PB5和PA0連起來,就會看到串口助手里以固定的時間寬度輸出。