STM32F103輸入捕獲實驗

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的博客,敬請關注!



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章