📄 8052.asm
字号:
Modbus code. (c)2005 Russell Bull.
;
; this module implements the Modbus rx/tx code and the register
; structure.
; In order to save ram, certain modbus registers are only implemented in EEprom, the read/write_modbus_reg
; routines take care of any shenanigans.
;
public t2_isr ; timer2 interrupt code
public read_modbus_reg ; reads a modbus reg into R7:R6
public write_modbus_reg ; writes a modbus reg into R7:R6
public cold_init ; loads defaults into ram based regs & eeprom base regs(if required)
public serial_isr ; int vector for the serial port
public MODBUS_READ_HOLDING_REGS
public modbus_buff
public process_modbus ; task to process modbus messages
public stack
public NUM_MODBUS_REGS
public our_addr
extern MODBUS_TYPE
extern RX_PKT
;
; kernel externals
;
extern TASK0_RUN
extern dispatch
extern kick_dog
;
;
;
extern _R0
extern _R1
extern _R2
extern _R3
extern _R4
extern _R5
extern _R6
extern _R7
extern bank1_R0
extern bank1_R1
extern bank1_R2
extern bank1_R3
extern bank1_R4
extern bank1_R5
extern bank1_R6
extern bank1_R7
;
; MODBUS command values
;
MODBUS_PRESET_REGS equ 16
MODBUS_READ_HOLDING_REGS equ 3
;
MAX_RW_REGS equ 16+1 ;maximum number of registers than can be read/written at one time
SIZEOF_MODBUS_BUFF equ (MAX_RW_REGS *2)+ 10 ;modbus rx/tx buffer
INIT_TAG equ 0aa55h ;tag stored in eeprom to see if we're initialised yet
CR equ 13
LF equ 10
CODE
;----------------------------------------------------------------------------
;
;
; process modbus. decodes the modbus packet in modbus_buff
; and performs the required command
; ** assumes the rx code has checked the modbus address **
; zaps:most regs!
;
;----------------------------------------------------------------------------
process_modbus
jb MODBUS_TYPE,pm_c ;if modbus_type is ascii then we don't need to check the CRC
;
; modbus transport is RTU, check the CRC before continuing
;
mov r0,#modbus_buff
mov a,bank1_R7 ;get the rx packet size
mov bank1_R7,#0 ;reset the packet size
cjne a,#7,pm_1
pm_1 jc pm_z ;ignore packet if it is too small
clr c
subb a,#2 ;-2 for CRC bytes
mov r6,a
lcall calculate_crc
jz pm_c ; if CRC was ok - process the packet
pm_z
ljmp L72 ;bad crc-skip the packet
pm_c
setb RX_PKT ;flash asterisk on the lcd for good rx pkts
mov r0,#modbus_buff+1
mov a,@r0 ;get the modbus command
cjne a,#MODBUS_READ_HOLDING_REGS,L59
;
; read holding regs command
;
mov r0,#modbus_buff+3 ;get the starting reg#
mov a,@r0
mov r2,a
mov r0,#modbus_buff+5 ;get # of regs
mov a,@r0
mov r5,a
clr c
subb a,#MAX_RW_REGS
jc pm_11
ljmp L62 ;if too many registers requested
pm_11
mov a,r5
add a,r5 ;register count times 2
mov r0,#modbus_buff+2
mov @r0,a ;set the reply byte count
inc r0
;
; copy mregs[] into the transmit buffer
;
pm_2
pm2_2
mov a,r2
lcall read_modbus_reg ;A has the modbus register#
jnz L51 ;if register error
mov a,r7
mov @r0,a ;store high
inc r0
mov a,r6
mov @r0,a ;store low
inc r0
inc r2 ;next register#
djnz r5,pm2_2 ;loop until regs copied
pm_3:
clr c
mov a,r0
subb a,#modbus_buff ;calc message length
sjmp send_modbus ;& send it
L51:
;
; register request exceeded the # of registers
;
mov r0,#modbus_buff+1
mov a,@r0 ;get modbus cmd
orl a,#80h ;set error flag
mov @r0,a
mov r0,#modbus_buff+2
mov a,#2 ;bad address
mov @r0,a
mov a,#4 ;length =4 including the LRC
sjmp send_modbus
L59
cjne a,#MODBUS_PRESET_REGS,L44
;
; Modbus preset registers command
;
mov r0,#modbus_buff+3
mov a,@r0 ;get the starting reg#
mov r2,a ;into R2
prc_4
mov r0,#modbus_buff+5
mov a,@r0 ;get # of regs
mov r5,a ;into R5
clr c
subb a,#MAX_RW_REGS
jnc L62 ;if too many registers requested
mov a,r5
add a,r2 ;add + count
clr c
subb a,#NUM_MODBUS_REGS
jnc L62
prc_1
mov a,r5 ;test reg count
jz prc_3 ;if all done
prc_2
mov r0,#modbus_buff+7 ;r0 ->modbus_buff[7]
;
; get the register from the rx buffer into R7:R6
;
mov a,@r0
mov r7,a ;reg high
inc r0
mov a,@r0
mov r6,a ;reg low
inc r0
mov a,r2 ;get modbus reg#
lcall write_modbus_reg
;
; next!!
;
inc r2
djnz r5,prc_1 ;count--
prc_3
mov a,#6 ;set reply pkt length
sjmp send_modbus
;
; bad register passed
;
L62
mov r0,#modbus_buff+1
mov a,@r0
orl a,#080h ;set error flag
mov @r0,a
inc r0
mov a,#2 ;bad address
mov @r0,a
mov a,#4 ;pkt length =4 inc LRC
sjmp send_modbus
;
; catch all for command not supported
;
L44
mov r0,#modbus_buff+1
mov a,@r0
orl a,#080h ;set error flag
mov @r0,a
inc r0
mov a,#1 ;bad command
mov @r0,a
mov a,#4 ;pkt length =4 inc LRC
;
; send the modbus data out
; A has the packet length
; modbus data is assumed to be in modbus_buff
;
send_modbus
orl a,a
jz L72 ;if length ==0, skip transmit
jb MODBUS_TYPE,send_ascii
push a
mov r6,a ;packet length
mov r0,#modbus_buff
call calculate_crc
pop a
add a,#2 ;+crc bytes
;
; use MODBUS RTU as the packet transport
;
clr ea ;no interrupts
dec a ;-1
clr EN_485 ;set 485 buffer to tx
mov bank1_R6,a
mov bank1_R0,#modbus_buff+1
mov bank1_R2,#1 ;set tx state
mov r0,#modbus_buff ;get the first character
mov a,@r0
mov SBUF,a ;and send it to start the tx interrupts
setb ea
sjmp L72
;
; use MODBUS ascii as the packet transport
;
send_ascii
clr EN_485 ;set 485 buffer to tx
inc a ;+1 on the packet size for the LRC
mov bank1_R6,a ;set the packet length
mov bank1_R0,#modbus_buff
mov bank1_R2,#0 ;clear tx state
mov bank1_R4,#0 ;clear LRC
mov SBUF,#':' ;send the start token (fires the tx interrupt)
clr TI
L72
L42
L41
clr TASK0_RUN ;reset task request
mov bank1_R3,#0 ;reset the rx state
ljmp dispatch
;----------------------------------------------------------------------------
;
; write MODBUS register
; entry:
; R7:R6 has the modbus register value to write
; A has the MODBUS register#
; returns: A == 0 if ok, A ==1 if bad register#
; zaps: A,PSW
;
;----------------------------------------------------------------------------
write_modbus_reg
push dph
push dpl
push _R0
push b
cjne a,#NUM_MODBUS_REGS,wmr_1 ;test for max reg#
wmr_1
jnc wmr_bad ;if reg# >=NUM_MODBUS_REGS
;
; dptr->modbus_options_table
;
mov b,#SIZEOF_MB
mul ab ;calc table offset
mov dptr,#modbus_options_table
add a,dpl
mov dpl,a
mov a,b
addc a,dph
mov dph,a ;dptr->modbus_options_table[reg#]
;
; check the register options
;
mov a,#MB_FLAGS
movc a,@a+dptr ;get the options byte
jnb a.MB_EEPROM,wmr_2
;
; EEprom option is set, write the register to eeprom
;
call kick_dog ; keep the dog happy whilst we write to eeprom
mov a,#MB_OFFSET
movc a,@a+dptr ; get the eeprom addr
clr c
rrc a ; calc the page addr
clr c
rrc a
mov EADRL,a ;set the page address
mov ECON,#01h ;read page -'cos we do a read_modify_write
jc wmr_11 ; if we're writing the hi two bytes in the page
;
; write the two low bytes in the page
;
mov a,R7
mov EDATA1,a
mov a,R6
mov EDATA2,a
sjmp wmr_12
;
; write the two low bytes in the page
;
wmr_11
mov a,R7
mov EDATA3,a
mov a,R6
mov EDATA4,a
;
; erase the eeprom page, then write it
;
wmr_12
mov ECON,#05h ;erase page (we sleep for 2mS)
mov ECON,#02h ;write the page (we sleep for 250uS)
sjmp wmr_3
;
; modbus register is in ram
;
wmr_2
mov a,#MB_OFFSET
movc a,@a+dptr
mov r0,a ;r0-> modbus register in ram
mov a,r7
mov @r0,a ;store hi byte
inc r0
mov a,r6
mov @r0,a ;store low byte
wmr_3
clr a
wmr_x
pop b
pop _R0
pop dpl
pop dph
ret
wmr_bad
mov a,1 ;return a bad status
sjmp wmr_x
;----------------------------------------------------------------------------
;
; read MODBUS register
; entry:
; A has the MODBUS register#
; returns: A == 0 if ok, A ==1 if bad register#, R7:R6 with the modbus reg value
; zaps: A,PSW
;
;----------------------------------------------------------------------------
read_modbus_reg
push dph
push dpl
push _R0
push b
cjne a,#NUM_MODBUS_REGS,rmr_1 ;test for max reg#
rmr_1
jnc rmr_bad ;if reg# >=NUM_MODBUS_REGS
;
; check the register options
;
mov b,#SIZEOF_MB
mul ab ;calc table offset
mov dptr,#modbus_options_table
add a,dpl
mov dpl,a
mov a,b
addc a,dph
mov dph,a ;dptr->modbus_options_table[reg#]
mov a,#MB_FLAGS
movc a,@a+dptr ;get the options byte
jnb a.MB_EEPROM,rmr_2
;
; EEprom option is set, read the register from eeprom
;
mov a,#MB_OFFSET
movc a,@a+dptr ; get the eeprom addr
clr c
rrc a ; calc the page addr
clr c
rrc a
mov EADRL,a ;set the page address
mov ECON,#01h ;read page
jc rmr_11 ;if we're reading the hi two bytes in the page
;
; read the low two bytes from the eeprom page
;
mov r7,EDATA1
mov r6,EDATA2
sjmp rmr_3
;
; read the hi two bytes from the eeprom page
;
rmr_11
mov r7,EDATA3
mov r6,EDATA4
sjmp rmr_3
;
; modbus register is in ram
;
rmr_2
mov a,#MB_OFFSET
movc a,@a+dptr
mov r0,a ;r0-> modbus register in ram
mov a,@r0
mov r7,a ;read hi byte
inc r0
mov a,@r0
mov r6,a ;read low byte
rmr_3
clr a
rmr_x
pop b
pop _R0
pop dpl
pop dph
ret
rmr_bad
mov a,1 ;return a bad status
sjmp rmr_x
;----------------------------------------------------------------------------
;
;
; called on power-up to initialise the modbus registers
; reads all the values from the modbus_options_table default values
; into the eeprom if the INIT_TOKEN is not set and reads the defaults
; into the ram based registers
;
;----------------------------------------------------------------------------
cold_init
mov r5,#NUM_MODBUS_REGS
mov dptr,#modbus_options_table
ci_loop
mov a,#MB_FLAGS
movc a,@a+dptr ;get the options var
jb a.MB_EEPROM,ci_2 ;if an eeprom based register, skip as no init required
;
;
;
mov a,#MB_OFFSET
movc a,@a+dptr
mov r0,a ;r0->ram modbus register
mov a,#MB_DEFAULT
movc a,@a+dptr
mov @r0,a ;store the hi default value
inc r0
mov a,#MB_DEFAULT+1
movc a,@a+dptr
mov @r0,a ;store the low default value
ci_2
mov a,#SIZEOF_MB
add a,dpl
mov dpl,a
mov a,#0
addc a,dph
mov dph,a ;->next record
djnz r5,ci_loop
;
; test INIT_TOKEN for the correct value. If not, load the eeprom with the default values from the modbus_options_table
;
mov EADRL,#<INIT_TOKEN
mov ECON,#1
mov a,EDATA1
cjne a,#>INIT_TAG,ci_do
mov a,EDATA2
cjne a,#<INIT_TAG,ci_do
ret
;if init tag was valid
ci_do
mov r5,#NUM_MODBUS_REGS
mov dptr,#modbus_options_table
mov r2,#0 ;modbus register #1
ci_1
mov a,#MB_FLAGS
movc a,@a+dptr
jnb a.MB_EEPROM,ci_3 ;skip init if a ram based register
;
; eeprom based register...init it.
;
mov a,#MB_DEFAULT
movc a,@a+dptr
mov r7,a
mov a,#MB_DEFAULT+1
movc a,@a+dptr
mov r6,a
push dph
push dpl
mov a,r2 ;get modbus reg#
lcall write_modbus_reg
pop dpl
pop dph
;
; next register..
;
ci_3
inc r2
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -