硬汉嵌入式论坛

 找回密码
 立即注册
查看: 185|回复: 5
收起左侧

[有问必答] STM32F407ADC采样有点飘

[复制链接]

4

主题

26

回帖

38

积分

新手上路

积分
38
发表于 2025-7-30 22:39:41 | 显示全部楼层 |阅读模式
各位大佬,麻烦帮忙看一下为啥我的F407采样这么飘,也添加了滤波。REF电源用的REF3025。


ADC的配置如下:
[C] 纯文本查看 复制代码


#define  ADC_TRANSFORM_NUM   (3) //ADC转换次数
#define  ADC_CHANNEL_NUM    (4) //ADC通道数目


 uint8_t ADC1_ConvertStartFlag = ADC_CONVERT_END;
uint16_t g_usInChipAdcChannelAverageValue[ADC_CHANNEL_NUM];
uint16_t uhADCConvertedValue[ADC_TRANSFORM_NUM][ADC_CHANNEL_NUM];
 

/*初始化部分*/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能ADC1时钟


DMA_InitStructure.DMA_Channel             = DMA_Channel_0;
	DMA_InitStructure.DMA_MemoryBurst         = DMA_MemoryBurst_Single;			    //非 burst 模式
	DMA_InitStructure.DMA_PeripheralBurst     = DMA_PeripheralBurst_Single;         //非 burst 模式
	DMA_InitStructure.DMA_Priority            = DMA_Priority_High;                  //DMA通道 x拥有高优先级
	DMA_InitStructure.DMA_PeripheralDataSize  = DMA_PeripheralDataSize_HalfWord;    //外设端单次 Single 传输数据大小为 16 bits。
	DMA_InitStructure.DMA_MemoryDataSize      = DMA_MemoryDataSize_HalfWord;        //内存端单次 Single 传输数据大小为 16 bits。
	DMA_InitStructure.DMA_PeripheralInc       = DMA_PeripheralInc_Disable;			//外设地址递增禁止
	DMA_InitStructure.DMA_MemoryInc           = DMA_MemoryInc_Enable;			    //内存地址递增使能
	DMA_InitStructure.DMA_Mode                = DMA_Mode_Circular;				    //NDTR归零后自动重装。可以在中断中结束ADC采样,下次启动转换不用初始化DMA。
	DMA_InitStructure.DMA_DIR                 = DMA_DIR_PeripheralToMemory;         //数据传输方向,从外设ADC发送到内存读取
	DMA_InitStructure.DMA_FIFOMode            = DMA_FIFOMode_Disable;			    //使用 direct 模式,禁用 FIFO
	DMA_InitStructure.DMA_FIFOThreshold       = DMA_FIFOThreshold_HalfFull;     
	DMA_InitStructure.DMA_BufferSize          = ADC_TRANSFORM_NUM * ADC_CHANNEL_NUM;					      
	DMA_InitStructure.DMA_PeripheralBaseAddr  = (uint32_t) & (ADC1->DR);                
	DMA_InitStructure.DMA_Memory0BaseAddr     = (uint32_t)&uhADCConvertedValue;                    
	DMA_Init(DMA2_Stream0, &DMA_InitStructure);

	DMA_Cmd(DMA2_Stream0, ENABLE);


        DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
	DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);



        NVIC_InitTypeDef NVIC_InitStructure;

	NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);



    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;//PA5 通道5
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模拟输入
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//不带上下拉
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化  



        ADC_CommonInitTypeDef ADC_CommonInitStructure;
	ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div6;					  //ADC分频参数为2,ADCCLK =  APB2CLK/2 = 84/2 = 32Mhz。
	ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;					  //ADC123独立模式
	ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;		  //多ADC模式的DMA禁止。其实不用配置,因为多ADC模式已经禁止了。
	ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles; //多ADC模式下interleaved模式的两个和alternative模式下两个 ADC 之间的时间间隔。
	ADC_CommonInit(&ADC_CommonInitStructure);



ADC_InitTypeDef ADC_InitStructure;

	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;						//12位采样精度。
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;								//Scan模式使能,
	ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //禁用外部触发模式。
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;		//外部触发禁止情况下,该参数无效。
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;						//数据对齐采用右对齐模式。
	ADC_InitStructure.ADC_NbrOfConversion = 4;									//通道组中的待采样通道个数为 。
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;							//DMA模式下使能连续采样模式。单次触发可以连续的进行采样操作。
																				//见 STM32F4xx 英文参考手册 page 423。ADC_CR2寄存器的 CONT 位说明。
																				//连续模式使能后。采样将连续执行直到 CONT 软件清零。
																				//当然连续采样的开始还是需要软件触发或者外部触发的。
	ADC_Init(ADC1, &ADC_InitStructure);
	//TODO::可以根据实际情况调整采样时间。
//	ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_480Cycles); //通道采样时间配制。采样时间为480 ADCCLK 转换时间12 ADCCLK。
    ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_112Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_SampleTime_56Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 3, ADC_SampleTime_56Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 4, ADC_SampleTime_56Cycles);

	ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
	ADC_DMACmd(ADC1, ENABLE);

	ADC_Cmd(ADC1, ENABLE);






