配置stm32cubemx采集stm32H743IIT6,通过DMA实现多通道和多模块ADC的采集,亲测有效!

 之前写到stm32cubemx通过阻塞实现单通道和多通道的ADC的采集。

本文分享通过DMA实现单模块多通道和多模块多通道的ADC采集。

stm32cubemx的版本6.10.0。

一、DMA采集多通道ADC数据

阻塞采集是每次采集adc数据,cpu死等,直到采集完或者在设定时间超时没能采集,返回到cpu。

DMA采集是每次采集adc数据,不占用cpu资源。

配置sm32cubemx:

1、配置时钟源

使用的是25M无源晶振。

这里power regulator voltage scale 选择“Power Regulator Voltage Scale 0”,系统时钟能达到480MHz。查看数据手册

2、时基选择系统滴答定时器

3、配置时钟

配置时钟为480MHz,系统自动生成时钟树。

ADC的时钟是64MHz。

4、配置ADC

选择通道18和19

DMA settings 里添加,Mode 选择“Circular”,Data Width选择“Half Word”,半字16位。

Continuous Conversion Mode(连续转换模式)

在连续转换模式下,如果发生软件或者硬件触发,ADC会执行所有常规通道的转换,随后会自动重启并继续执行每一个通道的转换

Conversion Data Managerment Mode(转换数据管理模式)

选择存放转换完成的模拟量数据的地方。

时钟设置为32MHz,

采样时间为32.5 时钟周期

转换时间=采样时间+7.5ADC时钟周期

=32.5+7.5 =40个时钟周期=1.25us

5、配置串口

6、调试模式

配置成SW模式

7、项目管理

配置完成后,生成初始化代码。

代码部分

(1)添加头文件

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

#include "stdio.h" //添加头文件
/* USER CODE END Includes */

(2)添加打印函数

/* USER CODE BEGIN 0 */

int fputc(int c, FILE *stream)    //重写fputc函数
{
 /*
    huart1是工具生成代码定义的UART1结构体,
    如果以后要使用其他串口打印,只需要把这个结构体改成其他UART结构体。
*/
    HAL_UART_Transmit(&huart1, (unsigned char *)&c, 1, 1000);   
    return 1;
}

/* USER CODE END 0 */

(3)添加变量

int main(void)
{
  /* USER CODE BEGIN 1 */
uint16_t ADC_Value[100];//定义16位的100个数据的数组,存储adc的数据
	uint8_t i;
	uint32_t ad1,ad2;//采集数据平均值
	float ad1x,ad2x;//电压值
	float ADCx;//转换后的电压值

  /* USER CODE END 1 */

(4)启动ADC的DMA转换

  /* USER CODE BEGIN 2 */
  MX_ADC1_Init();//初始化ADC1,

HAL_ADC_Start_DMA(&hadc1,(uint32_t *)&ADC_Value,100); //直接采集到50组,通道4和通道5的数据,ADC_Value[i],偶数存的是通道4的数据,奇数存的是通道5的数据
printf("<<<<<<<ADC many channel DMA test\r\n");
HAL_Delay(2000);
  /* USER CODE END 2 */

DMA每次使能,会把选择的通道都采集一次。

这里HAL_ADC_Start_DMA(&hadc1,(uint32_t *)&ADC_Value,100);

原函数HAL_ADC_Start_DMA(ADC_HandleTypeDef *hadc, uint32_t *pData, uint32_t Length);

我们看到缓冲区uint32_t *pData是32位。但是我们在配置DMA采集数据格式是HalfWord 16位。

uint16_t ADC_Value[100];//定义16位的100个数据的数组,直接调用

HAL_ADC_Start_DMA(&hadc1,ADC_Value,100);

就会报错:

../Core/Src/main.c(121): error:  #167: argument of type "uint16_t *" is incompatible with parameter of type "uint32_t *"。

如果定义存放数据的数组改成32位:

uint32_t ADC_Value[100];//定义32位的100个数据的数组

再编译就不会报错了。

恭喜,就会掉入新的坑里。

调试一下,就会发现。数组前面50个有数据,后面50个没数据。

注意观察,前面50个的数据,每个数据存了两个通道的数据。

因为采样的是16位数据,数组格式是32位的。就会出现下面的情况。

因此,我们HAL_ADC_Start_DMA(&hadc1,(uint32_t *)&ADC_Value,100);

(5)while添加采集

 while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		
		
		ad1=0,ad2=0;//清零

		for(i=0;i<50;i++) 
		{
			ad1+=ADC_Value[2*i]; //通道4数据累加
			ad2+=ADC_Value[2*i+1];//通道5数据累加
		}
		ad1/=50;//求平均值
		ad2/=50;//求平均值
		ad1x =ad1 *3.3/65536; //转化为电压值
		ad2x =ad2 *3.3/65536;  //转化为电压值
		printf("\r\n ****ADC DMA Example****\r\n\r\n");
    printf("AD1 value = %d, AD1电压是%.2fV\r\n",ad1,ad1x);
		printf("AD2 value = %d, AD2电压是%.2fV\r\n",ad2,ad2x);
		HAL_Delay(1000);
				
  }
  /* USER CODE END 3 */

(6)添加adc校准函数

