cc2530定时器和捕获比较_ALIENTEK 阿波罗 STM32F767 开发板资料连载十四章 输入捕获实验...
1)實驗平臺:alientek 阿波羅 STM32F767 開發板2)摘自《STM32F7 開發指南(HAL 庫版)》關注官方微信號公眾號,獲取更多資料:正點原子
http://weixin.qq.com/r/hEhUTLbEdesKrfIv9x2W (二維碼自動識別)
第十四章 輸入捕獲實驗
上一章,我們介紹了 STM32F7 的通用定時器作為 PWM 輸出的使用方法,這一章,我們將
向大家介紹通用定時器作為輸入捕獲的使用。在本章中,我們將用 TIM5 的通道 1(PA0)來做
輸入捕獲,捕獲 PA0 上高電平的脈寬(用 KEY_UP 按鍵輸入高電平),通過串口打印高電平脈
寬時間,從本章分為如下幾個部分:
14.1 輸入捕獲簡介
14.2 硬件設計
14.3 軟件設計
14.4 下載驗證
14.5 STM32CubeMX 配置定時器輸入捕獲功能
14.1 輸入捕獲簡介
輸入捕獲模式可以用來測量脈沖寬度或者測量頻率。我們以測量脈寬為例,用一個簡圖來
說明輸入捕獲的原理,如圖 14.1.1 所示:
圖 14.1.1 輸入捕獲脈寬測量原理
如圖 14.1.1 所示,就是輸入捕獲測量高電平脈寬的原理,假定定時器工作在向上計數模式,
圖中 t1~t2 時間,就是我們需要測量的高電平時間。測量方法如下:首先設置定時器通道 x 為
上升沿捕獲,這樣,t1 時刻,就會捕獲到當前的 CNT 值,然后立即清零 CNT,并設置通道 x
為下降沿捕獲,這樣到 t2 時刻,又會發生捕獲事件,得到此時的 CNT 值,記為 CCRx2。這樣,
根據定時器的計數頻率,我們就可以算出 t1~t2 的時間,從而得到高電平脈寬。
在 t1~t2 之間,可能產生 N 次定時器溢出,這就要求我們對定時器溢出,做處理,防止高
電平太長,導致數據不準確。如圖14.1.1所示,t1~t2之間,CNT計數的次數等于:N*ARR+CCRx2,
有了這個計數次數,再乘以 CNT 的計數周期,即可得到 t2-t1 的時間長度,即高電平持續時間。
輸入捕獲的原理,我們就介紹到這。
STM32F767 的定時器,除了 TIM6 和 TIM7,其他定時器都有輸入捕獲功能。STM32F767
的輸入捕獲,簡單的說就是通過檢測 TIMx_CHx 上的邊沿信號,在邊沿信號發生跳變(比如上
升沿/下降沿)的時候,將當前定時器的值(TIMx_CNT)存放到對應的通道的捕獲/比較寄存器
(TIMx_CCRx)里面,完成一次捕獲。同時還可以配置捕獲時是否觸發中斷/DMA 等。
本章我們用到 TIM5_CH1 來捕獲高電平脈寬,捕獲原理如圖 14.1.1 所示,這里我們就不再
多說了。接下來,我們介紹我們本章需要用到的一些寄存器配置,需要用到的寄存器有:TIMx_ARR、
TIMx_PSC、TIMx_CCMR1、TIMx_CCER、TIMx_DIER、TIMx_CR1、TIMx_CCR1 這些寄存
器在前面 2 章全部都有提到(這里的 x=5),我們這里就不再全部羅列了,我們這里針對性的介紹
這幾個寄存器的配置。
首先 TIMx_ARR 和 TIMx_PSC,這兩個寄存器用來設自動重裝載值和 TIMx 的時鐘分頻,
用法同前面介紹的,我們這里不再介紹。
再來看看捕獲/比較模式寄存器 1:TIMx_CCMR1,這個寄存器在輸入捕獲的時候,非常有
用,有必要重新介紹,該寄存器的各位描述如圖 14.1.2 所示:
圖 14.1.2 TIMx_CCMR1 寄存器各位描述
當在輸入捕獲模式下使用的時候,對應圖 14.1.2 的第二行描述,從圖中可以看出,
TIMx_CCMR1 明顯是針對 2 個通道的配置,低八位[7:0]用于捕獲/比較通道 1 的控制,而高八
位[15:8]則用于捕獲/比較通道 2 的控制,因為 TIMx 還有 CCMR2 這個寄存器,所以可以知道
CCMR2 是用來控制通道 3 和通道 4(詳見《STM32F7 中文參考手冊》705 頁,23.4.8 節)。
這里我們用到的是 TIM5 的捕獲/比較通道 1,我們重點介紹 TIMx_CCMR1 的[7:0]位(其
高 8 位配置類似),TIMx_CCMR1 的[7:0]位詳細描述見圖 14.1.3 所示:
圖 14.1.3 TIMx_CCMR1 [7:0]位詳細描述
其中 CC1S[1:0],這兩個位用于 CCR1 的通道配置,這里我們設置 IC1S[1:0]=01,也就是配
置 IC1 映射在 TI1 上(關于 IC1,TI1 不明白的,可以看《STM32F7 中文參考手冊》651 頁的圖
19.1 通用定時器框圖),即 CC1 對應 TIMx_CH1。
輸入捕獲 1 預分頻器 IC1PSC[1:0],這個比較好理解。我們是 1 次邊沿就觸發 1 次捕獲,所
以選擇 00 就是了。
輸入捕獲 1 濾波器 IC1F[3:0],這個用來設置輸入采樣頻率和數字濾波器長度。其中,
是定時器的輸入頻率(TIMxCLK),一般為 54Mhz/108Mhz(看該定時器在那個總線上),而
則是根據TIMx_CR1的CKD[1:0]的設置來確定的,如果CKD[1:0]設置為00,那么
=
。
N 值就是濾波長度,舉個簡單的例子:假設 IC1F[3:0]=0011,并設置 IC1 映射到通道 1 上,且
為上升沿觸發,那么在捕獲到上升沿的時候,再以
的頻率,連續采樣到 8 次通道 1 的電
平,如果都是高電平,則說明卻是一個有效的觸發,就會觸發輸入捕獲中斷(如果開啟了的話)。
這樣可以濾除那些高電平脈寬低于 8 個采樣周期的脈沖信號,從而達到濾波的效果。這里,我
們不做濾波處理,所以設置 IC1F[3:0]=0000,只要采集到上升沿,就觸發捕獲。
再來看看捕獲/比較使能寄存器:TIMx_CCER,該寄存器的各位描述見圖 14.1.3(在第 14
章)。本章我們要用到這個寄存器的最低 2 位,CC1E 和 CC1P 位。這兩個位的描述如圖 14.1.4
所示:
圖 14.1.4 TIMx_CCER 最低 2 位描述
所以,要使能輸入捕獲,必須設置 CC1E=1,而 CC1P 則根據自己的需要來配置。
接下來我們再看看 DMA/中斷使能寄存器:TIMx_DIER,該寄存器的各位描述見圖 13.1.2
(在第 13 章),本章,我們需要用到中斷來處理捕獲數據,所以必須開啟通道 1 的捕獲比較中
斷,即 CC1IE 設置為 1。
控制寄存器:TIMx_CR1,我們只用到了它的最低位,也就是用來使能定時器的,這里前
面兩章都有介紹,請大家參考前面的章節。
最后再來看看捕獲/比較寄存器 1:TIMx_CCR1,該寄存器用來存儲捕獲發生時,TIMx_CNT
的值,我們從 TIMx_CCR1 就可以讀出通道 1 捕獲發生時刻的 TIMx_CNT 值,通過兩次捕獲(一
次上升沿捕獲,一次下降沿捕獲)的差值,就可以計算出高電平脈沖的寬度(注意,對于脈寬
太長的情況,還要計算定時器溢出的次數)。
至此,我們把本章要用的幾個相關寄存器都介紹完了,本章要實現通過輸入捕獲,來獲取
TIM5_CH1(PA0)上面的高電平脈沖寬度,并從串口打印捕獲結果。下面我們介紹庫函數配置上
述功能輸入捕獲的步驟:
1)開啟 TIM5 和 GPIOA 時鐘,配置 PA0 為復用功能(AF2),并開啟下拉電阻。
要使用 TIM5,我們必須先開啟 TIM5 的時鐘。同時我們要捕獲 TIM5_CH1 上面的高電平
脈寬,所以先配置 PA0 為帶下拉的復用功能,同時,為了讓 PA0 的復用功能選擇連接到 TIM5,
所以設置 PA0 的復用功能為 AF2,即連接到 TIM5 上面。
開啟定時器和 GPIO 時鐘的方法和上一章是一樣的,這里我們就不做過多講解。
配置 PA0 為復用功能(AF2)并開啟下拉功能也和上一章一樣是通過函數 HAL_GPIO_Init
來實現。由于這一步配置過程和上一章幾乎沒有區別,所以這里我們直接列出配置代碼:
__HAL_RCC_TIM5_CLK_ENABLE(); //使能 TIM5 時鐘
__HAL_RCC_GPIOA_CLK_ENABLE(); //開啟 GPIOA 時鐘
GPIO_Initure.Pin=GPIO_PIN_0; //PA0
GPIO_Initure.Mode=GPIO_MODE_AF_PP;
//復用推挽輸出
GPIO_Initure.Pull=GPIO_PULLDOWN;
//下拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH
//高速
GPIO_Initure.Alternate=GPIO_AF2_TIM5; //PA0 復用為 TIM5 通道 1
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
跟上一講 PWM 輸出類似,這里我們使用的是定時器 5 的通道 1,所以我們從 STM32F7 對
應的數據手冊可以查看到對應的 IO 口為 PA0:
2)初始化 TIM5,設置 TIM5 的 ARR 和 PSC。
和上一講 PWM 輸出實驗一樣,當使用定時器做輸入捕獲功能時,在 HAL 庫中并不使用定
時器初始化函數 HAL_TIM_Base_Init 來實現,而是使用輸入捕獲特定的定時器初始化函數
HAL_TIM_IC_Init。當我們使用函數 HAL_TIM_IC_Init 來初始化定時器的輸入捕獲功能時,該
函數內部會調用輸入捕獲初始化回調函數HAL_TIM_IC_MspInit 來初始化與 MCU 無關的步驟。
函數 HAL_TIM_IC_Init 聲明如下:
HAL_StatusTypeDef HAL_TIM_IC_Init(TIM_HandleTypeDef *htim);
該函數非常簡單,和 HAL_TIM_Base_Init 函數以及函數 HAL_TIM_PWM_Init 使用方法是
一模一樣的,這里我們就不累贅。
回調函數 HAL_TIM_IC_MspInit 聲明如下:
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim);
該函數使用方法和 PWM 初始化回調函數 HAL_TIM_PWM_MspInit 使用方法一致。一般情
況下,輸入捕獲初始化回調函數中會編寫步驟 1 內容,以及后面講解的 NVIC 配置。
有了 PWM 實驗基礎知識,這兩個函數的使用就非常簡單,這里我們列出該步驟程序如下:
TIM_HandleTypeDef TIM5_Handler;
TIM5_Handler.Instance=TIM5; //通用定時器 5
TIM5_Handler.Init.Prescaler=89; //分頻系數
TIM5_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;
//向上計數器
TIM5_Handler.Init.Period= 0XFFFFFFFF;
//自動裝載值
TIM5_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; //時鐘分頻銀子
HAL_TIM_IC_Init(&TIM5_Handler);//初始化輸入捕獲時基參數
3)設置 TIM5 的輸入捕獲參數,開啟輸入捕獲。
TIM5_CCMR1 寄存器控制著輸入捕獲 1 和 2 的模式,包括映射關系,濾波和分頻等。這里
我們需要設置通道 1 為輸入模式,且 IC1 映射到 TI1(通道 1)上面,并且不使用濾波(提高響應
速度)器。HAL 庫是通過 HAL_TIM_IC_ConfigChannel 函數來初始化輸入比較參數的:
HAL_StatusTypeDef HAL_TIM_IC_ConfigChannel(TIM_HandleTypeDef *htim,
TIM_IC_InitTypeDef* sConfig, uint32_t Channel);
該函數有三個參數,第一個參數是定時器初始化結構體指針類型,該參數很好理解。第二
個參數是設置要初始化的定時器通道值,取值范圍為 TIM_CHANNEL_1~ TIM_CHANNEL_4。
接下來我們著重講解第二個入口參數 sConfig,該參數是 TIM_IC_InitTypeDef 結構體指針類型,
它是真正用來初始化定時器通道的捕獲參數的。該結構體類型定義為:
typedef struct
{
uint32_t ICPolarity;
uint32_t ICSelection;
uint32_t ICPrescaler;
uint32_t ICFilter;
} TIM_IC_InitTypeDef;
成員變量 ICPolarity 用來設置輸入信號的有效捕獲極性 , 取 值 范 圍 為 :
TIM_ICPOLARITY_RISING(上升沿捕獲),TIM_ICPOLARITY_FALLING(下降沿捕獲)和
TIM_ICPOLARITY_BOTHEDGE(雙邊沿)捕獲。實際上,HAL 還提供了設置輸入捕獲極性以
及清除輸入捕獲極性設置方法。如下:
TIM_RESET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1);//清除極性設置
TIM_SET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1,
TIM_ICPOLARITY_FALLING);//定時器 5 通道 1 設置為下降沿捕獲
成員變量 ICSelection 用來設置映射關系,我們配置 IC1 直接映射在 TI1 上,選擇
TIM_ICSELECTION_DIRECTTI。
成員變量ICPrescaler用來設置輸入捕獲分頻系數,可以設置為TIM_ICPSC_DIV1(不分頻),
TIM_ICPSC_DIV2(2 分頻),TIM_ICPSC_DIV4(4 分頻)以及 TIM_ICPSC_DIV8(8 分頻),
本實驗需要設置為不分頻,所以選值為 TIM_ICPSC_DIV1。
成員變量 ICFilter 用來設置濾波器長度,這里我們不使用濾波器,所以設置為 0。
本實驗,我們要設置輸入捕獲參數為:上升沿捕獲,不分頻,不濾波,同時 IC1 映射到 TI1(通
道 1)上,實例代碼如下:
TIM_IC_InitTypeDef TIM5_CH1Config;
TIM5_CH1Config.ICPolarity=TIM_ICPOLARITY_RISING; //上升沿捕獲
TIM5_CH1Config.ICSelection=TIM_ICSELECTION_DIRECTTI;//IC1 映射到 TI1 上
TIM5_CH1Config.ICPrescaler=TIM_ICPSC_DIV1; //配置輸入分頻,不分頻
TIM5_CH1Config.ICFilter=0; //配置輸入濾波器,不濾波
HAL_TIM_IC_ConfigChannel(&TIM5_Handler,&TIM5_CH1Config,TIM_CHANNEL_1);
4)使能捕獲和更新中斷(設置 TIM5 的 DIER 寄存器)
因為我們要捕獲的是高電平信號的脈寬,所以,第一次捕獲是上升沿,第二次捕獲時下降
沿,必須在捕獲上升沿之后,設置捕獲邊沿為下降沿,同時,如果脈寬比較長,那么定時器就
會溢出,對溢出必須做處理,否則結果就不準了,不過,由于 STM32F7 的 TIM5 是 32 位定時
器,假設計數周期為 1us,那么需要 4294 秒才會溢出一次,這基本上是不可能的。這兩件事,
我們都在中斷里面做,所以必須開啟捕獲中斷和更新中斷。
HAL 庫中開啟定時器中斷方法在定時器中斷實驗已經講解,方法為:
__HAL_TIM_ENABLE_IT(&TIM5_Handler,TIM_IT_UPDATE); //使能更新中斷
實際上,由于本章使用的是定時器的輸入捕獲功能,HAL 還提供了一個函數同時用來開啟
定時器的輸入捕獲通道和使能捕獲中斷,該函數為:
HAL_StatusTypeDef HAL_TIM_IC_Start_IT (TIM_HandleTypeDef *htim, uint32_t Channel);
實際上該函數同時還使能了定時器,一個函數具備三個功能。
如果我們不需要開啟捕獲中斷,只是開啟輸入捕獲功能,HAL 庫函數為:
HAL_StatusTypeDef HAL_TIM_IC_Start (TIM_HandleTypeDef *htim, uint32_t Channel);
5)使能定時器(設置 TIM5 的 CR1 寄存器)
在步驟 4 中,如果我們調用了函數 HAL_TIM_IC_Start_IT 來開啟輸入捕獲通道以及輸入捕
獲中斷,實際上它同時也開啟了相應的定時器。單獨的開啟定時器的方法為:
__HAL_TIM_ENABLE(); //開啟定時器方法
6)設置 NVIC 中斷優先級
因為我們要使用到中斷,所以我們在系統初始化之后,需要先設置中斷優先級,這里方法
跟我們前面講解一致,這里我們就不累贅了。、
這里大家要注意,一般情況下 NVIC 配置我們都會放在 MSP 回調函數中。對于輸入捕獲功
能,回調函數是我們步驟 2 講解的函數 HAL_TIM_IC_MspInit。
7) 編寫中斷服務函數
最后編寫中斷服務函數。定時器 5 中斷服務函數為:
void TIM5_IRQHandler(void);
和定時器中斷實驗一樣,一般情況下,我們都不把中斷控制邏輯直接編寫在中斷服務函數
中,因為 HAL 庫提供了一個共用的中斷處理入口函數 HAL_TIM_IRQHandler,該函數中會對
中斷來源進行判斷然后調用相應的中斷處理回調函數。HAL 庫提供了多個中斷處理回調函數,
本章實驗,我們要使用到更新中斷和捕獲中斷,所以我們要使用的回調函數為:
void
HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);//更新(溢出)中斷
void
HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim);//捕獲中斷
我們只需要在我們工程中,重新定義這兩個函數,編寫中斷處理控制邏輯即可。
14.2 硬件設計
本實驗用到的硬件資源有:
1) 指示燈 DS0
2) KEY_UP 按鍵
3) 串口
4) 定時器 TIM3
5) 定時器 TIM5
前面 4 個,在之前的章節均有介紹。本節,我們將捕獲 TIM5_CH1(PA0)上的高電平脈
寬,通過 KEY_UP 按鍵輸入高電平,并從串口打印高電平脈寬。同時我們保留上節的 PWM 輸
出,大家也可以通過用杜邦線連接 PF9 和 PA0,來測量 PWM 輸出的高電平脈寬。
14.3 軟件設計
相比上一章講解的 PWM 實驗,我們直接在 timer.c 和 timer.h 中直接添加了輸入捕獲相關程
序。對于輸入捕獲,我們也同樣使用的定時器相關操作,所以相比上一實驗我們并沒有添加其
他任何 HAL 庫文件。
接下來我們來看看 timer.c 文件中新增的內容如下:
TIM_HandleTypeDef TIM5_Handler; //定時器 5 句柄
//定時器 5 通道 1 輸入捕獲配置
//arr:自動重裝值(TIM2,TIM5 是 32 位的!!) psc:時鐘預分頻數
void TIM5_CH1_Cap_Init(u32 arr,u16 psc)
{
TIM_IC_InitTypeDef TIM5_CH1Config;
TIM5_Handler.Instance=TIM5;
//通用定時器 5
TIM5_Handler.Init.Prescaler=psc;
//分頻系數
TIM5_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;
//向上計數器
TIM5_Handler.Init.Period=arr;
//自動裝載值
TIM5_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; //時鐘分頻銀子
HAL_TIM_IC_Init(&TIM5_Handler); //初始化輸入捕獲時基參數
TIM5_CH1Config.ICPolarity=TIM_ICPOLARITY_RISING;
//上升沿捕獲
TIM5_CH1Config.ICSelection=TIM_ICSELECTION_DIRECTTI; //映射到 TI1 上
TIM5_CH1Config.ICPrescaler=TIM_ICPSC_DIV1;
//配置輸入分頻,不分頻
TIM5_CH1Config.ICFilter=0;
//配置輸入濾波器,不濾波
HAL_TIM_IC_ConfigChannel(&TIM5_Handler,&TIM5_CH1Config,TIM_CHANNEL_1);
//配置 TIM5 通道 1
HAL_TIM_IC_Start_IT(&TIM5_Handler,TIM_CHANNEL_1);
//開啟 TIM5 的捕獲通道 1,并且開啟捕獲中斷
__HAL_TIM_ENABLE_IT(&TIM5_Handler,TIM_IT_UPDATE); //使能更新中斷
}
//定時器 5 底層驅動,時鐘使能,引腳配置
//此函數會被 HAL_TIM_IC_Init()調用
//htim:定時器 5 句柄
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_TIM5_CLK_ENABLE();
//使能 TIM5 時鐘
__HAL_RCC_GPIOA_CLK_ENABLE();
//開啟 GPIOA 時鐘
GPIO_Initure.Pin=GPIO_PIN_0;
//PA0
GPIO_Initure.Mode=GPIO_MODE_AF_PP;
//復用推挽輸出
GPIO_Initure.Pull=GPIO_PULLDOWN;
//下拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH;
//高速
GPIO_Initure.Alternate=GPIO_AF2_TIM5;
//PA0 復用為 TIM5 通道 1
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
//初始化 PA0
HAL_NVIC_SetPriority(TIM5_IRQn,2,0); //設置中斷優先級,搶占 2,子優先級 0
HAL_NVIC_EnableIRQ(TIM5_IRQn); //開啟 ITM5 中斷通道
}
//捕獲狀態
//[7]:0,沒有成功的捕獲;1,成功捕獲到一次.
//[6]:0,還沒捕獲到低電平;1,已經捕獲到低電平了.
//[5:0]:捕獲低電平后溢出的次數(對于 32 位定時器來說,1us 計數器加 1,溢出時間:4294 秒)
u8 TIM5CH1_CAPTURE_STA=0; //輸入捕獲狀態
u32 TIM5CH1_CAPTURE_VAL;//輸入捕獲值(TIM2/TIM5 是 32 位)
//定時器 5 中斷服務函數
void TIM5_IRQHandler(void)
{
HAL_TIM_IRQHandler(&TIM5_Handler);//定時器共用處理函數
}
//定時器更新中斷(溢出)中斷處理回調函數, 在 HAL_TIM_IRQHandler 中會被調用
void
HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//更新中斷發生時執行
{
if((TIM5CH1_CAPTURE_STA&0X80)==0)//還未成功捕獲
{
if(TIM5CH1_CAPTURE_STA&0X40)//已經捕獲到高電平了
{
if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高電平太長了
{
TIM5CH1_CAPTURE_STA|=0X80;
//標記成功捕獲了一次
TIM5CH1_CAPTURE_VAL=0XFFFFFFFF;
}else TIM5CH1_CAPTURE_STA++;
}
}
}
//定時器輸入捕獲中斷處理回調函數,該函數在 HAL_TIM_IRQHandler 中會被調用
void
HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//捕獲中斷發生時執行
{
if((TIM5CH1_CAPTURE_STA&0X80)==0)//還未成功捕獲
{
if(TIM5CH1_CAPTURE_STA&0X40)
//捕獲到一個下降沿
{
TIM5CH1_CAPTURE_STA|=0X80; //標記成功捕獲到一次高電平脈寬
TIM5CH1_CAPTURE_VAL=
HAL_TIM_ReadCapturedValue(&TIM5_Handler,TIM_CHANNEL_1);
//獲取當前的捕獲值.
TIM_RESET_CAPTUREPOLARITY(&TIM5_Handler,
TIM_CHANNEL_1); //清除設置
TIM_SET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1,
TIM_ICPOLARITY_RISING);//上升沿捕獲
}else //還未開始,第一次捕獲上升沿
{
TIM5CH1_CAPTURE_STA=0;
//清空
TIM5CH1_CAPTURE_VAL=0;
TIM5CH1_CAPTURE_STA|=0X40;
//標記捕獲到了上升沿
__HAL_TIM_DISABLE(&TIM5_Handler); //關閉定時器 5
__HAL_TIM_SET_COUNTER(&TIM5_Handler,0);
TIM_RESET_CAPTUREPOLARITY(&TIM5_Handler,
TIM_CHANNEL_1); //清除原來設置
TIM_SET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1,
TIM_ICPOLARITY_FALLING);//下降沿捕獲
__HAL_TIM_ENABLE(&TIM5_Handler);//使能定時器 5
}
}
}
此部分代碼包含 5 個函數。函數 TIM5_CH1_Cap_Init 和回調函數 HAL_TIM_IC_MspInit
共同用來實現 14.1 小節講解的步驟 1~6。TIM5_IRQHandler 是 TIM5 的中斷服務函數,該函數
內部和定時器中斷實驗一樣,只有一行代碼就是直接調用函數 HAL_TIM_IRQHandler。根據我
們前面的講解,函數 HAL_TIM_IRQHandler 內部會對中斷來源進行判斷(中斷標志位),然后
分別調用對應的中斷處理回調函數 ,最后還會自動清除相應的中斷標志位 。函數
HAL_TIM_PeriodElapsedCallback 和
HAL_TIM_IC_CaptureCallback 就是我們要著重講解的定時
器更新中斷(溢出)以及輸入捕獲中斷處理回調函數。
同時,在該文件中我們還定義了兩個全局變量,用于輔助實現高電平捕獲。其中
TIM5CH1_CAPTURE_STA,是用來記錄捕獲狀態,該變量類似我們在 usart.c 里面自行定義的
USART_RX_STA 寄存器(其實就是個變量,只是我們把它當成一個寄存器那樣來使用)。
TIM5CH1_CAPTURE_STA 各位描述如表 14.3.1 所示:
表 14.3.1 TIM5CH1_CAPTURE_STA 各位描述
另外一個變量 TIM5CH1_CAPTURE_VAL,則用來記錄捕獲到下降沿的時候,TIM5_CNT
的值。
現在我們來介紹一下,捕獲高電平脈寬的思路:首先,設置 TIM5_CH1 捕獲上升沿,這在
TIM5_Cap_Init 函數執行的時候就設置好了,然后等待上升沿中斷到來,當捕獲到上升沿中斷
(執行中斷處理回調函數
HAL_TIM_IC_CaptureCallback),此時如果TIM5CH1_CAPTURE_STA
的第 6 位為 0,則表示還沒有捕獲到新的上升沿,就先把
TIM5CH1_CAPTURE_STA、TIM5CH1_CAPTURE_VAL 和計數器值 TIM5->CNT 等清零,然后
再設置 TIM5CH1_CAPTURE_STA 的第 6 位為 1,標記捕獲到高電平,最后設置為下降沿捕獲,
等待下降沿到來。如果等待下降沿到來期間,定時器發生了溢出(執行溢出中斷處理回調函數
HAL_TIM_PeriodElapsedCallback),就在 TIM5CH1_CAPTURE_STA 里面對溢出次數進行計數,
當最大溢出次數來到的時候,就強制標記捕獲完成(雖然此時還沒有捕獲到下降沿)。當下降沿
到來的時候,先設置 TIM5CH1_CAPTURE_STA 的第 7 位為 1,標記成功捕獲一次高電平,然
后讀取此時的定時器值到 TIM5CH1_CAPTURE_VAL 里面,最后設置為上升沿捕獲,回到初始
狀態。
這樣,我們就完成一次高電平捕獲了,只要 TIM5CH1_CAPTURE_STA 的第 7 位一直為 1,
那么就不會進行第二次捕獲,我們在main函數處理完捕獲數據后,將TIM5CH1_CAPTURE_STA
置零,就可以開啟第二次捕獲。
timer.h 頭文件內容比較簡單,主要是函數申明,這里我們不做過多講解。
接下來,我們看看 main 函數內容:
extern u8 TIM5CH1_CAPTURE_STA;
//輸入捕獲狀態
extern u32
TIM5CH1_CAPTURE_VAL;//輸入捕獲值
int main(void)
{
long long temp=0;
Cache_Enable();
//打開 L1-Cache
HAL_Init();
//初始化 HAL 庫
Stm32_Clock_Init(432,25,2,9); //設置時鐘,216Mhz
delay_init(216);
//延時初始化
uart_init(115200);
//串口初始化
LED_Init();
//初始化 LED
TIM3_PWM_Init(500-1,108-1); //108M/108=1M 的計數頻率,自動重裝載為 500,
//那么 PWM 頻率為 1M/500=2kHZ
TIM5_CH1_Cap_Init(0XFFFFFFFF,108-1); //以 1MHZ 的頻率計數
while(1)
{
delay_ms(10);
TIM_SetTIM3Compare4(TIM_GetTIM3Capture4()+1);
if(TIM_GetTIM3Capture4()==300)TIM_SetTIM3Compare4(0);
if(TIM5CH1_CAPTURE_STA&0X80)
//成功捕獲到了一次高電平
{
temp=TIM5CH1_CAPTURE_STA&0X3F;
temp*=0XFFFFFFFF;
//溢出時間總和
temp+=TIM5CH1_CAPTURE_VAL; //得到總的高電平時間
printf("HIGH:%lld usrn",temp);//打印總的高點平時間
TIM5CH1_CAPTURE_STA=0; //開啟下一次捕獲
}
}
}
該 main 函數是在 PWM 實驗的基礎上修改來的,我們保留了 PWM 輸出,同時通過設置
TIM5_Cap_Init(0XFFFFFFFF,108-1),將 TIM5_CH1 的捕獲計數器設計為 1us 計數一次,并設置
重裝載值為最大,所以我們的捕獲時間精度為 1us。
主函數通過 TIM5CH1_CAPTURE_STA 的第 7 位,來判斷有沒有成功捕獲到一次高電平,
如果成功捕獲,則將高電平時間通過串口輸出到電腦。
至此,我們的軟件設計就完成了。
14.4 下載驗證
在完成軟件設計之后,將我們將編譯好的文件下載到阿波羅 STM32 開發板上,可以看到
DS0 的狀態和上一章差不多,由暗?亮的循環。說明程序已經正常在跑了,我們再打開串口調
試助手,選擇對應的串口,然后按 KEY_UP 按鍵,可以看到串口打印的高電平持續時間,如圖
14.4.1 所示:
圖 14.4.1 PWM 控制 DS0 亮度
從上圖可以看出,其中有 2 次高電平在 100us 以內的,這種就是按鍵按下時發生的抖動。
這就是為什么我們按鍵輸入的時候,一般都需要做防抖處理,防止類似的情況干擾正常輸入。
大家還可以用杜邦線連接 PA0 和 PB1,看看上一節中我們設置的 PWM 輸出的高電平是如何變
化的。
14.5 STM32CubeMX 配置定時器輸入捕獲功能
使用 STM32CubeMX 配置輸入捕獲功能初始化代碼步驟如下:
① 在 Pinout->TIM5 配置項中,配置 Channel1 的值為 Input Capture direct mode,然后選中
Internal Clock。操作過程如下圖 14.5.1 所示:
圖 14.5.1 TIM3 配置
② 進入 Configuration->TIM5 配置頁,在彈出的界面中點擊 Parameter Settings 選項卡,
Counter Settings 配置欄下面的四個選項就是用來配置定時器的預分頻系數,自動裝載
值,計數模式以及時鐘分頻因子。在界面的 Input Capture Channel 1 配置欄配置輸入捕
獲通道 1 的捕獲極性,分頻系數,映射,濾波器等參數,操作方法如下圖 14.5.2 所示:
③ 進入 Configuration->NVIC 配置頁,在彈出的界面中點擊 NVIC 選項卡,配置 Interrupt
Table 中的 TIM5 global interrupt,使能中斷,配置搶占優先級和響應優先級。
配置完上面步驟后,生成代碼。在生成的代碼中,并沒有使能相應中斷的代碼,也沒有改
寫中斷處理回調函數,這些都是用戶根據自己需要來編寫的,這也說明 STM32CubeMX 不是萬
能的,大家還得認真學習 STM32 基礎知識。
總結
以上是生活随笔為你收集整理的cc2530定时器和捕获比较_ALIENTEK 阿波罗 STM32F767 开发板资料连载十四章 输入捕获实验...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android开发基本知识,Androi
- 下一篇: anaconda中tensorflow-