你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32G070的ADC多通道采集讲解

[复制链接]
STMCU-管管 发布时间:2021-6-18 17:13
本文讲述基于STM32G070进行ADC多通道采集,并分别介绍非DMA方式和DMA方式。
1. 非DMA方式采集
ADC初始化代码如下(使用STM32CubeMx自动生成),配置了3个通道:


  1. static void MX_ADC1_Init(void)
  2. {

  3.   /* USER CODE BEGIN ADC1_Init 0 */

  4.   /* USER CODE END ADC1_Init 0 */

  5.   ADC_ChannelConfTypeDef sConfig = {0};

  6.   /* USER CODE BEGIN ADC1_Init 1 */

  7.   /* USER CODE END ADC1_Init 1 */
  8.   /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
  9.   */
  10.   hadc1.Instance = ADC1;
  11.   hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
  12.   hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  13.   hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  14.   hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  15.   hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  16.   hadc1.Init.LowPowerAutoWait = DISABLE;
  17.   hadc1.Init.LowPowerAutoPowerOff = DISABLE;
  18.   hadc1.Init.ContinuousConvMode = DISABLE;
  19.   hadc1.Init.NbrOfConversion = 3;
  20.   hadc1.Init.DiscontinuousConvMode = ENABLE;
  21.   hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  22.   hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  23.   hadc1.Init.DMAContinuousRequests = DISABLE;
  24.   hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  25.   hadc1.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_1CYCLE_5;
  26.   hadc1.Init.SamplingTimeCommon2 = ADC_SAMPLETIME_1CYCLE_5;
  27.   hadc1.Init.OversamplingMode = DISABLE;
  28.   hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;
  29.   if (HAL_ADC_Init(&hadc1) != HAL_OK)
  30.   {
  31.     Error_Handler();
  32.   }
  33.   /** Configure Regular Channel
  34.   */
  35.   sConfig.Channel = ADC_CHANNEL_4;
  36.   sConfig.Rank = ADC_REGULAR_RANK_1;
  37.   sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1;
  38.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  39.   {
  40.     Error_Handler();
  41.   }
  42.   /** Configure Regular Channel
  43.   */
  44.   sConfig.Channel = ADC_CHANNEL_5;
  45.   sConfig.Rank = ADC_REGULAR_RANK_2;
  46.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  47.   {
  48.     Error_Handler();
  49.   }
  50.   /** Configure Regular Channel
  51.   */
  52.   sConfig.Channel = ADC_CHANNEL_9;
  53.   sConfig.Rank = ADC_REGULAR_RANK_3;
  54.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  55.   {
  56.     Error_Handler();
  57.   }
  58.   /* USER CODE BEGIN ADC1_Init 2 */

  59.   /* USER CODE END ADC1_Init 2 */

  60. }
复制代码
获取ADC数据
  1. // 校准
  2. HAL_ADCEx_Calibration_Start(&hadc1);

  3. for (idx = 0; idx < 3; idx++)
  4. {
  5.     HAL_ADC_Start(&hadc1);
  6.     HAL_ADC_PollForConversion(&hadc1, 50);

  7.     /* Check if the continous conversion is finished */
  8.     if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
  9.     {
  10.         /* Get the converted value */
  11.         AD_Value[idx] = HAL_ADC_GetValue(&hadc1);
  12.     }
  13. }

  14. HAL_ADC_Stop(&hadc1);
复制代码
1.1 关于ADC扫描定序(scan sequencer)
ADC scan sequencer can be used in two different modes. 配置ADC多通道采集时,对于各个通道的采集顺序有两种方式:


Sequencer fully configurable (The order in which the channels are scanned is independent from the channel number)
采用这种方式时,ADC的通道扫描顺序将和channel number不再相关,如1中代码,就采用了这种方式
  1. //扫描方式:ADC_SCAN_ENABLE
  2. hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  3. //...
  4. sConfig.Channel = ADC_CHANNEL_5;
  5. sConfig.Rank = ADC_REGULAR_RANK_2;
  6. if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  7. {
  8.     Error_Handler();
  9. }

  10. sConfig.Channel = ADC_CHANNEL_6;
  11. sConfig.Rank = ADC_REGULAR_RANK_1;
  12. if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  13. {
  14.     Error_Handler();
  15. }
复制代码
如果按照如上代码配置,在采集时,将先采集channel 6,再采集channel 5。但是使用该方式时,需要注意Only channel 0 to channel 14 can be selected in this sequence。即channel 15/16/17/18无法使用该方式,如果需要使用channel 15-18,则可以使用下面第二种扫描方式。


Sequencer not fully configurable (The order in which the channels are scanned is defined by the channel number)
这种方式比较好理解,就是按照channel number的大小,按顺序进行扫描,配置代码如下:
  1. // 扫描方式:ADC_SCAN_SEQ_FIXED
  2. hadc1.Init.ScanConvMode = ADC_SCAN_SEQ_FIXED;

  3. sConfig.Channel = ADC_CHANNEL_16;
  4. sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
  5. if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  6. {
  7.     Error_Handler();
  8. }
