以下是基于STM32標準庫(以STM32F103為例)實現PWM輸入模式(自動雙沿捕獲)的完整代碼,通過配置定時器的PWM輸入模式,可自動捕獲外部PWM信號的周期(頻率)?和占空比,無需手動切換邊沿。
🛠 ?完整代碼實現?
1. 硬件配置
- ?引腳?:PA6(TIM3_CH1,支持PWM輸入模式)
- ?定時器?:TIM3(支持從模式復位)
- ?功能?:自動捕獲上升沿(周期)和下降沿(占空比)
#include "stm32f10x.h"// 全局變量存儲PWM參數
volatile uint32_t PWM_Period = 0; // 周期值(頻率計算用)
volatile uint32_t PWM_Duty = 0; // 占空比值// 初始化函數
void PWM_Input_Init(void)
{// 1. 開啟時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);// 2. 配置PA6為浮空輸入(復用功能)GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空輸入GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStruct);// 3. 定時器基礎配置(1MHz計數頻率,72MHz主頻分頻后)TIM_TimeBaseInitTypeDef TIM_BaseStruct;TIM_BaseStruct.TIM_Period = 0xFFFF; // ARR = 65535(最大計數)TIM_BaseStruct.TIM_Prescaler = 72 - 1; // 72分頻 → 1MHz計數TIM_BaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;TIM_BaseStruct.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM3, &TIM_BaseStruct);// 4. 配置PWM輸入模式(關鍵!)TIM_ICInitTypeDef TIM_ICStruct;TIM_ICStruct.TIM_Channel = TIM_Channel_1; // 通道1(PA6)TIM_ICStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; // 上升沿觸發TIM_ICStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; // 直接輸入TIM_ICStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; // 不分頻TIM_ICStruct.TIM_ICFilter = 0x0; // 無濾波TIM_PWMIConfig(TIM3, &TIM_ICStruct); // 自動配置雙通道// 5. 從模式配置(復位模式)TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); // TI1作為觸發源TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); // 觸發時復位計數器// 6. 開啟捕獲中斷TIM_ITConfig(TIM3, TIM_IT_CC1 | TIM_IT_CC2, ENABLE); // 使能通道1&2中斷// 7. 配置NVICNVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);// 8. 啟動定時器TIM_Cmd(TIM3, ENABLE);
}// 中斷服務函數
void TIM3_IRQHandler(void)
{if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET) { // 通道1中斷(周期捕獲)PWM_Period = TIM_GetCapture1(TIM3); // 讀取周期值(上升沿時間)TIM_ClearITPendingBit(TIM3, TIM_IT_CC1); // 清除標志}if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET) { // 通道2中斷(占空比捕獲)PWM_Duty = TIM_GetCapture2(TIM3); // 讀取占空比值(下降沿時間)TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);}
}// 計算頻率(Hz)和占空比(%)
float PWM_Get_Frequency(void)
{return 1000000.0f / (PWM_Period ); // 1MHz計數 → 單位:Hz
}float PWM_Get_DutyCycle(void)
{return (PWM_Duty + 0.0f) / (PWM_Period + 0.0f) * 100.0f; // 占空比百分比
}
?? ?工作原理?
?PWM輸入模式?
- 使用?
TIM_PWMIConfig()
?自動配置兩個通道:- ?通道1(直接輸入)??:捕獲上升沿 → ?周期值存入CCR1。
- ?通道2(間接輸入)??:捕獲下降沿 → ?占空比值存入CCR2。
- 無需手動切換極性,硬件自動完成雙沿捕獲。
- 使用?
?從模式復位?
- 觸發源設為?
TI1FP1
(通道1的濾波后信號)。 - 從模式設為?
Reset
:上升沿時復位計數器,確保每次捕獲的周期值準確。
- 觸發源設為?
?參數計算?
- ?頻率?:
Freq = 1MHz / (CCR1 + 1)
- ?占空比?:
Duty = (CCR2 + 1) / (CCR1 + 1) * 100%
- ?頻率?:
?? ?關鍵注意事項?
- ?引腳復用?
- 確保PA6映射到TIM3_CH1(參考芯片手冊)。
- ?時鐘配置?
- 默認使用72MHz系統時鐘,需在?
SystemInit()
?中正確配置。
- 默認使用72MHz系統時鐘,需在?
- ?抗干擾設計?
- 若信號抖動大,增加?
TIM_ICStruct.TIM_ICFilter
(0-15)濾波。
- 若信號抖動大,增加?
- ?測量范圍?
- 最大頻率受限于定時器計數頻率(1MHz下最高約500kHz)。
🔍 ?擴展應用?
- ?多通道捕獲?:若需同時捕獲多路PWM,使用不同定時器(如TIM2/TIM4)。
- ?高精度需求?:減少預分頻值(如?
TIM_Prescaler = 0
)可提升計時分辨率。 - ?實時處理?:在中斷中直接計算頻率/占空比,避免全局變量延遲。
此代碼通過STM32硬件自動完成雙沿捕獲,顯著降低CPU負載,適用于電機控制、遙控信號解析等場景。實際使用時需根據信號特性調整濾波參數,并注意定時器溢出處理(如信號周期 > 65ms)