STM32L051C8T6 STM32CubeMx 輸入捕獲進行超聲波測距 案例

MCU主控:

STM32L051C8T6

超聲波模塊:

RCWL-1601

基本工作原理: 
1、採用IO口TRIG觸發測距,給至少10us的高電平信號; 
2、模塊自動發送8個40khz的方波,自動檢測是否有信號返回; 
3、有信號返回,通過IO口ECHO輸出一個高電平,高電平持續的時間就是超聲波從發射到返回的時間。測試距離=(高電平時間*聲速(340M/S))/2;

本模塊使用方法簡單,一個控制口發一個10US以上的高電平,就可以在接收口等待高電平輸出.一有輸出就可以開定時器計時,當此口變爲低電平時就可以讀定時器的值,此時就爲此次測距的時間,方可算出距離.如此不斷的週期測,即可以得到你移動測量的值。超聲波模塊時序圖如下: 

輸入捕獲簡介

輸入捕獲可以用來測量脈衝寬度或者測量頻率。超聲波用到的是測量脈寬,這裏我以測量脈寬爲例,用一個簡圖來說明輸入捕獲的原理,如下圖: 


如上圖所示,就是輸入捕獲測量高電平脈寬的原理,假定定時器工作在向上計數模式,圖中t1-t2時間,就是我們需要測量的高電平時間。測量方法如下:首先設置定時器通道x爲上升沿捕獲,這樣,t1時刻就會捕捉到CNT值,然後立即清零CNT,並設置通道x爲下降沿捕獲,這樣t2時刻又會發生捕獲事件,得到此時的CNT值,記爲CCRx2。這樣,根據定時器的計數頻率,我們就可以算出t1-t2的時間,從而得到高電平的脈寬。

在t1-t2之間,可能產生N次定時器溢出,這就要求我們對定時器溢出做處理,防止高電平太長,導致數據不準確。如上圖所示,t1-t2之間CNT計數的的次數等於:N*ARR+CRRx2,有了這個計數次數,再乘以CNT的計數週期,即可得到t1-t2的時間長度,即高電平持續時間。

2、STM32CubeMx 配置

1)、系統時鐘配置

2)、定時器22配置

3)、串口1配置

3、代碼說明:

tim.c文件

/* USER CODE BEGIN 0 */
#include "stdio.h"

uint8_t   text_flag = 0;
uint8_t   dis_fm = 0;
uint8_t   Channel2Edge = 0;
uint16_t  Channel2HighTime, Channel2RisingTime, Channel2FallingTime;

/* USER CODE END 0 */

.....

/* USER CODE END 1 */

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
  /*防止未使用參數(s)編譯警告*/
	UNUSED(htim);

	if(htim->Instance == htim22.Instance)
	{
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
		{
			if(Channel2Edge == 0)          //捕獲上升沿
			{
				Channel2RisingTime = HAL_TIM_ReadCapturedValue(&htim22, TIM_CHANNEL_2);                         //獲取上升沿時間點
				__HAL_TIM_SET_CAPTUREPOLARITY(&htim22, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING);        //切換捕獲極性
				HAL_TIM_IC_Start_IT(&htim22, TIM_CHANNEL_2);     //切換捕獲極性後需重新啓動

				Channel2Edge = 1;          	 //上升沿、下降沿捕獲標誌位
			}
			else if(Channel2Edge == 1)     //捕獲下降沿
			{
				Channel2FallingTime = HAL_TIM_ReadCapturedValue(&htim22, TIM_CHANNEL_2);                       //獲取下降沿時間點
				__HAL_TIM_SET_CAPTUREPOLARITY(&htim22, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING);        //切換捕獲極性
				HAL_TIM_IC_Start_IT(&htim22, TIM_CHANNEL_2);   	 //切換捕獲極性後需重新啓動

				Channel2HighTime = Channel2FallingTime < Channel2RisingTime ? Channel2FallingTime + 0xffff - Channel2RisingTime + 1 : Channel2FallingTime - Channel2RisingTime;
				//高電平持續時間 = 下降沿時間點 - 上升沿時間點
				dis_fm = Channel2HighTime * 17 / 100; //計算超聲波測量距離
				printf("dis_fm = %dcm \r\n", dis_fm);
				//i++;//累加計數
				Channel2Edge = 0;		  			 //一次採集完畢,清零
			}
			HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
		}
	}
}


/* USER CODE END 1 */

usart.c文件

/* USER CODE BEGIN 0 */
#include "stdio.h"
/* USER CODE END 0 */
....

/* USER CODE BEGIN 1 */
#ifdef __GNUC__
  /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
     set to 'Yes') calls __io_putchar() */
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
 
  return ch;
}
/* USER CODE END 1 */

main.c文件

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

void Delay_us(uint32_t t)//64M條件下的一微妙
{   
    int n  =  11;
    while(--t)
    {
        while(--n);
        n = 11;
    }
}

void gases_start_signal(void)
{  
  unsigned char i=0;

  HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET);
  //延時20us
  Delay_us(20);

  HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET);
}
/* USER CODE END 0 */

....

/* USER CODE BEGIN 2 */
	HAL_TIM_IC_Start_IT(&htim22, TIM_CHANNEL_2);
/* USER CODE END 2 */
....

/* USER CODE BEGIN WHILE */
  while (1)
  {
		//ADC_GetValue();
		gases_start_signal();
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

串口助手打印結果:

代碼連接

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