Day08_单片机-ADC和DMA

一、ADC相关概念

ADC(Analog-to-digital converter):模数转换器
作用:将模拟信号转化为数字信号

模拟信号:连续周期变化的电信号

数字信号:离散的以1/0组成的电信号

ADC的应用场景:一般用于电路中的电流/电压检测、也使用在各种传感器采集数据后进行传输(温湿度传感器)
ADC:就是将连续的模拟信号转换为离散的数字信号

ADC 的转换过程本质是通过采样->保持->量化->编码 四个关键步骤,将连续信号 "离散化" 为数字代码。

ADC的工作流程:

模拟信号就绪→通道采样并保持信号→量化为离散等级→编码为二进制代码→写入数据寄存器→用户读取数字信号"。

二、ADC1和ADC4

在STM32U575RIT6芯片中支持的是ADC1和ADC4外设控制器

1、采样位数:本质就是采样精度,ADC1采样转化后的数字信号是14位的,ADC4采样转化后的数字信号是12位

2、数据寄存器:采样转化得到的数字信号,会被存储到数据寄存器中,用户只需要读取数据寄存器中的值即可得到转化后的数字信号

3、电压转化公式:请看下图

待测电压=(ADC转化后的数字量*参考电压)/2^采样位数

4、ADC的采样校准和偏移补偿:请看下图

2.1采样原理

原理图:

解析:

STM32U575RIT6中使用的是ADC采样方式:逐次逼近法。

逐次逼近法:循环使用二分半查找(折半查找)

eg:

以ADC4为例,采样位数为12位,也就是得到的数字信号是12位的(最小是0v最大是3.3v换个思路来理解就是十二位中最小的是0,最大的是4096,中间是1.65v(2048)),现在要查找1.2v(1489)就是一直使用二分缩小范围直到找到他

2.2转换公式

电压转化公式:待测电压(1.2v)、参考电压(3.3v)、ADC转化后的数字量

2^采样位数

ADC转化得到的数字量=------------------- x 待测电压

参考电压
ADC的视线原理是逐次逼近发,但是在使用ADC时,用于只需要打开ADC、等待ADC采样并转化、获取转化后的值就可以了

2.3采样校准和偏移补偿

图:

注释:

ADC的采样就相当于录制一个跳舞的视频

一个跳舞的视频=很多跳舞动作的图片,按顺序播放

拍对应跳舞动作的图片的时机=ADC采样的时机

拍照的时机不可能固定=ADC采样时机可能发生偏移
如果ADC采样发生偏移,此时采样得到的诗句可能不是很准确,就需要使用硬件提供的偏移补偿机制(校准机制)
使用偏移补偿机制(校准机制)用于初始化采样机制

2.4ADC的通道

1、等待转化的模拟信号
2、ADC的通道:采样等待转化的模拟信号,在此处进行模拟信号转化为数字信号
3、ADC的数据寄存器:用户可以从此处读到转化完毕的数字信号

2.5ADC1的通道

图:

注释:

ADC1:具备20个独立通道(用于采样模拟信号,转化模拟信号)

20个独立通道中:存在17个链接GPIO引脚的通道(外部通道),

存在3个连接芯片内部传感去的通道(内部通道)

2.6ADC4的通道

图:

注释:

ADC4:具备24个独立通道(用于采样模拟信号,转化模拟信号)

24个独立通道中:存在19个链接GPIO引脚的通道(外部通道),
存在4个连接芯片内部传感去的通道(内部通道)
存在1个链接DAC外设控制器的通道

三、ADC的采样转化模式(扫描模式)

