給平頂山公安局做網(wǎng)站的公司前端培訓(xùn)哪個機(jī)構(gòu)靠譜
前言
學(xué)習(xí)是永無止境的,就算之前學(xué)過的東西再次學(xué)習(xí)一遍也能狗學(xué)習(xí)到很多東西,輸入捕獲很早之前就用過了,但是僅僅是照搬例程沒有去進(jìn)行理解。溫故而知新!
定時器
定時器簡介
定時器的分類
高級定時器 通用定時器 基本定時器,針對不同情況可以選擇自己所需要的定時器,以下是這幾種定時器的主要功能。
高級定時器:
- 計(jì)數(shù)器單元
- 輸入捕獲
- 重復(fù)計(jì)數(shù)器
- PWM模式
- 互補(bǔ)輸出和死區(qū)插入
- 支持針對定位的增量(正交)編碼器和霍爾傳感器電路
- 剎車功能
- DMA功能
通用定時器:
- 計(jì)數(shù)器單元
- 輸入捕獲
- PWM模式
- 支持針對定位的增量(正交)編碼器和霍爾傳感器電路
- DMA功能
基本定時器:
- 計(jì)數(shù)器單元
- DMA功能
定時器的功能
我們使用定時器很多時候使用都是用做于計(jì)數(shù)作用,同樣也可以作為PWM輸出,輸入捕獲(脈寬測量,頻率檢測)等等,有的時候我們還會使用DMA+PWM輸出這樣的功能,總之定時器對于我們進(jìn)行產(chǎn)品開發(fā)是必不可少的。
定時器的配置
主要寄存器
這里我使用的是航芯ACM32FP0X系列的單片機(jī),不過其他單片機(jī)用法也是一樣的。
這里我們主要關(guān)注以上六個寄存器,中斷使能寄存器、狀態(tài)寄存器、事件產(chǎn)生寄存器、預(yù)分頻寄存器、自動加載寄存器、捕獲/比較寄存器。其他的寄存器不是說不重要,只是在本次實(shí)驗(yàn)中主要理解這幾個寄存器就好。
PWM配置
因?yàn)楸敬螌?shí)驗(yàn)沒有使用外置的脈沖發(fā)生器,所以使用單片機(jī)上另一個通用定時器來配置PWM,然后使用高級定時器去進(jìn)行輸入捕獲。
TIM_Handler_PWM.Instance = TIM15;TIM_Handler_PWM.Init.ARRPreLoadEn = TIM_ARR_PRELOAD_ENABLE; TIM_Handler_PWM.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; TIM_Handler_PWM.Init.CounterMode = TIM_COUNTERMODE_UP; TIM_Handler_PWM.Init.RepetitionCounter = 0; TIM_Handler_PWM.Init.Prescaler = (timer_clock/TIM_CLOCK_FREQ)*1 - 1; if (timer_clock%TIM_CLOCK_FREQ > TIM_CLOCK_FREQ/2) {TIM_Handler_PWM.Init.Prescaler = TIM_Handler_PWM.Init.Prescaler + 1; }TIM_Handler_PWM.Init.Period = (TIM_CLOCK_FREQ/100000)*20 - 1; // period = 1ms
首先是常規(guī)的配置,這里我選擇的是定時器15作為PWM口進(jìn)行輸出,然后不分頻所以APB的時鐘就是定時器的時鐘。然后就是自動重裝載值A(chǔ)RR,和預(yù)分配系數(shù)Prescaler的配置;這兩個參數(shù)共同決定了配置的PWM輸出極限頻率是多少。
PWM輸出頻率 Fre =?。?
這里來解析一下為什么要使用 TIM_CLOCK_FREQ這個參數(shù):
TIM_CLOCK_FREQ 代表的是定時器經(jīng)過分頻之后能夠達(dá)到的極限頻率,我們可以來推導(dǎo)一下,timer_clock(也就是主時鐘APBCLK)分頻之后?就是?,
簡單約去公約數(shù),得到的就是TIM_CLOCK_FREQ,所以當(dāng)重裝載值為1的時候TIM_CLOCK_FREQ就是最高頻率。再來解釋一下周期是怎么得出的,由于1s之內(nèi)計(jì)數(shù)器計(jì)數(shù)了TIM_CLOCK_FREQ次,所以一次需要的時間是1/TIM_CLOCK_FREQ,所以周期和重裝載值之間的關(guān)系就是T= ,這里除以1000的原因是將秒的單位換算成毫秒。OK,也不知道講清楚了沒有,之前也搞不懂這個關(guān)系式,后來推導(dǎo)出來的時候還感覺蠻巧妙的。
配置完這些再配置一下模式和占空比(CCR)和引腳就行了
輸入捕獲的配置
TIM_IC_InitTypeDef Tim_IC_Init_Para; TIM_Handler.Instance = TIM1;TIM_Handler.Init.ARRPreLoadEn = TIM_ARR_PRELOAD_ENABLE; TIM_Handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; TIM_Handler.Init.CounterMode = TIM_COUNTERMODE_UP; TIM_Handler.Init.RepetitionCounter = 0; TIM_Handler.Init.Prescaler = 0; TIM_Handler.Init.Period = 0xFFFF; // max period TIM1_MSP_Pre_Init(&TIM_Handler); HAL_TIMER_Base_Init(&TIM_Handler); Tim_IC_Init_Para.TIFilter = TIM_TI1_FILTER_LVL(0); // no filter Tim_IC_Init_Para.ICPolarity = TIM_SLAVE_CAPTURE_ACTIVE_RISING_FALLING; Tim_IC_Init_Para.ICPrescaler = TIM_IC1_PRESCALER_1; Tim_IC_Init_Para.ICSelection = TIM_ICSELECTION_DIRECTTI; // TI1FP1 HAL_TIMER_Capture_Config(TIM_Handler.Instance, &Tim_IC_Init_Para, TIM_CHANNEL_1); TIM1_MSP_Post_Init();
上面也是一些很常規(guī)的配置,配置了分頻系數(shù)(為1意味著定時器的頻率和APB時鐘一致),重裝載值為0xFFFF,這些數(shù)據(jù)傳達(dá)了一個怎樣的信息呢?說明了使用輸入捕獲的頻率可高達(dá)64MHz(APB時鐘為64MHz),說明捕獲精度可以達(dá)到1/64000000 s,也就是15ns,最長捕獲時間間隔為1023us(15ns * 0xFFFF)。然后下一個就是設(shè)置捕獲觸發(fā)模式,可能不同的單片機(jī)的庫設(shè)置起來會有細(xì)微差別,但是大致意思是相同的。由于我們需要收集這些鞋數(shù)據(jù)然后在串口上打印出來所以我這里使用了中斷觸發(fā),在中斷里面收集數(shù)據(jù)。
HAL_TIMER_Clear_Capture_Flag(&TIM_Handler, TIM_CHANNEL_1);NVIC_ClearPendingIRQ(TIM1_CC_IRQn); NVIC_ClearPendingIRQ(TIM1_BRK_UP_TRG_COM_IRQn);NVIC_EnableIRQ(TIM1_CC_IRQn); NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn); HAL_TIMER_Base_Init(&TIM_Handler); HAL_TIM_ENABLE_IT(&TIM_Handler, TIM_IT_CC1);HAL_TIM_ENABLE_IT(&TIM_Handler, TIMER_INT_EN_UPD); //計(jì)數(shù)器向上溢出/向下溢出 用于記錄更新次數(shù)HAL_TIM_Capture_Start(TIM_Handler.Instance, TIM_CHANNEL_1);
當(dāng)然這里還加了個溢出中斷,用于輔助捕獲計(jì)算超出最大捕獲長度的電平時間,具體思路就是當(dāng)計(jì)數(shù)器溢出的時候在事件更新中斷里面設(shè)置一個變量進(jìn)行加加。
可以大致看一下捕獲中斷里面的函數(shù),主要是獲取觸發(fā)了捕獲中斷之后將數(shù)據(jù)寫入事先定義好的數(shù)組,然后在定義一個變量進(jìn)行計(jì)數(shù)。
void TIM1_CC_IRQHandler(void)
{uint32_t status; status = TIM1->SR; if ( (status & TIMER_SR_CC1IF) && ((TIM1->CCMR1) & (BIT0|BIT1)) ) {if(flag1 == 1)flag2 = 1;flag1 = 1;Capture_data[0][capture_times] = TIM1->CCR1;}if ((status & TIMER_SR_CC2IF) && ((TIM1->CCMR1) & (BIT8|BIT9)) ) {Capture_data[1][capture_times] = TIM1->CCR2; }capture_times++; NVIC_ClearPendingIRQ(TIM1_CC_IRQn);
}
然后在主函數(shù)里面獲取標(biāo)志位之后打印顯示就可以了
這樣在主函數(shù)當(dāng)中我們就可以是去使用到這些數(shù)據(jù)然后打印到串口。這里要注意一點(diǎn)我使用的是雙邊沿觸發(fā)所以打印出來的不是一個周期,而是兩段占空比的數(shù)值。
當(dāng)然這里我還使用了DMA+PWM進(jìn)行PWM輸出,如果再講下去就有點(diǎn)多了,這部分內(nèi)容網(wǎng)上也有很多。
總結(jié)
輸入捕獲是高級定時器和通用定時器才有的功能,主要通過設(shè)置觸發(fā)邊沿和設(shè)置捕獲頻率來對脈寬進(jìn)行一個測量,得出脈寬之后我們就可以很容易地計(jì)算出頻率和周期。