深入淺出STM32 定時器輸入捕獲實驗之四路超聲波講解(寄存器版)

輸入捕獲

定時器的輸入捕獲模式可以用來測量脈衝寬度或者測量頻率。本教程通過測量脈衝寬度,實現四路超聲波測量距離的目的。如圖所示:
在這裏插入圖片描述
首先,我們設定定時器工作模式爲向上計數模式,圖中t1-t2時間間隔就是我們需要測量的脈寬時間(即高電平時間)。測量方法如下:
1:設定定時器某通道爲上升沿捕獲,這樣在t1時刻,就會捕獲到當前值CNT值,然後馬上清零,同時設置該通道爲下降沿捕獲,這樣到t2時刻,又發生捕獲事件,得到此時的CNT值,記爲CCRx2。這樣,根據定時器的計數頻率可以算出t1-t2的時間,從而得到高電平脈寬。
2:在t1-t2的時間段裏,有可能發生N次溢出,我們需要對此進一步處理,防止高電平過長,導致數據不準確。因此,CNT計數的次數等於N*ARR+CCRx2,有了這個計數次數,再乘以 CNT 的計數週期,即可得到 t2-t1 的時間長度,即高電平持續時間。輸入捕獲的原理,我們就介紹到這。

超聲測距

超聲測距究竟是什麼高大上的玩意呢???超聲測距其實就是通過單片機控制超聲波模塊發出一系列超聲波,當超聲波遇到障礙物時反彈回來,根據聲音在空氣中的傳播速率340m/s,再結合上述所講的方法求得時間t,應用初高中物理知識,即可求解距離。
(驅動超聲波模塊需要給它一個10-20us高電平)

即 測量距離=(高電平持續時間(340M/S))/2*
至於爲啥要除以2,自個慢慢思量啦!!!)
此外,還可以這樣快速計算出距離:
由於,我們算出的高電平時間是以us爲單位,因此我們可以把聲波傳輸速度看成大約爲340M/S,合34,000CM/S。 即34,000除以1,000,000CM/US。 即爲:0.0340CM/US 換種角度:1/(0.0343 CM/US) 即:29.00 US/CM。 這就意味着,每290.0US表示10CM的距離。1釐米就是29.00US。 但是發送後到接收到回波,聲音走過的是2倍的距離呀。 所以實際距離就是1釐米,對應58.0US。
即 測量距離=(高電平持續時間/58.0(CM))

超聲測距實現步驟

