STM32CubeMX系列05——ADC(轮询、中断、DMA)

这篇具有很好参考价值的文章主要介绍了STM32CubeMX系列05——ADC(轮询、中断、DMA)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

====>>> 文章汇总(有代码汇总) <<<====

1. 所用硬件

正点原子Mini板,主控 STM32F103RCT6.

用到的外设:

  1. 串口1(PA9、PA10)
  2. 任意几个GPIO口(这里用PA1、PA2、PA3,对应ADC通道1、2、3)。

2. 生成工程

2.1. 创建工程选择主控

stm32 adc dma 中断,CubeMX,stm32,单片机,arm

2.2. 系统配置

配置时钟源
stm32 adc dma 中断,CubeMX,stm32,单片机,arm
配置debug模式(如果需要ST-Link下载及调试可以勾选)
stm32 adc dma 中断,CubeMX,stm32,单片机,arm
配置时钟树(可以直接在HCLK那里输入72,然后敲回车会自动配置)
stm32 adc dma 中断,CubeMX,stm32,单片机,arm

注意最后的ADC时钟,时钟频率最大14MHZ,因此这里设置6分频,刚好小于14。

2.3. 配置工程目录

stm32 adc dma 中断,CubeMX,stm32,单片机,armstm32 adc dma 中断,CubeMX,stm32,单片机,arm

2.4. 配置用到的外设

串口1配置(用于输出结果)
stm32 adc dma 中断,CubeMX,stm32,单片机,arm
stm32 adc dma 中断,CubeMX,stm32,单片机,arm

3. ADC配置(四选一)

有如下情况:

  1. 单通道轮询
  2. 单通道中断
  3. 多通道轮询
  4. DMA模式(单通道、多通道都能用)

设置说明:

  • ADC_Settings:
    • Data Alignment:
      • Right alignment :转换结果数据右对齐,一般我们选择右对齐模式。
      • Left alignment 转换结果数据左对齐。
    • Scan Conversion Mode:
      • Disabled 禁止扫描模式。如果是单通道 AD 转换使用 DISABLE。
      • Enabled 开启扫描模式。如果是多通道 AD 转换使用 ENABLE。
    • Continuous Conversion Mode:
      • Disabled 单次转换。转换一次后停止需要手动控制才重新启动转换。
      • Enabled 自动连续转换。
    • DiscontinuousConvMode:
      • Disabled 禁止间断模式。这个在需要考虑功耗问题的产品中很有必要,也就是在某个事件触发下,开启转换。
      • Enabled 开启间断模式。
  • ADC_Regular_ConversionMode:
    • Enable Regular Conversions 是否使能规则转换。
    • Number Of Conversion ADC转换通道数目,有几个写几个就行。
    • External Trigger Conversion Source 外部触发选择。这个有多个选择,一般采用软件触发方式。
  • Rank:
    • Channel ADC 转换通道
    • Sampling Time 采样周期选择,采样周期越短,ADC 转换数据输出周期就越短但数据精度也越低,采样周期越长,ADC 转换数据输出周期就越长同时数据精度越高。
  • ADC_Injected_ConversionMode:
    Enable Injected Conversions 是否使能注入转换。注入通道只有在规则通道存在时才会出现。
  • WatchDog:Enable Analog WatchDog Mode 是否使能模拟看门狗中断。当被 ADC 转换的模拟电压低于低阈值或者高于高阈值时,就会产生中断。

3.1. 单通道轮询

第一步:配置ADC
stm32 adc dma 中断,CubeMX,stm32,单片机,arm
第二步:点击生成代码

第三步:串口重定向,在usart.c中添加如下代码。具体的参考上一篇文章串口使用

// 需要调用stdio.h文件
#include <stdio.h>
//取消ARM的半主机工作模式
#pragma import(__use_no_semihosting)//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 
}; 
FILE __stdout;       
void _sys_exit(int x) //定义_sys_exit()以避免使用半主机模式
{ 
	x = x;
} 

int fputc(int ch, FILE *f)
{  
	HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
	return ch;
}