复制代码
2. DMA方式采集
直接上代码:
  1. static void MX_ADC1_Init(void)
  2. {

  3.   /* USER CODE BEGIN ADC1_Init 0 */

  4.   /* USER CODE END ADC1_Init 0 */

  5.   ADC_ChannelConfTypeDef sConfig = {0};

  6.   /* USER CODE BEGIN ADC1_Init 1 */

  7.   /* USER CODE END ADC1_Init 1 */
  8.   /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
  9.   */
  10.   hadc1.Instance = ADC1;
  11.   hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  12.   hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  13.   hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  14.   hadc1.Init.ScanConvMode = ADC_SCAN_SEQ_FIXED;
  15.   hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  16.   hadc1.Init.LowPowerAutoWait = DISABLE;
  17.   hadc1.Init.LowPowerAutoPowerOff = DISABLE;
  18.   hadc1.Init.ContinuousConvMode = ENABLE;
  19.   hadc1.Init.DiscontinuousConvMode = DISABLE;
  20.   hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  21.   hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  22.   hadc1.Init.DMAContinuousRequests = ENABLE;
  23.   hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
  24.   hadc1.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_12CYCLES_5;
  25.   hadc1.Init.OversamplingMode = DISABLE;
  26.   hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;
  27.   if (HAL_ADC_Init(&hadc1) != HAL_OK)
  28.   {
  29.     Error_Handler();
  30.   }
  31.   /** Configure Regular Channel
  32.   */
  33.   sConfig.Channel = ADC_CHANNEL_4;
  34.   sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
  35.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  36.   {
  37.     Error_Handler();
  38.   }
  39.   /** Configure Regular Channel
  40.   */
  41.   sConfig.Channel = ADC_CHANNEL_5;
  42.   sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
  43.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  44.   {
  45.     Error_Handler();
  46.   }
  47.   /** Configure Regular Channel
  48.   */
  49.   sConfig.Channel = ADC_CHANNEL_9;
  50.   sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
  51.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  52.   {
  53.     Error_Handler();
  54.   }
  55.   /** Configure Regular Channel
  56.   */
  57.   sConfig.Channel = ADC_CHANNEL_10;
  58.   sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
  59.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  60.   {
  61.     Error_Handler();
  62.   }
  63.   /** Configure Regular Channel
  64.   */
  65.   sConfig.Channel = ADC_CHANNEL_16;
  66.   sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
  67.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  68.   {
  69.     Error_Handler();
  70.   }
  71.   /* USER CODE BEGIN ADC1_Init 2 */

  72.   /* USER CODE END ADC1_Init 2 */

  73. }

  74. static void MX_DMA_Init(void)
  75. {

  76.   /* DMA controller clock enable */
  77.   __HAL_RCC_DMA1_CLK_ENABLE();

  78.   /* DMA interrupt init */
  79.   /* DMA1_Channel1_IRQn interrupt configuration */
  80.   HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
  81.   HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);

  82. }

  83. void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
  84. {
  85.   GPIO_InitTypeDef GPIO_InitStruct = {0};
  86.   if(hadc->Instance==ADC1)
  87.   {
  88.   /* USER CODE BEGIN ADC1_MspInit 0 */

  89.   /* USER CODE END ADC1_MspInit 0 */
  90.     /* Peripheral clock enable */
  91.     __HAL_RCC_ADC_CLK_ENABLE();

  92.     __HAL_RCC_GPIOA_CLK_ENABLE();
  93.     __HAL_RCC_GPIOB_CLK_ENABLE();
  94.     /**ADC1 GPIO Configuration
  95.     PA4     ------> ADC1_IN4
  96.     PA5     ------> ADC1_IN5
  97.     PB1     ------> ADC1_IN9
  98.     PB2     ------> ADC1_IN10
  99.     PB12     ------> ADC1_IN16
  100.     */
  101.     GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5;
  102.     GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  103.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  104.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  105.     GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_12;
  106.     GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  107.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  108.     HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  109.     /* ADC1 DMA Init */
  110.     /* ADC1 Init */
  111.     hdma_adc1.Instance = DMA1_Channel1;
  112.     hdma_adc1.Init.Request = DMA_REQUEST_ADC1;
  113.     hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
  114.     hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
  115.     hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
  116.     hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
  117.     hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
  118.     hdma_adc1.Init.Mode = DMA_CIRCULAR;
  119.     hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;
  120.     if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
  121.     {
  122.       Error_Handler();
  123.     }

  124.     __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc1);

  125.   /* USER CODE BEGIN ADC1_MspInit 1 */

  126.   /* USER CODE END ADC1_MspInit 1 */
  127.   }

  128. }
复制代码
初始化完成后,即可使用:
  1. //开始ADC转换
  2. HAL_ADCEx_Calibration_Start(&hadc1);
  3. HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&AD_Value_Buffer, AD_DMA_BUFF_LENGTH);
复制代码
注:AD_Value_Buffer为事先定义好的数组,长度为AD_DMA_BUFF_LENGTH
接下来,无需CPU参与,DMA将会把ADC采集到数据搬运至AD_Value_Buffer的地址中,当长度达到AD_DMA_BUFF_LENGTH时,将从头开始,此时会覆盖数据。







收藏 1 评论0 发布时间:2021-6-18 17:13

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版