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

关于STM32F103RET6 的ADC接口会输出200多mv的电压以及在工作中会输出低电平脉冲(频率是采样频率)的问题

[复制链接]
动于九天之上 提问时间:2023-4-10 10:18 / 未解决

``用单片机采集分压电阻过来的电压值,在调试期间,发现初始化完IO口后,ADC输入IO口的电压会上浮200mv左右,开始ADC采集时,会出现低电平脉冲,频率是ADC的采集频率,即35.7K。同时,采集到的电压值也不准确,不同电压值,ADC输出口上浮的电压不同。采集到的电压值和实际值偏差也不是固定,感觉有一个关系。

程序上是采用ADC+DMA的采集方式,数据是通过半传输完成这中断+传输完成中断里得到的,每次采集100个数据(数组)。一直连续采集500ms后停止,找出这一阶段中采集到的最大值。

程序如下

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "adc.h"

/* USER CODE BEGIN 0 */
#include "tim.h"
uint16_t adc_data[100]= {0};
/* USER CODE END 0 */

ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;

/* ADC1 init function */
void MX_ADC1_Init(void)
{

  /* USER CODE BEGIN ADC1_Init 0 */

  /* USER CODE END ADC1_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC1_Init 1 */

  /* USER CODE END ADC1_Init 1 */

  /** 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_14;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */

    //HAL_ADCEx_Calibration_Start(&hadc1);
  /* USER CODE END ADC1_Init 2 */

}

void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(adcHandle->Instance==ADC1)
  {
  /* USER CODE BEGIN ADC1_MspInit 0 */
      GPIO_InitStruct.Pull = GPIO_NOPULL;
      GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  /* USER CODE END ADC1_MspInit 0 */
    /* ADC1 clock enable */
    __HAL_RCC_ADC1_CLK_ENABLE();

    __HAL_RCC_GPIOC_CLK_ENABLE();
    /**ADC1 GPIO Configuration
    PC4     ------> ADC1_IN14
    */
    GPIO_InitStruct.Pin = GPIO_PIN_4;
    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_LOW;
    if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);

    /* ADC1 interrupt Init */
    HAL_NVIC_SetPriority(ADC1_2_IRQn, 2, 2);
    HAL_NVIC_EnableIRQ(ADC1_2_IRQn);
  /* USER CODE BEGIN ADC1_MspInit 1 */

    __HAL_DMA_DISABLE_IT(&hdma_adc1,DMA_IT_TC | DMA_IT_HT);
  //  HAL_DMA_RegisterCallback(&hdma_adc1, HAL_DMA_XFER_CPLT_CB_ID, ADCDataCollect_DmaCplCb);
  //  HAL_DMA_RegisterCallback(&hdma_adc1, HAL_DMA_XFER_HALFCPLT_CB_ID, ADCDataCollect_DmaHalfCplCb);
  /* USER CODE END ADC1_MspInit 1 */
  }
}

void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
{

  if(adcHandle->Instance==ADC1)
  {
  /* USER CODE BEGIN ADC1_MspDeInit 0 */

  /* USER CODE END ADC1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_ADC1_CLK_DISABLE();

    /**ADC1 GPIO Configuration
    PC4     ------> ADC1_IN14
    */
    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_4);

    /* ADC1 DMA DeInit */
    HAL_DMA_DeInit(adcHandle->DMA_Handle);

    /* ADC1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(ADC1_2_IRQn);
  /* USER CODE BEGIN ADC1_MspDeInit 1 */

  /* USER CODE END ADC1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
/**
  * @brief 鍚姩ADC+DMA浼犺緭
  * @retval None
  */
void ADC1Star(void)
{
    //HAL_ADCEx_Calibration_Start(&hadc1);
    //HAL_Delay(100);
    HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
    HAL_NVIC_EnableIRQ(ADC1_2_IRQn);
    __HAL_DMA_ENABLE_IT(&hdma_adc1, DMA_IT_TE | DMA_IT_TC);
    HAL_ADC_Start_DMA(&hadc1,(uint32_t*)adc_data,100);

}
/**
  * @brief 鍏抽棴ADC+DMA浼犺緭
  * @retval None
  */
void ADC1Stop(void)
{
    HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn);
    HAL_NVIC_DisableIRQ(ADC1_2_IRQn);
     __HAL_DMA_CLEAR_FLAG(&hdma_adc1, __HAL_DMA_GET_HT_FLAG_INDEX(&hdma_adc1));
     __HAL_DMA_CLEAR_FLAG(&hdma_adc1, __HAL_DMA_GET_TC_FLAG_INDEX(&hdma_adc1));
    __HAL_DMA_DISABLE_IT(&hdma_adc1, DMA_IT_TE | DMA_IT_TC);
    HAL_ADC_Stop_DMA(&hadc1);
    //HAL_ADC_MspDeInit(&hadc1);
}
/**
  * @brief DMA半传输完成中断
  * @retval None
  */
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{
    uint8_t i;

    if(__HAL_TIM_GET_COUNTER(&htim1) < 4920)
    {
        for(i = 0;i<50;i++)
        {
            if(adc_data[i] > S_GLOBAL_VARIBLE.ultrasonic_ADC_DATA)
            {
                S_GLOBAL_VARIBLE.ultrasonic_ADC_DATA = adc_data[i];//找出最大值
            }
        }
    }

    //__HAL_DMA_ENABLE_IT(&hdma_adc1,DMA_IT_TC);    //启动全传输完成中断

}
/**
  * @brief DMA全传输完成中断
  * @retval None
  */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    uint8_t i;
    if(__HAL_TIM_GET_COUNTER(&htim1) < 4920)
    {
        for(i = 50;i<100;i++)
        {
            if(adc_data[i] > S_GLOBAL_VARIBLE.ultrasonic_ADC_DATA)
            {
                S_GLOBAL_VARIBLE.ultrasonic_ADC_DATA = adc_data[i];//找到最大值
            }
        }
    }

        //__HAL_DMA_ENABLE_IT(&hdma_adc1,DMA_IT_HT);//启动半传输完成中断
}
/* USER CODE END 1 */
收藏 评论7 发布时间:2023-4-10 10:18

