目录
实验1:单ADC单通道中断
硬件原理图
USART配置
ADC1配置
初始化结构体的参数
ScanConvMode:扫描转换模式
ContinuousConvMode:连续转换模式
ExternalTrigConv:外部触发方式
测试环节
实验现象
实验2:单ADC单通道DMA
硬件原理图和USART配置
ADC1配置
测试环节
实验现象
实验3:单ADC多通道DMA
硬件原理图和USART配置
ADC1配置
测试环节
实验现象
实验4:双ADC单通道慢速交叉采集
硬件原理图和USART配置
快速交叉模式
慢速交叉模式
ADC配置
测试环节
实验现象
实验5:双ADC多通道同步规则采集
硬件原理图和USART配置
同步规则模式
ADC配置
测试环节
实验现象
实验6:读取芯片温度
温度传感器
ADC1配置
测试环节
实验现象
AD转换包括采样阶段和转换阶段。在采样阶段才对通道数据进行;在转换阶段只是将采集的数据进行转换为数字量输出,此刻通道数据变化不会改变转换结果。
由于PC1接到电位器上,所以我们实验选择PC1引脚作为ADC接口,查询STM32数据手册得知PC1可作为ADC1的IN11(ADC1_IN11)。
115200-8-N-1,重定向支持printf打印,勾选C库。
ADC_HandleTypeDef hadc1;
void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
/* Common config */
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/* Configure Regular Channel */
sConfig.Channel = ADC_CHANNEL_11;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
HAL_ADC_Start_IT(&hadc1);
}
void HAL_ADC_MspInit(ADC_HandleTypeDef *adcHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if (adcHandle->Instance == ADC1)
{
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/**ADC1 GPIO Configuration
PC1 ------> ADC1_IN11
*/
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* ADC1 interrupt Init */
HAL_NVIC_SetPriority(ADC1_2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(ADC1_2_IRQn);
}
}
void HAL_ADC_MspDeInit(ADC_HandleTypeDef *adcHandle)
{
if (adcHandle->Instance == ADC1)
{
__HAL_RCC_ADC1_CLK_DISABLE();
/**ADC1 GPIO Configuration
PC1 ------> ADC1_IN11
*/
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1);
/* ADC1 interrupt Deinit */
HAL_NVIC_DisableIRQ(ADC1_2_IRQn);
}
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
...
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
指定转换是扫描模式(多通道模式)还是单个转换(单通道模式)。ADC_SCAN_DISABLE 或 ADC_SCAN_ENABLE。
在扫描模式下,扫描一组选定的通道,它们将会被依次转换,由序列寄存器ADC_SQRx或ADC_JSQRx选中的通道被转换。如果分别设置了EOCIE位或JEOCIE位,只在最后一个通道转换完后才会产生EOC或JEOC中断。
ADC转换可以在一次转换后停止,然后再次触发后进行下一次转换(一般配置);
也可以是持续不断地进行转换。
通过ADC_CR2:CONT位决定。
根据项目需求配置触发源。实际上一般使用软件自动触发。
__IO uint32_t ADC_ConvertedValue;
float ADC_Vol;
/**
* @brief 转换完成中断回调函数(非阻塞模式)
* @param AdcHandle : ADC句柄
* @retval 无
*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *AdcHandle)
{
ADC_ConvertedValue = HAL_ADC_GetValue(AdcHandle);
}
void test(void)
{
while (1)
{
HAL_Delay(1000);
ADC_Vol =(float) ADC_ConvertedValue*(3.3/4096); // 读取转换的AD值
printf("\r\n The current AD value = %f V \r\n", ADC_Vol);
}
}
旋钮电位器,电压输入有变化。将PC1接到VCC,输出3.3V。
看实验1
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
__IO uint32_t ADC_ConvertedValue;
void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_11;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&ADC_ConvertedValue, 1);
}
void HAL_ADC_MspInit(ADC_HandleTypeDef *adcHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if (adcHandle->Instance == ADC1)
{
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/**ADC1 GPIO Configuration
PC1 ------> ADC1_IN11
*/
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* ADC1 DMA Init */
/* ADC1 Init */
hdma_adc1.Instance = DMA1_Channel1;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_DISABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_MEDIUM;
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(adcHandle, DMA_Handle, hdma_adc1);
}
}
void HAL_ADC_MspDeInit(ADC_HandleTypeDef *adcHandle)
{
if (adcHandle->Instance == ADC1)
{
__HAL_RCC_ADC1_CLK_DISABLE();
/**ADC1 GPIO Configuration
PC1 ------> ADC1_IN11
*/
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1);
/* ADC1 DMA DeInit */
HAL_DMA_DeInit(adcHandle->DMA_Handle);
}
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
...
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
extern __IO uint32_t ADC_ConvertedValue;
float ADC_Vol;
void test(void)
{
while (1)
{
HAL_Delay(1000);
ADC_Vol =(float) ADC_ConvertedValue*(3.3/4096); // 读取转换的AD值
printf("\r\n The current AD value = %f V \r\n", ADC_Vol);
}
}
旋钮电位器,电压输入有变化。将PC1接到VCC,输出3.3V。
对硬件原理图的PC0、PC1、PC2、PC3、PC4、PC5进行ADC配置,具体看实验1。
____IO uint16_t ADC_ConvertedValue[6] = {0};
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 6;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_10;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
sConfig.Channel = ADC_CHANNEL_11;
sConfig.Rank = ADC_REGULAR_RANK_2;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
sConfig.Channel = ADC_CHANNEL_12;
sConfig.Rank = ADC_REGULAR_RANK_3;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
sConfig.Channel = ADC_CHANNEL_13;
sConfig.Rank = ADC_REGULAR_RANK_4;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
sConfig.Channel = ADC_CHANNEL_14;
sConfig.Rank = ADC_REGULAR_RANK_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
sConfig.Channel = ADC_CHANNEL_15;
sConfig.Rank = ADC_REGULAR_RANK_6;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&ADC_ConvertedValue, 6);
}
void HAL_ADC_MspInit(ADC_HandleTypeDef *adcHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if (adcHandle->Instance == ADC1)
{
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/**ADC1 GPIO Configuration
PC0 ------> ADC1_IN10
PC1 ------> ADC1_IN11
PC2 ------> ADC1_IN12
PC3 ------> ADC1_IN13
PC4 ------> ADC1_IN14
PC5 ------> ADC1_IN15
*/
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* ADC1 DMA Init */
/* ADC1 Init */
hdma_adc1.Instance = DMA1_Channel1;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_MEDIUM;
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(adcHandle, DMA_Handle, hdma_adc1);
}
}
void HAL_ADC_MspDeInit(ADC_HandleTypeDef *adcHandle)
{
if (adcHandle->Instance == ADC1)
{
__HAL_RCC_ADC1_CLK_DISABLE();
/**ADC1 GPIO Configuration
PC0 ------> ADC1_IN10
PC1 ------> ADC1_IN11
PC2 ------> ADC1_IN12
PC3 ------> ADC1_IN13
PC4 ------> ADC1_IN14
PC5 ------> ADC1_IN15
*/
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5);
/* ADC1 DMA DeInit */
HAL_DMA_DeInit(adcHandle->DMA_Handle);
}
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
...
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
extern __IO uint16_t ADC_ConvertedValue[6];
float ADC_Vol[6];
void test(void)
{
while(1)
{
HAL_Delay(1000);
ADC_Vol[0] =(float) ADC_ConvertedValue[0]/4096*(float)3.3; // 读取转换的AD值
ADC_Vol[1] =(float) ADC_ConvertedValue[1]/4096*(float)3.3; // 读取转换的AD值
ADC_Vol[2] =(float) ADC_ConvertedValue[2]/4096*(float)3.3; // 读取转换的AD值
ADC_Vol[3] =(float) ADC_ConvertedValue[3]/4096*(float)3.3; // 读取转换的AD值
ADC_Vol[4] =(float) ADC_ConvertedValue[4]/4096*(float)3.3; // 读取转换的AD值
ADC_Vol[5] =(float) ADC_ConvertedValue[5]/4096*(float)3.3; // 读取转换的AD值
printf("ADC_CHANNEL10 value = %f V \r\n", ADC_Vol[0]);
printf("ADC_CHANNEL11 value = %f V \r\n", ADC_Vol[1]);
printf("ADC_CHANNEL12 value = %f V \r\n", ADC_Vol[2]);
printf("ADC_CHANNEL13 value = %f V \r\n", ADC_Vol[3]);
printf("ADC_CHANNEL14 value = %f V \r\n", ADC_Vol[4]);
printf("ADC_CHANNEL15 value = %f V \r\n", ADC_Vol[5]);
}
}
输出引脚悬空状态,依次将各引脚接到VCC,依次输出3.3V。
看实验1
该模式下只能在规则通道组(通常一个通道)上启动。外部触发源来自于ADC1的规则通道复用器。外部触发后:
ADC2立即启动。
ADC1延时7个ADC_CLK时钟周期后启动。
在ADC1(如果通过EOCIE位使能)产生EOC中断后,生成一个32位DMA传输请求(如果设置了DMA位),该请求将 ADC1_DR 寄存器传输到SRAM(ADC2转换的数据在高16位,ADC1转换的数据在低16位)。
允许的最大采样周期 < 7个ADC_CLK时钟周期,以避免在ADC1和ADC2转换相同通道的情况下采样相位转换重叠。
如果在ADC1和ADC2上都设置了CONT位,则两个ADC所选的规则通道将连续转换。
该模式下只能在规则通道组(只有一个通道)上启动。外部触发源来自于ADC1的规则通道复用器。外部触发后:
ADC2立即启动。
ADC1延时14个ADC_CLK时钟周期后启动。
ADC2在第二次延时14个ADC_CLK时钟周期后启动。依次类推,交叉采集。
在ADC1(如果通过EOCIE位使能)产生EOC中断后,生成一个32位DMA传输请求(如果设置了DMA位),该请求将 ADC1_DR 寄存器传输到SRAM(ADC2转换的数据在高16位,ADC1转换的数据在低16位)。
允许的最大采样周期 < 14个ADC_CLK时钟周期,以避免与下一次转换重叠。
CONT位不能在模式中设置,因为它不断地转换所选的规则通道。
应用程序必须确保在启用交叉模式时不会发生注入通道的外部触发器。
ADC_HandleTypeDef hadc1;
ADC_HandleTypeDef hadc2;
DMA_HandleTypeDef hdma_adc1;
void MX_ADC1_Init(void)
{
ADC_MultiModeTypeDef multimode = {0};
ADC_ChannelConfTypeDef sConfig = {0};
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure the ADC multi-mode
*/
multimode.Mode = ADC_DUALMODE_INTERLSLOW;
if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_11;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
void MX_ADC2_Init(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
/** Common config
*/
hadc2.Instance = ADC2;
hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc2.Init.ContinuousConvMode = ENABLE;
hadc2.Init.DiscontinuousConvMode = DISABLE;
hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc2.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc2) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_11;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
void HAL_ADC_MspInit(ADC_HandleTypeDef *adcHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if (adcHandle->Instance == ADC1)
{
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/**ADC1 GPIO Configuration
PC1 ------> ADC1_IN11
*/
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* ADC1 DMA Init */
/* ADC1 Init */
hdma_adc1.Instance = DMA1_Channel1;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_DISABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(adcHandle, DMA_Handle, hdma_adc1);
}
else if (adcHandle->Instance == ADC2)
{
__HAL_RCC_ADC2_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/**ADC2 GPIO Configuration
PC1 ------> ADC2_IN11
*/
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
}
void HAL_ADC_MspDeInit(ADC_HandleTypeDef *adcHandle)
{
if (adcHandle->Instance == ADC1)
{
__HAL_RCC_ADC1_CLK_DISABLE();
/**ADC1 GPIO Configuration
PC1 ------> ADC1_IN11
*/
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1);
/* ADC1 DMA DeInit */
HAL_DMA_DeInit(adcHandle->DMA_Handle);
}
else if (adcHandle->Instance == ADC2)
{
/* Peripheral clock disable */
__HAL_RCC_ADC2_CLK_DISABLE();
/**ADC2 GPIO Configuration
PC1 ------> ADC2_IN11
*/
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1);
}
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
...
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
float ADC_ConvertedValueLocal[2];
uint32_t ADC_ConvertedValue;
int test(void)
{
初始化
HAL_ADCEx_Calibration_Start(&hadc1);
HAL_ADCEx_Calibration_Start(&hadc2);
/* 启动AD转换并使能DMA传输和中断 */
HAL_ADC_Start(&hadc2);
HAL_ADCEx_MultiModeStart_DMA(&hadc1, &ADC_ConvertedValue, sizeof(ADC_ConvertedValue));
while (1)
{
HAL_Delay(1000);
// ADC1的值
ADC_ConvertedValueLocal[0] = (float)(ADC_ConvertedValue & 0xFFF) * 3.3 / 4096;
// ADC2的值
ADC_ConvertedValueLocal[1] = (float)((ADC_ConvertedValue>>16) & 0xFFF) * 3.3 / 4096;
printf("ADC1 电压值 = %f V \r\n", ADC_ConvertedValueLocal[0]);
printf("ADC2 电压值 = %f V \r\n", ADC_ConvertedValueLocal[1]);
}
}
同实验1
对硬件原理图的PC0、PC1进行ADC配置,具体看实验1。
该模式在规则通道组上启动。外部触发源来自于ADC1的规则组复用器(由ADC1_CR2:EXTSEL[2:0]位决定)。为ADC2提供一个同步触发器。
不要在两个ADC上转换同一通道(转换同一通道时,两个ADC没有重叠采样时间)。
在ADC1或ADC2上的转换事件结束时:
生成一个32位的DMA传输请求(如果设置了DMA位),该请求将 ADC1_DR 寄存器传输到SRAM(ADC2转换的数据在高16位,ADC1转换的数据在低16位)。
当ADC1/ADC2规则通道全部转换结束时,生成EOC中断(如果在两个ADC接口之一上启用)。
在同步规则模式下,应该为两个通道配置完全相同的采样时间,这两个通道将被ADC1和ADC2同时采样。
ADC_HandleTypeDef hadc1;
ADC_HandleTypeDef hadc2;
DMA_HandleTypeDef hdma_adc1;
void MX_ADC1_Init(void)
{
ADC_MultiModeTypeDef multimode = {0};
ADC_ChannelConfTypeDef sConfig = {0};
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure the ADC multi-mode
*/
multimode.Mode = ADC_DUALMODE_REGSIMULT;
if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_11;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
void MX_ADC2_Init(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
/** Common config
*/
hadc2.Instance = ADC2;
hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc2.Init.ContinuousConvMode = ENABLE;
hadc2.Init.DiscontinuousConvMode = DISABLE;
hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc2.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc2) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_10;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
void HAL_ADC_MspInit(ADC_HandleTypeDef *adcHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if (adcHandle->Instance == ADC1)
{
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/**ADC1 GPIO Configuration
PC1 ------> ADC1_IN11
*/
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* ADC1 DMA Init */
/* ADC1 Init */
hdma_adc1.Instance = DMA1_Channel1;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_DISABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(adcHandle, DMA_Handle, hdma_adc1);
}
else if (adcHandle->Instance == ADC2)
{
__HAL_RCC_ADC2_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/**ADC2 GPIO Configuration
PC0 ------> ADC2_IN10
*/
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
}
void HAL_ADC_MspDeInit(ADC_HandleTypeDef *adcHandle)
{
if (adcHandle->Instance == ADC1)
{
__HAL_RCC_ADC1_CLK_DISABLE();
/**ADC1 GPIO Configuration
PC1 ------> ADC1_IN11
*/
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1);
/* ADC1 DMA DeInit */
HAL_DMA_DeInit(adcHandle->DMA_Handle);
}
else if (adcHandle->Instance == ADC2)
{
__HAL_RCC_ADC2_CLK_DISABLE();
/**ADC2 GPIO Configuration
PC0 ------> ADC2_IN10
*/
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_0);
}
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
...
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
float ADC_ConvertedValueLocal[2];
uint32_t ADC_ConvertedValue;
int test(void)
{
初始化
HAL_ADCEx_Calibration_Start(&hadc1);
HAL_ADCEx_Calibration_Start(&hadc2);
/* 启动AD转换并使能DMA传输和中断 */
HAL_ADC_Start(&hadc2);
HAL_ADCEx_MultiModeStart_DMA(&hadc1, &ADC_ConvertedValue, sizeof(ADC_ConvertedValue));
while (1)
{
HAL_Delay(1000);
// ADC1的值
ADC_ConvertedValueLocal[0] = (float)(ADC_ConvertedValue & 0xFFF) * 3.3 / 4096;
// ADC2的值
ADC_ConvertedValueLocal[1] = (float)((ADC_ConvertedValue>>16) & 0xFFF) * 3.3 / 4096;
printf("ADC1 电压值 = %f V \r\n", ADC_ConvertedValueLocal[0]);
printf("ADC2 电压值 = %f V \r\n", ADC_ConvertedValueLocal[1]);
}
}
依次将PC0、PC1接到VCC,ADC依次输出3.3V。
温度传感器内部连接到ADCx_IN16输入通道,用于将传感器输出电压转换为数字值。温度传感器的采样时间建议为17.1us。不使用时,该传感器可置于断电模式。
TSVREFE位必须设置为使能内部通道:ADCx_IN16(温度传感器)和ADCx_IN17(VREFINT转换)。
温度传感器输出电压随温度线性变化。由于工艺变化,这条线性的偏移量因芯片而异。
内部温度传感器更适合检测温度变化而不是绝对温度的应用。如果需要精确的温度读数,则应该使用外部温度传感器部分。
使用温度传感器时,需要:
选择ADCx_IN16输入通道。
选择采样时间为17.1us。
设置ADC_CR2:TSVREFE位,将温度传感器从断电模式唤醒。
通过设置ADON位(或通过外部触发器)启动ADC转换。
读取ADC数据寄存器产生的Vsense数据。
温度计算公式:温度(℃) = (V25 - Vsense)/Avg_Slope + 25。V25表示25℃时的Vsense,Avg_Slope表示温度与Vsense间曲线的平均斜率(mV/℃或uV/℃)。V25和Avg_Slope的实际值参见电气特性部分。
传感器在从断电模式唤醒后有一个启动时间,然后才能在正确的水平上输出Vsense。ADC在上电后也有一个启动时间,因此为了最小化延迟,应该同时设置ADON和TSVREFE位。
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
void HAL_ADC_MspInit(ADC_HandleTypeDef *adcHandle)
{
if (adcHandle->Instance == ADC1)
{
__HAL_RCC_ADC1_CLK_ENABLE();
/* ADC1 DMA Init */
/* ADC1 Init */
hdma_adc1.Instance = DMA1_Channel1;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_DISABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(adcHandle, DMA_Handle, hdma_adc1);
}
}
void HAL_ADC_MspDeInit(ADC_HandleTypeDef *adcHandle)
{
if (adcHandle->Instance == ADC1)
{
__HAL_RCC_ADC1_CLK_DISABLE();
/* ADC1 DMA DeInit */
HAL_DMA_DeInit(adcHandle->DMA_Handle);
}
}
#define V25 0x6EE // 对于12位的ADC,3.3V的ADC值为0xfff,温度为25度时对应的电压值为1.43V即0x6EE
#define AVG_SLOPE 0x05 // 斜率,每摄氏度4.3mV,对应每摄氏度0x05
__IO uint16_t Current_Temperature;
uint16_t ADC_ConvertedValue;
void test(void)
{
初始化
HAL_ADCEx_Calibration_Start(&hadc1);
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&ADC_ConvertedValue, 1); /* 启动AD转换并使能DMA传输和中断 */
while(1)
{
HAL_Delay(1000);
Current_Temperature = ( V25 - ADC_ConvertedValue ) / AVG_SLOPE + 25;
printf("\r\n The IC current temp = %3d 摄氏度\r\n", Current_Temperature);
}
}