第四步:编写 main.c 代码 其他的什么都不用改

  while (1)
  {
		// 开启ADC
		HAL_ADC_Start(&hadc1);
		// 开始轮询转换
		HAL_ADC_PollForConversion(&hadc1,100);
		// 存储转换的值
		float value = 0;
		// 查询ADC状态
		uint32_t state = HAL_ADC_GetState(&hadc1);
		if (( state & HAL_ADC_STATE_REG_EOC) == HAL_ADC_STATE_REG_EOC)
		{
			// 获取ADC转换结果
			value = HAL_ADC_GetValue(&hadc1);
			printf("adc value:%f \r\n",value/4096.0*3.3);
		}
		else
		{
			printf("adc state %d \r\n",state);
		}
		// 关闭ADC
		HAL_ADC_Stop(&hadc1);
		HAL_Delay(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

效果验证
stm32 adc dma 中断,CubeMX,stm32,单片机,arm

单通道轮询 在转换时会阻塞直到转换完成。

3.2. 单通道中断

第一步:配置上:在“单通道轮询”实现配置基础上再打开ADC全局中断。
stm32 adc dma 中断,CubeMX,stm32,单片机,arm
第二步:点击生成代码

第三步:串口重定向,在usart.c中添加如下代码。具体的参考上一篇文章串口使用

// 需要调用stdio.h文件
#include <stdio.h>
//取消ARM的半主机工作模式
#pragma import(__use_no_semihosting)//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 
}; 
FILE __stdout;       
void _sys_exit(int x) //定义_sys_exit()以避免使用半主机模式
{ 
	x = x;
} 

int fputc(int ch, FILE *f)
{  
	HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
	return ch;
}

第四步:编写 main.c 代码

生成后查看代码,在stm32f1xx_it.c文件中有 ADC1通道2的中断函数ADC1_2_IRQHandler,这个中断函数又调用了HAL_ADC_IRQHandler(&hadc1);

/**
  * @brief This function handles ADC1 and ADC2 global interrupts.
  */
void ADC1_2_IRQHandler(void)
{
  /* USER CODE BEGIN ADC1_2_IRQn 0 */

  /* USER CODE END ADC1_2_IRQn 0 */
  HAL_ADC_IRQHandler(&hadc1);
  /* USER CODE BEGIN ADC1_2_IRQn 1 */

  /* USER CODE END ADC1_2_IRQn 1 */
}

HAL_ADC_IRQHandler(&hadc1);函数在stm32f1xx_hal_adc.c中,这个函数考虑了很多情况,其中调用了HAL_ADC_ConvCpltCallback(hadc);,还是在同一个文件中,这是一个弱函数。根据翻译,很好理解,我们直接重新定义这个方法即可。

/**
  * @brief  Conversion complete callback in non blocking mode 
  * @param  hadc: ADC handle
  * @retval None
  */
__weak void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hadc);
  /* NOTE : This function should not be modified. When the callback is needed,
            function HAL_ADC_ConvCpltCallback must be implemented in the user file.
   */
}

main.c

/* USER CODE BEGIN PFP */
// 重定义ADC转换完成回调函数
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	if(hadc == &hadc1)
	{
		uint16_t adc_value = HAL_ADC_GetValue(hadc);
		printf("refresh adc value:%f \r\n", adc_value/4096.0*3.3);
		// 重新开启ADC中断
		HAL_ADC_Start_IT(&hadc1);
	}
}
/* USER CODE END PFP */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* 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_ADC1_Init();
  MX_USART1_UART_Init();
  
  /* USER CODE BEGIN WHILE */
	// 开启ADC中断
	HAL_ADC_Start_IT(&hadc1);
  while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

效果和轮询的一样,不过这个会一直执行,而且很快

实际上,这里设置的是单次转换,所以中断只会触发一次,需要再次使用HAL_ADC_Start_IT开启中断。如果需要实时的转换,可以将转换设为连续模式,这样的话ADC转换器便会实时的持续的进行转换,那将是非常消耗CPU的,以至于main将不能正常执行(采样时间太短的话)。

开启中断后,一般需要实现HAL_ADC_ConvCpltCallback函数,在callback中GetValue,也可以在程序其他地方像轮询那样先判断ADC状态,再GetValue。