ADC的采样转化模式有五种:1、单通道单次转化模式 2、单通道连续转化模式 3、多通道单次转化模式 4、多通道连续转化模式 5、间隔转化模式(触发转化模式

1、单通道单次转化模式:

就是只使用一个ADC通道进行模拟信号的采样和转化,并且只转化一次,转化完的数据保存到数据寄存器中,此时当前转化就结束了

2、单通道连续转化模式:

使用一个ADC通道进行模拟信号的采样和转化,转化完的数据保存到数据寄存器中,紧接着开启下一次转换

单通道单次转化+while(1)=单通道连续转化

3、多通道单次转化模式:

就是使用多个ADC通道进行模拟信号的采样和转化,按照顺序依次转化通道中的模拟信号,转化完的数据保存到数据寄存器中,当这些使能通道中的数据转化并放到数据寄存器中后,此时当前多通道单次转化就结束了,如果想开次下一次转化,需要手动开启

4、多通道连续转化模式:

就是使用多个ADC通道进行模拟信号的采样和转化,按照顺序依次转化通道中的模拟信号,转化完的数据保存到数据寄存器中,当这些使能通道中的数据转化并放到数据寄存器中后,此时会回到最初始的通道开启二次或者N次转化,无需手动开启

多通道单次转化+while(1)=多通道连续转化

5、间隔转化模式(触发转化模式):

使用间隔转化模式时,需要触发源,触发源触发一次,ADC就转化一次

ADC的转化模式:独立模式(单通道模式)、扫描模式(多通道模式)、触发模式

四、分析电路图

ANA1->ADC_VDC->PB1

五、CubeMX配置

六、API接口

ADC采样和转化流程:

0、开启ADC采样校准模式

1、开启ADC采样转化功能
2、等待采样+转化结束,数字信号被存放到数据寄存器中
3、从数据寄存器中读取数字信号
4、通过模数转化公式,将数字信号转化为模拟信号,并串口打印

ADC的采样校准要么在开启采样前,要么在关闭采用后

HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef *hadc)

功能:

HAL库提供的用于开启ADC采样转化功能的函数

参数:

habc:ADC4外设控制器的句柄

返回值:

函数执行成功,返回HAL_OK

函数返回失败,返回错误码

uint32_t HAL_ADC_GetValue(const ADC_HandleTypeDef *hadc)

功能:

HAL库提供的用于获取转化完毕的数字信号的函数

参数:

habc:ADC4外设控制器的句柄

返回值:

返回成功获取的数字信号

HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef *hadc,uint32_t Timeout)

功能:

HAL库提供的用于阻塞等待ADC采样+转化完毕,数据被存放到数据寄存器中的函数

参数:

habc:ADC4外设控制器的句柄
Timeout:超时检测时间,当前函数的最大阻塞时间

返回值:

当ADC采样+转化数据完毕后,表示这个函数执行成功,函数执行成功,返回HAL_OK
当ADC采样+转化数据没结束时,此时这个函数处于阻塞状态
函数返回失败,返回错误码

#define HAL_MAX_DELAY 0xFFFFFFFU

HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef *hadc)

功能:

HAL库提供的用于关闭ADC采样转化功能的函数

参数:

habc:ADC4外设控制器的句柄

返回值:

函数执行成功,返回HAL_OK
函数返回失败,返回错误码
/**

* @brief Perform an ADC automatic self-calibration

* Calibration prerequisite: ADC must be disabled (execute this

* function before HAL_ADC_Start() or after HAL_ADC_Stop() ).

* @param hadc ADC handle

* @param CalibrationMode Selection of calibration offset or

* linear calibration offset.

* @arg ADC_CALIB_OFFSET Channel in mode calibration offset

* @arg ADC_CALIB_OFFSET_LINEARITY Channel in mode linear calibration offset

* @param SingleDiff Selection of single-ended or differential input

* This parameter can be one of the following values:

* @arg @ref ADC_SINGLE_ENDED Channel in mode input single ended

* @arg @ref ADC_DIFFERENTIAL_ENDED Channel in mode input differential ended

* @retval HAL status

*/

HAL_StatusTypeDef

HAL_ADCEx_Calibration_Start

(ADC_HandleTypeDef *hadc, uint32_t CalibrationMode, uint32_t SingleDiff)

功能:

HAL库提供的用于校准ADC采样的函数(此函数只需要开启一次即可)

