STM32初学入门笔记(3):STM32CubeMX配置STM32实现多通道ADC+DMA读取模拟量

这篇具有很好参考价值的文章主要介绍了STM32初学入门笔记(3):STM32CubeMX配置STM32实现多通道ADC+DMA读取模拟量。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

模拟信号的读取是我们在做很多项目是都要用到的,而模拟量的读取就要依赖于ADC数模转换器。对于初学者,学习使用ADC可以很大的帮助以后的STM32学习。

目录

ADC简介 :

DMA简介: 

工程开始:

STM32CubeMX配置区:

配置外部时钟:

配置调试:

配置ADC:

配置DMA:

配置串口:

配置工程文件: 

 KEIL编程:

 开启MicroLIB:

添加库函数: 

串口重定向:

定义变量:

while: 

回调函数:

成果展示: 

总结:


ADC简介 :

        ADC可以将模拟信号转换为数字信号,用于采集和处理模拟信号。ADC在嵌入式系统中应用广泛,应用场景包括但不限于电池电量检测、音频数据采集、波形捕获。

DMA简介: 

      DMA全称Direct Memory Access,即直接存储器访问。

      DMA传输可以将数据从一个地址空间直接复制到另一个地址空间,提供外设与储存器或者储存器之间的高速数据传输。

      DMA传输不需要CPU的参与,可以节省大量CPU资源以使程序更加快速高效。

工程开始:

STM32CubeMX配置区:

      打开STM32CubeMX,新建工程

配置外部时钟:

cubemx 多通道adc,STM32,stm32,笔记,嵌入式硬件

 cubemx 多通道adc,STM32,stm32,笔记,嵌入式硬件

  输入需要的频率,敲击回车,STM32CubeMX会自动配置。

配置调试:

cubemx 多通道adc,STM32,stm32,笔记,嵌入式硬件

 这里一定要配置好,不然会导致芯片自锁

配置ADC:

cubemx 多通道adc,STM32,stm32,笔记,嵌入式硬件

 开启ADC后时钟树可能会报错,点进去选择Yes自动配置就好了;

cubemx 多通道adc,STM32,stm32,笔记,嵌入式硬件

 这里要先更改通道数才可以更改其他的参数;

cubemx 多通道adc,STM32,stm32,笔记,嵌入式硬件

配置DMA:

cubemx 多通道adc,STM32,stm32,笔记,嵌入式硬件

 cubemx 多通道adc,STM32,stm32,笔记,嵌入式硬件

配置串口:

cubemx 多通道adc,STM32,stm32,笔记,嵌入式硬件

串口的参数使用默认设置就好了。

配置工程文件: 

cubemx 多通道adc,STM32,stm32,笔记,嵌入式硬件

cubemx 多通道adc,STM32,stm32,笔记,嵌入式硬件

 然后点击右上角的GENERATE CODE生成文件,点击打开文件,进入keil中

 KEIL编程:

 开启MicroLIB:

cubemx 多通道adc,STM32,stm32,笔记,嵌入式硬件

关于MicroLIB大家可以自行查找,在此不过多赘述

添加库函数: 

打开main.c,添加库函数,不加会报错

/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */

串口重定向:

/* USER CODE BEGIN PTD */

/*串口重定向*/
int fputc(int ch, FILE *f){
	HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
	return ch;
}

/* USER CODE END PTD */

定义变量:

/* USER CODE BEGIN 0 */

uint32_t ADC1_1, ADC1_2;   //两个通道的ADC
uint32_t ADC1_Value[10];   //ADC数据存放数组
uint8_t ADC1_Flag;         //ADC采集完毕标志位

/* USER CODE END 0 */

 这里把ADC数据存放数组长度定义为了10,因为有两个通道的ADC,所以每个通道各采样10次,轮询模式交错进行(即[ADC1_0; ADC1_1; ADC1_0; ADC1_1…]),最后两个通道累加后求平均值,实际使用如果需要更高的精度,可以采样更多次后求平均值。

初始化 :

  /* USER CODE BEGIN 2 */
 HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&ADC1_Value,10);
  /* USER CODE END 2 */

while: 

