|
![](static/image/common/ico_lz.png)
楼主 |
发表于 2012-6-24 17:55:34
|
显示全部楼层
本帖最后由 lilith 于 2012-6-24 23:00 编辑
单片机上的源程序,加入了简要的注释,一些英文注释是我写程序的时候写给自己看的,语法什么的就不要深究了
读取和处理 ADC 部分代码,我去年发过的用 1602 LCD 做的 6.5 位表头中写有比较详细的注释就不重新写注释了,传送门:http://www.amobbs.com/thread-4899126-1-1.html
$Device= m16 '声明使用的 IC
$Stack = 32
$Clock = 8 '声明单片机的频率
$Timer2 = PWM, 8, Normal '使用定时器 2 作为 PWM,这是为了给 12864 LCD 提供负压
$GLCD HD61202, Data=PORTC, Ctrl=PORTA, 128, 64, 3 '声明使用一个 12864 LCD,其驱动内置于编译器中
$Gctrl EN=0, WR=2, DI=1, CS1=5, CS2=4 '声明显示器使用的 IO
$ShiftIn Data=PORTA.6, Clock=PORTA.7, Msb '声明一个软 SPI 输入端口,由编译器驱动
$ShiftOut Data=PORTB.0, Clock=PORTB.1, Msb '声明一个软 SPI 输出端口,由编译器驱动
$LeadChar="0", Format(2,5)
$Baud = 1200,n,8,1 '声明硬件串口的设置
Const Reference = &b00000001 '声明模拟开关对应常量
Const ExternaIN = &b00000010
Const GndOffset = &b00000100
Const Synthesis = &b00001000
Dim F2HD As Flash Byte '声明软字体,由编译器提供
Dim F0HD As Flash Byte
Declare Function Setdac(MastDAC As Word, SlavDAC As Word) As Byte '声明用户函数 设置 DAC
Declare Function SetVoltage(fVoltage As Float) As Byte '声明用户函数 设置电压
Declare Function SetChannel(Channel As Byte) As Byte '声明用户函数 设置模拟开关通道
Declare Function Getinlerr(fVoltage As Float) As Word '声明用户函数 获得非线性误差
Declare Interrupt Urxc() '声明使用串口破中断
Enable Interrupts
Enable Urxc
Dim i As Byte
Dim iSmsetp As Byte
Dim iBusystp As Byte
Dim iTrd As Byte
Dim iDraw As Word
Dim CurrentChannel As Byte
Dim itm As Byte
Dim baCalChannel As Bit
Dim bUartset As Bit
Dim tTxt As String *15
Dim tm As String *7
Dim tCmd As String *4
Dim iDa As Byte
Dim iDb As Byte
Dim iDc As Byte
Dim iDd As Byte
Dim iTa As Byte
Dim iTb As Byte
Dim iTc As Byte
Dim iTd As Byte
Dim bREGas(33) As Byte
Dim bREGbs(33) As Byte
Dim bREGcs(33) As Byte
Dim bREGds(33) As Byte
Dim bREGar(33) As Byte
Dim bREGbr(33) As Byte
Dim bREGcr(33) As Byte
Dim bREGdr(33) As Byte
Dim fTrn As Float
Dim fOut As Float
Dim fReference As Float
Dim fSynthesis As Float
Dim fCalsacles As Float
Dim fCalfSynth As Float
Dim fVoltage As Float
Dim fError As Float
Dim fVset As Float
Dim fVtrn As Float
Dim Vseth As Word
Dim Vsetl As Word
'Dim uVseth As Word
'Dim uVsetl As Word
Dim fSetting As Float
Dim fCurerr As Float
Dim fPreerr As Float
Dim fIerr As Float
Dim fDerr As Float
Dim iPv As Word
Dim iIv As Word
Dim iDv As Word
Dim wErr As Word
Pwm2 = 3
Set DDRD.7 'Setting the VLCD Pwm Output
Set DDRB.2 'Setting the CD4094 Strobe Output
Set DDRA.3 'Setting the LCD 12864 PowerUp Reset Pin
Start Timer2
PORTB.2 = 0 'Setting the CD4094 Strobe Basical Status
' Reset and Init. the Graph LCD
PORTA.3 = 0
WaitMs 200
PORTA.3 = 1
GLcdInit
Gcls
FontSet F2HD
GLcd(0, 0), "Program Init"
Wait 1
Gcls
fVoltage = 9900000
stt: '程序重新开始执行的断点,设置新的电压值后会转跳到此重新执行
Gcls
' ******************** Init Variable ********************
CurrentChannel = &b01101000
baCalChannel = 0
fReference = 0
fSynthesis = 0
fCalsacles = 6880731
iPv = 100000
iIv = 400
iDv = 10
fPreerr = 0
fError = 0
fIerr = 0
bUartset = 0
For i = 0 To 33
bREGas(i) = 0
bREGbs(i) = 0
bREGcs(i) = 0
bREGds(i) = 0
bREGar(i) = 0
bREGbr(i) = 0
bREGcr(i) = 0
bREGdr(i) = 0
Next i
' ******************** Init Variable ********************
Vseth = ReadEE(0) '读取 EEPROM 中的校准数据
Vsetl = ReadEE(10)
fCalsacles = Vseth * 10000 + Vsetl
FontSet F0HD
Format(Scientific,6)
GLcd(0, 7), fCalsacles '这是为了方便调试加入的,将 EEPROM 中的校准数据显示在 LCD 上
SetVoltage(fVoltage)
WaitMs 500
FontSet F2HD
Format(2, 5)
GLcd(0, 0), "Set"; fVoltage / 1000000; "VDC"
itm = 0
iSmsetp = 0
Do
iSmsetp = iSmsetp + 1
If iSmsetp > 67 Then iSmsetp = 67
'GLcd(0, 7), "Smthsetp:"; iSmsetp '等待 ADC LTC2400 的忙碌信号,然后读取它
iBusystp = 0
Do
iBusystp = iBusystp + 1
WaitMs 1
Loop While PINA.6 = 1
'GLcd(0, 7), "iBusystp:"; iBusystp
baCalChannel = Not baCalChannel
If baCalChannel = 1 Then
CurrentChannel = SetChannel(Synthesis)
Else
CurrentChannel = SetChannel(Reference)
End If
WaitMs 10
iDa = ShiftIn
iDb = ShiftIn
iDc = ShiftIn
iDd = ShiftIn
iDd = iDd And &b11110000
iDd = Swap(iDd)
iTrd = iDc And &b00001111
iTrd = Swap(iTrd)
iTd = iDd + iTrd
iTrd = iDc And &b11110000
iTc = Swap(iTrd)
iTrd = iDb And &b00001111
iTrd = Swap(iTrd)
iTc = iTrd + iTc
iTrd = iDb And &b11110000
iTb = Swap(iTrd)
iTrd = iDa And &b00001111
iTrd = Swap(iTrd)
iTb = iTrd + iTb
iTrd = iDa And &b00110000
iTa = Swap(iTrd) ' 读取 LTC2400 的 32 个 bit 并处理成 24bit 格式
fTrn = 5 * (16777216 * iTa + 65536 * iTb + 256 * iTc + iTd - 33554432) / 16777216
'fTrn = fTrn * 2002676 / 1000000
FontSet F0HD
Format(Scientific,6) ' 用两串数组先入先出存放转换的结果,这样做是因为编译器提供的支持有限,无法使用单精度浮点数组。
If baCalChannel = 0 Then
'GLcd(0, 2), "Syn:"; fTrn
For i = 1 To 32
bREGds(i) = bREGds(i + 1)
bREGcs(i) = bREGcs(i + 1)
bREGbs(i) = bREGbs(i + 1)
bREGas(i) = bREGas(i + 1)
Next i
bREGds(32) = iTd
bREGcs(32) = iTc
bREGbs(32) = iTb
bREGas(32) = iTa
fTrn = 0
fOut = 0
For i = 1 To 32
iTa = bREGas(i)
iTb = bREGbs(i)
iTc = bREGcs(i)
iTd = bREGds(i)
fTrn = 5 * (16777216 * iTa + 65536 * iTb + 256 * iTc + iTd - 33554432) / 16777216
fOut = fOut + fTrn
Next i
fOut = fOut / 32
fSynthesis = fOut
'GLcd(0, 4), "sm_Syn:"; fSynthesis
Else
'GLcd(0, 3), "Ref:"; fTrn
For i = 1 To 32
bREGdr(i) = bREGdr(i + 1)
bREGcr(i) = bREGcr(i + 1)
bREGbr(i) = bREGbr(i + 1)
bREGar(i) = bREGar(i + 1)
Next i
bREGdr(32) = iTd
bREGcr(32) = iTc
bREGbr(32) = iTb
bREGar(32) = iTa
fTrn = 0
fOut = 0
For i = 1 To 32
iTa = bREGar(i)
iTb = bREGbr(i)
iTc = bREGcr(i)
iTd = bREGdr(i)
fTrn = 5 * (16777216 * iTa + 65536 * iTb + 256 * iTc + iTd - 33554432) / 16777216
fOut = fOut + fTrn
Next i
fOut = fOut / 32
fReference = fOut
'GLcd(0, 5), "sm_Ref:"; fReference
End If
fCalfSynth = fSynthesis / (fReference / fCalsacles) '经过先入先出寄存器后的转换结果被平滑,然后根据校准数据和非线性校正数据计算得到正确的电压值
fCalfSynth = fCalfSynth + Getinlerr(fCalfSynth/1000000)
'GLcd(0, 7), Getinlerr(fCalfSynth/1000000)
If iSmsetp > 66 Then '当寄存器满了才认为可以进行电压修正
FontSet F2HD
Format(2,5)
GLcd(0, 2), "Red"; fCalfSynth / 1000000; "VDC"
'fSetting = fVoltage
fCalfSynth = fCalfSynth
fError = fVoltage - fCalfSynth '获得测量值和设置值的差
FontSet F0HD
Format(3,1)
GLcd(0, 4), "Err:"; fError; " uV"
fCurerr = fVoltage - fCalfSynth '用这个差值作为 PID 算法的入口,得到校正值去重设 DAC
fIerr = fIerr + fCurerr
fDerr = fPreerr
fError = iPv * fCurerr + iIv * fIerr + iDv * fDerr
fPreerr = fCurerr
Format(Scientific,6)
'GLcd(0, 5), "PID:"; fError
fError = fVoltage + fError / 10000
GLcd(0, 5), "Adj:"; fError
SetVoltage(fError)
End If
FontSet F0HD
GLcd(96, 7), Hex(iSmsetp); "/43"
'GLcd(0, 5), "USet: "; tTxt
If bUartset = 1 Then
'GLcd(0, 6), "Usetf:"; fSetting
fVoltage = fSetting
'SetVoltage(fVoltage)
iSmsetp = 0
bUartset = 0
GoTo stt
End If
Loop
Function Setdac(MastDAC As Word, SlavDAC As Word) As Byte '设置 DAC 的子函数,将入口值转换为 MAX515 适合的格式;MAX515 的 CS 接在移位寄存器 CD4094 上
Local bMastMSB As Byte
Local bMastLSB As Byte
Local bSlavMSB As Byte
Local bSlavLSB As Byte
Local Channelset As Byte
bMastMSB = Msb(MastDAC)
bMastLSB = MastDAC - bMastMSB * 256
bSlavMSB = Msb(SlavDAC)
bSlavLSB = SlavDAC - bSlavMSB * 256
Channelset = CurrentChannel And &b00001111
ShiftOut &b00000000; &b00000000; &b00000000; &b00000000; Channelset
PORTB.2 = 1 : WaitUs 100: PORTB.2 = 0
Channelset = &b01100000 + Channelset
ShiftOut bMastMSB; bMastLSB; bSlavMSB; bSlavLSB; Channelset
PORTB.2 = 1 : WaitUs 100: PORTB.2 = 0
Return 0
End Function
Function SetVoltage(fVoltage As Float) As Byte '设置电压的子函数,根据电压合成公式逆运算得到两个 DAC 应当的设置值
' the addsch VOut = Gain * (Vmast * R2 + Vslave * R1) / (R1+R2), Fullscale of the Vm and Vs all = 5V, R1 = 1K ohm, R2 = 1M ohm, Gain = 2.01509
fVtrn = fVoltage
fVset = fVtrn
' Get the MastDAC Voltage Setting Value
fVtrn = fVtrn / 2015090 'the 2015090 is the Buffamp Gain( x2.01509)
fVtrn = fVtrn * 1001000 - 5000 'the 1001000 is the MastRes 1K and the SlaveRes 1M
fVtrn = fVtrn * 4095 / 4995005 'the 4095 is the 12bit DAC Full scale; 4995005 scale by addsch.(added the MastDAC Fullscale Voltage)
Vseth = fVtrn
fVtrn = Vseth * 5000000 / 4095
fVtrn = fVtrn / 1001000
fVtrn = fVset - fVtrn * 2015090
fVtrn = fVtrn * 1000000 / 2015090
fVtrn = fVtrn * 4095 / 5000
Vsetl = fVtrn
Setdac(Vseth,Vsetl)
Return 0
End Function
Function SetChannel(Channel As Byte) As Byte '设置模拟开关的子函数
Local Channelset As Byte
Channelset = &b01100000 + Channel
ShiftOut &b00000000; &b00000000; &b00000000; &b00000000; Channelset
PORTB.2 = 1 : WaitUs 100: PORTB.2 = 0
Return Channelset
End Function
Function Getinlerr(fVoltage As Float) As Word '获得非线性校正数据,它是通过测量和拟合得到的一个二次三项式,不过这没有经过深入的验证
Local bInlerr As Word
fVtrn = fVoltage
fVset = fVtrn
fVtrn = fVtrn * fVtrn * 7381
fVset = (fVset * 12381 + 645120)
fVset = (fVset - fVtrn) / 1000
bInlerr = fVset
Return bInlerr
End Function
Interrupt Urxc(),Save 1
Local uVseth As Word
Local uVsetl As Word
Local uMSBh As Byte
Local uLSBh As Byte
Local uMSBl As Byte
Local uLSBl As Byte
InputBin tTxt
tCmd = Mid(tTxt, 1, 3)
If tCmd = "STV" Then
tm = Mid(tTxt,4,4)
uVseth = Val(tm)
tm = Mid(tTxt,8,4)
uVsetl = Val(tm)
fSetting = uVseth
fSetting = fSetting * 10000
fSetting = fSetting + uVsetl
bUartset = 1
End If
If tCmd = "CAL" Then
tm = Mid(tTxt,4,4)
uVseth = Val(tm)
tm = Mid(tTxt,8,4)
uVsetl = Val(tm)
'uMSBh = Msb(uVseth)
'uMSBl = Msb(uVsetl)
'uLSBh = uVseth - uMSBh * 256
'uLSBl = uVsetl - uMSBl * 256
WriteEE (0,uVseth)
WriteEE (10,uVsetl)
bUartset = 1
End If
Enable Interrupts
End Interrupt
$Include "..\Help\samples\F2HD.bas" '编译器提供的软字体
$Include "..\Help\samples\F0HD.bas"
|
|