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

STM32F429 双通道AD转换采集纯软件查询非中断和DMA方式

[复制链接]
STMCU-管管 发布时间:2020-9-30 09:47

非中断和非DMA方式可以用于特殊场景,比如其它外设占据DMA负担比较重而CPU又比较清闲的时候。


1. STM32F429的AD转换最高12bit
12位分辨率意味着我们采集电压的精度可以达到:Vref /4096。
采集电压 = Vref * ADC_DR / 4096;
Vref:参考电压
ADC_DR:读取到ADC数据寄存器的值
一般使用3.3V为参考电压,则采集到的电压 = ADC_DR*3.3/4096 。



2. STM32F4的ADC转换不需要做程序校准。
这在HAL库里也可以看出来,官方没有HAL_ADCEx_Calibration_Start();这个校准函数。



3. STM32F4的ADC时钟最大36M。
STM32F1为14M,STM32F4快了2倍多。



4. 两个以上通道必须开启scan扫描模式。
ADC_ScanConvMode = ENABLE。
因为转换结果都在同一个寄存器里,所以单个通道转换完成后必须读走数据再启动转换下一个通道。



5. 不使用DMA不需要开连续方式。
ADC_ContinuousConvMode = DISABLE。
连续转换ENABLE后,也就是只需要启动(触发)转换一次,后面就不用再次启动(触发)就可以连续工作了。
单次转换DISABLE:也就是根据一次转换完后需要再次启动(触发)才能工作。



6. 触发方式一般选用软件触发。


7. 对齐方式一般选右对齐。


8. 通道数就是你要转换的通道数量

通道数要和后面的规格组相符合。



9. 设置规则组通道
下面例子是设置 channel5 和 channel8连个通道,开启触发AD转换后,通道5是首先转换的,转换完成后,再次触发转换,就会自动转换通道8。一轮完成后,不需要STOP ADC,可以直接再次触发转换,此时又回到了转换通道5,开始新的循环。

  
  1.   /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  2.    */
  3. sConfig.Channel = ADC_CHANNEL_5;
  4. sConfig.Rank = 1;
  5. sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
  6. if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  7. {
  8.    _Error_Handler(__FILE__, __LINE__);
  9. }

  10.    /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  11.    */
  12. sConfig.Channel = ADC_CHANNEL_8;
  13. sConfig.Rank = 2;
  14. if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  15. {
  16.    _Error_Handler(__FILE__, __LINE__);
  17. }
复制代码

10. 规则组间断模式配置。

如果不使用DMA,这里必须要配置为1,也就是说每触发一次转换一条通道。否则,结果寄存器里只会是本组最后一次转换的通道电压值。具体可以看下图: 20200912230507328.png




11. 其他ADC的基础配置见下面程序代码。


例子中单片机型号为STM32F429VIT6,代码全部经过实测,通过算法滤波,转换精度足够平常使用。而且有人提出多个通道之间会有干扰,此例未发现。选用的未PA5(ADC channel5)和PB0(ADC channel8)两个通道。



一、ADC配置

  1. /* ADC1 init function */
  2. void MX_ADC1_Init(void)
  3. {
  4.   ADC_ChannelConfTypeDef sConfig;

  5.     /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
  6.     */
  7.   hadc1.Instance = ADC1;
  8.   hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
  9.   hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  10.   hadc1.Init.ScanConvMode = ENABLE;
  11.   hadc1.Init.ContinuousConvMode = DISABLE;
  12.   hadc1.Init.DiscontinuousConvMode = ENABLE;
  13.   hadc1.Init.NbrOfDiscConversion = 1;
  14.   hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  15.   hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  16.   hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  17.   hadc1.Init.NbrOfConversion = 2;
  18.   hadc1.Init.DMAContinuousRequests = DISABLE;
  19.   hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  20.   if (HAL_ADC_Init(&hadc1) != HAL_OK)
  21.   {
  22.     _Error_Handler(__FILE__, __LINE__);
  23.   }

  24.     /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  25.     */
  26.   sConfig.Channel = ADC_CHANNEL_5;
  27.   sConfig.Rank = 1;
  28.   sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
  29.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  30.   {
  31.     _Error_Handler(__FILE__, __LINE__);
  32.   }

  33.     /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
  34.     */
  35.   sConfig.Channel = ADC_CHANNEL_8;
  36.   sConfig.Rank = 2;
  37.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  38.   {
  39.     _Error_Handler(__FILE__, __LINE__);
  40.   }

  41. }

  42. void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
  43. {

  44.   GPIO_InitTypeDef GPIO_InitStruct;
  45.   if(adcHandle->Instance==ADC1)
  46.   {
  47.   /* USER CODE BEGIN ADC1_MspInit 0 */

  48.   /* USER CODE END ADC1_MspInit 0 */
  49.     /* ADC1 clock enable */
  50.     __HAL_RCC_ADC1_CLK_ENABLE();

  51.     /**ADC1 GPIO Configuration
  52.     PA5     ------> ADC1_IN5
  53.     PB0     ------> ADC1_IN8
  54.     */
  55.     GPIO_InitStruct.Pin = GPIO_PIN_5;
  56.     GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  57.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  58.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  59.     GPIO_InitStruct.Pin = GPIO_PIN_0;
  60.     GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  61.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  62.     HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  63.   /* USER CODE BEGIN ADC1_MspInit 1 */

  64.   /* USER CODE END ADC1_MspInit 1 */
  65.   }
  66. }
