;Data Acquisition Device 数据采集办法
;* Module Description组件描述:
;* Analog Data Acquisition模拟数据采集器组件使用 EE314
;* 设备接口通过RS232串行口serial port到PC,同时提供协议protocol支持最多5个对;* 手方频道
;* oscillator clock15.36Mhz ///9600 baud rate/// 16F870
;************************************************************************
;* Revision History:
;* 06/01/2001(GeneA): created *
;* 06/06/2001(GeneA); version 1.0 complete *
;* 06/07/2001(GeneA): A/D conversion bug. Wasn't waiting the required *
;* Tacq time between selecting the analog channel and beginning *
;* the A/D conversion. Am now delaying 16 instruction cycles prior *
;* to starting the conversion. *
;* 07/12/2001(GeneA): Version 1.1 - Changed command mapping. Read *
;* analog channel commands are now 'A' - 'E'. Verify status is now *
;* '@'. Changed the default reporting mode to ASCII. Changed the *
;* ASCII response string to include a leading character of 'a' - *
;* 'e' and a terminating character of '@'. This was to improve *
;* robustness of the protocol. Changed the Verify Status response *
;* to be a single '!' character. Added conditional assembly *
;* switches to support clock frequencies of 15.36Mhz and 18.432Mhz.*
;************************************************************************
;
;SIMDEBUG equ 1
;DEBUG equ 1
list p=16F870
list b=4,n=45,mm=OFF,st=OFF
#include
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC & _DEBUG_OFF & _LVP_OFF
cpuclk equ 18 ; use 15 for 15.36Mhz clock
; use 16 for 16.00Mhz clock
; use 18 for 18.432Mhz clock
if (cpuclk != 15) & (cpuclk != 16) & (cpuclk != 18)
error Invalid CPU CLock Frequency Specified
endif
fbSerTxInit equ 0x20 ;asynchronous, tx enabled, BRGH=0
fbSerRxInit equ 0x90 ;使能串行口, 连续发送 8bit
if cpuclk == 15
cntBaudDiv equ 24
endif
if cpuclk == 16
cntBaudDiv equ 25
endif
if cpuclk == 18
cntBaudDiv equ 29
endif
fbTrisAInit equ 0x2F ;B‘00101111’RA4 output
fbTrisBInit equ 0x00 ; RB7-0 as output
fbTrisCInit equ 0x90 ;B‘10010000’TX,RC5 as output
; RX,RC4 as input
; RC3-0 as output
fbAdCon0Init equ 0x81 ;AD enabled, Fosc/32 clock, channel 0
fbAdCon1Init equ 0x80 ;right justified, AN4-0 as analog inputs
if cpuclk == 15
cntAdDelay equ 16 ;AD延时
endif
if cpuclk == 16
cntAdDelay equ 18
endif
if cpuclk == 18
cntAdDelay equ 20
endif
; 命令处理的字符常数
cmdReadA0 equ 'A' ; 读模拟通道 0 (read analog channel)
cmdReadA1 equ 'B' ; 读模拟通道 1
cmdReadA2 equ 'C' ; 读模拟通道 2
cmdReadA3 equ 'D' ; 读模拟通道 3
cmdReadA4 equ 'E' ; 读模拟通道 4
cmdVerify equ '@' ; 询问状态
cmdLoopBack equ 'L' ; 进入回送模式命令
chEsc equ 0x1B ; ESC - 退出回送模式
chAck equ '@' ; 确认符
chError equ '#' ; 错误反应符
chPrompt equ '>' ; > - 回送模式提示
chStatusOk equ '!' ; status ok.
; 送信复位或作为对状态命令的应答
bitModeAnalog equ 0 ;模式控制位 0 is 二进制 read back mode
; 1 is 十六进制 read back mode
VarRam equ 0x20 ; general purpose variable area
w_temp equ 0x70 ; variable used for context saving
s_temp equ 0x71 ; variable used for context saving
cblock VarRam
bRegA ; temporary working variable
bRegB ; temporary working variable
fbMode ; 模式控制位
chCommand ; 可变的保持电流字符
achRead ; 读模拟频道数
bAvalL ; LSB 模拟转变值
bAvalH ; MSB 模拟转变值
chSend ; 连续输出魏存器
endc
;===========================================================
ORG 0x000
goto Main
ORG 0x004
goto IsrEnter
IsrEnter
movwf w_temp
swapf STATUS,w
movwf s_temp
IsrExit:
swapf s_temp,w
movwf STATUS
swapf w_temp,f
swapf w_temp,w
retfie
;===========================================================
Main:
movlw 0
movwf INTCON
movwf PIR1
movwf fbMode ; 缺省模式是 ASCII Hex
bsf fbMode,bitModeAnalog
call InitConfig
call Delay
call Delay
call VerifyStatus
GetCommand: ; 等待下接收的一个命令字节
call GetSerialByte ; 从串行口获得下一个字符
movwf chCommand
movf chCommand,w
andlw 0xF0
xorlw 0x40
btfsc STATUS,Z
goto DispatchCommand4X
goto InvalidCommand ; 命令字节 范围是 0x40-0x4F.
DispatchCommand4X:
movf chCommand,w
andlw 0x0F
addwf PCL,f
goto DoCmdVerifyStatus ; 0x40 '@' - Verify status
goto DoCmdReadAnalog ; 0x41 'A' - read AN0
goto DoCmdReadAnalog ; 0x42 'B' - read AN1
goto DoCmdReadAnalog ; 0x43 'C' - read AN2
goto DoCmdReadAnalog ; 0x44 'D' - read AN3
goto DoCmdReadAnalog ; 0x45 'E' - read AN4
goto DoCmdSetBinary ; 0x46 'F' - set binary mode
goto DoCmdSetAscii ; 0x47 'G' - set ascii mode
goto DoCmdQueryMode ; 0x48 'H' - query analog mode
goto DoCmdReset ; 0x49 'I' - reset
goto InvalidCommand ; 0x4A 'J'
goto InvalidCommand ; 0x4B 'K'
goto DoCmdLoopBack ; 0x4C 'L' - enter loopback mode
goto InvalidCommand ; 0x4D 'M'
goto InvalidCommand ; 0x4E 'N'
goto InvalidCommand ; 0x4F 'O'
; 错误命令应答
InvalidCommand:
call SendError
goto GetCommand
;===========================================================
DoCmdVerifyStatus:
call VerifyStatus
goto GetCommand
DoCmdReset:
goto Main
;测试模式
DoCmdLoopBack:
movlw chPrompt
call PutSerialByte
call LoopBack
movlw chAck
call PutSerialByte
goto GetCommand
;读模拟频道
DoCmdReadAnalog:
movlw cmdReadA0
subwf chCommand,w
movwf achRead ;and store as channel to read
call ReadAnalogChannel ;get the analog value into bAvalL
; and bAvalH
btfss fbMode,bitModeAnalog ;if clear, in binary mode
call SendAnalogBinary
btfsc fbMode,bitModeAnalog ;if set, in ASCII mode
call SendAnalogAscii
goto GetCommand
;二进制
DoCmdSetBinary:
bcf fbMode,bitModeAnalog
movlw chAck
call PutSerialByte
goto GetCommand
;十六进制
DoCmdSetAscii:
bsf fbMode,bitModeAnalog
movlw chAck
call PutSerialByte
goto GetCommand
;模拟输出模式询问操作. 应答'A' if in ASCII mode, and a 'B' if in binary mode
DoCmdQueryMode:
movlw 0x41 ;ASCII 'A' for ASCII mode
btfss fbMode,bitModeAnalog ;if clear, we're in binary mode
movlw 0x42 ;ASCII 'B' for binary mode
call PutSerialByte ;send the response
goto GetCommand
clrf PORTA
clrf PORTB
clrf PORTC
bsf STATUS,RP0 ;access alternate file registers
movlw fbTrisAInit ;0X2F
movwf TRISA & 0x7F
movlw fbTrisBInit
movwf TRISB & 0x7F
movlw fbTrisCInit
movwf TRISC & 0x7F
bcf STATUS,RP0
movlw fbAdCon0Init ;0X81
movwf ADCON0
bsf STATUS,RP0
movlw fbAdCon1Init ;0X80
movwf ADCON1 & 0x7F
bcf STATUS,RP0
; 串行口异步, 波特9600
bsf STATUS,RP0
movlw fbSerTxInit ;0X20
movwf TXSTA & 0x7F
movlw cntBaudDiv ;9600 baud with BRGH=0
movwf SPBRG & 0x7F
bcf STATUS,RP0 ;access primary register file
movlw fbSerRxInit ;0X90
movwf RCSTA
return
;发送出错
SendError:
movlw chError
call PutSerialByte
return
;发送应答字符
VerifyStatus:
movlw chStatusOk
call PutSerialByte
return
LoopBack:
lpbk10:
call GetSerialByte ;等待在串行口收到字符
xorlw chEsc
btfsc STATUS,Z
goto lpbk90
xorlw chEsc
call PutSerialByte
goto lpbk10
lpbk90: return
;进行AD,值存bAvalL and bAvalH.
ReadAnalogChannel:
movf achRead,w
movwf bRegA
rlf bRegA,f
rlf bRegA,f
rlf bRegA,f
movf bRegA,w
iorlw fbAdCon0Init
movwf ADCON0
movlw cntAdDelay ; 容许样本保留电容变成充电
movwf bRegA
rdac20: decfsz bRegA,f
goto rdac20
bsf ADCON0,GO_DONE ; Start the conversion
rdac40: btfsc ADCON0,NOT_DONE
goto rdac40
bsf STATUS,RP0
movf ADRESL & 0x7F,w ;get the LSB of the result
bcf STATUS,RP0
movwf bAvalL
movf ADRESH,w
movwf bAvalH
return
SendAnalogBinary:
movf bAvalL,w ;get the LSB
call PutSerialByte ;and send it
movf bAvalH,w ;get the MSB
call PutSerialByte ;and send it
return
;
; -------------------------------------------------------
; SendAnalogAscii
;
; This routine will send the analog value currently
; stored in bAvalL and bAvalH out the serial port. The
; data is sent as a packet with a lead character that
; will be 'a' through 'e' (to indicate which channel the
; response is for, followed by a 3 digit hex
; number in ASCII. The value is send MSB first. The
; reponse packet is terminated by a '@' character.
SendAnalogAscii:
movf achRead,w ;get channel number
addlw 0x61 ;add Ascii 'a'
call PutSerialByte
movf bAvalH,w ;get MSB of value to send
andlw 0x0F ;mask to hex digit
call ConvertHexDigit ;turn into hex ascii digit
call PutSerialByte ;send out the serial port
movf bAvalL,w ;get LSB of value
movwf bRegA ;
rrf bRegA,f ;shift right by 4 bits to
rrf bRegA,f ; get the next digit into
rrf bRegA,f ; the correct bit positions
rrf bRegA,w
andlw 0x0F ;isolate the bits for this digit
call ConvertHexDigit ;turn into hex ascii digit
call PutSerialByte ;send out the serial port
movf bAvalL,w ;get LSB of value
andlw 0x0F ;isolate the lower hex digit
call ConvertHexDigit ;turn into hex ascii digit
call PutSerialByte ;send out the serial port
movlw chAck ; 送终止符
call PutSerialByte
return
GetSerialByte:
ifndef SIMDEBUG
gtsb10: btfss PIR1,RCIF
goto gtsb10
endif
movf RCREG,w
return
; -------------------------------------------------------
; PutSerialByte
; This routine will send a character out the serial port.
; It checks the status of the transmit buffer, and waits
; until it is clear before sending the byte.
PutSerialByte:
movwf chSend ;save output char temporarily
ifndef SIMDEBUG
ptsb10: btfss PIR1,TXIF ;wait until transmitter ready
goto ptsb10
endif
movf chSend,w ;send the character
movwf TXREG
return
; -------------------------------------------------------
; ConvertHexDigit
; This routine will convert the 4 bit value in W into
; an hexadecimal digit in ASCII. The result is returned
; in W.
;
; 0x0A is subtracted from the value to check if it is
; in the range 0-9 or A-F. If in the range A-F, the
; difference between ascii 9 and ascii A is added to
; bias the result. The value of ASCII '0' is added in
; (plus the 0x0A that was subtracted in the test) to
; convert the value to an ASCII numeric digit.
ConvertHexDigit:
movwf bRegA
movlw 0x0A
subwf bRegA,w
btfsc STATUS,C ;if carry set, is in range 0-9
addlw 0x41-0x39-1 ;bias for difference between '9' and 'A'
addlw 0x30+0x0A ;convert to ASCII range
return
Delay:
movlw 255
movwf bRegA
dely20: call BitDelay
decfsz bRegA,f
goto dely20
return
; This routine delays for one bit time on the serial
; port. The delay time is 3*(n-1)+6 clocks.
cntDlyBit equ 169
BitDelay:
movlw cntDlyBit
movwf bRegB
btdl20: decfsz bRegB,f
goto btdl20
return
;****************************************************************
end