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

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个回答

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似技术帖

官网相关资源

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