主要參考學習資料:
B站@江協科技
STM32入門教程-2023版 細致講解 中文字幕
開發資料下載鏈接:https://pan.baidu.com/s/1h_UjuQKDX9IpP-U1Effbsw?pwd=dspb
單片機套裝:STM32F103C8T6開發板單片機C6T6核心板 實驗板最小系統板套件科協
實驗:
- 輸入捕獲模式測頻率
- PWMI模式測頻率占空比
新函數:
- 定時器庫函數(輸入捕獲和主從觸發模式部分)
目錄
- 輸入捕獲簡介
- 頻率測量
- 輸入捕獲通道
- 主從觸發模式
- 輸入捕獲基本結構
- PWMI基本結構
- 函數詳解
- TIM_ICInit函數
- TIM_ICInitTypeDef結構體
- TIM_PWMIConfig函數
- TIM_ICStructInit函數
- TIM_SelectInputTrigger函數
- TIM_SelectOutputTrigger函數
- TIM_SelectSlaveMode函數
- TIM_SetICxPrescaler函數
- TIM_GetCapturex函數
- 實驗13 輸入捕獲模式測頻率
- 接線圖
- PWM驅動
- 輸入捕獲驅動
- 主程序
- 實驗14 PWMI模式測頻率占空比
- 輸入捕獲驅動
- 主程序
輸入捕獲簡介
- IC(Input Capture)輸入捕獲
- 輸入捕獲模式下,當通道輸入引腳出現指定電平跳變時,當前CNT的值將被鎖存到CCR中,可用于測量PWM波形的頻率、占空比、脈沖間隔、電平持續時間等參數。
- 每個高級定時器和通用定時器都擁有4個輸入捕獲通道。
- 可配置為PWMI模式,同時測量頻率和占空比。
- 可配合主從觸發模式,實現硬件全自動測量。
頻率測量
- 測頻法:在閘門時間T內,對上升沿計次,得到N,則頻率 f x = N / T f_x=N/T fx?=N/T,適合測高頻信號,數據相對穩定。
- 測周法:兩個上升沿內,以標準頻率 f C f_C fC?計次,得到 N N N,則頻率 f x = f c / N f_x=f_c/N fx?=fc?/N,適合測低頻信號,數據跳變快。
- 中界頻率:測頻法與測周法誤差相等(N相等)的頻率點 f m = f C / T f_m=\sqrt{f_C/T} fm?=fC?/T?,是選擇測頻法還是測周法的依據。
定時器外部時鐘和對射式紅外傳感器計次的代碼稍加改進,間隔相同時間讀取次數并清零即為測頻法。本節輸入捕獲采用測周法。
輸入捕獲通道
濾波器接收來自引腳的輸入TI1并對其進行濾波后輸出TI1F, f D T S f_{DTS} fDTS?為濾波器采樣時鐘來源,TIMx_CCMR1寄存器的ICF可以控制濾波器的參數,濾波器以采樣頻率對輸入信號采樣,當連續N個值都為高電平,輸出才為高電平,當連續N個值都為低電平,輸出才為低電平,否則輸出保持不變。
濾波后的信號通過邊沿檢測器捕獲上升沿或下降沿,TIMx_CCER寄存器的CC1P可以選擇極性,最終得到TI1FP1觸發信號,與來自通道2的觸發信號一同經過數據選擇器,由CC1S進行選擇。每個輸入捕獲通道都有兩條獨立的濾波器和邊沿檢測器路線,一路連接當前通道后續電路,另一路連接其他通道后續電路,由此實現一個通道靈活切換兩個引腳和兩個通道同時捕獲一個引腳的功能,其中CH1和CH2交叉,CH3和CH4交叉。
被選擇的觸發信號繼續通過由ICPS控制的分頻器,最后CC1E控制輸出使能或失能。如果使能,則觸發信號可以將CNT的值轉運到CCR中。每捕獲一次CNT的值,都要將CNT清零以進行下一次捕獲,在硬件電路中由TI1FP1到從模式控制器的映射自動完成。
主從觸發模式
主從觸發模式是主模式、從模式和觸發源選擇三個功能的簡稱。主模式將定時器內部信號映射到TRGO引腳,用于觸發別的外設。從模式將其他外設或者自身外設的信號映射到TRGI引腳,用于控制自身定時器的運行。觸發源選擇用于選擇從模式的觸發信號源,從模式從列表中選擇一項執行。輸入捕獲CNT自動清零即通過TI1FP1信號觸發從模式的Reset操作實現(只有通道1和通道2可以,通道3和通道4需在中斷函數手動清零)。信號的具體解釋參見芯片數據手冊。
輸入捕獲基本結構
使用輸入捕獲基本結構測量頻率,測頻法的標準頻率即為系統時鐘經過預分頻后計數器自增的時鐘頻率。GPIO口輸入方波信號,通過濾波器和邊沿檢測,選擇上升沿觸發,直連當前通道,分頻器不分頻。同時觸發源選擇選擇TI1FP1為觸發信號,從模式選擇復位操作。電路工作時,CCR1的值始終保持為最新一個周期的計數值,即測頻法中的N,再計算 f C / N f_C/N fC?/N即可得到輸入頻率。
PWMI基本結構
PWMI模式使用兩個通道同時捕獲一個引腳,可以同時測量頻率和占空比。TI1FP1和輸入捕獲基本結構中一樣,TI1FP2則配置為下降沿觸發,通過交叉通道觸發通道2的捕獲單元。此時CCR2捕獲高電平期間的計數值,但不觸發清零,CNT繼續計數直至上升沿被CCR1捕獲到一個周期的計數值,CNT清零。占空比為CCR2/CCR1。
函數詳解
TIM_ICInit函數
簡介:配置輸入捕獲單元(單一通道)。
參數一:定時器名稱
參數二:指向初始化信息TIM_ICInitTypeDef結構體的指針
TIM_ICInitTypeDef結構體
成員TIM_Channel:輸入捕獲通道
TIM_Channel_1, ..., TIM_Channel_4
成員TIM_ICFilter:濾波器
成員TIM_ICPolarity:極性
TIM_ICPolarity_Rising, TIM_ICPolarity_Falling, TIM_ICPolarity_BothEdge
成員TIM_ICPrescaler:分頻器
TIM_ICPSC_DIV1, TIM_ICPSC_DIV2, TIM_ICPSC_DIV4, TIM_ICPSC_DIV8
成員TIM_ICSelection:數據選擇器
TIM_ICSelection_DirectTI(直連通道輸入)
TIM_ICSelection_IndirectTI(交叉通道輸入)
TIM_ICSelection_TRC(暫時不用)
TIM_PWMIConfig函數
簡介:配置輸入捕獲單元(PWMI模式,限通道1和通道2),函數自動為另一個通道初始化為相反的配置。
參數一:定時器名稱
參數二:指向初始化信息TIM_ICInitTypeDef結構體的指針
TIM_ICStructInit函數
簡介:給TIM_ICInitTypeDef結構體賦默認值。
參數:指向初始化信息TIM_ICInitTypeDef結構體的指針
TIM_SelectInputTrigger函數
簡介:選擇輸入觸發源TRGI。
參數一:定時器名稱
參數二:TRGI觸發源
TIM_TS_觸發源名稱
TIM_SelectOutputTrigger函數
簡介:選擇輸出觸發源TRGO。
參數一:定時器名稱
參數二:TRGO觸發源
TIM_TRGOSource_觸發源名稱
TIM_SelectSlaveMode函數
簡介:選擇從模式。
參數一:定時器名稱
參數二:從模式
TIM_SlaveMode_從模式名稱(列表后四個)
TIM_SetICxPrescaler函數
簡介:單獨配置通道x的分頻器(x可選1、2、3、4)。
參數一:定時器名稱
參數二:分頻器
TIM_GetCapturex函數
簡介:讀取通道x的CCR(x可選1、2、3、4)。
實驗13 輸入捕獲模式測頻率
接線圖
在沒有信號發生器的情況下,我們使用PA0口輸出方波信號,由PA6口測量。
PWM驅動
PWM驅動沿用實驗10,新增了調節頻率函數。
PWM.h
#ifndef __PWM_H
#define __PWM_Hvoid PWM_Init(void);
void PWM_SetCompare1(uint16_t Compare);
void PWM_SetPrescaler(uint16_t Prescaler);#endif
PWM.c
#include "stm32f10x.h" void PWM_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);TIM_InternalClockConfig(TIM2);TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//固定ARR為100-1,此時PSC調節頻率,CCR調節占空比TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructure.TIM_Pulse = 0;TIM_OC1Init(TIM2, &TIM_OCInitStructure);TIM_Cmd(TIM2, ENABLE);
}//配置CCR改變占空比
void PWM_SetCompare1(uint16_t Compare)
{TIM_SetCompare1(TIM2, Compare);
}//配置PSC改變頻率
void PWM_SetPrescaler(uint16_t Prescaler)
{//由于要求不高,PSC使用無預裝模式TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate);
}
輸入捕獲驅動
由于同一通道不能同時輸入捕獲和輸出比較,輸入捕獲我們使用TIM3。
IC.h
#ifndef __IC_H
#define __IC_Hvoid IC_Init(void);
uint32_t IC_GetFreq(void);#endif
IC.c
#include "stm32f10x.h"void IC_Init(void)
{//配置PA6(TIM3的CH1引腳)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//配置TIM3的時基單元RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);TIM_InternalClockConfig(TIM3);TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//ARR設大,防止計數器溢出TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;//標準頻率1MHz,根據信號頻率分布范圍調整TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);//配置輸入捕獲單元TIM_ICInitTypeDef TIM_ICInitStructure;TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;TIM_ICInitStructure.TIM_ICFilter = 0x0F;TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;TIM_ICInit(TIM3, &TIM_ICInitStructure);//配置TRGI觸發源TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);//配置從模式ResetTIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);TIM_Cmd(TIM3, ENABLE);
}//讀取并計算頻率
uint32_t IC_GetFreq(void)
{//實測CCR總是會少1,此處做補償return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}
主程序
#include "stm32f10x.h"
#include "Delay.h"
#include "PWM.h"
#include "OLED.h"
#include "IC.h"int main(void)
{OLED_Init();PWM_Init();IC_Init();OLED_ShowString(1, 1, "Freq:00000Hz");//頻率Freq = 72M / (PSC + 1) / 100PWM_SetPrescaler(720 - 1);//占空比Duty = CCR / 100PWM_SetCompare1(50);while(1){OLED_ShowNum(1, 6, IC_GetFreq(), 5);}
}
實驗14 PWMI模式測頻率占空比
接線圖、PWM驅動同實驗13,輸入捕獲驅動新增配置PWMI模式和獲取占空比函數。
輸入捕獲驅動
IC.h
#ifndef __IC_H
#define __IC_Hvoid IC_Init(void);
uint32_t IC_GetFreq(void);
uint32_t IC_GetDuty(void);#endif
IC.c
#include "stm32f10x.h"void IC_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);TIM_InternalClockConfig(TIM3);TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);TIM_ICInitTypeDef TIM_ICInitStructure;TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;TIM_ICInitStructure.TIM_ICFilter = 0x0F;TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;TIM_ICInit(TIM3, &TIM_ICInitStructure);//配置PWMI模式TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);TIM_Cmd(TIM3, ENABLE);
}uint32_t IC_GetFreq(void)
{return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}//獲取并計算占空比,乘一百轉換為百分比
uint32_t IC_GetDuty(void)
{return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1);
}
主程序
#include "stm32f10x.h"
#include "Delay.h"
#include "PWM.h"
#include "OLED.h"
#include "IC.h"int main(void)
{OLED_Init();PWM_Init();IC_Init();OLED_ShowString(1, 1, "Freq:00000Hz");OLED_ShowString(2, 1, "Duty:00%");//頻率Freq = 72M / (PSC + 1) / 100PWM_SetPrescaler(720 - 1);//占空比Duty = CCR / 100PWM_SetCompare1(50);while(1){OLED_ShowNum(1, 6, IC_GetFreq(), 5);OLED_ShowNum(2, 6, IC_GetDuty(), 2);}
}