• 正文
    • 1 前言
    • 2 定時器中斷
    • 3 PWM模式
    • 4 輸入捕獲
    • 5 比較輸出
    • 6 強制輸出
  • 相關(guān)推薦
申請入駐 產(chǎn)業(yè)圖譜

STM32中定時器全功能代碼實現(xiàn)(3)

01/22 09:35
4725
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

1 前言

前幾期我們介紹了STM32CubeMX中關(guān)于定時器的各個配置參數(shù)及其功能,本期我們來介紹各個功能的具體代碼實現(xiàn)。

分別是:定時器中斷,PWM模式,輸出捕獲模式,比較輸出模式,強制輸出模式。

進行時鐘配置,這里主頻是170MHZ,定時器時鐘為170MHZ。

2 定時器中斷

打開CubeMX,配置定時器分頻系數(shù)為170-1,周期計數(shù)值為1000,主頻為170MHZ。由此我們可以計算一次溢出的為:

170M/(170+1)/1000 = 1000即1ms一次。

開啟定時器中斷以確保我們的定時器中斷回調(diào)函數(shù)能被正常觸發(fā)。

接著選擇好編譯器和文件路徑和文件名( 不要用中文路徑)生成工程。

/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim1);
/* USER CODE END 2 */

添加啟動定時器并啟用中斷的函數(shù),參數(shù)為我們開啟的定時器句柄。

//開啟定時器并開啟中斷
HAL_TIM_Base_Start_IT(&htim1);
//開啟定時器不開啟中斷
//HAL_TIM_Base_Start(&htim1);

當然也有不啟用中斷的,后者僅僅開啟定時器計數(shù)功能,但是會發(fā)生定時器溢出產(chǎn)生事件更新,不過不會觸發(fā)中斷請求。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
static int number = 0;
if(htim->Instance == TIM1) // 判斷是否是 TIM1 觸發(fā)的中斷
{
// 1ms觸發(fā)一次
number++;
if(number==1000)
{
//1ms*1000 = 1s
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);
number = 0;//清零
}
}
}

接著我們需要重寫定時器中斷回調(diào)函數(shù)來實現(xiàn)我們的功能,由于我們定時器是1ms觸發(fā)一次,因此我們使用一個計數(shù)器來判斷觸發(fā)的次數(shù)。當我們定時時間到達1s時,使我們的LED燈翻轉(zhuǎn)。

我們可以看到,中斷回調(diào)函數(shù)在底層被一個虛函數(shù)定義,這段注釋告訴用戶,不要修改這個函數(shù)的默認實現(xiàn)。如果需要自定義的回調(diào)行為,應該在用戶的代碼中重新實現(xiàn)這個回調(diào)函數(shù)。

當我們在程序中需要修改定時器觸發(fā)時間的時候,我們可以重新修改定時器的參數(shù)并進行初始化。

htim1.Init.Prescaler = new_prescaler;//新的分頻系數(shù)
htim1.Init.Period = new_arr;//新的周期值
HAL_TIM_Base_Init(&htim1); // 重新初始化定時器
HAL_TIM_Base_Start_IT(&htim1); // 重新啟動定時器

下面要用。

3 PWM模式

上面我們設(shè)置了定時器的單周期參數(shù)為1000,接著我們設(shè)置PWM的比較值(Output compare preload)為500,那么占空比就是:500/1000 = 50%。

接著生成我們的代碼。

/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
/* USER CODE END 2 */

啟動定時器PWM,參數(shù)分別為定時器句柄和通道。

這樣子我們通道一對應的IO就可以輸出方波了。

htim1.Init.Prescaler = new_prescaler;//新的分頻系數(shù)
htim1.Init.Period = new_arr;//新的周期值
HAL_TIM_Base_Init(&htim1); // 重新初始化定時器
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1); // 重新啟動PWM

通過修改定時器的計數(shù)頻率來修改PWM的頻率。

/* USER CODE BEGIN 2 */
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, duty); //修改占空比
/* USER CODE END 2 */

通過修改通道的比較值CCR來改變PWM的占空比 = CCR/ARR.

4 輸入捕獲

通道配置為輸入捕獲之后,需要注意捕獲模式是上升沿捕獲、下降沿捕獲還是雙邊捕獲。

這里要開啟中斷,我們需要使用中斷回調(diào)函數(shù)。

HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); // 啟動定時器并使能中斷
調(diào)用開啟輸入捕獲的函數(shù),接著重寫輸入捕獲的回調(diào)函數(shù)。

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
static uint32_t last_capture = 0; // 上次捕獲的計數(shù)值
uint32_t capture_value = 0;
if (htim->Instance == TIM1) // 判斷是否是定時器1觸發(fā)的中斷
{
capture_value = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); // 讀取捕獲
// 計算捕獲值之間的時間差(信號周期或脈沖寬度)
if (capture_value > last_capture)
{
uint32_t pulse_width = capture_value - last_capture; // 計算脈沖寬度
last_capture = capture_value; // 更新上次捕獲值
}
}
}

