【MM32 eMiniBoard测评】3. 测试ADC精度和线性 + 江湖可能失传小技
[复制链接]
本帖最后由 mig29 于 2020-11-22 14:31 编辑
本例使用 ..\MM32F013x_Samples\LibSamples\ADC\ADC_Polling 这个 Demo,测量 ADC 的
精度和线性。
1. 首先用高位表校准4位半的表,“传递”到家里再测:
2. 找出ADC的死区范围和最大ADC值,求出新的线性转换公式
(死区:调节 RV1,测量 VAin1电压,直到 ADC数值变为1)
(最大ADC数值:短接 Vcc 到 pin Ain1,看 ADC读数)
3. 尽量多地测量不同测试点,看在新的线性关系下的误差范围:
(把main.c 函数改成底下的代码)
#define Vdd 3303 //mV
#define ADMax 4090
s32 main(void)
{
u32 mV;
DELAY_Init();
CONSOLE_Init(115200);
ADC1SingleChannelInit();
while(1) {
ADCVAL = GetAdcAverage(8);
//fValue = ((float)ADCVAL / 4090) * 3.303; //use 3.3V as VDD
mV = ADCVAL * Vdd ;
mV /= ADMax;
mV += 3;
printf(" m1: ADC_Value = 0x%03X = %04d, pin Ain1 = %d mV \r\n", ADCVAL, ADCVAL, mV);
fValue = ((float)ADCVAL * 0.8070904645476773 ) + 3;
printf(" m2: ADC_Value = 0x%03X = %04d, pin Ain1 = %f mV \r\n", ADCVAL, ADCVAL, fValue);
mV = (ADCVAL * 13223 / 16384 ) + 3; //(0.8070904645476773 * 16384) / 16384
printf(" m3: pin Ain1 = %d mV \r\n", mV);
DELAY_Ms(1000);
}
//return 0;
}
结论:
1. 死区大约3mV,最大AD值4090(12位), Vdd = 3.304V。 (补充:写本文时想起来,死区应该只能用 3mV 的一半算。。)
按 y=kx+b 公式计算: 3 = b ,3304 = 4090k + 3 ===> k = 0.8084169317347688
2. 3.3V,12位ADC,则 1LSB = 0.8mV, 从全程测量结果看,整体误差不超过 3LSB。也就是不校准可以无脑当 10.5 位ADC用
3. 本实验只是个人粗略测量, 不代表官方意见。
4. 原厂程序只是简单地做了计算:
fValue = ((float)ADCVAL / 4095) * 3.3 ,
更严谨的做法是:不需要使用浮点,把系数乘以 2的某次方(本例中最大可以乘 2^20),就可以转换成整形数计算。
二者之间的差距,看本文末尾的汇编就知道了。
当然,对于现在的少年,没有经历过需要在 64Byte RAM 里做道场,也就没有人关注这些雕虫小技了。
60: fValue = ((float)ADCVAL * 0.8070904645476773 ) + 3;
0x0800182E 8820 LDRH r0,[r4,#0x00]
0x08001830 F7FEFDAC BL.W __aeabi_ui2d (0x0800038C)
0x08001834 4632 MOV r2,r6
0x08001836 463B MOV r3,r7
0x08001838 F7FEFD40 BL.W __aeabi_dmul (0x080002BC)
0x0800183C 2200 MOVS r2,#0x00
0x0800183E 4B20 LDR r3,[pc,#128] ; @0x080018C0
0x08001840 F7FEFC8A BL.W __aeabi_dadd (0x08000158)
0x08001844 F7FEFDC4 BL.W __aeabi_d2f (0x080003D0)
61: printf(" m2: ADC_Value = 0x%03X = %04d, pin Ain1 = %f mV \r\n", ADCVAL, ADCVAL, fValue);
62:
0x08001848 6060 STR r0,[r4,#0x04]
0x0800184A F7FEFDAD BL.W __aeabi_f2d (0x080003A8)
0x0800184E 9101 STR r1,[sp,#0x04]
0x08001850 9000 STR r0,[sp,#0x00]
0x08001852 8822 LDRH r2,[r4,#0x00]
0x08001854 8821 LDRH r1,[r4,#0x00]
0x08001856 A01B ADR r0,{pc}+0x70 ; @0x080018C4
0x08001858 F7FFFB12 BL.W __0printf (0x08000E80)
---------------------------------------
63: mV = (ADCVAL * 13223 / 16384 ) + 3; //(0.8070904645476773 * 16384) / 16384
0x0800185C 8820 LDRH r0,[r4,#0x00]
0x0800185E 4926 LDR r1,[pc,#152] ; @0x080018F8
0x08001860 4348 MULS r0,r1,r0
0x08001862 0B81 LSRS r1,r0,#14
64: printf(" m3: pin Ain1 = %d mV \r\n", mV);
65:
0x08001864 A025 ADR r0,{pc}+0x98 ; @0x080018FC
0x08001866 1CC9 ADDS r1,r1,#3
0x08001868 F7FFFB0A BL.W __0printf (0x08000E80)
|