STM32G431单片机多路ADC通道配置问题及解决方案记录

本文作为个人嵌入式学习记录,也希望能帮助到遇到相同问题的人。

叠甲:编者算嵌入式入门初学者,有许多考虑不周到的细节、解释的不清楚甚至错误的知识点,恳请恳请恳请各位大佬指教批评,及时指出!如果有问题,我期待并等待各位的留言!希望能共同进步!

本文“捉虫”&修正更新记录:

①25.3.31

发现问题:

蓝桥杯赛前练习做到嵌入式第十三届国赛题时,发现有个要求是用PA4、PA5模拟电压输入。配置的时候发现这两个引脚对应都是ADC2,说明是用一个ADC开多通道分别采集电压(这里是开两路通道)。

一开始我直接Active了ADC2_IN17和ADC2_IN13,但是Number Of Conversion是1,时钟采用的是同步2分频模式,单采样时间拉到最高是640.5Cycles,然后编写相关代码,测出来的结果:3.3V只接入一个引脚时,两个通道都显示采集到电压并且数值相同;后来上各大论坛查了一下资料,将配置改成Number Of Conversion=2,此时会强制使能连续模式Scan Conversion Mode,同步2分频改为异步2分频,两个通道的采样时间仍拉到最高640.5Cycles。

关于采样时间,浅谈简单理解:模拟转数字的一般步骤是采样-量化-编码,而要对模拟信号进行正确采样(“正确”是指在需要精度下,能采到输进去的电压值,比如3.3V进去就采出来3.3V,0V进去就采到0V),就需要让ADC有足够的处理时间,这里Sampling Time如是。对于一定频率的输入信号,设置Sampling Time的Cycles越高,就越能还原输入信号的精度,但同时需要的时间就越长。总结来说就是用时间换精度

查STM32G431数据手册:

编者是懒人思维,直接拉高Sampling Time的Cycles,就保证了采到的精度,但需要的时间就久一点。这里设置640.5Cycles,则Tconv=640.5+12.5 Cycles=653ADC clock cycles;SysCLK=80M=AHB,经异步2分频,ADCCLK=40M,故一次ADC转换时间:

Tconv=653ADC clock cycles/40M=16.325us

然后为啥是异步分频不是同步分频:首先要声明一点是ADCCLK是源于AHB,同步异步是说ADCCLK与AHB的是否有相位差(这点是查出来的,关于同步异步的解释有很多)。①同步虽然简单,但是异步对于多个状态的处理更有优势(这点也是查出来的,我还没有深刻地体会,如果有大佬愿意举例的话,感谢!)②最主要的一点:异步可选择更多分频系数。当然,可以不针对ADC进行分频,只对AHB的频率进行降低也可以达到调整ADCCLK的效果。

相关配置(正确版)-

相关代码:

给出两种处理方式,一种是不借助HAL库函数ADC标志,另一种是借助HAL库函数ADC标志。

第一种:不借助HAL库函数ADC标志

```c

uint16_t getADC(void)
{
	uint16_t adc=0;
	HAL_ADC_Start(&hadc2);
	adc=HAL_ADC_GetValue(&hadc2);
	return adc;
}

void Lcd_Proc(void)
{
	if((uwTick-uwTick_Lcd)<50) return;
	uwTick_Lcd=uwTick;

    //通过HAL_Delay-ms级,保证一次转换完毕;重复getADC()是确保能采到ADC的值
    VoltPA4=getADC()*3.3/4096;
	HAL_Delay(15); 
	VoltPA5=getADC()*3.3/4096;
	HAL_Delay(15);
	VoltPA4=getADC()*3.3/4096;
	HAL_Delay(15);
	VoltPA5=getADC()*3.3/4096;
	HAL_Delay(15);

	sprintf((char*)LcdString,"TPA4:%4.2f",VoltPA4);
	LCD_DisplayStringLine(Line5,LcdString);
	sprintf((char*)LcdString,"TPA5:%4.2f",VoltPA5);
	LCD_DisplayStringLine(Line6,LcdString);
}

第二种:借助HAL库函数ADC标志

```c

/**********************************
*函数功能:获取单ADC多通道的值
*函数参数:
*          ADC_HandleTypeDef *hadc:ADC
*          float*data:保存ADC的值
*          uint8_t n:ADC通道个数
*函数返回值:无
**********************************/

void getMuchADC(ADC_HandleTypeDef *hadc,float *data,uint8_t n)
{
	HAL_ADC_Start(hadc);
	for(int i=0;i<n;i++)
	{	
		HAL_ADC_PollForConversion(hadc,1);//该函数会阻塞线程直至ADC转换完成
		data[i]=(float)(HAL_ADC_GetValue(hadc)*3.3/4096);//立刻处理转换数据
	}
	HAL_ADC_Stop(hadc);
}

void Lcd_Proc(void)
{
	if((uwTick-uwTick_Lcd)<50) return;
	uwTick_Lcd=uwTick;

	getMuchADC(&hadc2,ADCgetValue,2);//直接调用,有HAL_ADC_PollForConversion则不需要延时

	sprintf((char*)LcdString,"PA5:%4.2f",ADCgetValue[0]);
	LCD_DisplayStringLine(Line1,LcdString);
	sprintf((char*)LcdString,"PA4:%4.2f",ADCgetValue[1]);
	LCD_DisplayStringLine(Line3,LcdString);
}

上板现象:

图示TPA4和TPA5,显示“T”的是采用第一种方式;没有显示“T”的是第二种方式。这也证实两种方式都能用。

图一:板子引线,3.3V引到PA5脚

图二:板子引线,3.3V引到PA4脚

发现又有些问题:3.3V输入PA4的时候,PA4能采出3.3V,虽然PA5也有数值,但0.7V看着也还行(?);3.3V输入PA5的时候,PA5能采出3.3V,但是PA4居然采到1.7V(理论值是0V,这就不能忍受了。(希望知道的大佬可以解答一下,非常感谢!)

后面请教了一些也玩这个的大佬们,建议我用信号发生器产生输出来测,怀疑可能是板子问题。然后用信号发生器输入了一个1MHz的、占空比97.5%的脉冲信号(模拟输入直流),最后测出来就正常了。如图:

图三:信号发生器,3V振幅引到PA4脚

图四:信号发生器,3V振幅引到PA5脚

小结&细节补充(待完善)

相关资料:

1.【江科大】STM32:ADC转换(单通道+多通道)https://blog.csdn.net/weixin_52958292/article/details/135762821?fromshare=blogdetail&sharetype=blogdetail&sharerId=135762821&sharerefer=PC&sharesource=&sharefrom=from_link

2.使用HAL库开发STM32:ADC基础使用

https://blog.csdn.net/Naisu_kun/article/details/121532288?fromshare=blogdetail&sharetype=blogdetail&sharerId=121532288&sharerefer=PC&sharesource=2201_75847016&sharefrom=from_link3.【蓝桥杯嵌入式】第十三届蓝桥杯嵌入式国赛程序设计试题以及详细题解https://blog.csdn.net/qq_53960242/article/details/129054668?fromshare=blogdetail&sharetype=blogdetail&sharerId=129054668&sharerefer=PC&sharesource=2201_75847016&sharefrom=from_link

作者:野生余弦曲线

物联沃分享整理
物联沃-IOTWORD物联网 » STM32G431单片机多路ADC通道配置问题及解决方案记录

发表回复