参数:

hadc:ADC4外设控制器的句柄

CalibrationMode:校准模式的设置

ADC_CALIB_OFFSET 偏移量校准方式(最基础的)
ADC_CALIB_OFFSET_LINEARITY 硬件线性化校准(高级的)
线性化校准比偏移量校准更准确,一般使用一些高精度仪器上

SingleDiff:输入的模拟信号的选择

ADC_SINGLE_ENDED:输入单端信号(一个信号就代表一个电信号)
ADC_DIFFERENTIAL_ENDED:输入差分信号(两个信号代表一个电信号)

返回值:

函数执行成功,返回HAL_OK

函数执行失败,返回错误码

七、代码编写

7.1单通道单次转化模式

cpp 复制代码
/* 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 "stdio.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);
static void SystemPower_Config(void);
/* USER CODE BEGIN PFP */
 
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
//printf重定向
int fputc(int ch,FILE *stream)
{
	HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,5);
	return ch;
}
/* 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();
 
  /* Configure the System Power */
  SystemPower_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC4_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	uint32_t value_digital=0;
	//uint32_t value_digital[2]={0};
	float value_analog=0;
//stm32u575RIT6需要手动开启VDD电源管理单元的功能
	HAL_PWREx_EnableVddA();
	HAL_PWREx_EnableVddIO2();
	
	//开启采样ADC4校准
	HAL_ADCEx_Calibration_Start(&hadc4,ADC_CALIB_OFFSET,ADC_SINGLE_ENDED);
	//HAL_ADC_Start(&hadc4);
	//int i=0;
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		//开启ADC的采样+转化功能
		HAL_ADC_Start(&hadc4);
		//等待ADC采样+转化完毕
		HAL_ADC_PollForConversion(&hadc4,5);
		//获取采样完毕的数字信号
		value_digital=HAL_ADC_GetValue(&hadc4);
		//通过模数转换公式,把获得电压转化为模拟信号
		value_analog=value_digital*3.3/4096;
		//串口打印
		printf("digital=%d,analog=%.4f\n",value_digital,value_analog);
		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};
 
  /** Configure the main internal regulator output voltage
  */
  if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_MSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_0;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
  RCC_OscInitStruct.PLL.PLLMBOOST = RCC_PLLMBOOST_DIV4;
  RCC_OscInitStruct.PLL.PLLM = 3;
  RCC_OscInitStruct.PLL.PLLN = 10;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 1;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLLVCIRANGE_1;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  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_CLOCKTYPE_PCLK3;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }
}
 
/**
  * @brief Power Configuration
  * @retval None
  */
static void SystemPower_Config(void)
{
 
  /*
   * Disable the internal Pull-Up in Dead Battery pins of UCPD peripheral
   */
  HAL_PWREx_DisableUCPDDeadBattery();
/* USER CODE BEGIN PWR */
/* USER CODE END PWR */
}
 
/* 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 */

效果

cpp 复制代码
/* 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 "stdio.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);
static void SystemPower_Config(void);
/* USER CODE BEGIN PFP */
 
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
//printf重定向
int fputc(int ch,FILE *stream)
{
	HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,5);
	return ch;
}
/* 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();
 
  /* Configure the System Power */
  SystemPower_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC4_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	uint32_t value_digital=0;
	//uint32_t value_digital[2]={0};
	float value_analog=0;
//stm32u575RIT6需要手动开启VDD电源管理单元的功能
	HAL_PWREx_EnableVddA();
	HAL_PWREx_EnableVddIO2();
	
	//开启采样ADC4校准
	//HAL_ADCEx_Calibration_Start(&hadc4,ADC_CALIB_OFFSET,ADC_SINGLE_ENDED);
	//HAL_ADC_Start(&hadc4);
	//int i=0;
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		//开启采样ADC4校准
	  HAL_ADCEx_Calibration_Start(&hadc4,ADC_CALIB_OFFSET,ADC_SINGLE_ENDED);
		//开启ADC的采样+转化功能
		HAL_ADC_Start(&hadc4);
		//等待ADC采样+转化完毕
		HAL_ADC_PollForConversion(&hadc4,5);
		//获取采样完毕的数字信号
		value_digital=HAL_ADC_GetValue(&hadc4);
		//通过模数转换公式,把获得电压转化为模拟信号
		value_analog=value_digital*3.3/4096;
		//串口打印
		printf("digital=%d,analog=%.4f\n",value_digital,value_analog);
		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};
 
  /** Configure the main internal regulator output voltage
  */
  if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_MSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_0;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
  RCC_OscInitStruct.PLL.PLLMBOOST = RCC_PLLMBOOST_DIV4;
  RCC_OscInitStruct.PLL.PLLM = 3;
  RCC_OscInitStruct.PLL.PLLN = 10;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 1;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLLVCIRANGE_1;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  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_CLOCKTYPE_PCLK3;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }
}
 
/**
  * @brief Power Configuration
  * @retval None
  */
static void SystemPower_Config(void)
{
 
  /*
   * Disable the internal Pull-Up in Dead Battery pins of UCPD peripheral
   */
  HAL_PWREx_DisableUCPDDeadBattery();
/* USER CODE BEGIN PWR */
/* USER CODE END PWR */
}
 
/* 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 */

7.2单通道连续转化模式

cpp 复制代码
/* 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 "stdio.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);
static void SystemPower_Config(void);
/* USER CODE BEGIN PFP */
 
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
//printf重定向
int fputc(int ch,FILE *stream)
{
	HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,5);
	return ch;
}
/* 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();
 
  /* Configure the System Power */
  SystemPower_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC4_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	uint32_t value_digital=0;
	//uint32_t value_digital[2]={0};
	float value_analog=0;
//stm32u575RIT6需要手动开启VDD电源管理单元的功能
	HAL_PWREx_EnableVddA();
	HAL_PWREx_EnableVddIO2();
	
	//开启采样ADC4校准
	HAL_ADCEx_Calibration_Start(&hadc4,ADC_CALIB_OFFSET,ADC_SINGLE_ENDED);
	HAL_ADC_Start(&hadc4);//开启ADC连续转化模式后这一行代码只需要执行一次后续的ADC采样和转化会自动执行
	//int i=0;
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		//开启ADC的采样+转化功能
		//HAL_ADC_Start(&hadc4);
		//等待ADC采样+转化完毕
		HAL_ADC_PollForConversion(&hadc4,5);
		//获取采样完毕的数字信号
		value_digital=HAL_ADC_GetValue(&hadc4);
		//通过模数转换公式,把获得电压转化为模拟信号
		value_analog=value_digital*3.3/4096;
		//串口打印
		printf("digital=%d,analog=%.4f\n",value_digital,value_analog);
		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};
 
  /** Configure the main internal regulator output voltage
  */
  if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_MSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_0;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
  RCC_OscInitStruct.PLL.PLLMBOOST = RCC_PLLMBOOST_DIV4;
  RCC_OscInitStruct.PLL.PLLM = 3;
  RCC_OscInitStruct.PLL.PLLN = 10;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 1;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLLVCIRANGE_1;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  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_CLOCKTYPE_PCLK3;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }
}
 
/**
  * @brief Power Configuration
  * @retval None
  */
static void SystemPower_Config(void)
{
 
  /*
   * Disable the internal Pull-Up in Dead Battery pins of UCPD peripheral
   */
  HAL_PWREx_DisableUCPDDeadBattery();
/* USER CODE BEGIN PWR */
/* USER CODE END PWR */
}
 
/* 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 */

7.3多通道连续转化模式

cpp 复制代码
/* 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 "stdio.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);
static void SystemPower_Config(void);
/* USER CODE BEGIN PFP */
 
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
//printf重定向
int fputc(int ch,FILE *stream)
{
	HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,5);
	return ch;
}
/* 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();
 
  /* Configure the System Power */
  SystemPower_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC4_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	//uint32_t value_digital=0;
	uint32_t value_digital[2]={0};
	float value_analog=0;