3.3. 多通道轮询

第一步:ADC配置
多通道时扫描模式会自动打开。要开启“Discontinuous Conversion Mode”。
stm32 adc dma 中断,CubeMX,stm32,单片机,arm
第二步:点击生成代码

第三步:串口重定向,在usart.c中添加如下代码。具体的参考上一篇文章串口使用

// 需要调用stdio.h文件
#include <stdio.h>
//取消ARM的半主机工作模式
#pragma import(__use_no_semihosting)//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 
}; 
FILE __stdout;       
void _sys_exit(int x) //定义_sys_exit()以避免使用半主机模式
{ 
	x = x;
} 

int fputc(int ch, FILE *f)
{  
	HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
	return ch;
}

第四步:编写 main.c 代码

HAL_ADCEx_Calibration_Start(&hadc1);
const uint8_t kNbrOfPin = 3;
  while (1)
  {
	for(int i = 0; i < kNbrOfPin; i++)
	{
		HAL_ADC_Start(&hadc1);
		HAL_ADC_PollForConversion(&hadc1, 100);
		float value = 0;
		uint32_t state = HAL_ADC_GetState(&hadc1);
		if (( state & HAL_ADC_STATE_REG_EOC) == HAL_ADC_STATE_REG_EOC)
		{
			value = HAL_ADC_GetValue(&hadc1);
			printf("adc value [%d]:%f\r\n", i,value/4096.0*3.3);
		}
		else
		{
			printf("adc state[%d]:%d\r\n", i, state);
		}
	}
	HAL_ADC_Stop(&hadc1);
	HAL_Delay(200);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

效果验证
stm32 adc dma 中断,CubeMX,stm32,单片机,arm

3.4. DMA模式

第一步:ADC配置
stm32 adc dma 中断,CubeMX,stm32,单片机,arm
stm32 adc dma 中断,CubeMX,stm32,单片机,arm
第二步:点击生成代码

第三步:串口重定向,在usart.c中添加如下代码。具体的参考上一篇文章串口使用

// 需要调用stdio.h文件
#include <stdio.h>
//取消ARM的半主机工作模式
#pragma import(__use_no_semihosting)//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 
}; 
FILE __stdout;       
void _sys_exit(int x) //定义_sys_exit()以避免使用半主机模式
{ 
	x = x;
} 

int fputc(int ch, FILE *f)
{  
	HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
	return ch;
}

第四步:编写 main.c 代码

