主控板
- NUCLEO-F411RE
NUCLEO-F411RE 是ST公司推出的一款針對STM32F4系列設計的Cortex-M4開發板,具有 mbed 功能,支持Arduino。同時還提供 ST Morpho 擴展排針,可連接微控制器的所有周邊外設。
開發板基於STM32F411RET6設計,開發板還集成了ST-LINK/V2-1仿真下載器(但僅對外提供SWD接口),免除另外採購仿真器或下載器的麻煩。並且具備Arduino接口,可接入 Arduino 巨大生態系統的各種 Shield 擴展板,能夠輕鬆快速增加特殊功能。
超聲波模塊
- HC-SR04超聲波模塊
使用HC-SR04超聲波模塊,此模塊性能穩定,測度距離精確,模塊高精度,盲區小。主要的電氣參數如下:
電氣參數 HC-SR04超聲波模塊
工作電壓 DC 5V
工作電流 15mA
工作頻率 40Hz
最遠射程 4m
最近射程 2cm
測量角度 15度
輸入觸發信號 10Us的TTL脈衝
輸出迴響信號 輸出TTL電平信號,與射程成比例
規格尺寸 45*20*15mm
基本工作原理:
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的時間長度,即高電平持續時間。
STM32CubeMX配置定時器輸入捕獲功能
使用STM32CubeMX配置輸入捕獲功能初始化代碼步驟如下:
- 在Pinout->TIM2配置項中,配置Channel1的值爲Input Capture direct mode,然後選中Internal Clock。操作過程如下圖所示
進入Configuration->TIM2配置頁,在彈出的界面中點擊Parameter Settings選項卡,Counter Settings配置欄下面的四個選項就是用來配置定時器的預分頻係數,自動裝載值,計數模式以及時鐘分頻因子。在界面的Input Capture Channel 1配置欄配置輸入捕獲通道1的捕獲極性,分頻係數、映射、濾波器等參數,操作方法如下圖:
進入Configuration->NVIC配置頁,在彈出的界面中點擊NVIC選項卡,配置Interrupt
配置PA1口爲輸出口
配置完上面步驟後,生成代碼。在生成的代碼中,並沒有使能相應中斷的代碼,也沒有改寫中斷處理回調函數,這都需要我們自己來編寫
軟件設計
tim.c文件新增的內容如下
/* USER CODE BEGIN 1 */
uint8_t TIM2CH1_CAPTURE_STA=0; //ÊäÈ벶»ñ״̬
uint32_t TIM2CH1_CAPTURE_VAL; //ÊäÈ벶»ñÖµ(TIM2/TIM5ÊÇ32λ)
//¶¨Ê±Æ÷¸üÐÂÖжϣ¨¼ÆÊýÒç³ö£©Öжϴ¦Àí»Øµ÷º¯Êý£¬ ¸Ãº¯ÊýÔÚHAL_TIM_IRQHandlerÖлᱻµ÷ÓÃ
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//¸üÐÂÖжϣ¨Òç³ö£©·¢ÉúʱִÐÐ
{
if((TIM2CH1_CAPTURE_STA&0X80)==0)//»¹Î´³É¹¦²¶»ñ
{
if(TIM2CH1_CAPTURE_STA&0X40)//ÒѾ²¶»ñµ½¸ßµçƽÁË
{
if((TIM2CH1_CAPTURE_STA&0X3F)==0X3F)//¸ßµçƽ̫³¤ÁË
{
TIM2CH1_CAPTURE_STA|=0X80; //±ê¼Ç³É¹¦²¶»ñÁËÒ»´Î
TIM2CH1_CAPTURE_VAL=0XFFFFFFFF;
}
else TIM2CH1_CAPTURE_STA++;
}
}
}
//¶¨Ê±Æ÷ÊäÈ벶»ñÖжϴ¦Àí»Øµ÷º¯Êý£¬¸Ãº¯ÊýÔÚHAL_TIM_IRQHandlerÖлᱻµ÷ÓÃ
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//²¶»ñÖжϷ¢ÉúʱִÐÐ
{
if((TIM2CH1_CAPTURE_STA&0X80)==0)//»¹Î´³É¹¦²¶»ñ
{
if(TIM2CH1_CAPTURE_STA&0X40) //²¶»ñµ½Ò»¸öϽµÑØ
{
TIM2CH1_CAPTURE_STA|=0X80; //±ê¼Ç³É¹¦²¶»ñµ½Ò»´ÎµÍµçƽÂö¿í
TIM2CH1_CAPTURE_VAL=HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);//»ñÈ¡µ±Ç°µÄ²¶»ñÖµ.
long long temp=0;
temp=TIM2CH1_CAPTURE_STA&0X3F;
temp*=0XFFFFFFFF; //Òç³öʱ¼ä×ܺÍ
temp+=TIM2CH1_CAPTURE_VAL; //µÃµ½×ܵĸߵçƽʱ¼ä
temp=temp*17/1000;
printf("distence:%lld cm\r\n",temp);//´òÓ¡×ܵĸߵãƽʱ¼ä
__HAL_TIM_DISABLE(&htim2); //¹Ø±Õ¶¨Ê±Æ÷2
}
else //»¹Î´¿ªÊ¼,µÚÒ»´Î²¶»ñÉÏÉýÑØ
{
TIM2CH1_CAPTURE_STA=0; //Çå¿Õ
TIM2CH1_CAPTURE_VAL=0;
TIM2CH1_CAPTURE_STA|=0X40; //±ê¼Ç²¶»ñµ½ÁËÉÏÉýÑØ
__HAL_TIM_DISABLE(&htim2); //¹Ø±Õ¶¨Ê±Æ÷2
__HAL_TIM_SET_COUNTER(&htim2,0);
TIM_RESET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1); //Ò»¶¨ÒªÏÈÇå³ýÔÀ´µÄÉèÖã¡£¡
TIM_SET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING);//¶¨Ê±Æ÷2ͨµÀ1ÉèÖÃΪÉÏϽµÑز }
}
}
/* USER CODE END 1 */
定義了兩個全局變量,用於輔助實現高電平捕獲。其中TIM2CH1_CAPTURE_STA是用來記錄捕獲狀態,各位描述如下:輔助實現高電平捕獲。其中TIM2CH1_CAPTURE_STA是用來記錄捕獲狀態,各位描述如下:
bit7:捕獲完成標誌
bit6:捕獲到高電平的標誌
bit5~0:捕獲高電平後定時器溢出的次數
另一個變量TIM2CH1_CAPTURE_VAL,則用來記錄捕獲到下降沿的時候,TIM2_CNT的值。
main函數內容
int main(void)
{
/* USER CODE BEGIN 1 */
long long temp=0;
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1); //¿ªÆôTIM5µÄ²¶»ñͨµÀ1£¬²¢ÇÒ¿ªÆô²¶»ñÖжÏ
__HAL_TIM_ENABLE_IT(&htim2,TIM_IT_UPDATE); //ʹÄܸüÐÂÖжÏ
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
if(TIM2CH1_CAPTURE_STA&0X80) //³É¹¦²¶»ñµ½ÁËÒ»´ÎµÍµçƽ
{
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
__HAL_TIM_SET_COUNTER(&htim2,0);
TIM_RESET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1); //Ò»¶¨ÒªÏÈÇå³ýÔÀ´µÄÉèÖã¡£¡
TIM_SET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);//¶¨Ê±Æ÷2ͨµÀ1ÉèÖÃΪÉÏÉýÑز¶»ñ
__HAL_TIM_ENABLE(&htim2);//ʹÄܶ¨Ê±Æ÷5
TIM2CH1_CAPTURE_STA=0;
}
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}