复制代码

二、滤波算法处理

  1. uint16_t adc_values_ch5[14] = {0};
  2. uint16_t adc_values_ch8[14] = {0};

  3. /*进行单次AD转换,50ms超时*/
  4. uint32_t Perform_single_AD_conversion(void)
  5. {
  6.         HAL_ADC_Start(&hadc1);
  7.         HAL_ADC_PollForConversion(&hadc1, 50);
  8.         uint8_t i=255;
  9.         while (!HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
  10.         {
  11.                 i--;
  12.                 if (i ==0)
  13.                 {
  14.                         break;   //防止AD死循环
  15.                 }
  16.         }
  17.         uint32_t ad_Temp = HAL_ADC_GetValue(&hadc1);
  18.         return ad_Temp;
  19. }

  20. /*对14次采样的电压按照从小到大进行排序*/
  21. void Sort_ADC_Values(uint16_t *adc_nums)
  22. {
  23.         int i, j, temp, isSorted;  
  24.         //优化算法:最多进行 n-1 轮比较
  25.         for(i=0; i<14-1; i++)
  26.         {
  27.                 isSorted = 1;  //假设剩下的元素已经排序好了
  28.                 for(j=0; j<14-1-i; j++)
  29.                 {
  30.                         if(adc_nums[j] > adc_nums[j+1])
  31.                         {
  32.                                 temp = adc_nums[j];
  33.                                 adc_nums[j] = adc_nums[j+1];
  34.                                 adc_nums[j+1] = temp;
  35.                                 isSorted = 0;  //一旦需要交换数组元素,就说明剩下的元素没有排序好
  36.                         }
  37.                 }
  38.                 if(isSorted) break; //如果没有发生交换,说明剩下的元素已经排序好了
  39.         }       
  40. }
  41. /*去掉2个最大值,2个最小值,剩余10个值求平均数*/
  42. uint16_t Find_Average_ADC_Values(uint16_t *adc_nums)
  43. {
  44.         uint16_t sum = 0;
  45.         for(uint8_t i=2; i<12; i++)
  46.         {
  47.                 sum = sum + adc_nums[i];
  48.         }
  49.         return sum/10;
  50. }

  51. /*软件滤波求出ADC转换平均值*/
  52. uint16_t Software_filtering_ADC(uint16_t *adc_nums)
  53. {
  54.         uint16_t adc_avg = 0;
  55.         Sort_ADC_Values(adc_nums);
  56.         adc_avg = Find_Average_ADC_Values(adc_nums);
  57.         return adc_avg;
  58. }

  59. void Get_Two_Channel_ADC_Votage(void)  
  60. {  
  61.         float votage = 0.0;
  62.         for(uint8_t i=0; i<14; i++)
  63.         {
  64.                 adc_values_ch5[i] = Perform_single_AD_conversion();
  65.                 printf("\r\nadc_values_ch5[%d] = %d\r\n", i,adc_values_ch5[i]);
  66.                 adc_values_ch8[i] = Perform_single_AD_conversion();
  67.                 printf("\r\nadc_values_ch8[%d] = %d\r\n", i,adc_values_ch8[i]);
  68.         }
  69.         HAL_ADC_Stop(&hadc1);

  70.         votage = Software_filtering_ADC(adc_values_ch5)*3.3/4096;
  71.         printf("\r\nPA5采集电压: %f \r\n",votage);
  72.        
  73.         votage = Software_filtering_ADC(adc_values_ch8)*3.3/4096;
  74.         printf("\r\nPB0采集电压: %f \r\n",votage);          
  75. }
复制代码

三、打印输出结果
在main函数的主循环while里调用Get_Two_Channel_ADC_Votage(),即可输出打印结果。

  1. int main(void)
  2. {
  3.   /* USER CODE BEGIN 1 */

  4.   /* USER CODE END 1 */

  5.   /* MCU Configuration----------------------------------------------------------*/

  6.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  7.   HAL_Init();

  8.   /* USER CODE BEGIN Init */

  9.   /* USER CODE END Init */

  10.   /* Configure the system clock */
  11.   SystemClock_Config();

  12.   /* USER CODE BEGIN SysInit */

  13.   /* USER CODE END SysInit */

  14.   /* Initialize all configured peripherals */
  15.   MX_GPIO_Init();
  16.   MX_DMA_Init();  
  17.   MX_IWDG_Init();
  18.   MX_ADC1_Init();
  19.   MX_USART1_UART_Init();
  20.   /* Infinite loop */
  21.   /* USER CODE BEGIN WHILE */
  22.   while (1)
  23.   {
  24.         Get_Two_Channel_ADC_Votage();   
  25.         HAL_Delay(2000);       
  26.   /* USER CODE END WHILE */

  27.   /* USER CODE BEGIN 3 */          
  28.          HAL_IWDG_Refresh(&hiwdg);   //看门狗喂狗
  29.   }
  30.   /* USER CODE END 3 */
  31. }
复制代码


2020091223204561.png

收藏 评论0 发布时间:2020-9-30 09:47

举报

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