void DMA2_Stream0_IRQHandler(void)
{
	if (SET == DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0))
	{
        DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0); //清除 DMA 中断标示。
        
        
		ADC1_ConvertStartFlag = ADC_CONVERT_END;			  //标示本次ADC转换结束。
															  //STM32F4xx不能像STM32F103那样的直接通过清零触发源停止转换。
         
		ADC_ContinuousModeCmd(ADC1, DISABLE);				  //确保该bit可以在 ADCON 置位的情况下进行修改。确保是可以的。
	}
}



/*该函数定时调用*/
void ADC1_GetVolt(void)
{

   float advalue;
    uint8_t i=0,j=0, k=0;
    uint16_t AxtractData[ADC_CHANNEL_NUM][ADC_TRANSFORM_NUM] = {0};
    uint16_t usTemp;
    uint32_t uiSum[ADC_CHANNEL_NUM] = {0};

	ADC_ContinuousModeCmd(ADC1, ENABLE); //启动 ADC1 连续采样模式
	ADC_SoftwareStartConv(ADC1);		 //ADC1 采样使能

	ADC1_ConvertStartFlag = ADC_CONVERT_START;
	while (ADC_CONVERT_END != ADC1_ConvertStartFlag)
		; //等待采样结束



     /*****************取出每个ADC通道的值 ***************/
    for(i=0;i<ADC_TRANSFORM_NUM;i++)        //
    {
        for(j=0;j<ADC_CHANNEL_NUM;j++)  //
        {
            AxtractData[j][i] = uhADCConvertedValue[i][j];
        }        
    }



  /***************************排序****************************/
    for( k=0;k<ADC_CHANNEL_NUM;k++ )
    {
        for( i=1;i<ADC_TRANSFORM_NUM;i++ ) 
        { 
            usTemp=AxtractData[k][i];                         //usTemp为插入的元素
            j=i-1; 
            while( ( j>=0 ) && ( usTemp<AxtractData[k][j] ) ) //查找array[i-1] 后比它小的数
            { 
                AxtractData[k][j+1]=AxtractData[k][j]; 
                j--; 
            } 
            AxtractData[k][j+1]=usTemp;                       //插入数据
        } 
    }



     /******************计算每个ADC通道平均值******************/
    for( i=0;i<ADC_CHANNEL_NUM;i++ )        
    {
        for( j=1;j<ADC_TRANSFORM_NUM-1;j++ )//去掉一个最大值和最小值
        {
            uiSum[i] += AxtractData[i][j];
        }         
        g_usInChipAdcChannelAverageValue[i] = uiSum[i]/(ADC_TRANSFORM_NUM-2);
        
    } 

}
 


这是以200ms获取一次g_usInChipAdcChannelAverageValue[1]得到的数据

3855
3839
3848
3837
3842
3850
3841
3831
3823
3861
3837
3835
3838
3851
3839
3839
3856
3864
3846
3843
3841
3839
3837
3829
3848
3858
3845
3831
3868
3833
3835
3830
3837
3848
3833
3831
3847
3839
3827
3839
3846
3848
3839
3845
3858
3837
3845
3843
3864
3833
3839
3843
3856
3845
3845
3848
3846
3832
3842
3838
3823
3831

数值波动很大,不知道是不是软件配置有问题?还是电源的纹波引起的



回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2025-7-31 09:03:23 | 显示全部楼层
可能你板子的电源干扰略大。

另外这个值设置到最大ADC_SampleTime_480Cycles
回复

使用道具 举报

0

主题

290

回帖

290

积分

高级会员

积分
290
发表于 2025-7-31 09:07:33 | 显示全部楼层
407的ADC确实不好。
回复

使用道具 举报

4

主题

26

回帖

38

积分

新手上路

积分
38
 楼主| 发表于 2025-7-31 09:09:51 | 显示全部楼层
eric2013 发表于 2025-7-31 09:03
可能你板子的电源干扰略大。

另外这个值设置到最大ADC_SampleTime_480Cycles

感谢硬汉哥的回复。
用的freeRtos系统。MCU供电使用的AMS1117-3.3,输出后面一个470uf铝电解,每个引脚都有0.1uF电容,这难道是PCB布局引起的吗?
回复

使用道具 举报

4

主题

26

回帖

38

积分

新手上路

积分
38
 楼主| 发表于 2025-7-31 09:11:39 | 显示全部楼层
regbbs 发表于 2025-7-31 09:07
407的ADC确实不好。

正常理论情况下应该不会波动这么大,优点怀疑配置有问题
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117512
QQ
发表于 2025-8-1 08:27:13 | 显示全部楼层
枫华雪悦 发表于 2025-7-31 09:09
感谢硬汉哥的回复。
用的freeRtos系统。MCU供电使用的AMS1117-3.3,输出后面一个470uf铝电解,每个引脚 ...

降低采集速度,程序仅添加ADC测量,其他代码先注释掉看看好点不
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-8-12 00:03 , Processed in 0.083861 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表