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 */
串口助手打印結果: