天天看點

STM32 CubeMX學習:7. ADC模數轉化STM32 CubeMX學習:7. ADC模數轉化0 前言1. 基礎知識學習2. 程式學習3. 進階學習總結

STM32 CubeMX學習:7. ADC模數轉化

系列文章目錄

  1. 前期的準備
  2. 點亮 LED
  3. 閃爍 LED
  4. 定時器閃爍LED
  5. PWM控制LED亮度
  6. 常見的PWM裝置
  7. 按鍵的外部中斷
  8. ADC模數轉換
  9. 序列槽收發
  10. 序列槽列印遙控器資料
  11. 未完待續…

文章目錄

  • STM32 CubeMX學習:7. ADC模數轉化
  • 0 前言
  • 1. 基礎知識學習
    • 1.1 ADC原理介紹
    • 1.2 STM32F4x ADC介紹
  • 2. 程式學習
    • 2.1 ADC在CubeMX的配置
    • 2.2 内部VREFINT電壓的使用
    • 2.3 相關函數介紹
    • 2.4 程式執行流程
  • 3. 進階學習
  • 總結

0 前言

我們已經知道,在單片機中傳輸的信号均為數字信号,通過離散的高低電平表示數字邏輯的1和0,但是在現實的實體世界中,隻存在模拟信号,即連續變化的信号,将這些連續變化的信号——比如熱,光,聲音,速度通過各種傳感器轉化成連續的電信号,再通過ADC功能将連續的模拟信号轉化成離散的數字信号給單片機進行處理。

1. 基礎知識學習

1.1 ADC原理介紹

一般ADC的工作流程為采樣,比較,轉換。

  • 采樣:是指對某一時刻的模拟電壓進行采集,
  • 比較:是指将采樣的電壓在比較電路中進行比較,
  • 轉換:是指将比較電路中結果轉換成數字量。

    在我們這裡,使用的STM32f4采用12位逐次逼近型ADC(SAR-ADC)。現在,以下圖為例,介紹3位ADC的比較過程:

    STM32 CubeMX學習:7. ADC模數轉化STM32 CubeMX學習:7. ADC模數轉化0 前言1. 基礎知識學習2. 程式學習3. 進階學習總結

    不同的位數分别賦予1/2,1/4,1/8的權值,模拟信号的采樣值為Vin,

    1)與1/2Vref進行比較,Vin大于1/2Vref,則将第一位标記為1,

    2)與3/4Vref進行比較,Vin小于3/4Vref,則将第二位标記為0,

    3)與5/8Vref進行比較,Vin小于5/8Vref,則将第三位标記為0。

    圖中的Vin通過這個三位的ADC後輸出的結果為100。轉換的結果為1/2Vref,通過這樣逐次比較過程,将采樣取得的模拟電壓和内部參考電壓Vref的權重值進行比較,不同的位數賦予不同的權值。

    但是,如果我們輸入為一個未知的電壓,完整的比較流程圖如下:

    STM32 CubeMX學習:7. ADC模數轉化STM32 CubeMX學習:7. ADC模數轉化0 前言1. 基礎知識學習2. 程式學習3. 進階學習總結

    STM32支援最高12位ADC,一般ADC的位數越多則轉換精度越高,但與此同時轉換的速度也會變慢。

    此外,STM32内部有一個校準電壓VREFINT,電壓為1.2V,當供電電壓不為3.3V,可以使用内部的vrefint通道采集1.2V電壓作為Vref,以提高精度。

1.2 STM32F4x ADC介紹

  1. STM32F4x ADC特點
    STM32 CubeMX學習:7. ADC模數轉化STM32 CubeMX學習:7. ADC模數轉化0 前言1. 基礎知識學習2. 程式學習3. 進階學習總結
  2. STM32F40x系列ADC外部通道和引腳對應關系
    STM32 CubeMX學習:7. ADC模數轉化STM32 CubeMX學習:7. ADC模數轉化0 前言1. 基礎知識學習2. 程式學習3. 進階學習總結

2. 程式學習

2.1 ADC在CubeMX的配置

這次我們使用引腳PF10作為電源ADC引腳,使用ADC3的通道8,STM32内部的1.2V校準電壓Vrefint在ADC1中。是以我們需要按如下方式在CubeMX裡進行配置。

  1. 開啟ADC1和ADC3分别用于内部1.2V的Vrefint通道讀取和電池電壓ADC3的通道8讀取。
  2. 在cubeMX中開啟ADC1,在設定中将Vrefint Channel勾選,用于讀取内部參考電壓。ADC在cubeMX中的設定如圖采樣頻率設定為PCLK2/4,采樣位數為12位,資料設定為右對齊,其餘均保持預設。其中Vrefine在stm32内部完成,沒有對應引腳。
    STM32 CubeMX學習:7. ADC模數轉化STM32 CubeMX學習:7. ADC模數轉化0 前言1. 基礎知識學習2. 程式學習3. 進階學習總結
    最終ADC配置如圖所示。
    STM32 CubeMX學習:7. ADC模數轉化STM32 CubeMX學習:7. ADC模數轉化0 前言1. 基礎知識學習2. 程式學習3. 進階學習總結
    《補充》:但是,這裡還是把其中參數的具體含義給大家科普一下吧
名稱 功能
Clock Prescaler 設定采樣時鐘頻率
Resolution 設定采樣精度
Data Alignment 設定資料對齊方式
Scan Conversion Mode 掃描轉換模式開啟/關閉
Continuous Conversion Mode 連續轉換模式開啟/關閉
Discontinuous Conversion Mode 非連續轉換模式開啟/關閉
DMA Continuous Requests DMA連續啟動開啟/關閉
End of Conversion Selection 每個通道轉換結束後發送EOC标志/所有通道轉換結束後發送EOC标志
  1. 在CubeMX中開啟ADC3,并打開其IN8用于電池電壓的讀取,其設定和ADC1一緻。可以看到引腳圖像中ADC3對應的PF10變綠。
    STM32 CubeMX學習:7. ADC模數轉化STM32 CubeMX學習:7. ADC模數轉化0 前言1. 基礎知識學習2. 程式學習3. 進階學習總結
    STM32 CubeMX學習:7. ADC模數轉化STM32 CubeMX學習:7. ADC模數轉化0 前言1. 基礎知識學習2. 程式學習3. 進階學習總結
  2. 這裡我們需要把PC0,PC1,PC2引腳設定為輸入模式,且這三個引腳拉為高電平,如圖所示
    STM32 CubeMX學習:7. ADC模數轉化STM32 CubeMX學習:7. ADC模數轉化0 前言1. 基礎知識學習2. 程式學習3. 進階學習總結
  3. 點選GENERATE CODE生成代碼

2.2 内部VREFINT電壓的使用

VREFINT 即 ADC的内部參照電壓1.2V。通過将采樣内部參照電壓1.2V的 ADC 值和 Vref 的權重值進行比較,進而得到 ADC 的輸出值。一般來說STM32的 ADC 采用 Vcc 作為 Vref ,但為了防止 Vcc 存在波動較大導緻Vref不穩定,進而導緻采樣值的比較結果不準确,STM32可以通過内部已有的參照電壓VREFINT來進行校準,接着以VREFINT為參照來比較ADC的采樣值,進而獲得比較高的精度,VREFINT的電壓為1.2V。

通過一個函數對1.2V的電壓進行多次采樣,并計算其平均值,接着将其與ADC采出的資料值做對比,得到機關數字電壓對應的模拟電壓值voltage_vrefint_proportion,其計算公式如下,設采樣得到的數字值為average_adc:

a v e r a g e _ a d c = t o t a l _ d a c 200 average\_adc=\frac{total\_dac}{200} average_adc=200total_dac​

v o l t a g e _ v r e f i n t _ p r o p o r t i o n = 1.2 v a v e r a g e _ a d c = 200 ∗ 1.2 t o t a l _ a d c voltage\_vrefint\_proportion=\frac{1.2v}{average\_adc}=\frac{200 ∗ 1.2}{total\_adc} voltage_vrefint_proportion=average_adc1.2v​=total_adc200∗1.2​

其代碼如下所示

void init_vrefint_reciprocal(void) 
{ 
	uint8_t i = 0; 
	uint32_t total_adc = 0; 
	for(i = 0; i < 200; i++)
	 {
	 	 total_adc += adcx_get_chx_value(&hadc1, ADC_CHANNEL_VREFINT);
	  } 
	  voltage_vrefint_proportion = 200 * 1.2f / total_adc;
}
           

2.3 相關函數介紹

Hal庫提供了以下很多有關ADC的函數

  1. ADC通道設定函數
函數作用 設定ADC通道的各個屬性值,包括轉換通道,序列排序,采樣時間等
傳回值 HAL_StatusTypeDef,HAL庫定義的幾種狀态,如果成功使ADC開始工作,則傳回HAL_OK
參數1 TIM_HandleTypeDef * hadc即ADC的句柄指針,如果是adc1就輸入&hadc1,adc2就輸入&adc2
參數2 ADC_ChannelConfTypeDef* sConfig即指向ADC設定的結構體指針。我們先對sConfig結構體進行指派,然後再将其指針作為參數輸入函數
  1. ADC開啟采樣函數
函數作用 開啟ADC的采樣
傳回值 HAL_StatusTypeDef,HAL庫定義的幾種狀态,如果成功使ADC開始工作,則傳回HAL_OK
參數 TIM_HandleTypeDef * hadc即ADC的句柄指針,如果是adc1就輸入&hadc1,adc2就輸入&adc2
  1. 等待ADC轉換結束函數
函數作用 等待ADC轉換結束
傳回值 HAL_StatusTypeDef,HAL庫定義的幾種狀态,如果成功使ADC開始工作,則傳回HAL_OK
參數1 TIM_HandleTypeDef * hadc即ADC的句柄指針,如果是adc1就輸入&hadc1,adc2就輸入&adc2
參數2 HAL_StatusTypeDef,HAL庫定義的幾種狀态,如果成功使ADC開始工作,則傳回HAL_OK
  1. 擷取ADC函數
函數作用 擷取ADC值
傳回值 HAL_StatusTypeDef,HAL庫定義的幾種狀态,如果成功使ADC開始工作,則傳回HAL_OK
參數 TIM_HandleTypeDef * hadc即ADC的句柄指針,如果是adc1就輸入&hadc1,adc2就輸入&adc2

2.4 程式執行流程

本程式中,首先對内部參考電壓電壓VREFINT進行adc采樣将其作為校準值,在init_vrefint_reciprocal中,對VREFINT電壓進行200次的采樣,接着求其均值後使用VREFINT的電壓值1.2V去除以該ADC采樣得到的均值,算出voltage_vrefint_proportion,後續ADC中采樣到的電壓值與voltage_vrefint_proportion相乘就可以計算出以内部參考電壓做過校準的ADC值了。

void init_vrefint_reciprocal(void) 
{ 
	uint8_t i = 0; uint32_t total_adc = 0; 
	
	for(i = 0; i < 200; i++) 
	{ 
		total_adc += adcx_get_chx_value(&hadc1, ADC_CHANNEL_VREFINT); 
	} 
	
	voltage_vrefint_proportion = 200 * 1.2f / total_adc; 
}
           

接着通過ADC對經過了分壓電路的電池電壓值進行采樣,将該采樣結果與voltage_vrefint_proportion相乘,就得到了取值範圍在0-3.3V之間的ADC采樣值,由于這個采樣值是分壓後的結果,需要反向計算出電壓的值。分壓的電阻值為200KΩ和22KΩ,由于 (22K Ω + 200K Ω) / 22K Ω = 10.09,乘以這個值之後就可以得到電池的電壓值。

(注意,這裡我們是根據一個具體的分壓電路給出的計算公式,當我們實際使用時,要根據自己所使用的具體電路修改對應的計算方法,)

