一。如何測量脈沖寬度或脈沖頻率
輸入捕獲的原理
用51單片機檢測的方法:(這里我們不用51的輸入中斷功能,只利用定時器來檢測)
前提是定時器沒有溢出。
用STM32檢測脈沖寬度:
這里的CC1E,CC1P指的是捕獲通道1,捕獲通道2是CC2E,CC2P。。。。
CC1E控制使能,CC1P控制極性
捕獲/比較使能寄存器(TIMx_CCER)
CC1P設(shè)置為0為上升沿有效,設(shè)置為1時為下降沿有效。
a. 開啟定時器
b. 使能相應(yīng)的輸入捕獲
c. 設(shè)置捕獲極性
捕獲以后會進入相應(yīng)的中斷,同時把計數(shù)器中的值保存下來。
二。 STM32的輸入捕獲模式
輸入捕獲模式可以用來測量脈沖寬度或者測量頻率。 STM32 的定時器,除了 TIM6 和 TIM7,其他定時器都有輸入捕獲功能。
在輸入捕獲模式下,當(dāng)檢測到ICx信號上相應(yīng)的邊沿后,計數(shù)器的當(dāng)前值被鎖存到捕獲/比較寄器(TIMx_CCRx)中。當(dāng)捕獲事件發(fā)生時,相應(yīng)的CCxIF標(biāo)志(TIMx_SR寄存器)被置’1’,如果使能了中斷或者DMA操作,則將產(chǎn)生中斷或者DMA操作。
三。STM32輸入捕獲模式相關(guān)的寄存器
本實驗利用TIM5的通道1(PA0)來做輸入捕獲。捕獲 PA0 上高電平的脈寬(用 WK_UP 按鍵輸入高電平),通過串口打印高電平脈寬時間。
1. 捕獲/比較模式寄存器 1:TIMx_CCMR1
當(dāng)在輸入捕獲模式下使用的時候,對應(yīng)圖 15.1.1 的第二行描述,從圖中可以看出,TIMx_CCMR1 明顯是針對 2 個通道的配置,低八位[7: 0]用于捕獲/比較通道 1 的控制,而高八位[15:8]則用于捕獲/比較通道 2 的控制。
2. 捕獲/比較使能寄存器:TIMx_CCER
本次實驗我們要用到這個寄存器的最低 2 位,CC1E 和 CC1P 位。
3.控制寄存器:TIMx_CR1
我們只用到了它的最低位,也就是用來使能定時器的。
4.DMA/中斷使能寄存器:TIMx_DIER
本實驗我們需要用到中斷來處理捕獲數(shù)據(jù),所以必須開啟通道 1 的捕獲比較中斷,即 CC1IE 設(shè)置為 1。
5.狀態(tài)寄存器(TIMx_SR)
CC1IF:捕獲/比較1 中斷標(biāo)記(Capture/Compare 1 interrupt flag)
如果通道CC1配置為輸出模式:
當(dāng)計數(shù)器值與比較值匹配時該位由硬件置’1’,但在中心對稱模式下除外(參考TIMx_CR1寄存器的CMS位)。它由軟件清’0’。
四。輸入捕獲的配置步驟:
1)開啟 TIM5 時鐘和 GPIOA 時鐘,配置 P A0 為下拉輸入。
2)初始化 TIM5,設(shè)置 TIM5 的 ARR 和 PSC。
例:
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = arr; //設(shè)定計數(shù)器自動重裝值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //設(shè)置預(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); //根據(jù)指定的參數(shù)初始化 Tim5
3)設(shè)置 TIM5 的輸入比較參數(shù),開啟輸入捕獲。
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
例:
TIM_ICInitTypeDef TIM5_ICInitStructure;
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);
4)使能捕獲和更新中斷(設(shè)置 TIM5 的 DIER 寄存器)
TIM_ITConfig( TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允許更新中斷和捕獲中斷
因為我們要捕獲的是高電平信號的脈寬,所以,第一次捕獲是上升沿,第二次捕獲時下降沿,必須在捕獲上升沿之后,設(shè)置捕獲邊沿為下降沿,同時,如果脈寬比較長,那么定時器就會溢出,對溢出必須做處理,否則結(jié)果就不準(zhǔn)了。這兩件事,我們都在中斷里面做,所以必須開啟捕獲中斷和更新中斷。
5)設(shè)置中斷分組,編寫中斷服務(wù)函數(shù)
6)使能定時器(設(shè)置 TIM5 的 CR1 寄存器)
TIM_Cmd(TIM5,ENABLE ); //使能定時器 5
通過以上 6 步設(shè)置,定時器 5 的通道 1 就可以開始輸入捕獲了。
五。 實驗例程
//定時器 5 通道 1 輸入捕獲配置
TIM_ICInitTypeDef TIM5_ICInitStructure;
void TIM5_Cap_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //①使能 TIM5 時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //①使能 GPIOA 時鐘
//初始化 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
}
程序設(shè)計思路:
完成一次高電平捕獲后,只要 TIM5CH1_CAPTURE_STA 的第 7 位一直為 1,那么就不會進行第二次捕獲,我們在 main 函數(shù)處理完捕獲數(shù)據(jù)后,將 TIM5CH1_CAPTURE_STA置零,就可以開啟第二次捕獲。
main函數(shù)中:
if(TIM5CH1_CAPTURE_STA&0X80)//成功捕獲到了一次上升沿
{
temp=TIM5CH1_CAPTURE_STA&0X3F;
temp*=65536;//溢出時間總和
temp+=TIM5CH1_CAPTURE_VAL;//得到總的高電平時間
printf("HIGH:%d usrn",temp); //打印總的高點平時間
TIM5CH1_CAPTURE_STA=0; //開啟下一次捕獲
}