# 硬體
- 模組:VL53L3A2擴充板 (VL53L3CX sensor)
- 腳位與Arduino Uno通用
- 微控制板:STM32F401_Nucleo-64
# 官方GUI
[官方下載點](https://www.st.com/en/embedded-software/stsw-img016.html)
- 一次使用一顆sensor(A2模組共3顆),單顆sensor可以偵測最多4個物體
- 實際測試只能偵測單一物體,原因不明
- <font color=red>僅輸出距離的中位數(可額外開啟最大最小值),沒有Histogram分佈行為供分析</font>
- 包含ref_sensor/Xtalk/Offset的快速校正功能
- 包含data log輸出功能
- 
# 使用完整功能
- 官方僅提供如GUI包含的簡易測距功能,若要呼叫其他函式,需要做分位編程及燒錄
- 需要工具:
- 模組API: 提供範例代碼及完整函式
- 序列通訊軟體: 接收資料
- IDE軟體: 編程
## 官方API
[官方下載點](https://www.st.com/en/embedded-software/stsw-img015.html)
- 下載資料包含"Docs"跟"BareDriver","Docs"內有簡易使用手冊,包含針對常見函式的介紹
- "BareDriver"的"example"內包含適用三種IDE軟體的檔案(官方CubeIDE、MDK-ARM、EWARM)
- "Binary"內有已轉換好的Binary檔 **VL53L3CX_SimpleRanging_F401.bin**,電腦接上微控制板後,微控制板會同時顯示為一個隨身碟,把此檔案拉進去即燒錄完成,使用序列通訊軟體即可接收資料。此範例輸出資訊與GUI相同,僅有單一距離資料
- **GettingStartedGuide.pdf**大致內容如上述,另外包含==序列通訊軟體的使用方式==
- 
- "BareDriver"的"doc"內有API的完整說明書 **VL53LX_API.chm**
## 序列通訊軟體
- STM手冊中使用的範例為Tera Term,為簡單易用的軟體,設定方式參考 **GettingStartedGuide.pdf**
- ==重點:位元速率(Baud Rate)需要設定為115200,否則會接收異常如出現亂碼==
- 沒有官方載點,隨意下載別中毒就好
## 官方IDE
[官方下載點](https://www.st.com/en/development-tools/stm32cubeide.html)
- 優點:可與微控制板燒錄程序直接對接,不須額外燒錄軟體
- 缺點:使用較複雜,網路可參考資訊少(跟樹莓派、Arduino等相比)
### 設定步驟
[參考影片](https://www.youtube.com/watch?v=7yhW7jzaWuY&ab_channel=STMicroelectronics)
1. 安裝IDE
2. 電腦接上微控制板
3. 在上述API部分中的example\STM32CubeIDE路徑,點開 **.cproject**,IDE軟體會自動開啟
- 
4. 在畫面左側的Project Explorer中,點開如下圖路徑的 **main.c** (若沒有Project Explorer視窗,可在控制列\Window\Show View開啟)
- 
5. 點擊控制列\Refactor下方的**鐵鎚圖案** (Build Debug)。若執行正常,在畫面下方的Console視窗會顯示==Build Finished==
6. 在Project Explorer單點選擇VL53L3CX_SimpleRanging_F401 (in STM32CubeIDE)
7. 點擊控制列\Help下方的**蟲蟲圖案 右邊箭頭**,選擇Debug As :arrow_right: 1 STM C/C++ Application
8. 中途跳出的視窗選項都確認執行。若執行正常,在畫面下方的Console視窗會顯示 ==Download verified successfully==
9. 此時微控制板上的燈號LD1應該會持續綠/紅閃爍,代表微控制板正由IDE程序控制
10. 打開序列通訊軟體接受資料
- 若是亂碼:如前述,確認位元速率是否正確(115200)。可在控制列\控制Setup\連接埠Serial port內設定
- 若排版不正常:可在控制列\控制Setup\終端機Terminal內,調整換行接收為**Auto**
- 若沒有資料出現:IDE燒錄完可能會停在某個指令等待繼續,按控制列\Search下方的 **Resume**繼續執行
11. 以範例代碼,會接收到如下圖資訊
- 
12. 由於微控制板已燒錄完成,持續執行迴圈狀態,即使終止IDE程序,依然能夠持續輸出資料。此時燈號LD1為長亮紅燈
## 範例代碼 (main.c)
### 代碼
:::spoiler
```cpp=
/**
******************************************************************************
* File Name : main.c
* Description : Main program body
******************************************************************************
*
* COPYRIGHT(c) 2020 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32xxx_hal.h"
/* USER CODE BEGIN Includes */
#include "main.h"
#include "vl53lx_api.h"
#include "53L3A2.h"
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;
UART_HandleTypeDef huart2;
VL53LX_Dev_t dev;
VL53LX_DEV Dev = &dev;
int status;
volatile int IntCount;
#define isInterrupt 1 /* If isInterrupt = 1 then device working in hardware interrupt mode, else device working in polling mode */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void Error_Handler(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_I2C1_Init(void);
void RangingLoop(void); /* */
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart2, (uint8_t*)&ch, 1, 0xFFFF);
return ch;
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin==VL53L1X_INT_Pin)
{
IntCount++;
}
}
/* USER CODE END 0 */
int main(void)
{
/* USER CODE BEGIN 1 */
uint8_t byteData;
uint16_t wordData;
uint8_t ToFSensor = 1; // 0=Left, 1=Center(default), 2=Right
/* 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_I2C1_Init();
XNUCLEO53L3A2_Init();
/* USER CODE END 1 */
/* USER CODE BEGIN 2 */
printf("VL53L1X Examples...\n");
Dev->I2cHandle = &hi2c1;
Dev->I2cDevAddr = 0x52;
/* Allow to select the sensor to be used, multi-sensor is not managed in this example.
Only when use use the Left ToF in interrupt mode, solder the U7 on the X-Nucleo-53L3A2 board
Only when use the Right ToF in interrupt mode, solder the U7 on the X-Nucleo-53L3A2 board
See "Solder drop configurations" in the X-Nucleo-53L3A2 User Manual for more details */
ToFSensor = 1; // Select ToFSensor: 0=Left, 1=Center, 2=Right
status = XNUCLEO53L3A2_ResetId(ToFSensor, 0); // Reset ToF sensor
HAL_Delay(2);
status = XNUCLEO53L3A2_ResetId(ToFSensor, 1); // Reset ToF sensor
HAL_Delay(2);
VL53LX_RdByte(Dev, 0x010F, &byteData);
printf("VL53LX Model_ID: %02X\n\r", byteData);
VL53LX_RdByte(Dev, 0x0110, &byteData);
printf("VL53LX Module_Type: %02X\n\r", byteData);
VL53LX_RdWord(Dev, 0x010F, &wordData);
printf("VL53LX: %02X\n\r", wordData);
RangingLoop();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/** System Clock Configuration
*/
#ifdef STM32F401xE
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
/**Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 16;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
/**Configure the Systick interrupt time
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**Configure the Systick
*/
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
#endif
#ifdef STM32L476xx
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_PeriphCLKInitTypeDef PeriphClkInit;
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = 16;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 1;
RCC_OscInitStruct.PLL.PLLN = 10;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2|RCC_PERIPHCLK_I2C1;
PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
/**Configure the main internal regulator output voltage
*/
if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
{
Error_Handler();
}
/**Configure the Systick interrupt time
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
/**Configure the Systick
*/
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
#endif
#ifdef STM32F401xE
/* I2C1 init function */
static void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
}
#endif
#ifdef STM32L476xx
/* I2C1 init function */
static void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x10909CEC;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
/**Configure Analogue filter
*/
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}
/**Configure Digital filter
*/
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
{
Error_Handler();
}
}
#endif
/* USART2 init function */
static void MX_USART2_UART_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
}
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : B1_Pin */
GPIO_InitStruct.Pin = B1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : VL53L1X_INT_Pin */
GPIO_InitStruct.Pin = VL53L1X_INT_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(VL53L1X_INT_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : LD2_Pin */
GPIO_InitStruct.Pin = LD2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI4_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI4_IRQn);
}
/* USER CODE BEGIN 4 */
/* ranging and display loop */
void RangingLoop(void)
{
VL53LX_MultiRangingData_t MultiRangingData;
VL53LX_MultiRangingData_t *pMultiRangingData = &MultiRangingData;
uint8_t NewDataReady=0;
int no_of_object_found=0,j;
printf("Ranging loop starts\n");
status = VL53LX_WaitDeviceBooted(Dev);
status = VL53LX_DataInit(Dev);
status = VL53LX_StartMeasurement(Dev);
if(status){
printf("VL53LX_StartMeasurement failed: error = %d \n", status);
while(1);
}
if (isInterrupt){
do // HW interrupt mode
{
__WFI();
if(IntCount !=0 ){
IntCount=0;
status = VL53LX_GetMultiRangingData(Dev, pMultiRangingData);
no_of_object_found=pMultiRangingData->NumberOfObjectsFound;
printf("Count=%5d, ", pMultiRangingData->StreamCount);
printf("#Objs=%1d ", no_of_object_found);
for(j=0;j<no_of_object_found;j++){
if(j!=0)printf("\n ");
printf("status=%d, D=%5dmm, Signal=%2.2f Mcps, Ambient=%2.2f Mcps",
pMultiRangingData->RangeData[j].RangeStatus,
pMultiRangingData->RangeData[j].RangeMilliMeter,
pMultiRangingData->RangeData[j].SignalRateRtnMegaCps/65536.0,
pMultiRangingData->RangeData[j].AmbientRateRtnMegaCps/65536.0);
}
printf ("\n");
if (status==0){
status = VL53LX_ClearInterruptAndStartMeasurement(Dev);
}
}
}
while(1);
}
else{
do{ // polling mode
status = VL53LX_GetMeasurementDataReady(Dev, &NewDataReady);
HAL_Delay(1); // 1 ms polling period, could be longer.
if((!status)&&(NewDataReady!=0)){
status = VL53LX_GetMultiRangingData(Dev, pMultiRangingData);
no_of_object_found=pMultiRangingData->NumberOfObjectsFound;
printf("Count=%5d, ", pMultiRangingData->StreamCount);
printf("#Objs=%1d ", no_of_object_found);
for(j=0;j<no_of_object_found;j++){
if(j!=0)printf("\n ");
printf("status=%d, D=%5dmm, Signal=%2.2f Mcps, Ambient=%2.2f Mcps",
pMultiRangingData->RangeData[j].RangeStatus,
pMultiRangingData->RangeData[j].RangeMilliMeter,
pMultiRangingData->RangeData[j].SignalRateRtnMegaCps/65536.0,
pMultiRangingData->RangeData[j].AmbientRateRtnMegaCps/65536.0);
}
printf ("\n");
if (status==0){
status = VL53LX_ClearInterruptAndStartMeasurement(Dev);
}
}
}
while (1);
}
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @param None
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler */
/* User can add his own implementation to report the HAL error return state */
while(1)
{
}
/* USER CODE END Error_Handler */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
```
:::
### ChatGPT註解
```typescript=
這段程式碼是針對STMicroelectronics的VL53L1X激光測距模組所編寫的,這個模組使用了STM32微控制器。以下是程式碼的功能分析:
檔案註釋及版權聲明:
該程式碼開頭包含有版權聲明以及檔案描述的註釋,它是STM32CubeIDE自动生成的一部分。
標頭檔引入及全域變數聲明:
引入了一系列的標頭檔,包括STM32相關的標頭以及VL53L1X模組的相關標頭。
定義了全域變數,包括I2C、UART、VL53L1X模組的裝置結構等。
中斷回調函式及PUTCHAR_PROTOTYPE函式:
定義了中斷回調函式HAL_GPIO_EXTI_Callback,當VL53L1X_INT引腳產生中斷時,計數器IntCount會遞增。
定義了PUTCHAR_PROTOTYPE函式,用於將標準輸出printf的內容通過UART輸出。
主函式:
主函式main中進行了一系列的初始化,包括系統初始化、時鐘配置、GPIO初始化、UART初始化、I2C初始化等。
使用XNUCLEO53L3A2_Init初始化VL53L1X模組。
顯示VL53L1X的模型ID、模組類型、一些數值。
調用RangingLoop函式進入測距循環。
系統時鐘配置函式:
根據不同的STM32型號,配置系統時鐘。
I2C初始化函式:
根據不同的STM32型號,進行I2C1的初始化。
UART初始化函式:
配置USART2串口的初始化。
GPIO初始化函式:
配置一系列的GPIO引腳,包括按鈕引腳、LD2指示燈引腳、VL53L1X中斷引腳。
PUTCHAR_PROTOTYPE函式實現:
實現fputc函式,將字符通過UART輸出。
測距循環函式 RangingLoop:
初始化VL53L1X模組,開始測距。
根據isInterrupt的值,分為中斷模式和輪詢模式。
若為中斷模式,則在中斷回調函式中處理測距數據。
若為輪詢模式,則透過輪詢方式處理測距數據。
錯誤處理函式 Error_Handler:
若程式碼執行到此處,表示發生了錯誤,這個函式中僅包含一個無窮迴圈。
時鐘配置及斷言處理:
包含時鐘配置函式和斷言處理的相關內容,用於處理硬體的錯誤情況。
總的來說,這段程式碼主要用於初始化STM32微控制器以及VL53L1X激光測距模組,然後進入測距循環,根據中斷或輪詢的方式處理測距數據。
```
**針對測距循環函式補充**
```typescript=
當程式執行到RangingLoop函式時,將執行VL53L1X模組的初始化,然後開始進入測距循環。這個函式主要分為兩個部分,根據isInterrupt的值分為中斷模式和輪詢模式。
中斷模式:
當isInterrupt為真時,表示使用中斷模式。在這種模式下,程式進入無窮迴圈,並使用__WFI()進入等待模式,等待中斷發生。
當VL53L1X_INT引腳產生中斷時,會觸發HAL_GPIO_EXTI_Callback函式,計數器IntCount遞增。
然後在迴圈中,如果IntCount不為0,表示有中斷發生,就執行VL53L1X模組的測距函式,獲取測距數據,並輸出相關信息。
最後,清除中斷並重新啟動測距。
輪詢模式:
當isInterrupt為假時,表示使用輪詢模式。在這種模式下,程式進入無窮迴圈,定期輪詢VL53L1X模組的測距數據。
使用VL53LX_GetMeasurementDataReady函式檢查是否有新的測距數據就緒。
如果有新的數據,則執行VL53L1X模組的測距函式,獲取數據,並輸出相關信息。
最後,清除中斷並重新啟動測距。
這樣的設計可以選擇中斷或輪詢的方式來處理VL53L1X模組的測距數據,具體的使用方式取決於isInterrupt的設置。這樣的設計在需要實時性的應用中,例如測距結果需要立即被處理的情況下,使用中斷模式能夠更即時地獲取測距數據。
```
## 其它補充
### Status列表
- 資料來源:API說明文件
- 若數值非0,表示有異常狀況
