细说STM32单片机双ADC同步转换和DMA传输数据到Buffer并通过串口发送数据的方法

发布于:2024-11-28 ⋅ 阅读:(14) ⋅ 点赞:(0)

目录

一、 工程配置

1、工程描述

2、 时钟、DEBUG、Timer3、USART2

3、 NVIC

4、 ADC1

(1) ADC1 Mode

(2) ADCs_Common_Settings组

(3)ADC_Settings组

(4)ADC_Regular_ConversionMode

5、 ADC2

(1) ADC2 Mode

(2) ADCs_Common_Settings组

(3)ADC_Settings组

(4)ADC_Regular_ConversionMode

6、DMA

(1)DMA Settings

(2) 使用DMA时是否开启外设的全局中断

7、Project Manager Code Generater

二、软件设计

1、main.c

三、下载运行


        作者将在本文中通过实际例演示STM32单片机双ADC同步转换机制、通过DMA把采集到的数据发送到DMA Buffer中去,最后在ADC传输完成事件中断回调函数HAL_ADC_ConvCpltCallback()里,通过串口把转换的工程值发送到串口助手。

        可以参考本文作者的其他文章: 细说STM32单片机ADC规则组多通道输入和DMA传输数据到Buffer并通过串口发送数据的方法-CSDN博客  https://wenchm.blog.csdn.net/article/details/144060957

一、 工程配置

1、工程描述

        开发板的底板上有2个可调电位器的模拟信号输入到PA0和PA1引脚。

        使用ADC1和ADC2同步采集两个通道的信号,双重ADC同步采集时,不能采集同一个通道,所以使用ADC1_IN1采集可调电位器的模拟信号输入到PA0,使用ADC2_IN2采集另一个可调电位器的模拟信号输入到PA1,多重ADC模式只能采用DMA方式传输数据。

2、 时钟、DEBUG、Timer3、USART2

        同参考文章。

3、 NVIC

        只需开启DMA1  Channel1 global interupt。抢占式优先级设置为1。

4、 ADC1

(1) ADC1 Mode

  •   ADC1_IN1,single_ended;

(2) ADCs_Common_Settings组

  • Mode:选择Dual regular simultaneous mode only;
  • DMAAccess Mode:DMA访问模式,选择DMA access mode Enabled;
  • Delay between 2 sampling phases:1;两次采样之间的间隔。这个参数用于交替模式时,设置交替采样的间隔时间,如1 Cycles表示1个ADCCLK周期。本例是同步模式,因此此参数无影响。

(3)ADC_Settings组

  • Clock Prescaler:选择同步时钟4分频;
  • Resolution:12位;
  • Data Alignment:右对齐(Right alignment);
  • Scan Conversion Mode:Disabled;因为只有一个通道,所以参数Scan Conversion Mode(扫描转换模式)设置为Disabled。
  • End of Conversion Selection:end of single conversion;
  • Continuous Conversion Mode:Enabled;
  • Discontinuous Conversion Mode:Disabled;
  • DMA Continuous Requests:Enabled;多重ADC只能使用DMA方式传输数据,所以参数DMA Continuous Requests(DMA连续请求)设置为Enabled。

(4)ADC_Regular_ConversionMode

  • Enable Regular Conversions:Enabled;
  • Number of Conversion:1;
  • External Trigger Conversion Source:Timer 3 Trigger out envent;用于设置启动ADC转换的外部触发信号源,列表中列出了所有可选的信号源,是一些定时器的Trigger Out event或Capture Compare event,这里选择Timer 3 Trigger Out event,也就是定时器TIM3的TRGO信号。
  • External Trigger Conversion Edge:上跳沿;用于设置触发转换的跳变沿,可选上跳沿、下跳沿或双边都触发。这里选择上跳沿,因为TRGO是一个短时正脉冲信号。
  • Rank1:Channel1,采样时间(Sampling Time)=24.5,无偏移; 

5、 ADC2

(1) ADC2 Mode

  •   ADC2_IN2,single_ended;

(2) ADCs_Common_Settings组

  • Mode:选择Dual regular simultaneous mode only,也就是ADC1和ADC2规则同步转换模式。
  • DMAAccess Mode:DMA访问模式,选择DMA access mode Enabled;
  • Delay between 2 sampling phases:1;

(3)ADC_Settings组

  • Clock Prescaler:选择同步时钟4分频;
  • Resolution:12位;
  • Data Alignment:右对齐(Right alignment);
  • Scan Conversion Mode:Disabled;
  • End of Conversion Selection:end of single conversion;
  • Continuous Conversion Mode:Enabled;
  • Discontinuous Conversion Mode:Disabled;
  • DMA Continuous Requests:Enabled;

