⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 8052.asm

📁 Modbus rtu for I8052
💻 ASM
📖 第 1 页 / 共 2 页
字号:
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 + -