# 硬體 - 模組: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輸出功能 - ![image](https://hackmd.io/_uploads/HJPLSYQdT.png) # 使用完整功能 - 官方僅提供如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**大致內容如上述,另外包含==序列通訊軟體的使用方式== - ![image](https://hackmd.io/_uploads/rkUI9Ymua.png) - "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軟體會自動開啟 - ![image](https://hackmd.io/_uploads/rk-OWcQ_a.png) 4. 在畫面左側的Project Explorer中,點開如下圖路徑的 **main.c** (若沒有Project Explorer視窗,可在控制列\Window\Show View開啟) - ![image](https://hackmd.io/_uploads/B1JxM5mdp.png) 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. 以範例代碼,會接收到如下圖資訊 - ![image](https://hackmd.io/_uploads/H1x7boQdT.png) 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,表示有異常狀況 ![image](https://hackmd.io/_uploads/ByTDEiXFp.png)