STM32-ADC实验

目录

实验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转换包括采样阶段和转换阶段。在采样阶段才对通道数据进行;在转换阶段只是将采集的数据进行转换为数字量输出,此刻通道数据变化不会改变转换结果。

实验1:单ADC单通道中断

硬件原理图

由于PC1接到电位器上,所以我们实验选择PC1引脚作为ADC接口,查询STM32数据手册得知PC1可作为ADC1的IN11(ADC1_IN11)。

USART配置

115200-8-N-1,重定向支持printf打印,勾选C库。

ADC1配置

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();
  }
}

初始化结构体的参数

ScanConvMode:扫描转换模式

指定转换是扫描模式(多通道模式)还是单个转换(单通道模式)。ADC_SCAN_DISABLE 或 ADC_SCAN_ENABLE。

在扫描模式下,扫描一组选定的通道,它们将会被依次转换,由序列寄存器ADC_SQRx或ADC_JSQRx选中的通道被转换。如果分别设置了EOCIE位或JEOCIE位,只在最后一个通道转换完后才会产生EOC或JEOC中断。

ContinuousConvMode:连续转换模式

ADC转换可以在一次转换后停止,然后再次触发后进行下一次转换(一般配置);

也可以是持续不断地进行转换。

通过ADC_CR2:CONT位决定。

ExternalTrigConv:外部触发方式

根据项目需求配置触发源。实际上一般使用软件自动触发。

测试环节

__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。

实验2:单ADC单通道DMA

硬件原理图和USART配置

看实验1

ADC1配置

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。

实验3:单ADC多通道DMA

硬件原理图和USART配置

对硬件原理图的PC0、PC1、PC2、PC3、PC4、PC5进行ADC配置,具体看实验1。

ADC1配置

____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。

实验4:双ADC单通道慢速交叉采集

硬件原理图和USART配置

看实验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配置

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

实验5:双ADC多通道同步规则采集

硬件原理图和USART配置

对硬件原理图的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配置

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。

实验6:读取芯片温度

温度传感器

温度传感器内部连接到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位。

ADC1配置

 

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);
	}
}

实验现象

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/106326.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【疑问解决】在自动装箱中Integer赋予一个常量1,为什么会出现==判断true和flase的情况(JDK源码、内部缓冲)

问题来源自讲课时的Integer练习中 当时第一反应是false true true 因为第一段的输出为flase毋庸置疑了&#xff0c;因为已经new了两个新的堆空间&#xff0c;当然指向不同的空间了 但是第二段第三段就没有头绪了&#xff0c;自动装箱了难道不是执行同一个空间吗…

服务网络基础

服务网络基础 目录 前言 从今天开始我们将进入服务网格的学习&#xff0c;服务网格是微服务架构中的一种重要的技术&#xff0c;它可以解决微服务架构中的一些问题&#xff0c;比如服务发现、服务治理、服务监控等等&#xff0c;我们将从服务网格的基础开始&#xff0c;逐步深…

怎么突破反爬虫机制

在当今的数字化时代&#xff0c;网络爬虫已经成为了收集信息和数据的重要工具。然而&#xff0c;许多网站和平台都配备了反爬虫机制&#xff0c;以防止恶意攻击和过度访问。对于普通用户来说&#xff0c;如何突破这些反爬虫机制呢&#xff1f;本文将为你提供一些实用的技巧和建…

权限系统设计(转载)

1 为什么需要权限管理 2 权限模型 2.1 权限设计 2.2 为什么需要角色 2.3 权限模型的演进 2.4 用户划分 2.5 理想的RBAC模型 3 权限系统表设计 3.1 标准RBAC模型表设计 3.2 理想RBAC模型表设计 4 结语 1 为什么需要权限管理 日常工作中权限的问题时时刻刻伴随着我们&a…

流程引擎-自定义函数的应用

背景&#xff1a; 某些业务需求比较特殊&#xff0c;需要在表单中校验或实现一些功能&#xff0c;泛微流程表单配置时实现的方式多种多样&#xff1a;JS脚本、SQL语句、公式以及其他一些标准化拖拽功能&#xff0c;本次给大家分享一下流程表单中的公式实现的一些需求场景。泛微…

Python轮廓追踪【OpenCV形态学操作】

文章目录 概要代码运行结果 概要 一些理论知识 OpenCV形态学操作理论1 OpenCV形态学操作理论2 OpenCV轮廓操作|轮廓类似详解 代码 代码如下&#xff0c;可以直接运行 import cv2 as cv# 定义结构元素 kernel cv.getStructuringElement(cv.MORPH_RECT, (3, 3)) # print kern…

安装虚拟机找不到虚拟网啦1(eth1)不出现

一、安装虚拟机找不到虚拟网啦1&#xff08;eth1&#xff09;不出现 1、先安装virtualbox 2、再安装vagrant 3、在windows使用ipconfig没有VirtualBoxHost-OnlyNetWork解决方法 1) 解决办法 在windows的设置中找到 网络和Internet 选项&#xff0c;选择右侧 更改适配器选项 …

selenium+python web自动化测试框架项目实战实例教程

