目录
7、Project Manager Code Generater
作者将在本文中通过实际例演示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采集的值。调节开发板上的可调电阻,显示值跟随变化。