1.使能定時器時鐘(寄存器APB1ENR/APB2ENR)。
2.使能複用IO口時鐘(寄存器AHB1ENR )配置相應IO 口,此教成不加以說明,欲想了解翻之前博客。
3.設置重裝載值與預分頻係數(寄存器ARR和PSC)
4.每個通道選擇輸入端,設置爲輸入;配置濾波器於分頻器(CCMR1/CCMR2寄存器)
5.每個通道設置允許捕獲計數器的值到捕獲寄存器中,設置捕獲模式(CCER寄存器),最後開啓捕獲中斷(DIER寄存器),這樣通道配置就完成了。
6.最後,使能捕獲(DIER寄存器)和使能計數器(CR1寄存器),設置中斷分組(MY_NVIC_Init();//中斷分組函數)
7.編寫中斷服務函數,距離求解函數(公式)
注:相關寄存器請自行翻閱芯片數據手冊。

程序部分

void TIM4_CapHC_Init(u32 arr,u32 psc)
{
	
				RCC->APB1ENR=1<<2;//使能TIM4時鐘
				RCC->AHB1ENR|=1<<1;
				GPIO_Set(GPIOB,PIN6|PIN7|PIN8|PIN9,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_100M,GPIO_PUPD_PD);
				GPIO_AF_Set(GPIOB,6,2);
				GPIO_AF_Set(GPIOB,7,2);
				GPIO_AF_Set(GPIOB,8,2);
				GPIO_AF_Set(GPIOB,9,2);

				TIM4->ARR=arr;     //設置重裝載值              
				TIM4->PSC=psc;             //預分頻器    
			
//CH1	
				TIM4->CCMR1|=1<<0;       //選擇輸入端 1通道設置爲輸入
        TIM4->CCMR1&=~(15<<4);         //配置爲輸入濾波器,不濾波
        TIM4->CCMR1&=~(3<<2);         //配置輸入分頻,不分頻
        TIM4->CCER|=1<<0;           //允許捕獲計數器的值到捕獲寄存器中      
        TIM4->CCER&=~(1<<1);         //上升沿捕獲
        TIM4->DIER|=1<<1;   //允許捕獲中斷
//CH2       
				TIM4->CCMR1|=1<<8;          //選擇輸入端 2通道設置爲輸入
        TIM4->CCMR1&=~(15<<12);          //配置爲輸入濾波器,不濾波
        TIM4->CCMR1&=~(3<<10);          //配置輸入分頻,不分頻
        TIM4->CCER|=1<<4;         //允許捕獲計數器的值到捕獲寄存器中  
        TIM4->CCER&=~(1<<5);         //上升沿捕獲
        TIM4->DIER|=1<<2;   //允許捕獲中斷
//CH3
				TIM4->CCMR2|=1<<0;          //選擇輸入端 3通道設置爲輸入
        TIM4->CCMR2&=~(15<<4);          //配置爲輸入濾波器,不濾波
        TIM4->CCMR2&=~(3<<2);         //配置輸入分頻,不分頻
        TIM4->CCER|=1<<8;          //允許捕獲計數器的值到捕獲寄存器中  
        TIM4->CCER&=~(1<<9);         //上升沿捕獲
        TIM4->DIER|=1<<3;               //允許捕獲中斷
//CH4	
				TIM4->CCMR2|=1<<8;          //選擇輸入端 3通道設置爲輸入
        TIM4->CCMR2&=~(15<<12);          //配置爲輸入濾波器,不濾波
        TIM4->CCMR2&=~(3<<10);          //配置輸入分頻,不分頻
        TIM4->CCER|=1<<12;          //允許捕獲計數器的值到捕獲寄存器中  
        TIM4->CCER&=~(1<<13);         //上升沿捕獲
        TIM4->DIER|=1<<3;               //允許捕獲中斷    				
        

				TIM4->DIER|=1<<0; 
				TIM4->CR1|=1<<7; 
				TIM4->CR1|=0x01; 
				
				MY_NVIC_Init(2,0,TIM4_IRQn,2);//搶佔2,子優先0,組2

}



/**************************************************************************
函數功能:超聲波回波脈寬讀取中斷
入口參數:無
返回  值:無
**************************************************************************/
u8 TIM4CH1_CAPTURE_STA=0;//通道一
u32 TIM4CH1_CAPTURE_VAL;
u8 TIM4CH2_CAPTURE_STA=0;//通道二
u32 TIM4CH2_CAPTURE_VAL;
u8 TIM4CH3_CAPTURE_STA=0;//通道三
u32 TIM4CH3_CAPTURE_VAL;
u8 TIM4CH4_CAPTURE_STA=0;//通道四
u32 TIM4CH4_CAPTURE_VAL;
void TIM4_IRQHandler(void)
{ 		    		  			    
	u16 tsr;
	tsr=TIM4->SR;
/*******************************************************************
	
********************************************************************/
	if((TIM4CH1_CAPTURE_STA&0X80)==0)//還未成功捕獲	
				{ 
								if(tsr&0X01)//溢出
								{	    
										if(TIM4CH1_CAPTURE_STA&0X40)//已經捕獲到高電平了
										{
											if((TIM4CH1_CAPTURE_STA&0X3F)==0X3F)//高電平太長了
											{
												TIM4CH1_CAPTURE_STA|=0X80;//標記成功捕獲了一次
												TIM4CH1_CAPTURE_VAL=0XFFFF;
											}else TIM4CH1_CAPTURE_STA++;
										}	 
								}
						   	if(tsr&0x02)//捕獲1發生捕獲事件
				    	{	
											if(TIM4CH1_CAPTURE_STA&0X40)		//捕獲到一個下降沿 		
											{	  			
											TIM4CH1_CAPTURE_STA|=0X80;		//標記成功捕獲到一次高電平脈寬
											TIM4CH1_CAPTURE_VAL=TIM4->CCR1;	//獲取當前的捕獲值.
											TIM4->CCER&=~(1<<1);			//CC1P=0 設置爲上升沿捕獲
									  	}else  								//還未開始,第一次捕獲上升沿
				   	{
											TIM4CH1_CAPTURE_STA=0;			//清空
											TIM4CH1_CAPTURE_VAL=0;
											TIM4CH1_CAPTURE_STA|=0X40;		//標記捕獲到了上升沿
											TIM4->CNT=0;					//計數器清空
											TIM4->CCER|=1<<1; 				//CC1P=1 設置爲下降沿捕獲
						}		    
					    }			     	    					   
		  }
				
/*************************************************************************/
			 
/*************************************************************************/

	if((TIM4CH2_CAPTURE_STA&0X80)==0)//還未成功捕獲	
			{ 
								if(tsr&0X01)//溢出
								{	    
										if(TIM4CH2_CAPTURE_STA&0X40)//已經捕獲到高電平了
										{
											if((TIM4CH2_CAPTURE_STA&0X3F)==0X3F)//高電平太長了
											{
												TIM4CH2_CAPTURE_STA|=0X80;//標記成功捕獲了一次
												TIM4CH2_CAPTURE_VAL=0XFFFF;
											}else TIM4CH2_CAPTURE_STA++;
										}	 
								}
						   	if(tsr&0x04)//捕獲2發生捕獲事件
				    	{	
											if(TIM4CH2_CAPTURE_STA&0X40)		//捕獲到一個下降沿 		
											{	  			
											TIM4CH2_CAPTURE_STA|=0X80;		//標記成功捕獲到一次高電平脈寬
											TIM4CH2_CAPTURE_VAL=TIM2->CCR2;	//獲取當前的捕獲值.
											TIM4->CCER&=~(1<<5);			//CC1P=0 設置爲上升沿捕獲
									  	}else  								//還未開始,第一次捕獲上升沿
				   	{
											TIM4CH2_CAPTURE_STA=0;			//清空
											TIM4CH2_CAPTURE_VAL=0;
											TIM4CH2_CAPTURE_STA|=0X40;		//標記捕獲到了上升沿
											TIM4->CNT=0;					//計數器清空
											TIM4->CCER|=1<<5; 				//CC1P=1 設置爲下降沿捕獲
						}		    
					   }			     	    					   
		   }
/***************************************************************************************
			 
****************************************************************************************/

	if((TIM4CH3_CAPTURE_STA&0X80)==0)//還未成功捕獲	
				{ 
								if(tsr&0X01)//溢出
								{	    
										if(TIM4CH3_CAPTURE_STA&0X40)//已經捕獲到高電平了
										{
											if((TIM4CH3_CAPTURE_STA&0X3F)==0X3F)//高電平太長了
											{
												TIM4CH3_CAPTURE_STA|=0X80;//標記成功捕獲了一次
												TIM4CH3_CAPTURE_VAL=0XFFFF;
											}else TIM4CH3_CAPTURE_STA++;
										}	 
								}
						   	if(tsr&0x08)//捕獲1發生捕獲事件
				    	{	
											if(TIM4CH3_CAPTURE_STA&0X40)		//捕獲到一個下降沿 		
											{	  			
											TIM4CH3_CAPTURE_STA|=0X80;		//標記成功捕獲到一次高電平脈寬
											TIM4CH3_CAPTURE_VAL=TIM2->CCR3;	//獲取當前的捕獲值.
											TIM4->CCER&=~(1<<9);			//CC1P=0 設置爲上升沿捕獲
									  	}else  								//還未開始,第一次捕獲上升沿
				   	{
											TIM4CH3_CAPTURE_STA=0;			//清空
											TIM4CH3_CAPTURE_VAL=0;
											TIM4CH3_CAPTURE_STA|=0X40;		//標記捕獲到了上升沿
											TIM4->CNT=0;					//計數器清空
											TIM4->CCER|=1<<9; 				//CC1P=1 設置爲下降沿捕獲
							}		    
					    	}			     	    					   
				}

/***************************************************************************************
			 
****************************************************************************************/

	if((TIM4CH4_CAPTURE_STA&0X80)==0)//還未成功捕獲	
				{ 
								if(tsr&0X01)//溢出
								{	    
										if(TIM4CH4_CAPTURE_STA&0X40)//已經捕獲到高電平了
										{
											if((TIM4CH4_CAPTURE_STA&0X3F)==0X3F)//高電平太長了
											{
												TIM4CH4_CAPTURE_STA|=0X80;//標記成功捕獲了一次
												TIM4CH4_CAPTURE_VAL=0XFFFF;
											}else TIM4CH4_CAPTURE_STA++;
										}	 
								}
						   	if(tsr&0x08)//捕獲1發生捕獲事件
				    	{	
											if(TIM4CH4_CAPTURE_STA&0X40)		//捕獲到一個下降沿 		
											{	  			
											TIM4CH4_CAPTURE_STA|=0X80;		//標記成功捕獲到一次高電平脈寬
											TIM4CH4_CAPTURE_VAL=TIM2->CCR3;	//獲取當前的捕獲值.
											TIM4->CCER&=~(1<<13);			//CC1P=0 設置爲上升沿捕獲
									  	}else  								//還未開始,第一次捕獲上升沿
				   	{
											TIM4CH4_CAPTURE_STA=0;			//清空
											TIM4CH4_CAPTURE_STA=0;
											TIM4CH4_CAPTURE_STA|=0X40;		//標記捕獲到了上升沿
											TIM4->CNT=0;					//計數器清空
											TIM4->CCER|=1<<13; 				//CC4P=1 設置爲下降沿捕獲
							}		    
					    	}			     	    					   
		   }
			 		TIM4->SR&=~(1<<0);//清除中斷標誌
	}

/**************************************************************************
函數功能:超聲波接收回波函數
入口參數:無
返回  值:有
**************************************************************************/
u32 DisT4C1,DisT4C2,DisT4C3,DisT4C4;       //超聲測距  
u8 ReadT4C1_Distane(void)
{   
	
	 PCout(4)=1;
	 delay_us(10);  
	 PCout(4)=0;	
			if(TIM4CH1_CAPTURE_STA&0X80)//成功捕獲到了一次高電平
			{
			DisT4C1=TIM4CH1_CAPTURE_STA&0X3F;
			DisT4C1*=65536;					        //溢出時間總和
			DisT4C1+=TIM4CH1_CAPTURE_VAL;		//得到總的高電平時間us
      DisT4C1=DisT4C1/58.0;
			printf("DIST4C1:%d\n",DisT4C1);
			TIM4CH1_CAPTURE_STA=0;			//開啓下一次捕獲
		  }	
			return DisT4C1;			
}




u8 ReadT4C2_Distane(void)
{   
	 PCout(5)=1;
	 delay_us(20);  
	 PCout(5)=0;	
			if(TIM4CH2_CAPTURE_STA&0X80)//成功捕獲到了一次高電平
			{
			DisT4C2=TIM4CH2_CAPTURE_STA&0X3F;
			DisT4C2*=65536;					        //溢出時間總和
			DisT4C2+=TIM4CH2_CAPTURE_VAL;		//得到總的高電平時間
			DisT4C2=DisT4C2/58.0;
			printf("DIST4C2:%d\n",DisT4C2);
			TIM4CH2_CAPTURE_STA=0;			//開啓下一次捕獲
		  }	
				return DisT4C2;
}

u8 ReadT4C3_Distane(void)
{   
	 PCout(6)=1;
	 delay_us(20);  
	 PCout(6)=0;	
			if(TIM4CH3_CAPTURE_STA&0X80)//成功捕獲到了一次高電平
			{
			DisT4C3=TIM4CH3_CAPTURE_STA&0X3F;
			DisT4C3*=65536;					        //溢出時間總和
			DisT4C3+=TIM4CH3_CAPTURE_VAL;		//得到總的高電平時間
			DisT4C3=DisT4C3/58.0;
			printf("DIST4C3:%d\n",DisT4C3);
			TIM4CH3_CAPTURE_STA=0;			//開啓下一次捕獲
		  }			
		return DisT4C3;			
}

u8 ReadT4C4_Distane(void)
{   
			PCout(7)=1;
			delay_us(20);  
			PCout(7)=0;	
			if(TIM4CH4_CAPTURE_STA&0X80)//成功捕獲到了一次高電平
			{
			DisT4C4=TIM4CH4_CAPTURE_STA&0X3F;
			DisT4C4*=65536;					        //溢出時間總和
			DisT4C4+=TIM4CH4_CAPTURE_VAL;		//得到總的高電平時間
			DisT4C4=DisT4C4/58.0;
			printf("DIST4C4:%d\n",DisT4C4);
			TIM4CH4_CAPTURE_STA=0;			//開啓下一次捕獲
		  }			
		return DisT4C4;			
}


以上僅是輸入捕獲初始化函數,定時器中斷服務函數和距離求解函數,實測可以行得通。大家可以根據自己需求,自行添加或修改代碼應用到實際工程。希望本教程對大家有所幫助,寫得不好或者有誤的地方,歡迎大家指正批評,謝謝大家!!!!

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