在while循环中编写主程序(这里直接把一整个while贴上了)

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

    /* USER CODE BEGIN 3 */
	  if(ADC1_Flag==1)
	  {
		  ADC1_Flag=0;  //清空标志位
		  ADC1_1=0;
		  ADC1_2=0;
		  for(int i=0;i<10;){
			  ADC1_1+=ADC1_Value[i++];
			  ADC1_2+=ADC1_Value[i++];
				//读取ADC值
		  }
		  printf("\n");
		  printf("ADC_IN0(PA0)=%4.0d,Voltage0=%1.4f\r\n",ADC1_1/5,ADC1_1/5*3.3f/4096);
		  printf("ADC_IN1(PA1)=%4.0d,Voltage1=%1.4f\r\n",ADC1_2/5,ADC1_2/5*3.3f/4096);
			//串口打印
		  HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&ADC1_Value,10);
	  }
		HAL_Delay(1000);   //延时1s
  }
  /* USER CODE END 3 */

回调函数:

主程序写完后还要在下面的用户代码区写回调函数,不然程序将无法运行

/* USER CODE BEGIN 4 */

/*回调函数*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	if(hadc->Instance == ADC1){
		ADC1_Flag=1;
		HAL_ADC_Stop_DMA(&hadc1);  //关闭DMA
	}
}

/* USER CODE END 4 */

这里加了一句关闭DMA的语句,因为发现实际使用中如果不加会出现数值跑飞的情况 

最后贴上完整的main.c代码: 

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 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 "dma.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 */

/*串口重定向*/
int fputc(int ch, FILE *f){
	HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
	return ch;
}

/* 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 */

uint32_t ADC1_1, ADC1_2;   //两个通道的ADC
uint32_t ADC1_Value[10];   //ADC数据存放数组
uint8_t ADC1_Flag;         //ADC采集完毕标志位

/* 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_DMA_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&ADC1_Value,10);    //开启DMA传输

  /* USER CODE END 2 */

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

    /* USER CODE BEGIN 3 */
	  if(ADC1_Flag==1)
	  {
		  ADC1_Flag=0;  //清空标志位
		  ADC1_1=0;
		  ADC1_2=0;
		  for(int i=0;i<10;){
			  ADC1_1+=ADC1_Value[i++];
			  ADC1_2+=ADC1_Value[i++];
				//读取ADC值
		  }
		  printf("\n");
		  printf("ADC_IN0(PA0)=%4.0d,Voltage0=%1.4f\r\n",ADC1_1/5,ADC1_1/5*3.3f/4096);
		  printf("ADC_IN1(PA1)=%4.0d,Voltage1=%1.4f\r\n",ADC1_2/5,ADC1_2/5*3.3f/4096);
			//串口打印
		  HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&ADC1_Value,10);
	  }
		HAL_Delay(1000);   //延时1s
  }
  /* 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_MUL2;
  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_0) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
  PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV2;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/*回调函数*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	if(hadc->Instance == ADC1){
		ADC1_Flag=1;
		HAL_ADC_Stop_DMA(&hadc1);  //关闭DMA
	}
}

/* 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 */

这次的程序没有更改任何的头文件和STM32CubeMX生成的初始化函数,全部在main.c中实现,只要在规定的用户代码区写代码,就不会影响后面再次使用STM32CubeMX添加外设或者做更改

成果展示: 

 编译后下载到MCU中,PA9连接USB转串口模块的RXD,PA10连接TXD(因为串口通信要反接),如果MCU与USB转串口用的不是同一路电源,还要把两电源共地(不要把正极也接了,不然可能会烧)。作为试验,我们把PA0接3.3v,PA1接地,打开串口调试助手应该可以看到上面接收到的信息:cubemx 多通道adc,STM32,stm32,笔记,嵌入式硬件

一定要注意,ADC的最大输入电压为3.6V,超过会烧MCU(亲身体会,烧了一个ZET6)

总结:

 此方法可以实现快速读取模拟量的同时占用较少的资源,泛用性比较强。

都看到这里了点点关注再走呗

 交流Q群:659512171文章来源地址https://www.toymoban.com/news/detail-697759.html

