dsPIC33EP512GM604 ADC1转换值异常 首次采样准后续偏差大
问题根因
你的ADC配置存在3个核心错误,直接导致连续采样时结果异常:
- ADC转换时钟(ADCS)配置违反器件电气规范
dsPIC33EP系列12位ADC要求转换时钟周期TAD最小为118ns,你将AD1CON3bits.ADCS = 0时,TAD = 1*Tcy(指令周期)。如果芯片运行在常规70MIPS主频下,Tcy≈14.3ns,对应TAD仅14.3ns,远低于最小要求。ADC内部采样保持电容、比较器电路没有足够时间完成电荷建立和转换,第一次转换前你手动延时了25us,电容刚好充到接近真实输入电压,所以第一次结果偏差小,后续连续转换时电路始终处于未建立状态,结果就卡在偏高的固定值。
- ADC转换时钟(ADCS)配置违反器件电气规范
- 采样触发模式和手动操作逻辑冲突
你配置SSRC = 7对应自动转换模式:硬件会在SAMP位置1后,按照SAMC位设定的采样时长自动计数,到时间后自动清零SAMP位启动转换,不需要手动操作SAMP位。你在代码里手动在置位SAMP后延时5us就清零SAMP,直接打断了硬件自动采样的时序逻辑,导致采样时长完全不满足要求。
- 采样触发模式和手动操作逻辑冲突
- 参考电压配置和硬件不匹配
AD1CON2bits.VCFG = 0b001对应选择外部VREF+引脚作为正参考、AVSS作为负参考,如果你的硬件板卡没有在VREF+引脚连接独立精准参考源、而是打算使用AVDD作为ADC参考,这个配置是错误的,会因为VREF引脚电平不稳定引入额外误差。
- 参考电压配置和硬件不匹配
- 额外问题:你代码里的5us采样延时是硬编码值,没有和TAD绑定,一旦主频调整,采样时长就会不满足要求。
修正方案
按以下步骤修改配置即可解决问题:
- 重新计算并设置ADCS值,保证TAD在120ns~200ns区间(兼顾速度和精度)。以70MIPS主频为例,Tcy≈14.3ns,根据TAD计算公式
TAD = Tcy*(ADCS+1),将ADCS设置为8时,TAD = 9*14.3≈129ns,符合规范。 - 如果你要使用手动控制采样启动的逻辑,把SSRC改为0(手动清零SAMP启动转换);如果要使用自动采样模式,就删掉手动清零SAMP和对应的延时代码,等待DONE标志位即可。
- 确认硬件参考源连接:如果使用AVDD作为参考,将VCFG改为0b000;如果确实使用外部参考,需在VREF引脚加100nF去耦电容保证电平稳定。
- 采样时长通过SAMC位配置(自动模式)或按TAD倍数计算延时(手动模式),保证采样时间至少10个TAD,让采样电容充分充电。
修正后的参考代码
/* Setup ADC1 for measuring R */ ANSELBbits.ANSB3 = 1; // RB3/AN5设为模拟模式 TRISBbits.TRISB3 = 1; // RB3/AN5设为输入 AD1CON1 = 0; AD1CON1bits.ADSIDL = 1; // 空闲模式下停止ADC AD1CON1bits.AD12B = 1; // 12位转换模式 AD1CON1bits.FORM = 0; // 结果为无符号整数格式,右对齐 AD1CON1bits.SSRC = 0; // 手动清零SAMP位启动转换,和手动操作逻辑匹配 AD1CON2 = 0; AD1CON2bits.VCFG = 0b000; // 使用AVDD/AVSS作为参考源,若用外部参考改回0b001 AD1CON2bits.SMPI = 0; // 每完成1次转换触发中断 AD1CON3=0; AD1CON3bits.SAMC = 0b11111; // 自动模式下采样31TAD,手动模式下该位不生效 AD1CON3bits.ADCS = 8; // 70MIPS下TAD≈129ns,符合电气要求 AD1CON4 = 0; // 不使用DMA AD1CHS0bits.CH0NA = 0; // 负输入选择AVSS AD1CHS0bits.CH0SA = 5; // 正输入选择AN5 IFS0bits.AD1IF = 0; // 清ADC中断标志 IEC0bits.AD1IE = 0; // 不使能ADC中断 /* Read voltage value */ AD1CON1bits.ADON = 1; // 使能ADC __delay_us(25); // 等待ADC上电稳定 for (N=0; N<10; N++) { AD1CON1bits.SAMP = 1; // 启动采样 __delay_us(2); // 2us≈15.5TAD,源阻抗<10k时满足采样电容充电要求 AD1CON1bits.SAMP = 0; // 手动启动转换 while (!AD1CON1bits.DONE); // 等待转换完成 res[N] = (double) ADC1BUF0; /* --- test log ---*/ sprintf(deb,"ADC1BUF0 = %.0f\r\n", res[N]); WriteStringUART1(deb); /* ---- end of test ----*/ }
注:如果你的芯片主频不是70MIPS,需要重新按公式计算ADCS值,始终保证TAD≥118ns即可;如果输入信号源阻抗超过10k,需要适当加长采样延时。
内容的提问来源于stack exchange,提问作者Guille
相关产品推荐
相关产品推荐