(4)ADC_Regular_ConversionMode

  • Enable Regular Conversions:Enabled;
  • Number of Conversion:1;
  • Rank1:Channel2,采样时间(Sampling Time)=24.5,无偏移; 

       ADC2的参数(如时钟分频系数、分辨率、数据采样时间等)都应该与ADC1保持一致,以保证两个ADC能同步采集。ADC2的设置没有触发源选项,在双ADC同步模式下,ADC2由ADC1的触发源触发

6、DMA

        ADC1、ADC2各只有一个DMA请求,为ADC1的DMA请求配置DMA1 Channel1,为ADC2的DMA请求配置DMA1 Channel2,设置DMA传输属性参数,DMA传输方向自动设置为Peripheral To Memory(外设到存储器)在DMA Request Settings组中将Mode(工作模式)设置为Circular(循环模式),将外设和存储器的数据宽度都设置为Word,因为ADC转换结果数据寄存器是32位的。存储器设置为地址自增加。

(1)DMA Settings

  • 为ADC1选择DMA1 Channel1,为ADC2选择DMA1 Channel2外设到内存,优先级中等;
  • Mode:Circular;
  • Data Width:Word;

(2) 使用DMA时是否开启外设的全局中断

        在使用ADC1的DMA方式传输时,即使不开启ADC1的全局中断,DMA传输功能也能正常工作,所以在NVIC设置部分关闭ADC1的全局中断。

7、Project Manager Code Generater

        ☑Generate peripheral initialization as a pair of'c/h'fles per peripheral

二、软件设计

1、main.c

/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */
/* USER CODE BEGIN PV */
#define BATCH_DATA_LEN 1				// Dual ADC captures 32-bit data stored at once
uint32_t dmaDataBuffer[BATCH_DATA_LEN];	// DMA Buffer
/* USER CODE END PV */
/* USER CODE BEGIN 2 */
 HAL_ADCEx_MultiModeStart_DMA(&hadc1, dmaDataBuffer, BATCH_DATA_LEN);	// Start ADC1
 HAL_ADCEx_MultiModeStart_DMA(&hadc2, dmaDataBuffer, BATCH_DATA_LEN);	// Start ADC2
 HAL_TIM_Base_Start(&htim3);	// Start TIM3
/* USER CODE END 2 */
/* USER CODE BEGIN 4 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	uint32_t Volt;
	uint32_t adcValue=dmaDataBuffer[0];			// Data for ADC2 and ADC1

	uint32_t ADC1_val = adcValue & 0x0000FFFF;	// The lower 16 bits are the data of ADC1
	Volt=3300*ADC1_val;
	Volt=Volt>>12;
	printf("ADC1 = %ld\r\n",Volt );

	uint32_t ADC2_val = adcValue & 0xFFFF0000;	// The higher 16 bits are the data of ADC2
	ADC2_val =  ADC2_val>>16;
	Volt=3300*ADC2_val;	// mV unit
	Volt=Volt>>12;		// divided by 2^12
	printf("ADC2 = %ld\r\n",Volt );
}

//串口打印
int __io_putchar(int ch)
{
	HAL_UART_Transmit(&huart2, (uint8_t*)&ch, 1, 0xFFFF);
	return ch;
}
/* USER CODE END 4 */

        上述代码定义了一个uint32_t类型的全局数组dmaDataBuffer用作DMA缓冲区,只有一个元素。因为在双ADC同步模式下,MCU自动将ADC1和ADC2一次转换的数据组合成一个32位数,高16位是ADC2的数据,低16位是ADC1的数据。

        main()函数使用函数HAL_ADCEx_MultiModeStart_DMA()以多重模式DMA传输方式启动了ADC1和ADC2,且都使用缓冲区dmaDataBuffer

        重写了DMA流传输完成事件中断关联的回调函数HAL_ADC_ConvCpltCallback()。因为dmaDataBuffer的长度为1,所以完成一次转换就会调用一次这个回调函数。dmaDataBuffer[0]包含ADC1和ADC2一次转换的数据,高16位是ADC2的数据,低16位是ADC1的数据。这个回调函数实现的功能就是将ADC1和ADC2的转换结果数据读取出来,计算为mV后在串口助手上显示。

三、下载运行

        构建项目后,下载到开发板并运行测试,可以发现串口助手上每隔约500ms刷新显示一次ADC1和ADC2采集的值。调节开发板上的可调电阻,显示值跟随变化。