这里很关键!stm32cubemx初始化不包含校准函数,需要自己手动添加。

在adc.c的初始化函数void MX_ADC1_Init(void)内添加

  /* USER CODE BEGIN ADC1_Init 2 */
  HAL_ADCEx_Calibration_Start(&hadc1, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED); /* ADC校准 */
  /* USER CODE END ADC1_Init 2 */

(7)编译

stm32H7系列编译起来时间超级长

花了十分钟多。有两个解决办法:

①、不勾选“Browse information”

②编译器选择“version 6“

两个方法都能编译速度极大的提升!

Debug一次。

能看到直接采集100个数据,保存到数组里。

运行

二、DMA多模块多通道ADC数据

和单模块多通道ADC数据一样的配置就不贴图了。

(1)ADC配置

增加ADC模块ADC3的芯片温度和内部基准电压采集,采集时间设置为850.5个周期

时钟设置为32MHz,

采样时间为810.5时钟周期

转换时间=采样时间+7.5ADC时钟周期

=810.5+7.5 =812个时钟周期=25.375us

配置完成后,生成初始化代码。

代码部分

(1)添加头文件

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

#include "stdio.h" //添加头文件
/* USER CODE END Includes */

(2)添加打印函数

/* USER CODE BEGIN 0 */

int fputc(int c, FILE *stream)    //重写fputc函数
{
 /*
    huart1是工具生成代码定义的UART1结构体,
    如果以后要使用其他串口打印,只需要把这个结构体改成其他UART结构体。
*/
    HAL_UART_Transmit(&huart1, (unsigned char *)&c, 1, 1000);   
    return 1;
}

/* USER CODE END 0 */

(3)添加变量

int main(void)
{
   /* USER CODE BEGIN 1 */

uint16_t ADC1_Value[100];//定义16位的100个数据的数组,存储adc的数据
uint16_t ADC3_Value[100];//定义16位的100个数据的数组,存储adc的数据
	
	uint8_t i;
	uint32_t ad1,ad2;//平均值
	uint32_t ad3,ad4;//平均值
	float ad1x,ad2x;//转换后的电压值
	float ad3x,ad4x;//转换后的电压值
	float temp; //芯片内部温度
  
	
  /* USER CODE END 1 */

(4)启动ADC的DMA转换

 /* USER CODE BEGIN 2 */
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)&ADC1_Value,100); //直接采集到50组,通道4和通道5的数据,ADC_Value[i],偶数存的是通道4的数据,奇数存的是通道5的数据
HAL_ADC_Start_DMA(&hadc3,(uint32_t *)&ADC3_Value,100); //直接采集到50组,通道4和通道5的数据,ADC_Value[i],偶数存的是通道4的数据,奇数存的是通道5的数据

printf("<<<<<<<ADC + many module+channel DMA test\r\n");
HAL_Delay(2000);
  /* USER CODE END 2 */

(5)while添加采集

  while (1)
  {
		
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		ad1=0,ad2=0;
		ad3=0,ad4=0;
		
			for(i=0;i<50;i++) 
		{
			ad1+=ADC1_Value[2*i]; //通道4数据累加
			ad2+=ADC1_Value[2*i+1];//通道5数据累加
			ad3+=ADC3_Value[2*i]; //通道4数据累加
			ad4+=ADC3_Value[2*i+1];//通道5数据累加
		}
     ad1/=50;//求平均值
		 ad2/=50;//求平均值
		ad3/=50;//求平均值
		 ad4/=50;//求平均值
			ad1x =ad1 *3.3/65536;
		ad2x =ad2 *3.3/65536;
		ad3x =ad3 *3.3/65536;
		ad4x = (110.0-30.0)/(*(unsigned short*)(0x1FF1E840) - *(unsigned short*)(0x1FF1E820));//芯片内部温度计算公式
		temp = ad4x*(ad4 - *(unsigned short*)(0x1FF1E820))+30;//芯片内部温度计算公式
		//temp为最终的温度值

		
		printf("\r\n ****ADC DMA  Example****\r\n\r\n");
    printf("AD1 value = %d, AD1电压是%.2fV\r\n",ad1,ad1x);
		printf("AD2 value = %d, AD2电压是%.2fV\r\n",ad2,ad2x);
		 printf("AD3 value = %d, AD3内部参考电压是%.2fV\r\n",ad3,ad3x);
		printf("AD4 value = %d, AD4温度是%.2f℃\r\n",ad4,temp);
		HAL_Delay(1000);
  }
  /* USER CODE END 3 */
}

(6)添加adc校准函数

这里很关键!stm32cubemx初始化不包含校准函数,需要自己手动添加。

在adc.c的初始化函数void MX_ADC1_Init(void)内添加

  /* USER CODE BEGIN ADC1_Init 2 */
  HAL_ADCEx_Calibration_Start(&hadc1, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED); /* ADC校准 */
  HAL_ADCEx_Calibration_Start(&hadc3, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED); /* ADC校准 */
  /* USER CODE END ADC1_Init 2 */

运行

验证准确性

(1)我们查看芯片数据手册,

内部参考电压是1.216V

采集的电压是1.21V,能够对的起来。

(2)内部温度

我们运行正点原子的例程

采集的温度在41.5到42摄氏度之间。

  • 14
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值