當外部信號來臨的時候,我們可以讀取通道值來獲得當前的計數(shù)值。通過比較兩次的計數(shù)值可以知道兩個信號之間的觸發(fā)事件。

這種方法我們也可以用來測量PWM的高低電平時間。通過修改觸發(fā)方式,當上升沿觸發(fā)的時候,修改觸發(fā)方式為下降沿,就可以知道高電平的時間。反過來就可以知道低電平的時間。

// 輸入捕獲中斷回調(diào)函數(shù)
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
capture_value = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); // 讀取捕獲值
if (htim->Instance == TIM1) // 判斷是否是定時器2觸發(fā)的中斷
{
if (capture_value > last_capture) // 如果是上升沿
{
// 處理上升沿捕獲邏輯
printf("上升沿時間: %lun", capture_value);
// 修改下一次捕獲為下降沿觸發(fā)
TIM_IC_InitTypeDef sConfigIC = {0};
sConfigIC.ICPolarity = TIM_ICPOLARITY_FALLING; // 設(shè)置為下降沿觸發(fā)
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; // 直接從輸入端口獲取信號
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; // 不進行預分頻
sConfigIC.ICFilter = 0; // 無輸入濾波器
HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1); // 配置通道1為下降沿觸發(fā)
}
else // 如果是下降沿
{
// 處理下降沿捕獲邏輯
printf("下降沿時間: %lun", capture_value);
// 修改下一次捕獲為上升沿觸發(fā)
TIM_IC_InitTypeDef sConfigIC = {0};
sConfigIC.ICPolarity = TIM_ICPOLARITY_RISING; // 設(shè)置為上升沿觸發(fā)
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; // 直接從輸入端口獲取信號
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; // 不進行預分頻
sConfigIC.ICFilter = 0; // 無輸入濾波器
HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1); // 配置通道1為上升沿觸發(fā)
}
last_capture = capture_value; // 更新上次捕獲值
}
}

5 比較輸出

比較輸出的配置和PWM模式的差不多。

HAL_TIM_OC_Start(&htim1, TIM_CHANNEL_1); // 啟動通道1的輸出比較

利用該函數(shù)開啟通道的比較輸出的功能,它除了能輸出PWM波之外,還可以在比較值的時候觸發(fā)中斷回調(diào)函數(shù)。

void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM1) // 檢查是否是TIM1的比較輸出中斷
{

}
}

并且,當我們把模式修改為電平翻轉(zhuǎn)之后,可以讓通道實現(xiàn)方波輸出。

6 強制輸出

強制輸出模式勝在可以使用軟件強制修改引腳高低電平。

利用如下函數(shù)實現(xiàn)強制輸出。

// 配置強制輸出模式為強制低電平
__HAL_TIM_OC_SET_FORCED_ACTION(&htim1, TIM_CHANNEL_1, TIM_OCFORCE_LOW);
// 或者配置強制輸出模式為強制高電平
// __HAL_TIM_OC_SET_FORCED_ACTION(&htim1, TIM_CHANNEL_1, TIM_OCFORCE_HIGH);

通過在定時器溢出、比較事件或外部觸發(fā)事件發(fā)生時,強制定時器輸出高電平或低電平,可以靈活地控制STM32微控制器的輸出行為。

意法半導體

意法半導體

意法半導體(ST)集團于1987年6月成立,是由意大利的SGS微電子公司和法國Thomson半導體公司合并而成。1998年5月,SGS-THOMSON Microelectronics將公司名稱改為意法半導體有限公司。意法半導體是世界最大的半導體公司之一,公司銷售收入在半導體工業(yè)五大高速增長市場之間分布均衡(五大市場占2007年銷售收入的百分比):通信(35%),消費(17%),計算機(16%),汽車(16%),工業(yè)(16%)。 據(jù)最新的工業(yè)統(tǒng)計數(shù)據(jù),意法半導體是全球第五大半導體廠商,在很多市場居世界領(lǐng)先水平。例如,意法半導體是世界第一大專用模擬芯片和電源轉(zhuǎn)換芯片制造商,世界第一大工業(yè)半導體和機頂盒芯片供應商,而且在分立器件、手機相機模塊和車用集成電路領(lǐng)域居世界前列.

意法半導體(ST)集團于1987年6月成立,是由意大利的SGS微電子公司和法國Thomson半導體公司合并而成。1998年5月,SGS-THOMSON Microelectronics將公司名稱改為意法半導體有限公司。意法半導體是世界最大的半導體公司之一,公司銷售收入在半導體工業(yè)五大高速增長市場之間分布均衡(五大市場占2007年銷售收入的百分比):通信(35%),消費(17%),計算機(16%),汽車(16%),工業(yè)(16%)。 據(jù)最新的工業(yè)統(tǒng)計數(shù)據(jù),意法半導體是全球第五大半導體廠商,在很多市場居世界領(lǐng)先水平。例如,意法半導體是世界第一大專用模擬芯片和電源轉(zhuǎn)換芯片制造商,世界第一大工業(yè)半導體和機頂盒芯片供應商,而且在分立器件、手機相機模塊和車用集成電路領(lǐng)域居世界前列.收起

查看更多

相關(guān)推薦