fp32 get_battery_voltage(void) 
{ 
	fp32 voltage; 
	uint16_t adcx = 0; 
	adcx = adcx_get_chx_value(&hadc3, ADC_CHANNEL_8);
	
	//(22K Ω + 200K Ω) / 22K Ω = 10.090909090909090909090909090909 
	voltage = (fp32)adcx * voltage_vrefint_proportion * 10.090909090909090909090909090909f; 
	return voltage; 
}
           

其實,我們還可以通過ADC獲得闆載的溫度傳感器的溫度值,同樣是先經過ADC值進行采樣,采樣結束後,将ADC采樣結果adc帶入公式temperate = (adc - 0.76f) * 400.0f + 25.0f,進而計算出溫度值。

fp32 get_temprate(void) 
{ 
	uint16_t adcx = 0; 
	fp32 temperate; 
	
	adcx = adcx_get_chx_value(&hadc1, ADC_CHANNEL_TEMPSENSOR);
	
	temperate = (fp32)adcx * voltage_vrefint_proportion;
	temperate = (temperate - 0.76f) * 400.0f + 25.0f;
	 
	return temperate; 
}
           

在我們完成代碼時,還需要像以前一樣自己建立一個Boards目錄,在裡面建立一個bsp_adc.c檔案

#include "bsp_adc.h"
#include "main.h"
extern ADC_HandleTypeDef hadc1;
extern ADC_HandleTypeDef hadc3;


volatile fp32 voltage_vrefint_proportion = 8.0586080586080586080586080586081e-4f;

static uint16_t adcx_get_chx_value(ADC_HandleTypeDef *ADCx, uint32_t ch)
{
    static ADC_ChannelConfTypeDef sConfig = {0};
    sConfig.Channel = ch;
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;//ADC_SAMPLETIME_3CYCLES;

    if (HAL_ADC_ConfigChannel(ADCx, &sConfig) != HAL_OK)
    {
        Error_Handler();
    }

    HAL_ADC_Start(ADCx);

    HAL_ADC_PollForConversion(ADCx, 10);
    return (uint16_t)HAL_ADC_GetValue(ADCx);

}
void init_vrefint_reciprocal(void)
{
    uint8_t i = 0;
    uint32_t total_adc = 0;
    for(i = 0; i < 200; i++)
    {
        total_adc += adcx_get_chx_value(&hadc1, ADC_CHANNEL_VREFINT);
    }

    voltage_vrefint_proportion = 200 * 1.2f / total_adc;
}
fp32 get_temprate(void)
{
    uint16_t adcx = 0;
    fp32 temperate;

    adcx = adcx_get_chx_value(&hadc1, ADC_CHANNEL_TEMPSENSOR);
    temperate = (fp32)adcx * voltage_vrefint_proportion;
    temperate = (temperate - 0.76f) * 400.0f + 25.0f;

    return temperate;
}


fp32 get_battery_voltage(void)
{
    fp32 voltage;
    uint16_t adcx = 0;

    adcx = adcx_get_chx_value(&hadc3, ADC_CHANNEL_8);
    //(22K Ω + 200K Ω)  / 22K Ω = 10.090909090909090909090909090909
    voltage =  (fp32)adcx * voltage_vrefint_proportion * 10.090909090909090909090909090909f;

    return voltage;
}

uint8_t get_hardware_version(void)
{
    uint8_t hardware_version;
    hardware_version = HAL_GPIO_ReadPin(HW0_GPIO_Port, HW0_Pin)
                                | (HAL_GPIO_ReadPin(HW1_GPIO_Port, HW1_Pin)<<1)
                                | (HAL_GPIO_ReadPin(HW2_GPIO_Port, HW2_Pin)<<2);



    return hardware_version;
}


           

接着建立一個對應的bsp_adc.h檔案放置于對應目錄之下

#ifndef BSP_ADC_H
#define BSP_ADC_H
#include "#ifndef BSP_ADC_H
#define BSP_ADC_H
#include "struct_typedef.h"