举报

7个回答
动于九天之上 回答时间:2023-4-10 10:22:24

微信图片_20230410101908.jpg

单片机实际测试电压为0.95~1V这样

动于九天之上 回答时间:2023-4-10 10:23:23

微信图片_20230410101908.jpg

单片机实际测到电压值为300mV左右

butterflyspring 回答时间:2023-4-10 17:35:30
楼主是要采集这个低脉冲的波形么?
ADC 硬件线路与ADC的采样频率有很大关系,保证ADC的采样电容充放电时间合理与采样频率需要平衡。
另外外部信号如果是高阻抗的信号,这时候有可能ADC的开关动作会对外部的弱信号产生一点影响(示波器看到快关脉冲频率),如果不影响结果就没问题,否则需要调整采样时间或外部线路。
动于九天之上 回答时间:2023-4-11 11:20:26

butterflyspring 发表于 2023-4-10 17:35
楼主是要采集这个低脉冲的波形么?
ADC 硬件线路与ADC的采样频率有很大关系,保证ADC的采样电容充放电时间 ...

根据波形看 低电平的位置才是正确的电压值,如果我调节采样频率 采样频率最快的情况下 ,还是有脉冲,只是从高电平占大多数变成了低电平占大多数,而且高电平的电压值有所下降,但是这样还不够,我还需要如何修改我的电路呢?是加一个RC滤波还是加一个运放跟随器?我需要采集低电平的电压值,那个才是我想要的,因为我的信号中,会有一个很高的脉冲信息,这个脉冲信息的最高值才是我想要的。但是我现在还没有接入到脉冲发生的电路,只是用两个可调电阻分压来测试我的ADC,就看到现在这样的波形。

而且我发现,我只要打开电路板上的DCDC开关电源给我的模拟芯片供电,就会出现这个情况,如果不打开DCDC给模拟芯片供电,就不会出现这个情况,可是我已经把脉冲发生电路断开,用两个可调电阻分压来测试ADC了 分压电阻的输入电源是DCDC的输入电源。

所以我这个还需要如何改进吗?谢谢

butterflyspring 回答时间:2023-4-12 11:01:13
动于九天之上 发表于 2023-4-11 11:20
[md]根据波形看 低电平的位置才是正确的电压值,如果我调节采样频率 采样频率最快的情况下 ,还是有脉冲 ...

1. 楼主首先确定需要采集的信号中是否有来自DC-DC的噪声。
2. 如果要采集低脉冲波形,那么ADC的采样转换频率要超过低脉冲的频率才有可能采集的到。
3.  ADC的采样转换频率高了之后,还要看看采样时间。之前提到过,收到电容和阻抗影响(时间常数),充放电时间要足够,
     这与提高ADC频率成反比,所以需要平衡。
4.  分压电阻过大,导致输出阻抗变大,充放电时间过长,因此可以试试减小分压电阻看看。ADC内部的采样电容如果充放电不够,必然导致结果不准确。

动于九天之上 回答时间:2023-4-12 14:19:29

butterflyspring 发表于 2023-4-12 11:01</p>
<ol>
<li>楼主首先确定需要采集的信号中是否有来自DC-DC的噪声。</li>
<li>如果要采集低脉冲波形,那么ADC的采样转换 ...

1、我尝试把DCDC关掉,虽然这个脉冲的幅值有所减小,但是还在,且影响采集精度,ADC会采集到高电平的电压值。

2、我搭建过电压跟随器,应该可以让ADC接口阻抗匹配把?但是搭建电压跟随器也是一样的波形,采集的幅值也是高电平的电压值。

3、低电平脉冲波形随着幅值的增大而增大。电压越大,脉冲的幅值越大。

4、同样的程序,换到另外一个电路板上,用10K可调电阻分压,没有跟随器,有开DCDC,虽然也会出现那个脉冲,但是不影响采集精度,采集到的是低电平的电压值,也就是程序是没问题的,无论是多少采样时间。

以上现象不知如何解决呢?谢谢~

butterflyspring 回答时间:2023-4-13 14:30:13
楼主还是先考虑好对于高内阻信号下采样时间与充放电的关系。下面有两张截图能说明这个重要性。
考虑好这个关系就好调整软硬件了。
ADC sample time 1.png ADC sample time 2.png

所属标签

相似问题

官网相关资源

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