什么是 ADC(模數轉換器)
ADC(Analog to Digital Converter)是將 模擬信號(電壓)轉換成數字信號(數值) 的器件。
在 STM32 中,ADC 通常具有以下特性:
特性 | 描述 |
---|---|
分辨率 | 12 位(即 0 ~ 4095) |
輸入電壓范圍 | 0 ~ 3.3V(取決于 VREF+ ) |
轉換方式 | 單次轉換、連續轉換、掃描模式 |
支持觸發方式 | 軟件觸發 / 硬件定時器 / 外部中斷 |
支持 DMA | 可配合 DMA 進行高效數據采集 |
STM32 + HAL 庫 + 光敏傳感器 + ADC 采集的實現
這里我們的示例是通過 STM32 的 ADC 采集光敏傳感器的模擬電壓值,并通過串口將 ADC 數值發送到上位機顯示。
ADC 硬件配置(STM32CubeMX)
此處的 ADC 配置:
項目 配置內容
ADC 通道 ADC1_IN10(對應 PC0)
模式 Independent mode
數據對齊 Right alignment(右對齊)
Regular Conversion Mode Enabled
Conversion Trigger Software trigger(軟件觸發)
Sampling Time 239.5 cycles(采樣時間越長越穩定)PC0 接入光敏傳感器的模擬輸出
CubeMX 配置步驟:
1. 選擇 ADC 模擬通道比如:選擇 ADC1_IN10(對應 PC0 引腳)
2. 配置 ADC 模式Mode:Independent ModeScan Conversion Mode:Disabled(若單通道)Continuous Conversion:Disabled(手動觸發)Sampling Time:推薦設置較長,如 239.5 cycles(提升穩定性)
3. 開啟 ADC勾選“Enable Regular Conversion”設置觸發方式為:Software Trigger(軟件控制啟動)
HAL 庫中常用 ADC 函數
函數 | 作用 |
---|---|
HAL_ADC_Start() | 啟動 ADC 轉換 |
HAL_ADC_PollForConversion() | 等待轉換完成(阻塞) |
HAL_ADC_GetValue() | 獲取轉換值(0 ~ 4095) |
HAL_ADC_Stop() | 停止轉換 |
HAL_ADC_Start_DMA() | 啟動 DMA 模式采集 |
HAL_ADCEx_Calibration_Start() | 啟動校準(部分芯片支持) |
HAL 庫 API 調用(main.c)
📄 main.c
/* USER CODE BEGIN Header */
/********************************************************************************* @file : main.c* @brief : Main program body******************************************************************************* @attention** Copyright (c) 2025 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "usart.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "string.h"
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint16_t ADC_Value = 0;
/* USER CODE END 0 *//*** @brief The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_USART1_UART_Init();MX_ADC1_Init();/* USER CODE BEGIN 2 */HAL_UARTEx_ReceiveToIdle_IT( &huart1 , U1RxData, U1RxDataSize);HAL_ADCEx_Calibration_Start( &hadc1 ); //開啟校準/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){HAL_ADC_Start( &hadc1 ); //開啟ADC轉換HAL_ADC_PollForConversion( &hadc1, 50); //等待轉換完成if(HAL_IS_BIT_SET( HAL_ADC_GetState( &hadc1 ), HAL_ADC_STATE_REG_EOC) ) //判斷是否轉換完成{ADC_Value = HAL_ADC_GetValue(&hadc1);printf(" ADC_Value = %d \r\n",ADC_Value);}HAL_Delay(1000);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIState = RCC_HSI_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses 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();}PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK){Error_Handler();}
}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//*** @brief This function is executed in case of error occurrence.* @retval None*/
void Error_Handler(void)
{/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1){}/* USER CODE END Error_Handler_Debug */
}#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 /* USE_FULL_ASSERT */
ADC代碼邏輯:
HAL_ADC_Start(&hadc1); // 啟動ADC
HAL_ADC_PollForConversion(&hadc1, 50); // 等待轉換完成(阻塞,最多50ms)if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
{ADC_Value = HAL_ADC_GetValue(&hadc1); // 獲取ADC值(0~4095)printf("ADC_Value = %d\r\n", ADC_Value); // 通過串口發送
}
? ADC 數據類型說明:
ADC 是 12 位精度,HAL_ADC_GetValue()
返回值范圍為:
0 ~ 4095(對應 0V ~ 3.3V)例如:
ADC_Value = 1926 → 電壓約為 1926 / 4095 * 3.3 ≈ 1.55V
ADC_Value = 3844 → 電壓約為 3.1V(光線強)
串口調試助手實時查看采樣數據
光照強度變化的驗證(ADC 值高低變化)
ADC 原始值與電壓換算
STM32 的 ADC 通常是 12 位,最大值為 4095
,換算公式如下:
電壓值(V) = adc_value / 4095.0 * 參考電壓(通常是 3.3V)
比如:
adc_value = 2048
→ 電壓約為1.65V
*adc_value = 4095
→ 電壓約為3.3V
這里拿光敏傳感器作為ADC的例子介紹,但ADC的應用場景還有很多:① 光敏傳感器,根據光照強度輸出電壓,ADC 采集判斷亮度;② 熱敏電阻,電壓隨溫度變化,用 ADC 采樣計算溫度;③ 電池電壓檢測,ADC 采集電池端電壓,判斷電量;④ 模擬搖桿,采集 X/Y 兩軸的電壓值進行控制;⑤ 電位器調節,采集旋轉角度電壓,作為輸入參數。
此外,ADC還存在一些進階用法,感興趣的小伙伴可自行深入:
多通道采集 開啟 Scan Mode,配置多個通道
連續采樣 Continuous Mode = Enabled
DMA 模式 使用 HAL_ADC_Start_DMA() 實現高效采集
外部觸發 使用定時器 / 外部中斷觸發 ADC
濾波處理 多次采集后取平均值 / 中值濾波提高準確性
以上。 這便是 STM32 + HAL 庫 + 光敏傳感器 + ADC 采集 的實現。
以上,歡迎有從事同行業的電子信息工程、互聯網通信、嵌入式開發的朋友共同探討與提問,我可以提供實戰演示或模板庫。希望內容能夠對你產生幫助!