看到一些坛友在自检的时候始终过不去 ADC 侦测这一关,在不增加额外代码的情况下,我试了一下用示波器/逻辑分析仪对电压源的初始化和自检做了一个捕捉,坛友可以根据捕捉的逻辑状态和代码的对应关系掌握自检是如何工作的,以及如何排查错误。
一般来说,本错误通常的可能性是:
1、ADC 本身确实有问题
2、串行数据链有问题,导致控制逻辑没有从单片机传递到模拟板
2.1、磁耦有问题
2.2、磁耦的模拟测供电有问题
2.3、作为控制逻辑的串入并出移位寄存器 CD4094(74HC4094)有问题或配置不正确
在阅读本文前,建议先检查:
1、模拟板供电,包括正负 15V、模拟 +5V、数字 +5V 几个供电情况是否正确
2、模拟板的基准电压,包括 LM399 +7V(TP2)、主基准 +10V(TP1)、ADC 基准 +5V、DAC 主基准(+5V)、DAC 副基准(+2.5V)是否正确
(上述各电压在模拟板上的位置见后)
代码对照:
https://bbs.38hot.net/forum.php?mod=viewthread&tid=123047
0、IO 对应关系
使用磁耦的版本中,IO 的对应关系如下:
$Def IO_REG_STB = PORTB.0
$Def IO_REG_DAT = PORTB.1
$Def IO_REG_CLK = PORTB.2
$Def IO_ADC_CLK = PORTB.4
$Def IO_ADC_DAT = PINB.3
模拟板上,控制逻辑的移位寄存器和其余设备对应关系如下:
Const Synthesis = &b00000001 ' Analog Switch = Synthesis Voltage Output | DG412 Pin
Const Reference = &b00000010 ' Analog Switch = Internal Reference(LM399) | DG412 Pin
Const ExternaIN = &b00000100 ' Analog Switch = Externa Voltage Input | DG412 Pin
Const GndOffset = &b00001000 ' Analog Switch = Auto Zero | DG412 Pin
解说:
移位寄存器的 Q1 接到模拟开关的 DAC 输出缓冲器(数字同步的电压)上
移位寄存器的 Q2 接到模拟开关的 内部参考基准(LM399 +7V)上
移位寄存器的 Q3 接到模拟开关的 外部参考基准上
移位寄存器的 Q4 接到模拟开关的 模拟地 上
此外,
移位寄存器的 Q5 接到 ADC 的 ChipSet 上,低电平有效
移位寄存器的 Q6 和 Q7 在标准中不使用
移位寄存器的 Q8 接到 DAC 的 ChipSet 上,低电平有效
1、初始化
代码
'///////////////////////////////////////////////////////////////////////////////////////////////////
' Program Initialization
'///////////////////////////////////////////////////////////////////////////////////////////////////
' Analog Board Initialization, Open all Analog Switch
bSregister = &b00000000
WriteSReg(bSregister)
解释:
初始化模拟板,所以模拟开关均断开
' DAC Initialization to 0V Output
SetVoltage(0)
将 DAC 输出为 0V
因为我没有逻辑分析仪,所以用带数字通道的混合信号示波器捕捉了这一过程,捕捉时,将触发源设置为 REG_STB,斜率下降方式,单次触发。将数字板的重启动按钮按下不放后,按下示波器的单次采样按钮,然后放开重启动按钮,示波器将捕捉这一过程如下。为方便观察,这里设置为 500us/div,捕捉时建议使用 1ms/div 以便观察到整个事件。
这里示波器的模拟通道 2 接到了 REG_STB,数字通道接到上述所有 IO
可以看到,REG_STB 有三个正脉冲,第一个长度为 1ms,第二第三个比较短。
将 X 轴调整为 50us/div 以观察 REG_STB 的第一个正脉冲之前的情况,数字通道中
D4=REG_CLK
D3=REG_DAT
D2=REG_STB
可见在 8bit 的时钟脉冲中,输送的数据为 0x00
bSregister = &b00000000
WriteSReg(bSregister)
第二个正脉冲之前
这是向 DAC 写入电压(值为 0),一共 40 bit
写过程有两次,这两次 DAC(前 32 bit)的数据是一样的,但最后 8bit 为移位寄存器的控制信号,第一次为 0x00,此时 DAC 的 ChipSet 为 0 有效,数据可以写入 DAC(但不会更新电压)
第二次,注意最后的 8 个时钟脉冲,倒数第 8 个对应的 REG_DAT 为高电平,后面 7 个时钟脉冲时是低电平
也就是说写入移位寄存器的控制逻辑是 0x80(&b10000000),最高位 1 对应寄存器 Q8,将两个 DAC 的 ChipSet 拉高,拉高后数据无法再写入 DAC,同时之前写入的数据将更新到电压
至此,初始化完成。
初始化完成后,屏幕将显示 Voltgen 字样和程序版本 2 秒钟,然后开始自检。自检开始的代码为:
If IO_ADC_DAT = 1 Then
Charat = ">ADC Detect...Failed" : DrawChr(1,3)
iTestcode = iTestcode Or &b00000010
Else
SetChannel(GndOffset)
bADCResult(3) = ShiftIn : bADCResult(2) = ShiftIn : bADCResult(1) = ShiftIn : bADCResult(0) = ShiftIn
iBusystp = 0
For i = 1 To 200
iBusystp = iBusystp + 1
If IO_ADC_DAT = 0 Then Exit For
WaitMs 1
Next i
If iBusystp < 155 Or iBusystp > 166 Then
Charat = ">ADC ChK Failed" : DrawChr(1,3)
Charat = Str(iBusystp) : DrawChr(94,3)
iTestcode = iTestcode Or &b00000100
Else
Charat = ">ADC Checked...Passed" : DrawChr(1,3)
.......
.....
...
.
可见,程序首先检测 IO_ADC_DAT 的电平,LTC2400 在 Chipset 为 0 后(初始化时已经设置为 0)开始进行一次转换,此时 IO_ADC_DAT 设置为 BUSY = 1,但显示 Voltgen 字样和程序版本经过了 2 秒钟,所以此时这里应该为 READY = 0 了,如果侦测不到 READY 信号,则认为 ADC 不存在,对应代码:
If IO_ADC_DAT = 1 Then
Charat = ">ADC Detect...Failed" : DrawChr(1,3)
iTestcode = iTestcode Or &b00000010
此时将设置错误代码 &b00000010
如果这一步通过,将检查 ADC 是否正常,检查原理是检查 ADC 的一次转换的时间是否是该 ADC 手册中指定的时间,且在 IO_ADC_DAT 上正确输出 BUSY 和 READY 信号。在这之前,程序将设置输入通道为模拟地,因此在屏幕显示 Voltgen 字样和软件版本号时,再次按下示波器的单次采样,X 轴设置为 5ms/dvi 即可采样到自检开始的信号,为了方便观察,这里调整 X 轴为 2md/div,可见在 REG_STB 上有两次正脉冲,对应代码
SetChannel(GndOffset)
SetChannel() 函数将断开所有模拟开关,10ms 后再次闭合所选择的模拟开关,因此这两个 REG_STB 脉冲之间宽度大概应该是 10ms
放大第一个脉冲之前的数据,可见 8bit 时钟脉冲对应的数据是 &b10000000,此时所有模拟开关断开,但 DAC 保持不得写入状态,所以最高位是 1
然后转移到第二个脉冲之前,可见写入的数据是 &b10001000,对应“Const GndOffset = &b00001000 ' Analog Switch = Auto Zero”,接到模拟地负责自动调零的模拟开关闭合。
操做模拟开关之后接着,程序发送 32 个脉冲给 ADC,以读取上一次转换结果,最后一个 bit 数据从 ADC 读出后,ADC 开始下一次的转换。
bADCResult(3) = ShiftIn : bADCResult(2) = ShiftIn : bADCResult(1) = ShiftIn : bADCResult(0) = ShiftIn
数字通道的 D6 接到 ADC_CLK
数字通道的 D5 接到 ADC_DAT
D6 的第 32 个脉冲之后,D5 置为 BUSY = 1,程序开始计时
iBusystp = 0
For i = 1 To 200
iBusystp = iBusystp + 1
If IO_ADC_DAT = 0 Then Exit For
WaitMs 1
Next i
If iBusystp < 155 Or iBusystp > 166 Then
Charat = ">ADC ChK Failed" : DrawChr(1,3)
Charat = Str(iBusystp) : DrawChr(94,3)
iTestcode = iTestcode Or &b00000100
Else
Charat = ">ADC Checked...Passed" : DrawChr(1,3)
将示波器设置为 20ms/div 可以很好观察到 D5(示波器模拟通道 1 也接到了 ADC_DAT)在 D6 的最后一个脉冲到达后变为高电平且持续了 160ms 左右重新变为低电平,这是程序认为 ADC 正常的关键。
至此,对 ADC 的检测完毕,遇到这个问题的坛友可以用示波器/逻辑分析仪对此进行调试,首先检查单片机是否在约定的时间送出正确的寄存器控制信号,然后检查信号是否正确到达模拟板,最后检查 ADC_DAT 是否通过磁耦正确返回单片机,那么问题就很容易找到了。
|