STM32F103輸入捕獲實驗
實驗介紹:本實驗利用TIM5的通道1(IO為PAO)來捕獲按鍵KEY_UP(按下)輸入的高電平脈寬的時間,并且利用串口列印出來,
一:實驗思路
要得出高電平脈寬的時間,就要設定兩次捕獲,第一次捕獲時,先設定為上升沿捕獲,捕當獲到了高電平觸發相關計數器開始計數,然后再設定為下降沿捕獲,捕獲到了低電平,即高電平結束的時候停止計數,如果高電平時間過長,超過了計數器的最大計數范圍,導致溢位,這個時候就要設定觸發相關中斷服務函式,計數溢位的次數,再算出總時間,
二:硬體配置
1.stm32f103
2.KEY_UP按鍵
3.串口
4.定時器TIM5
三:相關函式介紹
1.開啟TIM5和GPIOA的時鐘
因為TIM5的通道1(CH1),它對應的管腳為PA0,IO口就是GPIOA了,我們知道TIM5作為通用定時器是掛載在APB1總線下,而PCLK是提供給GPIO外設的時鐘,它是掛載在APB2總線下,于是我們的函式如下,
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //使能 TIM5 時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能 GPIOA 時鐘
2.初始化TIM5
這里通過兩個很常用的暫存器ARR 和 PSC分別來設定自動重裝載值預分頻系數,關于暫存器相關位的配置大家就自己查手冊,這里不多介紹,放代碼,
voidTIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
typedef struct
{
uint16_t TIM_Prescaler; //設定預分頻值
uint16_t TIM_CounterMode; //設定計數模式
uint16_t TIM_Period; //設定計數器自動重裝載值
uint16_t TIM_ClockDivision; //設定時鐘分頻因子
} TIM_TimeBaseInitTypeDef;
以上是包含結構體指標的函式定義部分,初始化部分如下
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//前面為結構體型別,后面為結構體名
TIM_TimeBaseStructure.TIM_Period = arr; //設定計數器自動重裝值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //設定預分頻值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上計數模式
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //根據指定的引數初始化 Tim5
3.配置輸入捕獲
設定這一步的目的就是前面已經講解的,要開啟計數器在上升沿的時候開始計數,設定上升沿捕獲是在TI1(通道 1)配置的,所以就要把IC1 映射到 TI1(通道 1)上面,定義相關函式如下:
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
typedef struct
{
uint16_t TIM_Channel; //設定為通道1
uint16_t TIM_ICPolarity; //設定捕獲極性
uint16_t TIM_ICSelection; //設定映射關系
uint16_t TIM_ICPrescaler; //分頻系數
uint16_t TIM_ICFilter; //濾波器長度
} TIM_ICInitTypeDef;
初始化
TIM_ICInitTypeDef TIM5_ICInitStructure;
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //選擇輸入端 IC1 映射到 TI1 上
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕獲
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到 TI1 上
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置輸入分頻,不分頻
TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置輸入濾波器 不濾波
TIM_ICInit(TIM5, &TIM5_ICInitStructure);
下面就是中斷相關的
4.使能捕獲和更新中斷
所謂捕獲中斷,就是在TIM5捕獲到了上升沿或者下降沿的信號就去執行相關指令
更新中斷,顧名思義,就是計數器溢位了,不得不重新計數,就叫做更新,產生更新中斷就會計數一次溢位的次數,使能函式如下
TIM_ITConfig( TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);
5.中斷服務函式
接下來我們就要撰寫中斷服務函式了,在此之前,不得不說明一下,中斷函式與一般函式的執行條件是不同的,一般函式一定要人工呼叫,而中斷函式只要設定的中斷條件滿足了,它會自動呼叫!
void TIM5_IRQHandler(void)
{
if((TIM5CH1_CAPTURE_STA&0X80)==0)//還未成功捕獲
{
if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)
{
if(TIM5CH1_CAPTURE_STA&0X40) //已經捕獲到高電平了
{
if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高電平太長了
{
TIM5CH1_CAPTURE_STA|=0X80; //標記成功捕獲了一次
TIM5CH1_CAPTURE_VAL=0XFFFF;
}else TIM5CH1_CAPTURE_STA++;
} }
if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET) //捕獲 1 發生捕獲事件
{
if(TIM5CH1_CAPTURE_STA&0X40) //捕獲到一個下降沿
{
TIM5CH1_CAPTURE_STA|=0X80; //標記成功捕獲到一次下降沿
TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //設定為上升沿捕獲
}else //還未開始,第一次捕獲上升沿
{
TIM5CH1_CAPTURE_STA=0; //清空
TIM5CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM5,0);
TIM5CH1_CAPTURE_STA|=0X40; //標記捕獲到了上升沿
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //設定為下降沿捕獲
}
}
}
TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中斷標志位
}
這個函式我就口頭說明一下,它可以拆分為兩個部分來看,前面一部分是有關捕獲中斷的,先判斷有沒有捕獲到高電平,捕獲到了高電平再判斷有沒有溢位,一旦溢位,則直接配置暫存器相關位來表示,并重新計數,如果沒有溢位,則繼續計數,直到溢位為止(這里只討論溢位的情況)
后面一部分就是有關更新中斷的了,這里比較好理解,如果最開始捕獲到一個下降沿,就說明第一次一定捕獲到上升沿,標記一次,然后捕獲極性設定為下降沿捕獲,等待下降沿的到來,同理,如果開頭捕獲到一個上升沿…
最后,別忘了用TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update);清除中斷標志位,
6.當然這里還有GPIO,和串口的使能及初始化,這里不是重點,我就不寫了…
最后我們用TIM5_Cap_Init這個函式來包涵進來,
四:程式介紹
#include "sys.h"
#include "usart.h"
#include "timer.h"
extern u8 TIM5CH1_CAPTURE_STA; //輸入捕獲狀態
extern u16 TIM5CH1_CAPTURE_VAL; //輸入捕獲值
int main(void)
{
u32 temp=0;
uart_init(115200); //串口初始化為115200
TIM5_Cap_Init(0XFFFF,72-1); //以1Mhz的頻率計數
while(1)
{
TIM_SetCompare2(TIM3,TIM_GetCapture2(TIM3)+1);
if(TIM_GetCapture2(TIM3)==300)TIM_SetCompare2(TIM3,0);
if(TIM5CH1_CAPTURE_STA&0X80)//成功捕獲到了一次上升沿
{
temp=TIM5CH1_CAPTURE_STA&0X3F;
temp*=65536;//溢位時間總和
temp+=TIM5CH1_CAPTURE_VAL;//得到總的高電平時間
printf("HIGH:%d us\r\n",temp);//列印總的高電平時間
TIM5CH1_CAPTURE_STA=0;//開啟下一次捕獲
}
}
}
五:使用及現象
打開串口助手,波特率設定為115200,打開串口
按下KEY_UP按鍵之后PC接收端會顯示高電平的時間,但是是不是可以一直按下去呢,當然不是,因為我們設定了TIM5CH1_CAPTURE_VAL=0XFFFF;VAL暫存器是16位暫存器,這里已經設定了最大數為0xFFFF,換算成十進制數就是4194303,所以我們看到輸入過長時間超過了4194303us就會強制輸出,

就是這樣了…
后續會陸續更新有關stm32的博客,敬請關注!
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/254784.html
標籤:其他
上一篇:Linux內核行程調度時機和程序
下一篇:Py之seaborn:資料可視化seaborn庫的柱狀圖、箱線圖(置信區間圖)、散點圖/折線圖、核密度圖/等高線圖、盒形圖/小提琴圖/LV多框圖的簡介、使用方法之最強攻略(建議收藏)