自动化测试对程序的回归测试更方便。 由于回归测试的动作和用例是完全设计好的,测试期望的结果也是完全可以预料的,将回归测试自动运行... 可以运行更加繁琐的测试 自动化测试的一个明显好处就是可以在很短的时间内运行更多的测试。学习自动化测试最终目的是应用到实际项目中&…

Android Studio 导出 jar

AS版本&#xff1a;Android Studio Giraffe | 2022.3.1 Patch 1 1、File——New Module——Android Library 2、mylibrary——main——新建功能类 3、mylibrary——build.gradle——android {}内复制以下代码——Sync Now //Copy类型 tasks.register(makeJar, Copy) { //删…

【Java 进阶篇】Java Request 继承体系详解

在Java编程中&#xff0c;Request&#xff08;请求&#xff09;是一个常见的概念&#xff0c;特别是在Web开发中。Request通常用于获取来自客户端的信息&#xff0c;以便服务器能够根据客户端的需求提供相应的响应。在Java中&#xff0c;Request通常涉及到一系列类和接口&#…

CentOS 编译安装TinyXml2

安装 TinyXml2 Git 源码下载地址:https://github.com/leethomason/tinyxml2 步骤1&#xff1a;首先&#xff0c;你需要下载tinyxml2的源代码。你可以从Github或者源代码官方网站下载。并上传至/usr/local/source_code/ 步骤2&#xff1a;下载完成后&#xff0c;需要将源代码解…

Java IDEA feign调用上传文件MultipartFile以及实体对象亲测可行

Java IDEA feign调用上传文件MultipartFile以及实体对象亲测可行 1. 报错 java.lang.IllegalStateException: Body parameter cannot be used with form parameters2. 解决参考 1. 报错 java.lang.IllegalStateException: Body parameter cannot be used with form parameters …

1-多媒体通信概述

文章目录 媒体和多媒体媒体多媒体VarityIntergrationInteraction 多媒体通信(MMC)业务类型 MMC主要问题和关键技术主要问题关键技术 MMC发展动向重要事件趋势 标准化组织 媒体和多媒体 媒体 承载信息的载体. 感知媒体, 表示媒体, 显示媒体, 存储媒体, 传输媒体. 多媒体 Var…

【设计模式】第3节:设计模式概论

设计模式不是代码&#xff0c;而是某类问题的通用方案。设计模式的本质是提高软件的维护性、通用性和扩展性&#xff0c;并降低软件的复杂度。一共有24种设计模式&#xff0c;可以分为创建型模式、结构型模式和行为型模式三大类。设计模式中比较重要的有&#xff1a;单例模式、…

Spring Authorization Server 1.1 扩展实现 OAuth2 密码模式与 Spring Cloud 的整合实战

目录 前言无图无真相创建数据库授权服务器maven 依赖application.yml授权服务器配置AuthorizationServierConfigDefaultSecutiryConfig 密码模式扩展PasswordAuthenticationTokenPasswordAuthenticationConverterPasswordAuthenticationProvider JWT 自定义字段自定义认证响应认…

C++(Qt)软件调试---线程死锁调试(15)

C(Qt)软件调试—线程死锁调试&#xff08;15&#xff09; 文章目录 C(Qt)软件调试---线程死锁调试&#xff08;15&#xff09;1、前言2、常见死锁3、linux下gdb调试C死锁1.1 使用代码1.2 gdb调试 3、linux下gdb调试Qt死锁1.1 使用代码1.2 gdb调试 4、Windows下gdb调试C死锁5、W…

Selenium+Pytest自动化测试框架详解

前言 selenium自动化 pytest测试框架 本章你需要 一定的python基础——至少明白类与对象&#xff0c;封装继承&#xff1b;一定的selenium基础——本篇不讲selenium&#xff0c;不会的可以自己去看selenium中文翻译网 一、测试框架简介 测试框架有什么优点 代码复用率高&…

【LeetCode】5. 最长回文子串

题目链接 文章目录 Python3方法&#xff1a; 暴力求解 ⟮ O ( n 3 ) 、 O ( 1 ) ⟯ \lgroup O(n^3)、O(1)\rgroup ⟮O(n3)、O(1)⟯方法一&#xff1a; 动态规划 (回文串同时去掉头尾后 依然是回文串) ⟮ O ( n 2 ) ⟯ \lgroup O(n^2)\rgroup ⟮O(n2)⟯⭐ 方法二&#xff1a;…

网工内推 | 急招网工,思科、华为认证优先,法定节假日三薪

01 江苏臻云技术 招聘岗位&#xff1a;网络工程师 职责描述&#xff1a; 1、负责落实数据中心机房日常网络监测及巡检任务&#xff1b; 2、负责数据中心网络设备日常监控、变更、维护、巡检&#xff1b; 3、负责日常巡检报告、故障维护报告、变更申请的文档的编制&#xff1b;…

番外8.2 --- 后续

### 01&#xff1a;dd命令&#xff1a;在新挂载点创建swap文件大小10MB&#xff1b;&#xff08;dd if/dev/zero of/swap bs1024 count10240&#xff09; 02&#xff1a;给swap建立文件系统&#xff0c;将其分属到swap文件&#xff08;mkswap /swap&#xff1b; swapon /swap &…