• 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配置

    1. ADC_HandleTypeDef hadc1;
    2. void MX_ADC1_Init(void)
    3. {
    4. ADC_ChannelConfTypeDef sConfig = {0};
    5. /* Common config */
    6. hadc1.Instance = ADC1;
    7. hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
    8. hadc1.Init.ContinuousConvMode = ENABLE;
    9. hadc1.Init.DiscontinuousConvMode = DISABLE;
    10. hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    11. hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    12. hadc1.Init.NbrOfConversion = 1;
    13. if (HAL_ADC_Init(&hadc1) != HAL_OK)
    14. {
    15. Error_Handler();
    16. }
    17. /* Configure Regular Channel */
    18. sConfig.Channel = ADC_CHANNEL_11;
    19. sConfig.Rank = ADC_REGULAR_RANK_1;
    20. sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
    21. if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    22. {
    23. Error_Handler();
    24. }
    25. HAL_ADC_Start_IT(&hadc1);
    26. }
    27. void HAL_ADC_MspInit(ADC_HandleTypeDef *adcHandle)
    28. {
    29. GPIO_InitTypeDef GPIO_InitStruct = {0};
    30. if (adcHandle->Instance == ADC1)
    31. {
    32. __HAL_RCC_ADC1_CLK_ENABLE();
    33. __HAL_RCC_GPIOC_CLK_ENABLE();
    34. /**ADC1 GPIO Configuration
    35. PC1 ------> ADC1_IN11
    36. */
    37. GPIO_InitStruct.Pin = GPIO_PIN_1;
    38. GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    39. HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    40. /* ADC1 interrupt Init */
    41. HAL_NVIC_SetPriority(ADC1_2_IRQn, 0, 0);
    42. HAL_NVIC_EnableIRQ(ADC1_2_IRQn);
    43. }
    44. }
    45. void HAL_ADC_MspDeInit(ADC_HandleTypeDef *adcHandle)
    46. {
    47. if (adcHandle->Instance == ADC1)
    48. {
    49. __HAL_RCC_ADC1_CLK_DISABLE();
    50. /**ADC1 GPIO Configuration
    51. PC1 ------> ADC1_IN11
    52. */
    53. HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1);
    54. /* ADC1 interrupt Deinit */
    55. HAL_NVIC_DisableIRQ(ADC1_2_IRQn);
    56. }
    57. }
    1. /**
    2. * @brief System Clock Configuration
    3. * @retval None
    4. */
    5. void SystemClock_Config(void)
    6. {
    7. RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
    8. ...
    9. PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
    10. PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
    11. if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    12. {
    13. Error_Handler();
    14. }
    15. }

    初始化结构体的参数

    ScanConvMode:扫描转换模式

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

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

    ContinuousConvMode:连续转换模式

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

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

    通过ADC_CR2:CONT位决定。

    ExternalTrigConv:外部触发方式

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

    测试环节

    1. __IO uint32_t ADC_ConvertedValue;
    2. float ADC_Vol;
    3. /**
    4. * @brief 转换完成中断回调函数(非阻塞模式)
    5. * @param AdcHandle : ADC句柄
    6. * @retval 无
    7. */
    8. void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *AdcHandle)
    9. {
    10. ADC_ConvertedValue = HAL_ADC_GetValue(AdcHandle);
    11. }
    12. void test(void)
    13. {
    14. while (1)
    15. {
    16. HAL_Delay(1000);
    17. ADC_Vol =(float) ADC_ConvertedValue*(3.3/4096); // 读取转换的AD值
    18. printf("\r\n The current AD value = %f V \r\n", ADC_Vol);
    19. }
    20. }

    实验现象

    旋钮电位器,电压输入有变化。将PC1接到VCC,输出3.3V。

    实验2:单ADC单通道DMA

    硬件原理图和USART配置

    看实验1

    ADC1配置

    1. ADC_HandleTypeDef hadc1;
    2. DMA_HandleTypeDef hdma_adc1;
    3. __IO uint32_t ADC_ConvertedValue;
    4. void MX_ADC1_Init(void)
    5. {
    6. ADC_ChannelConfTypeDef sConfig = {0};
    7. /** Common config
    8. */
    9. hadc1.Instance = ADC1;
    10. hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
    11. hadc1.Init.ContinuousConvMode = ENABLE;
    12. hadc1.Init.DiscontinuousConvMode = DISABLE;
    13. hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    14. hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    15. hadc1.Init.NbrOfConversion = 1;
    16. if (HAL_ADC_Init(&hadc1) != HAL_OK)
    17. {
    18. Error_Handler();
    19. }
    20. /** Configure Regular Channel
    21. */
    22. sConfig.Channel = ADC_CHANNEL_11;
    23. sConfig.Rank = ADC_REGULAR_RANK_1;
    24. sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
    25. if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    26. {
    27. Error_Handler();
    28. }
    29. HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&ADC_ConvertedValue, 1);
    30. }
    31. void HAL_ADC_MspInit(ADC_HandleTypeDef *adcHandle)
    32. {
    33. GPIO_InitTypeDef GPIO_InitStruct = {0};
    34. if (adcHandle->Instance == ADC1)
    35. {
    36. __HAL_RCC_ADC1_CLK_ENABLE();
    37. __HAL_RCC_GPIOC_CLK_ENABLE();
    38. /**ADC1 GPIO Configuration
    39. PC1 ------> ADC1_IN11
    40. */
    41. GPIO_InitStruct.Pin = GPIO_PIN_1;
    42. GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    43. HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    44. /* ADC1 DMA Init */
    45. /* ADC1 Init */
    46. hdma_adc1.Instance = DMA1_Channel1;
    47. hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
    48. hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
    49. hdma_adc1.Init.MemInc = DMA_MINC_DISABLE;
    50. hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    51. hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    52. hdma_adc1.Init.Mode = DMA_CIRCULAR;
    53. hdma_adc1.Init.Priority = DMA_PRIORITY_MEDIUM;
    54. if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
    55. {
    56. Error_Handler();
    57. }
    58. __HAL_LINKDMA(adcHandle, DMA_Handle, hdma_adc1);
    59. }
    60. }
    61. void HAL_ADC_MspDeInit(ADC_HandleTypeDef *adcHandle)
    62. {
    63. if (adcHandle->Instance == ADC1)
    64. {
    65. __HAL_RCC_ADC1_CLK_DISABLE();
    66. /**ADC1 GPIO Configuration
    67. PC1 ------> ADC1_IN11
    68. */
    69. HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1);
    70. /* ADC1 DMA DeInit */
    71. HAL_DMA_DeInit(adcHandle->DMA_Handle);
    72. }
    73. }
    1. /**
    2. * @brief System Clock Configuration
    3. * @retval None
    4. */
    5. void SystemClock_Config(void)
    6. {
    7. RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
    8. ...
    9. PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
    10. PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
    11. if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    12. {
    13. Error_Handler();
    14. }
    15. }

    测试环节

    1. extern __IO uint32_t ADC_ConvertedValue;
    2. float ADC_Vol;
    3. void test(void)
    4. {
    5. while (1)
    6. {
    7. HAL_Delay(1000);
    8. ADC_Vol =(float) ADC_ConvertedValue*(3.3/4096); // 读取转换的AD值
    9. printf("\r\n The current AD value = %f V \r\n", ADC_Vol);
    10. }
    11. }

    实验现象

    旋钮电位器,电压输入有变化。将PC1接到VCC,输出3.3V。

    实验3:单ADC多通道DMA

    硬件原理图和USART配置

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

    ADC1配置

    1. ____IO uint16_t ADC_ConvertedValue[6] = {0};
    2. ADC_HandleTypeDef hadc1;
    3. DMA_HandleTypeDef hdma_adc1;
    4. void MX_ADC1_Init(void)
    5. {
    6. ADC_ChannelConfTypeDef sConfig = {0};
    7. /** Common config
    8. */
    9. hadc1.Instance = ADC1;
    10. hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
    11. hadc1.Init.ContinuousConvMode = ENABLE;
    12. hadc1.Init.DiscontinuousConvMode = DISABLE;
    13. hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    14. hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    15. hadc1.Init.NbrOfConversion = 6;
    16. if (HAL_ADC_Init(&hadc1) != HAL_OK)
    17. {
    18. Error_Handler();
    19. }
    20. /** Configure Regular Channel
    21. */
    22. sConfig.Channel = ADC_CHANNEL_10;
    23. sConfig.Rank = ADC_REGULAR_RANK_1;
    24. sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
    25. if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    26. {
    27. Error_Handler();
    28. }
    29. sConfig.Channel = ADC_CHANNEL_11;
    30. sConfig.Rank = ADC_REGULAR_RANK_2;
    31. if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    32. {
    33. Error_Handler();
    34. }
    35. sConfig.Channel = ADC_CHANNEL_12;
    36. sConfig.Rank = ADC_REGULAR_RANK_3;
    37. if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    38. {
    39. Error_Handler();
    40. }
    41. sConfig.Channel = ADC_CHANNEL_13;
    42. sConfig.Rank = ADC_REGULAR_RANK_4;
    43. if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    44. {
    45. Error_Handler();
    46. }
    47. sConfig.Channel = ADC_CHANNEL_14;
    48. sConfig.Rank = ADC_REGULAR_RANK_5;
    49. if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    50. {
    51. Error_Handler();
    52. }
    53. sConfig.Channel = ADC_CHANNEL_15;
    54. sConfig.Rank = ADC_REGULAR_RANK_6;
    55. if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    56. {
    57. Error_Handler();
    58. }
    59. HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&ADC_ConvertedValue, 6);
    60. }
    61. void HAL_ADC_MspInit(ADC_HandleTypeDef *adcHandle)
    62. {
    63. GPIO_InitTypeDef GPIO_InitStruct = {0};
    64. if (adcHandle->Instance == ADC1)
    65. {
    66. __HAL_RCC_ADC1_CLK_ENABLE();
    67. __HAL_RCC_GPIOC_CLK_ENABLE();
    68. /**ADC1 GPIO Configuration
    69. PC0 ------> ADC1_IN10
    70. PC1 ------> ADC1_IN11
    71. PC2 ------> ADC1_IN12
    72. PC3 ------> ADC1_IN13
    73. PC4 ------> ADC1_IN14
    74. PC5 ------> ADC1_IN15
    75. */
    76. GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5;
    77. GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    78. HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    79. /* ADC1 DMA Init */
    80. /* ADC1 Init */
    81. hdma_adc1.Instance = DMA1_Channel1;
    82. hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
    83. hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
    84. hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
    85. hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    86. hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    87. hdma_adc1.Init.Mode = DMA_CIRCULAR;
    88. hdma_adc1.Init.Priority = DMA_PRIORITY_MEDIUM;
    89. if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
    90. {
    91. Error_Handler();
    92. }
    93. __HAL_LINKDMA(adcHandle, DMA_Handle, hdma_adc1);
    94. }
    95. }
    96. void HAL_ADC_MspDeInit(ADC_HandleTypeDef *adcHandle)
    97. {
    98. if (adcHandle->Instance == ADC1)
    99. {
    100. __HAL_RCC_ADC1_CLK_DISABLE();
    101. /**ADC1 GPIO Configuration
    102. PC0 ------> ADC1_IN10
    103. PC1 ------> ADC1_IN11
    104. PC2 ------> ADC1_IN12
    105. PC3 ------> ADC1_IN13
    106. PC4 ------> ADC1_IN14
    107. PC5 ------> ADC1_IN15
    108. */
    109. HAL_GPIO_DeInit(GPIOC, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5);
    110. /* ADC1 DMA DeInit */
    111. HAL_DMA_DeInit(adcHandle->DMA_Handle);
    112. }
    113. }
    1. /**
    2. * @brief System Clock Configuration
    3. * @retval None
    4. */
    5. void SystemClock_Config(void)
    6. {
    7. RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
    8. ...
    9. PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
    10. PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
    11. if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    12. {
    13. Error_Handler();
    14. }
    15. }

    测试环节

    1. extern __IO uint16_t ADC_ConvertedValue[6];
    2. float ADC_Vol[6];
    3. void test(void)
    4. {
    5. while(1)
    6. {
    7. HAL_Delay(1000);
    8. ADC_Vol[0] =(float) ADC_ConvertedValue[0]/4096*(float)3.3; // 读取转换的AD值
    9. ADC_Vol[1] =(float) ADC_ConvertedValue[1]/4096*(float)3.3; // 读取转换的AD值
    10. ADC_Vol[2] =(float) ADC_ConvertedValue[2]/4096*(float)3.3; // 读取转换的AD值
    11. ADC_Vol[3] =(float) ADC_ConvertedValue[3]/4096*(float)3.3; // 读取转换的AD值
    12. ADC_Vol[4] =(float) ADC_ConvertedValue[4]/4096*(float)3.3; // 读取转换的AD值
    13. ADC_Vol[5] =(float) ADC_ConvertedValue[5]/4096*(float)3.3; // 读取转换的AD值
    14. printf("ADC_CHANNEL10 value = %f V \r\n", ADC_Vol[0]);
    15. printf("ADC_CHANNEL11 value = %f V \r\n", ADC_Vol[1]);
    16. printf("ADC_CHANNEL12 value = %f V \r\n", ADC_Vol[2]);
    17. printf("ADC_CHANNEL13 value = %f V \r\n", ADC_Vol[3]);
    18. printf("ADC_CHANNEL14 value = %f V \r\n", ADC_Vol[4]);
    19. printf("ADC_CHANNEL15 value = %f V \r\n", ADC_Vol[5]);
    20. }
    21. }

    实验现象

    输出引脚悬空状态,依次将各引脚接到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配置

    1. ADC_HandleTypeDef hadc1;
    2. ADC_HandleTypeDef hadc2;
    3. DMA_HandleTypeDef hdma_adc1;
    4. void MX_ADC1_Init(void)
    5. {
    6. ADC_MultiModeTypeDef multimode = {0};
    7. ADC_ChannelConfTypeDef sConfig = {0};
    8. /** Common config
    9. */
    10. hadc1.Instance = ADC1;
    11. hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
    12. hadc1.Init.ContinuousConvMode = ENABLE;
    13. hadc1.Init.DiscontinuousConvMode = DISABLE;
    14. hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    15. hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    16. hadc1.Init.NbrOfConversion = 1;
    17. if (HAL_ADC_Init(&hadc1) != HAL_OK)
    18. {
    19. Error_Handler();
    20. }
    21. /** Configure the ADC multi-mode
    22. */
    23. multimode.Mode = ADC_DUALMODE_INTERLSLOW;
    24. if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
    25. {
    26. Error_Handler();
    27. }
    28. /** Configure Regular Channel
    29. */
    30. sConfig.Channel = ADC_CHANNEL_11;
    31. sConfig.Rank = ADC_REGULAR_RANK_1;
    32. sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
    33. if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    34. {
    35. Error_Handler();
    36. }
    37. }
    38. void MX_ADC2_Init(void)
    39. {
    40. ADC_ChannelConfTypeDef sConfig = {0};
    41. /** Common config
    42. */
    43. hadc2.Instance = ADC2;
    44. hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;
    45. hadc2.Init.ContinuousConvMode = ENABLE;
    46. hadc2.Init.DiscontinuousConvMode = DISABLE;
    47. hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    48. hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    49. hadc2.Init.NbrOfConversion = 1;
    50. if (HAL_ADC_Init(&hadc2) != HAL_OK)
    51. {
    52. Error_Handler();
    53. }
    54. /** Configure Regular Channel
    55. */
    56. sConfig.Channel = ADC_CHANNEL_11;
    57. sConfig.Rank = ADC_REGULAR_RANK_1;
    58. sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
    59. if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
    60. {
    61. Error_Handler();
    62. }
    63. }
    64. void HAL_ADC_MspInit(ADC_HandleTypeDef *adcHandle)
    65. {
    66. GPIO_InitTypeDef GPIO_InitStruct = {0};
    67. if (adcHandle->Instance == ADC1)
    68. {
    69. __HAL_RCC_ADC1_CLK_ENABLE();
    70. __HAL_RCC_GPIOC_CLK_ENABLE();
    71. /**ADC1 GPIO Configuration
    72. PC1 ------> ADC1_IN11
    73. */
    74. GPIO_InitStruct.Pin = GPIO_PIN_1;
    75. GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    76. HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    77. /* ADC1 DMA Init */
    78. /* ADC1 Init */
    79. hdma_adc1.Instance = DMA1_Channel1;
    80. hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
    81. hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
    82. hdma_adc1.Init.MemInc = DMA_MINC_DISABLE;
    83. hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    84. hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    85. hdma_adc1.Init.Mode = DMA_CIRCULAR;
    86. hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
    87. if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
    88. {
    89. Error_Handler();
    90. }
    91. __HAL_LINKDMA(adcHandle, DMA_Handle, hdma_adc1);
    92. }
    93. else if (adcHandle->Instance == ADC2)
    94. {
    95. __HAL_RCC_ADC2_CLK_ENABLE();
    96. __HAL_RCC_GPIOC_CLK_ENABLE();
    97. /**ADC2 GPIO Configuration
    98. PC1 ------> ADC2_IN11
    99. */
    100. GPIO_InitStruct.Pin = GPIO_PIN_1;
    101. GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    102. HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    103. }
    104. }
    105. void HAL_ADC_MspDeInit(ADC_HandleTypeDef *adcHandle)
    106. {
    107. if (adcHandle->Instance == ADC1)
    108. {
    109. __HAL_RCC_ADC1_CLK_DISABLE();
    110. /**ADC1 GPIO Configuration
    111. PC1 ------> ADC1_IN11
    112. */
    113. HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1);
    114. /* ADC1 DMA DeInit */
    115. HAL_DMA_DeInit(adcHandle->DMA_Handle);
    116. }
    117. else if (adcHandle->Instance == ADC2)
    118. {
    119. /* Peripheral clock disable */
    120. __HAL_RCC_ADC2_CLK_DISABLE();
    121. /**ADC2 GPIO Configuration
    122. PC1 ------> ADC2_IN11
    123. */
    124. HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1);
    125. }
    126. }
    1. /**
    2. * @brief System Clock Configuration
    3. * @retval None
    4. */
    5. void SystemClock_Config(void)
    6. {
    7. RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
    8. ...
    9. PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
    10. PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
    11. if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    12. {
    13. Error_Handler();
    14. }
    15. }

    测试环节

    1. float ADC_ConvertedValueLocal[2];
    2. uint32_t ADC_ConvertedValue;
    3. int test(void)
    4. {
    5. 初始化
    6. HAL_ADCEx_Calibration_Start(&hadc1);
    7. HAL_ADCEx_Calibration_Start(&hadc2);
    8. /* 启动AD转换并使能DMA传输和中断 */
    9. HAL_ADC_Start(&hadc2);
    10. HAL_ADCEx_MultiModeStart_DMA(&hadc1, &ADC_ConvertedValue, sizeof(ADC_ConvertedValue));
    11. while (1)
    12. {
    13. HAL_Delay(1000);
    14. // ADC1的值
    15. ADC_ConvertedValueLocal[0] = (float)(ADC_ConvertedValue & 0xFFF) * 3.3 / 4096;
    16. // ADC2的值
    17. ADC_ConvertedValueLocal[1] = (float)((ADC_ConvertedValue>>16) & 0xFFF) * 3.3 / 4096;
    18. printf("ADC1 电压值 = %f V \r\n", ADC_ConvertedValueLocal[0]);
    19. printf("ADC2 电压值 = %f V \r\n", ADC_ConvertedValueLocal[1]);
    20. }
    21. }

    实验现象

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

    1. ADC_HandleTypeDef hadc1;
    2. ADC_HandleTypeDef hadc2;
    3. DMA_HandleTypeDef hdma_adc1;
    4. void MX_ADC1_Init(void)
    5. {
    6. ADC_MultiModeTypeDef multimode = {0};
    7. ADC_ChannelConfTypeDef sConfig = {0};
    8. /** Common config
    9. */
    10. hadc1.Instance = ADC1;
    11. hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
    12. hadc1.Init.ContinuousConvMode = ENABLE;
    13. hadc1.Init.DiscontinuousConvMode = DISABLE;
    14. hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    15. hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    16. hadc1.Init.NbrOfConversion = 1;
    17. if (HAL_ADC_Init(&hadc1) != HAL_OK)
    18. {
    19. Error_Handler();
    20. }
    21. /** Configure the ADC multi-mode
    22. */
    23. multimode.Mode = ADC_DUALMODE_REGSIMULT;
    24. if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
    25. {
    26. Error_Handler();
    27. }
    28. /** Configure Regular Channel
    29. */
    30. sConfig.Channel = ADC_CHANNEL_11;
    31. sConfig.Rank = ADC_REGULAR_RANK_1;
    32. sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
    33. if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    34. {
    35. Error_Handler();
    36. }
    37. }
    38. void MX_ADC2_Init(void)
    39. {
    40. ADC_ChannelConfTypeDef sConfig = {0};
    41. /** Common config
    42. */
    43. hadc2.Instance = ADC2;
    44. hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;
    45. hadc2.Init.ContinuousConvMode = ENABLE;
    46. hadc2.Init.DiscontinuousConvMode = DISABLE;
    47. hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    48. hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    49. hadc2.Init.NbrOfConversion = 1;
    50. if (HAL_ADC_Init(&hadc2) != HAL_OK)
    51. {
    52. Error_Handler();
    53. }
    54. /** Configure Regular Channel
    55. */
    56. sConfig.Channel = ADC_CHANNEL_10;
    57. sConfig.Rank = ADC_REGULAR_RANK_1;
    58. sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
    59. if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
    60. {
    61. Error_Handler();
    62. }
    63. }
    64. void HAL_ADC_MspInit(ADC_HandleTypeDef *adcHandle)
    65. {
    66. GPIO_InitTypeDef GPIO_InitStruct = {0};
    67. if (adcHandle->Instance == ADC1)
    68. {
    69. __HAL_RCC_ADC1_CLK_ENABLE();
    70. __HAL_RCC_GPIOC_CLK_ENABLE();
    71. /**ADC1 GPIO Configuration
    72. PC1 ------> ADC1_IN11
    73. */
    74. GPIO_InitStruct.Pin = GPIO_PIN_1;
    75. GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    76. HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    77. /* ADC1 DMA Init */
    78. /* ADC1 Init */
    79. hdma_adc1.Instance = DMA1_Channel1;
    80. hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
    81. hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
    82. hdma_adc1.Init.MemInc = DMA_MINC_DISABLE;
    83. hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    84. hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    85. hdma_adc1.Init.Mode = DMA_CIRCULAR;
    86. hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
    87. if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
    88. {
    89. Error_Handler();
    90. }
    91. __HAL_LINKDMA(adcHandle, DMA_Handle, hdma_adc1);
    92. }
    93. else if (adcHandle->Instance == ADC2)
    94. {
    95. __HAL_RCC_ADC2_CLK_ENABLE();
    96. __HAL_RCC_GPIOC_CLK_ENABLE();
    97. /**ADC2 GPIO Configuration
    98. PC0 ------> ADC2_IN10
    99. */
    100. GPIO_InitStruct.Pin = GPIO_PIN_0;
    101. GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    102. HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    103. }
    104. }
    105. void HAL_ADC_MspDeInit(ADC_HandleTypeDef *adcHandle)
    106. {
    107. if (adcHandle->Instance == ADC1)
    108. {
    109. __HAL_RCC_ADC1_CLK_DISABLE();
    110. /**ADC1 GPIO Configuration
    111. PC1 ------> ADC1_IN11
    112. */
    113. HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1);
    114. /* ADC1 DMA DeInit */
    115. HAL_DMA_DeInit(adcHandle->DMA_Handle);
    116. }
    117. else if (adcHandle->Instance == ADC2)
    118. {
    119. __HAL_RCC_ADC2_CLK_DISABLE();
    120. /**ADC2 GPIO Configuration
    121. PC0 ------> ADC2_IN10
    122. */
    123. HAL_GPIO_DeInit(GPIOC, GPIO_PIN_0);
    124. }
    125. }
    1. /**
    2. * @brief System Clock Configuration
    3. * @retval None
    4. */
    5. void SystemClock_Config(void)
    6. {
    7. RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
    8. ...
    9. PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
    10. PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
    11. if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    12. {
    13. Error_Handler();
    14. }
    15. }

    测试环节

    1. float ADC_ConvertedValueLocal[2];
    2. uint32_t ADC_ConvertedValue;
    3. int test(void)
    4. {
    5. 初始化
    6. HAL_ADCEx_Calibration_Start(&hadc1);
    7. HAL_ADCEx_Calibration_Start(&hadc2);
    8. /* 启动AD转换并使能DMA传输和中断 */
    9. HAL_ADC_Start(&hadc2);
    10. HAL_ADCEx_MultiModeStart_DMA(&hadc1, &ADC_ConvertedValue, sizeof(ADC_ConvertedValue));
    11. while (1)
    12. {
    13. HAL_Delay(1000);
    14. // ADC1的值
    15. ADC_ConvertedValueLocal[0] = (float)(ADC_ConvertedValue & 0xFFF) * 3.3 / 4096;
    16. // ADC2的值
    17. ADC_ConvertedValueLocal[1] = (float)((ADC_ConvertedValue>>16) & 0xFFF) * 3.3 / 4096;
    18. printf("ADC1 电压值 = %f V \r\n", ADC_ConvertedValueLocal[0]);
    19. printf("ADC2 电压值 = %f V \r\n", ADC_ConvertedValueLocal[1]);
    20. }
    21. }

    实验现象

    依次将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配置

     

    1. ADC_HandleTypeDef hadc1;
    2. DMA_HandleTypeDef hdma_adc1;
    3. void MX_ADC1_Init(void)
    4. {
    5. ADC_ChannelConfTypeDef sConfig = {0};
    6. /** Common config
    7. */
    8. hadc1.Instance = ADC1;
    9. hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
    10. hadc1.Init.ContinuousConvMode = ENABLE;
    11. hadc1.Init.DiscontinuousConvMode = DISABLE;
    12. hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    13. hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    14. hadc1.Init.NbrOfConversion = 1;
    15. if (HAL_ADC_Init(&hadc1) != HAL_OK)
    16. {
    17. Error_Handler();
    18. }
    19. /** Configure Regular Channel
    20. */
    21. sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
    22. sConfig.Rank = ADC_REGULAR_RANK_1;
    23. sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
    24. if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    25. {
    26. Error_Handler();
    27. }
    28. }
    29. void HAL_ADC_MspInit(ADC_HandleTypeDef *adcHandle)
    30. {
    31. if (adcHandle->Instance == ADC1)
    32. {
    33. __HAL_RCC_ADC1_CLK_ENABLE();
    34. /* ADC1 DMA Init */
    35. /* ADC1 Init */
    36. hdma_adc1.Instance = DMA1_Channel1;
    37. hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
    38. hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
    39. hdma_adc1.Init.MemInc = DMA_MINC_DISABLE;
    40. hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    41. hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    42. hdma_adc1.Init.Mode = DMA_CIRCULAR;
    43. hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
    44. if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
    45. {
    46. Error_Handler();
    47. }
    48. __HAL_LINKDMA(adcHandle, DMA_Handle, hdma_adc1);
    49. }
    50. }
    51. void HAL_ADC_MspDeInit(ADC_HandleTypeDef *adcHandle)
    52. {
    53. if (adcHandle->Instance == ADC1)
    54. {
    55. __HAL_RCC_ADC1_CLK_DISABLE();
    56. /* ADC1 DMA DeInit */
    57. HAL_DMA_DeInit(adcHandle->DMA_Handle);
    58. }
    59. }

    测试环节

    1. #define V25 0x6EE // 对于12位的ADC,3.3V的ADC值为0xfff,温度为25度时对应的电压值为1.43V即0x6EE
    2. #define AVG_SLOPE 0x05 // 斜率,每摄氏度4.3mV,对应每摄氏度0x05
    3. __IO uint16_t Current_Temperature;
    4. uint16_t ADC_ConvertedValue;
    5. void test(void)
    6. {
    7. 初始化
    8. HAL_ADCEx_Calibration_Start(&hadc1);
    9. HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&ADC_ConvertedValue, 1); /* 启动AD转换并使能DMA传输和中断 */
    10. while(1)
    11. {
    12. HAL_Delay(1000);
    13. Current_Temperature = ( V25 - ADC_ConvertedValue ) / AVG_SLOPE + 25;
    14. printf("\r\n The IC current temp = %3d 摄氏度\r\n", Current_Temperature);
    15. }
    16. }

    实验现象

  • 相关阅读:
    Mysql加锁流程详解
    综述---知识蒸馏
    openharmony容器组件之Grid
    ubuntu下基于systemctl的守护进程编写
    C++赋值函数,为什么通常需要返回类的引用
    【译】使用保留大小写的查找和替换来保存您的命名方式
    迷你内裤洗衣机排名前十名:2024年十大口碑一流内衣洗衣机推荐
    Spring是如何管理事务的?@Transactional注解详解
    Excel表格如何设置成不可编辑的模式?
    注解及其使用
  • 原文地址:https://blog.csdn.net/weixin_47077788/article/details/133989958