/* USER CODE BEGIN PFP */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	if(hadc == &hadc1)
	{
		// 使用DMA其实也会运行到这里,也可以将结果在这里输出。
		// 当然此函数也可以不写。
	}
}
/* USER CODE END PFP */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
	uint16_t adc_value[3] = {0};
  /* USER CODE END 1 */

  /* 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_DMA_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
  
  /* USER CODE BEGIN WHILE */
	HAL_ADCEx_Calibration_Start(&hadc1);
	// enable DMA通道
	// 参数:ADC1、目标缓冲区地址、从ADC外围设备传输到内存的数据长度
	/*
	 * 此处有个大坑,经过测试,DMA中断非常容易进(具体的不知道)
	 *
	 * 如果ADC采样周期短的话,一直在执行中断,
	 * 导致无法执行主程序,因此会卡死在这个函数里面出不去。
	 *
	 * 因此,ADC的采用周期需要长一点。
	 */
	HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_value, 3);
	
  while (1)
  {
	printf("-------------------- \r\n");
	printf("adc value[0]:%f \r\n", adc_value[0]/4096.0*3.3);
	printf("adc value[1]:%f \r\n", adc_value[1]/4096.0*3.3);
	printf("adc value[2]:%f \r\n", adc_value[2]/4096.0*3.3);
	HAL_Delay(1000);
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

注意
用到 DMA 的外设,MX_DMA_Init(); 一定要在外设初始化前面,比如这里的 MX_ADC1_Init(); 。

效果验证
stm32 adc dma 中断,CubeMX,stm32,单片机,arm

多通道DMA和单通道DMA配置基本相同,只需注意存储AD转换结果的数组,如果有两个通道,数组长度为2,则每个通道的值分别对应数组的每一位;如果数组长度为2的整数倍,如10,则数组内[0] [2] [4] [6] [8]的值对应其中一个通道的AD值,即存储了连续采集5次的AD值,这样可以用多个AD值求平均值。文章来源地址https://www.toymoban.com/news/detail-691984.html

到了这里,关于STM32CubeMX系列05——ADC(轮询、中断、DMA)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • STM32 ADC采集 DMA中断处理

    //============================================ //函数名称:ADC1_Mode_Config(void) //功能描述:配置ADC1的工作模式为MDA模式 //输入:无 //输出:无 //============================================ void ADC1_Mode_Config(void) {         DMA_InitTypeDef DMA_InitStructure;         ADC_InitTypeDef ADC_InitStructure;              

    2024年02月14日
    浏览(40)
  • STM32CubeMX配置-ADC多通道配置(DMA) (STM32G070)

    一、写在前面         ADC通道采集数据的两种方式:         1)ADC轮询采集数据直接放到数组中;         2)采用中断方式,ADC采集完成进入中断,中断关闭ADC采集,取数据之后再打开ADC采集。 以下按第一种方式实现: 二、ADC多通道配置 1)配置通道及参数     如果要控

    2024年02月05日
    浏览(42)
  • 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日
    浏览(44)
  • 【STM32+HAL库+CubeMX】UART轮询收发、中断收发、DMA收发方法及空闲中断详解

    Author: DrinkCat(szt@drinkcat.com) Copyright © 2023 DrinkCat Original link: DrinkCat’s Blog UART是一种异步串行通信接口,常用于通过串口与外部设备进行通信。它通过发送和接收数据帧来实现数据传输,使用起来相对简单。UART通常包含发送器(Transmitter)和接收器(Receiver),通过两根信号线

    2024年02月10日
    浏览(34)
  • STM32初学入门笔记(3):STM32CubeMX配置STM32实现多通道ADC+DMA读取模拟量

    模拟信号的读取是我们在做很多项目是都要用到的,而模拟量的读取就要依赖于ADC数模转换器。对于初学者,学习使用ADC可以很大的帮助以后的STM32学习。 目录 ADC简介 : DMA简介:  工程开始: STM32CubeMX配置区: 配置外部时钟: 配置调试: 配置ADC: 配置DMA: 配置串口: 配

    2024年02月09日
    浏览(41)
  • 定时器(PWM输出)触发ADC采样(DMA)——STM32CubeMX

    我用的单片机是STM32F103CBTX 定时器:使用PWM输出的模式 ADC:使用DMA的模式 (在不使用DMA的情况下,定时器控制ADC进行数据采集只能是单通道!如果开启了多通道,读取到的ADC采集值只会是最后一个通道的值!所以,要想使用定时器控制ADC采集 多通道 , 必须使用DMA !)  看

    2024年04月10日
    浏览(46)
  • STM32HAL ADC+TIM+DMA采集交流信号 基于cubemx

    本文主要讲解定时器触发ADC去采集交流信号,DMA把数据搬移到内存。 所需工具: 开发板:STM32F103C8T6 STM32CubeMX IDE: Keil-MDK 相关文章: STM32HAL ADC+TIM+DMA采集交流信号 基于cubemx(二) STM32cubemx ADC+TIM+DMA超频采样 ADC+TIM+DMA采集交流信号是电赛中使用范围最为广泛的一个技术。这个模

    2024年02月03日
    浏览(42)
  • STM32CubeMX配置STM32G031多通道ADC + DMA采集(HAL库开发)

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

    2024年02月08日
    浏览(47)
  • STM32_ADC————ADC+DMA多路数据传输,看门狗中断,传感器控制LED

    一:介绍ADC与DMA的基本情况与初始化 二:利用ADC+DMA+看门狗中断+传感器控制LED灯代码 三:总结实验过程中碰到的错误与问题 通过DMA转运ADC的数据,设置ADC的中断看门狗阈值,当光敏传感器的ADC采样值在看门狗高低阈值中间,不触发中断,如果超过看门狗的高低阈值就会触发

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

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

    2024年02月01日
    浏览(42)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包