到了这里,关于STM32初学入门笔记(3):STM32CubeMX配置STM32实现多通道ADC+DMA读取模拟量的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32CubeMX配置STM32G031多通道ADC + DMA采集(HAL库开发)

     时钟配置HSI主频配置64M  勾选打开8个通道的ADC  使能连续转换模式  添加DMA  DMA模式选择循环模式  使能DMA连续请求 采样时间配置160.5 转换次数为8  配置好8次转换的顺序  配置好串口,选择异步模式 配置好需要的开发环境并获取代码  修改main.c 串口重定向  串口重定向

    2024年02月08日
    浏览(54)
  • 【STM32】定时器1触发ADC多(规则)通道采样+DMA(CUBEMX配置)

    在用单片机做电源控制时不得不提ADC采集,离散系统是有固定的执行周期的,所以我们采样也是要固定时间去采样。然后就是我希望pwm波(定时器1产出)的频率与采样频率一致。 我下面演示的是G431CBU6,当然其他芯片也大差不差了。 说一下大致流程,TIM1触发ADC采样,然后

    2024年02月01日
    浏览(46)
  • STM32CubeMx配置ADC(多通道采集+DMA读取数据)(HAL库开发)

    目录 1、函数配置过程(这是标准库配置过程): 2、STM32CubeMx配置过程  3、main函数源文件 采集5路ADC数据,并用串口printf()函数打印出来。 实验现象:  ADC转换的初始条件: 1、使能 2、触发源条件完成(这个需要自己配置)利用:HAL_ADC_Start_DMA()函数; ADC中HAL开发优势就是,

    2023年04月08日
    浏览(74)
  • STM32CubeMx实现ADC多通道+DMA读取(HAL库)

    目录 一、实验结果  二、STM32CubeMx配置 三、main.c测试代码 1、RCC配置 (外部晶振选择8MHz。设置相应的分频器M=8,倍频器倍频系数N=336,分频器分频系数P=2,那么主PLL生成的第一个输出高速时钟PLLP为:168MHz)  2、SYS配置  3、ADC(规则)通道配置(独立模式,预分频4分频,1

    2024年02月15日
    浏览(50)
  • STM32入门笔记08_ADC模数转换器+案例: ADC单通道&ADC多通道

    ADC(Analog-Digtal Converter) 模拟-数字转换器 ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量, 建立模拟电路到数字电路的桥梁 12位逐次逼近型ADC, 1us转换时间 输入电压范围: 0~3.3V, 转换结果范围: 0~4095 18个输入通道, 可测量16个外部和2个内部信号源 规则组和注入组

    2024年02月04日
    浏览(48)
  • STM32CubeMX教程13 ADC - 单通道转换

    开发板(正点原子stm32f407探索者开发板V2.4) STM32CubeMX软件(Version 6.10.0) keil µVision5 IDE(MDK-Arm) ST-LINK/V2驱动 野火DAP仿真器 XCOM V2.6串口助手 1个滑动变阻器 使用STM32CubeMX软件配置STM32F407开发板的 ADC实现单通道ADC采集 ,具体为使用ADC1_IN5通道通过软件/定时器触发采集滑动变阻

    2024年02月02日
    浏览(51)
  • STM32初学入门笔记(5):使用STM32CubeMX通过SPI,IIC驱动OLED屏幕

    随着时代的进步,OLED显示屏成为了继LCD显示屏之后的新一代显示屏技术,OLED具有可视角高,功耗低,厚度薄,耐冲击、振动能力强,像素响应时间低等优点,在嵌入式开发中,OLED显示器也是一个主要的部分,制作OLED显示模块的驱动也是学习STM32路上的重要一部分,本篇将从

    2024年02月04日
    浏览(41)
  • STM32 CubeMX ADC采集 单通道,多通道,内部温度(轮询,DMA,中断)(HAL库)

    12位ADC是一种逐次逼近型模拟数字转换器。它有多达18个通道,可测量16个外部和2个内部 信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右 对齐方式存储在16位数据寄存器中。 模拟看门狗特性允许应用程序检测输入电压是否超出用户定

    2024年02月06日
    浏览(80)
  • STM32开发(14)----CubeMX配置ADC

    本章介绍使用STM32CubeMX对ADC进行配置的方法,ADC的原理、概念和特点,配置各个步骤的功能,并通过单通道,多通道,DMA三种方式实现采集。 ADC 即模拟数字转换器,英文详称 Analog-to-digital converter,可以将外部的模拟信号转换为数字信号。 以下是datasheet当中的内容,我就做个

    2023年04月13日
    浏览(46)
  • STM32CubeMX学习六 之ADC配置

    记录一下STM32CubeMX的学习笔记,同时分享给初学的小白,希望一起进步。 如何使用STM32CubeMX以及工程创建在之前的博客有提到,这里就直接从ADC配置讲起。 编译环境:KEIL 代码生成:STM32CubeMX 库:HAL MCU:STM32F072 假设你的cubeMX工程已经建好,这里我们开始配置ADC引脚(PA1设置为

    2023年04月10日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包