extern void init_vrefint_reciprocal(void);
extern fp32 get_temprate(void);
extern fp32 get_battery_voltage(void);
extern uint8_t get_hardware_version(void);
#endif
"

extern void init_vrefint_reciprocal(void);
extern fp32 get_temprate(void);
extern fp32 get_battery_voltage(void);
extern uint8_t get_hardware_version(void);
#endif

           

在這個檔案中,我們還用到了一個定義結構體的頭檔案:struct_typedef.h

#ifndef STRUCT_TYPEDEF_H
#define STRUCT_TYPEDEF_H


typedef signed char int8_t;
typedef signed short int int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;

/* exact-width unsigned integer types */
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef unsigned char bool_t;
typedef float fp32;
typedef double fp64;


#endif




           

最終的main.c檔案如下所示

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "bsp_adc.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 */
fp32 voltage;
fp32 temperature;
uint8_t handware_version;
/* 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_ADC1_Init();
  MX_ADC3_Init();
  /* USER CODE BEGIN 2 */
	
	//use vrefint voltage to calibrate
  //使用基準電壓來校準
  init_vrefint_reciprocal();
		
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		
				//get battery voltage
        //擷取電源電壓
        voltage = get_battery_voltage();
        //get chip temperate
        //擷取片内溫度
        temperature = get_temprate();
        //get handware version
        //擷取硬體版本
        handware_version = get_hardware_version();
        HAL_Delay(100);
		
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage 
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 6;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  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_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != 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 */

  /* 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,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

           

3. 進階學習

逐次型ADC是通過一位位進行比較得出轉換值,其原理圖如下所示。

STM32 CubeMX學習:7. ADC模數轉化STM32 CubeMX學習:7. ADC模數轉化0 前言1. 基礎知識學習2. 程式學習3. 進階學習總結

如圖所示,我們發現整個電路由比較器、D/A轉換器、緩沖寄存器和若幹控制邏輯電路構成。作用如下所示:

  • 比較器:用于輸入電壓值D/A轉換器輸出電壓進行比較,當輸入電壓大于D/A轉換器電壓時,輸出為1,反之輸出為0;
  • D/A轉換器:ADC的逆向過程,将緩沖寄存器的記錄數字量轉換成模拟量。
  • 緩沖寄存器:記錄目前轉換的數字量。

整個過程如下:

  1. 将緩沖寄存器清零;
  2. 将逐次逼近寄存器 最高位 置1;
  3. 把數字值送入D/A轉換器,經D/A轉換後的模拟量送入比較器,稱為 Vo;
  4. Vo與比較器的待轉換的模拟量Vi 比較,若Vo<Vi,該位被保留,否則被清0。
  5. 再置 寄存器 次高位為1,将寄存器中新的數字量送D/A轉換器,
  6. 輸出的 Vo再與Vi比較,若Vo<Vi,該位被保留,否則被清0。
  7. 循環此過程,直到寄存器最低位,得到數字量的輸出。

    在這個過程中,D/A轉換器使用的電壓為STM32的電源電壓Vref+和Vref-,如圖所示:

    STM32 CubeMX學習:7. ADC模數轉化STM32 CubeMX學習:7. ADC模數轉化0 前言1. 基礎知識學習2. 程式學習3. 進階學習總結
    STM32的标準電壓為 3.3V。例如第一次轉換時,輸出為 1/2Vre電壓,即1.65V。但由于外部供電電壓不一定為 3.3V。故而為了在這種情況提高ADC精度,STM32内部有VERFINT1.2V穩定電壓,可以使用ADC采樣該電壓來提高ADC的精度。

代碼我已經放到了我的GitHub倉庫,如有需要可以下載下傳使用:

CubeMX學習

總結

這次的部落格,我們重點學習了ADC的相關知識,ADC是模拟量變成數字量的過程,單片機擷取電壓,電流傳感器等模拟量的方法。通過ADC功能,我們能夠擷取各種傳感器的模拟值,并将其轉化為單片機可以處理的數字量,也可以擷取電池的電壓值,并将其通過電量形式顯示出來。