MYQQ2018 发表于 2019-5-6 16:43:04

又是STC8A8K,两个ADC通道,采样顺序不一样结果不一致

又是STC8A8K,两个ADC通道,采样顺序不一样结果不一致
初始化程序
void ADCinit()
{
P0M0 = 0x00; //P0.6为AD口,ADC14
P0M1 = 0x40;

P1M0 = 0x00; //P1.0为AD口,ADC0
P1M1 = 0x01;
ADCCFG = 0x0f; //ADC时钟为系统时钟/2/16/16,转换结果左对齐ADC_RES存储高8位,ADC_RESL的高4位存储转换结果的低4位,低4位为0
ADC_CONTR = 0x80; //使能ADC模块
}
uchar ADCresult(uchar channel)
{
       
        ADC_CONTR &=0xF8;
        ADC_CONTR |=0x40;//启动AD转换
        ADC_CONTR |= channel;
_nop_();
_nop_();
while (!(ADC_CONTR & 0x20)); //查询ADC完成标志
ADC_CONTR &= ~0x20; //清标志
return ADC_RES;
}
下面这个代码完全没有问题
        ADCinit();
        InitUART();
       for(i=0;i<10;i++)
{
       delay(65534);
                SBUF=ADCresult(0);//高8位
               while(!TI);
               TI=0;
               //SBUF=ADC_RESL;   //低4位
               //while(!TI);
               //TI=0;
}
for(i=0;i<10;i++)
{
       delay(65534);
                SBUF=ADCresult(14);//高8位
               while(!TI);
               TI=0;
                // SBUF=ADC_RESL;   //低4位
                // while(!TI);
                // TI=0;
}
交换两个通道的顺序,如下,其中14通道仍然没有问题,0通道的结果整个是错的,真是日了狗了
        ADCinit();
        InitUART();
for(i=0;i<10;i++)
{
       delay(65534);
                SBUF=ADCresult(14);//高8位
               while(!TI);
               TI=0;
                // SBUF=ADC_RESL;   //低4位
                // while(!TI);
                // TI=0;
}
       for(i=0;i<10;i++)
{
       delay(65534);
                SBUF=ADCresult(0);//高8位
               while(!TI);
               TI=0;
               //SBUF=ADC_RESL;   //低4位
               //while(!TI);
               //TI=0;
}

MYQQ2018 发表于 2019-5-6 17:05:46

我又增加了一个通道ADC1(P1.1),把6种顺序组合试了一遍,结果如下
1、14(正确)1(错误)0(错误)
2、0(正确)14(正确)1(错误)
3、1(正确)0(正确)14(正确)
4、0(正确)1(正确)14(正确)
5、14(正确)0(错误)1(错误)
6、1(正确)14(正确)0(错误)
貌似14通道必须放在最后,不然它后面的通道都是错的,又专门这样试了一下
7、0(正确)1(正确)14(正确)0(错误)

su33691 发表于 2019-5-6 17:33:48

楼主不知道转换通道后的AD数据要抛弃,只会抱怨,我就呵呵了。

MYQQ2018 发表于 2019-5-6 17:58:55

本帖最后由 MYQQ2018 于 2019-5-6 18:02 编辑

su33691 发表于 2019-5-6 17:33
楼主不知道转换通道后的AD数据要抛弃,只会抱怨,我就呵呵了。

我是采样了10次呀,楼主位的程序;错误的时候,10次全是错的,且无规律,我采的是很稳定的直流信号

su33691 发表于 2019-5-6 18:10:56

问题出在:ADC_CONTR |= channel;
应改为:ADC_CONTR = (ADC_CONTR & 0xf0) | channel;

MYQQ2018 发表于 2019-5-6 18:25:30

su33691 发表于 2019-5-6 18:10
问题出在:ADC_CONTR |= channel;
应改为:ADC_CONTR = (ADC_CONTR & 0xf0) | channel;

谢谢,明白了;非常感谢

rclong 发表于 2019-5-6 18:39:14

su33691 发表于 2019-5-6 18:10
问题出在:ADC_CONTR |= channel;
应改为:ADC_CONTR = (ADC_CONTR & 0xf0) | channel;

请教一下其他ADC是不是也要做类似操作?
尤其是内部通过模拟开关切换实现多路采集的ADC,是不是切换之后要先这样操作?

小李非刀 发表于 2019-5-8 21:14:12

对于外挂的ADC芯片或MCU自带的逼近式ADC(SAR ADC),如果采样保持电路之前没有缓冲(起到阻抗变换作用),则通道切换后采样保持电容的电压值会受到上一次通道的影响,特别是切换前后通道间电压差比较大,信号内阻又比较大时,特别明显。
对于STC的ADC,是开关电容方式的SAR ADC,上面为采样示意图,采样保持电路之前无缓冲,输入多通道通过K1选择其中一个通道,通过采样开关连接采样电阻和采样电容。图中电阻值和电容值为示意值,可能跟实际的有差别。
假设上一个通道为Chn(P1.0~P1.7的任意一个通道),转换结束后,本次切换到内部1.25V,启动ADC转换,在采样时间内接通K2经过Rs Cs采样,采样结束,断开K2,开始ADC转换,转换过程保持电压不变。
由于存在时间常数Rs*Cs=0.182us,假设采样时间为5*Rs*Cs=0.91us,从0开始的充电系数为0.993262,对于10位的ADC还嫌不够,12位的ADC更加不够。
说回STC的例子,使用90T的情况,22MHZ时钟,转换时间大约4us,STC手册查不到采样时间,那就平分吧,姑且按11个时隙算(采样1个时隙,每位ADC需要1个时隙),则采样时间为4/11=0.36us,时间太短了,充放电时间太短,所以受到上一通道的影响很大,如果使用540T,则采样达到2us,则通道间影响就很小了。
再比如,读取内部1.25V的ADC值,如果将上一个通道P1.2接VCC,能读到300,P1.2接GND,能读到240,就是上面原因。但是如果不切换通道,你只对内部1.25V转换,你会发现各种速度读数都一样的。
解决方法是:通道切换后开始读的第1次甚至第2次转换都丢弃结果,取第三次的。速度越快,丢弃的越多。或者使用比较慢的速度来转换。
例子中只需要多做2次ADC并丢弃,就可以正常。

lswood 发表于 2019-5-8 21:40:13

电工遇到问题先从自身排查,别总是先让别人背锅
页: [1]
查看完整版本: 又是STC8A8K,两个ADC通道,采样顺序不一样结果不一致