//stm32u575RIT6需要手动开启VDD电源管理单元的功能
	HAL_PWREx_EnableVddA();
	HAL_PWREx_EnableVddIO2();
	
	//开启采样ADC4校准
	HAL_ADCEx_Calibration_Start(&hadc4,ADC_CALIB_OFFSET,ADC_SINGLE_ENDED);
	HAL_ADC_Start(&hadc4);//开启ADC连续转化模式后这一行代码只需要执行一次后续的ADC采样和转化会自动执行
	int i=0;
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
        for(i=0;i<2;i++)
        {
					//等待ADC采样+转化完毕
            HAL_ADC_PollForConversion(&hadc4,HAL_MAX_DELAY);
					//获取采样完毕的数字信号
            value_digital[i]=HAL_ADC_GetValue(&hadc4);
        }
        printf("%.4f\n",4*value_digital[0]*3.3/4096);
        printf("%.4f\n",value_digital[1]*3.3/4096);
			 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};
 
  /** Configure the main internal regulator output voltage
  */
  if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_MSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_0;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
  RCC_OscInitStruct.PLL.PLLMBOOST = RCC_PLLMBOOST_DIV4;
  RCC_OscInitStruct.PLL.PLLM = 3;
  RCC_OscInitStruct.PLL.PLLN = 10;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 1;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLLVCIRANGE_1;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  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_CLOCKTYPE_PCLK3;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }
}
 
/**
  * @brief Power Configuration
  * @retval None
  */
static void SystemPower_Config(void)
{
 
  /*
   * Disable the internal Pull-Up in Dead Battery pins of UCPD peripheral
   */
  HAL_PWREx_DisableUCPDDeadBattery();
/* USER CODE BEGIN PWR */
/* USER CODE END PWR */
}
 
/* 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 */

7.4练习:采集Vbat电源电压

八、DMA 相关概念

GPDMA(General purpose direct memory access controler):直接内存访问(内存:实际的虚拟内存、外设控制器)

为什么需要使用DMA?

由于cpu具备高性能特点,正常需要设计到CPU的介入是关于数据的复杂度处理相关的逻辑

此时,一些简单的数据传输,如串口数据传输、ADC采样后的数据传输,可以不需要CPU的介入

也就是,如果使用DWA,DMA会开辟一片通道(16个独立通道),专门用于简单的数据传输,这些数据就不需要让CPU来调度传输

相关推荐
清风6666664 小时前
基于单片机的螺旋藻生长大棚PH智能控制设计
单片机·嵌入式硬件·毕业设计·课程设计
ting_zh6 小时前
微控制器(Micro Controller Unit, MCU)基础整理
单片机·嵌入式硬件
清风6666666 小时前
基于单片机的图书馆智能座位管理平台
数据库·单片机·嵌入式硬件·毕业设计·课程设计
得单片机的运7 小时前
STM32的以太网的搭建
stm32·单片机·嵌入式硬件·物联网·以太网·iot·w5500
酷飞飞8 小时前
RTC和看门狗基于GD32F407VE的天空星的配置
stm32·单片机·嵌入式硬件·mcu
WD1372980155710 小时前
WD5030A,24V降5V,15A 大电流,应用于手机、平板、笔记本充电器
stm32·单片机·嵌入式硬件·智能手机·汽车·电脑·51单片机
日更嵌入式的打工仔10 小时前
GPIO 中断通用配置指南
stm32·单片机·嵌入式硬件
平凡灵感码头10 小时前
基于 STM32 的智能门锁系统,系统界面设计
stm32·单片机·嵌入式硬件
Truffle7电子11 小时前
STM32理论 —— 存储、中断
stm32·嵌入式硬件·嵌入式·存储·中断
报错小能手11 小时前
linux学习笔记(32)网络编程——UDP
单片机·嵌入式硬件