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

📄 8052.asm

📁 Modbus rtu for I8052
💻 ASM
📖 第 1 页 / 共 2 页
字号:
        mov     a,#<SIZEOF_MB
        add     a,dpl
        mov     dpl,a
        mov     a,#>SIZEOF_MB
        addc    a,dph
        mov     dph,a        ;next entry
        djnz    r5,ci_1
  
        mov     EADRL,#<INIT_TOKEN
        mov     EDATA1,#>INIT_TAG
        mov     EDATA2,#<INIT_TAG
        mov     ECON,#05h       ;erase page (we sleep for 2mS)
        nop                     ;I'm suspicious!!!
        mov     ECON,#02h       ;write the page (we sleep for 250uS)
        nop
        ret
;
;
;    calculates and appends the CRC for a MODBUS RTU message
;    R0->modbus msg
;    R6 has the msg length   
;    return value ==0 if crc on a rx packet was ok else 1 = crc error
;    zaps:A,B,R0,R2,R4,R5,R6
;
;       crc_lo R4
;       crc_hi R5
;
;
;
calculate_crc

        mov     r4,#0ffh
        mov     r5,#0ffh                ;preload the crc accumulator

cc_lp
        mov     a,@r0                   ;get a byte from the buffer
        inc     r0
        
        xrl     a,r4
        mov     r4,a                    ;CRC ^= *buff
        
        mov     r2,#8                   ;for x=1 to 8
cc_1
        clr     c
        mov     a,r5
        rrc     a
        mov     r5,a
        
        mov     a,r4
        rrc     a
        mov     r4,a                    ;CRC >>=1
        
        jnc     cc_2
        
        mov     a,#0a0h
        xrl     a,r5
        mov     r5,a
        
        mov     a,#01h
        xrl     a,r4
        mov     r4,a                    ;if (carry) CRC ^= 0xa001

cc_2
        djnz    r2,cc_1                 ;next x
        
        djnz    r6,cc_lp
        
        mov     b,#0                    ;B has the error status
        mov     a,@r0
        xrl     a,r4                    ;if crc_lo != *buff then err = 1
        jz      cc_3

        mov     b,#1                    ;flag error

cc_3
        mov     a,r4
        mov     @r0,a
        inc     r0                      ; *buff++ = crc_lo
        
        mov     a,@r0
        xrl     a,r5
        jz      cc_4
        
        mov     b,#1                    ;flag error

cc_4
        mov     a,r5
        mov     @r0,a
        inc     r0                      ;*buff++ = crc_hi
        
        mov     a,b                     ;get the return result
        ret
;----------------------------------------------------------------------------
;
;
;  outputs the modbus ascii data. converts the buffer data to ascii and
;  appends the modbus LRC and cr/lf
;
;  we use register bank 1 exclusively
;
;  R0 is tx_ptr
;  R1 is rx_ptr
;  R2 is tx_state
;  R3 is rx_state
;  R4 is tx_lrc
;  R5 is rx_lrc
;  R6 is tx_length
;  R7 is rx_length
;
serial_isr
        jb      MODBUS_TYPE,ascii
        jb      TI,txrtu
        jb      RI,rxrtu
        sjmp    serial_exit
ascii  
        jb      TI,txascii
        jnb     RI,serial_exit
        ljmp    rxascii
serial_exit
        reti    
;
;
;       modbus RTU rx code
;  we use register bank 1 exclusively
;
;  R0 is tx_ptr
;  R1 is rx_ptr
;  R2 is tx_state
;  R3 is rx_state
;  R4 is tx_lrc
;  R5 is rx_lrc
;  R6 is tx_length
;  R7 is rx_length
;
;
;
rxrtu
        push    psw
        push    a
        mov     psw,#00001000b    ;select register bank#1  
       
        mov     a,r3                    ;get the rx state
        cjne    a,#0,rxrtu_1
;
;       RTU rx state 0, grab the rx data & store into the buffer
;        
;        mov     r5,#3                   ;load the timeout with 2 character times
        mov     a,r7                    ;test the rx length
        clr     c
        subb    a,#SIZEOF_MODBUS_BUFF-2
        jnc     rxrtu0_1                 ;rx count too large! exit
        
        mov     a,SBUF                  ;rx buff ok, grab the rx char
        clr     RI
        mov     @r1,a                   ;store it
        inc     r1                      ;rx->++
        inc     r7                      ;rx length++
;
;       use timer2 for end of packet timeout
;    
        clr     TR2
        mov     TH2,#0fah
        mov     TL2,#060h               ;3 char times
        setb    TR2

        sjmp    rxrtu_x
        
rxrtu_1
;
;       RTU rx state1, ignore any more rx chars for the moment
;
rxrtu0_1
        mov     a,SBUF                  ;junk the rx character
        clr     RI
rxrtu_x
  pop  a
  pop  psw
  reti
;
;
;       the tx code is a little trickier since we use the tx as a timer for the
;       rx packet timeout when we're not actually transmitting a packet
;
;                
txrtu
        push    psw
        push    a
        mov     psw,#00001000b    ;select register bank#1  
        
        mov     a,r2                    ;get the tx state
        cjne    a,#0,txrtu_1
;
;       RTU tx state 0. nothing happening so disable the interrupts
;        
        setb    EN_485                  ;don't send anything to the outside!
        clr     TI
        sjmp    txrtu_x        
        
;        mov     a,r5                    ;get the rx timer
;        jz      txrtu_x                 ;already 0, don't do anything!
        
;        djnz    r5,txrtu_x              ;dec the timer
;
;       timer just hit 0, activate the rx process code
;        
;  mov  r1,#modbus_buff
;  mov  a,@r1      ;get the first byte (modbus addr)
;  xrl  a,our_addr    ;test with our address
;  jnz  txrtu0_2    ;if not us
;  setb  TASK0_RUN    ;if a good packet, activate the rx task
;  mov  r3,#1      ;set state for rx idle, when packet is processed, we are reset
;  sjmp  txrtu_x
;
;       restart the RTU rx code
;
;txrtu0_2
;        mov     r1,#modbus_buff         ;reset the rx->
;        mov     r7,#0                   ;reset the byte count
;        mov     r3,#0                   ;reset the rx state
;        
;        sjmp    txrtu_x

txrtu_1
        cjne    a,#1,txrtu_x
;
;       RTU tx state 1. here we send tx data to the outside world
;       
;                        
        clr     EN_485
        mov     a,@r0
        mov     SBUF,a
        clr     TI
        inc     r0
        djnz    r6,txrtu_x
;
;       last character of the packet, next state is 0
;        
        mov     r2,#0        

txrtu_x
        pop     a
        pop     psw
        reti
;
;
;  implements the MODBUS ASCII protocol. 
;  user routine must set tx_ptr (R0), tx_length (R6) and send the ':' start token
;  to fire the tx interupt
;
;
txascii
  push  psw
  push  a
  mov  psw,#00001000b    ;select register bank#1  
  mov  a,r2      ;get the state into A
  cjne  a,#0,tx_st1
;
;  state = 0
;
  mov  a,@r0
  add  a,r4
  mov  r4,a      ;accumulate the checksum
  mov  a,@r0
  swap  a      ;get hi nibble
  anl  a,#0fh
  cjne  a,#10,mti_1
mti_1
  jnc  L96  
  add  a,#'0'      ;ascii offset 0..9
  sjmp  L97
L96
  add  a,#'0' + 7    ;ascii offset A..F
L97
  mov  SBUF,a
  clr  TI
  mov  r2,#1      ;next state = 1
  sjmp  L95_X
tx_st1
  cjne  a,#1,tx_st2
;
;  state = 1. send ascii low nibble
;
  mov  a,@r0
  inc  r0
  anl  a,#0fh      ;get low nibble
  cjne  a,#10,mti_2
mti_2  jnc  L96_1  
  add  a,#'0'      ;ascii offset 0..9
  sjmp  L97_1
L96_1
  add  a,#'0' + 7    ;ascii offset A..F
L97_1
  mov  SBUF,a
  clr  TI
  dec  r6
  mov  a,r6
  cjne  a,#1,mti_3    ;length == 1?
  sjmp  L102      ;yep! calc the lrc
mti_3  
  jnz  L103      ;if the last byte
  mov  r2,#2      ;next state =2,send CR
  sjmp  L95_X
L103
  mov  r2,#0      ;next state = 0,send next byte
  sjmp  L95_X
L102
  mov  a,r4      ;get the lrc
  cpl  a      ;ones complement
  inc  a      ;plus 1
  mov  @r0,a      ;store the lrc
  mov  r2,#0      ;next state =send hi nibble
  sjmp  L95_X
tx_st2
  cjne  a,#2,tx_st3
;
;  state = 2. send CR
;
  mov  SBUF,#CR    ;send CR
  clr  TI
  mov  r2,#3      ;next state = 3 send line feed
  sjmp  L95_X
tx_st3
  cjne  a,#3,tx_st4
;
;  state = 3. send line feed
;
  mov  SBUF,#LF    ;send LF
  clr  TI
  mov  r2,#4      ;next state = 4
  sjmp  L95_X
tx_st4
  cjne  a,#4,L95_X
;
;  state = 4. end of transmit, set 485 buffer to receive and sit
;  here until the tx code re-activates us
;  
  clr  TI
  setb  EN_485
L95_X
  pop  a
  pop  psw
  reti
;
;
;  implements the MODBUS ASCII receive protocol
;
;
rxascii
  push  psw
  push  a
  push  b
  mov  psw,#00001000b    ;select register bank#1  
  mov  b,SBUF      ;get the rx char into B
  clr  RI
;
;  always test for the start token
;
  mov  a,b
  cjne  a,#':',L129    ;start token?
  mov  r5,#0      ;rx_lrc = 0
  mov  r7,#0      ;rx_length = 0
  mov  r1,#modbus_buff    ;->start of rx buffer
  mov  r3,#1      ;next state = 1  
  sjmp  L116_X

L129


rx_st1
  mov     a,r3                    ; get the rx state
        cjne  a,#1,rx_st2
;
;  rx_state = 1. expect a hex ascii char or a carriage return
;  for end of packet
;
  clr  c
  mov  a,b
  subb  a,#'0'    ;minus ascii offset
  jc  L127    ;if number < '0'
  cjne  a,#9+1,rx_st1_2
rx_st1_2
  jnc  L125    ;if rx char > 9
  sjmp  L126
L125
  clr  c
  subb  a,#7
  cjne  a,#0ah,rx_st1_3
rx_st1_3
  jc  L127      ;if rx char is < 'A'  
  cjne  a,#0fh+1,rx_st1_4
rx_st1_4
  jnc  L127      ;if rx char > 'F'
L126
  anl  a,#0fh
  swap  a
  mov  @r1,a
  mov  r3,#2      ;next state = 2
  sjmp  L116_X
L127
  mov  a,b
  cjne  a,#CR,L124    ;carriage return? (end of packet?)
;
;  end of packet
;
  mov  a,r5      ;get our rx_lrc
  jnz  L124      ;if lrc was bad!
  mov  r1,#modbus_buff
  mov  a,@r1      ;get the first byte (modbus addr)
  xrl  a,our_addr    ;test with our address
  jnz  L124      ;if not us
  setb  TASK0_RUN    ;if a good packet, activate the rx task
  mov  r3,#4      ;idle in an illegal state, when packet is processed, we are reset
  sjmp  L116_X
L124
  mov  r3,#0      ;next state = 0
  sjmp  L116_X
rx_st2
  cjne  a,#2,L116_X
;
;  state = 2. expect hex ascii for low byte nibble
;
  clr  c
  mov  a,b
  subb  a,#'0'    ;minus ascii offset
  jc  L137    ;if number < '0'
  cjne  a,#9+1,rx_st2_2
rx_st2_2
  jnc  L135    ;if rx char > 9
  sjmp  L133
L135
  clr  c
  subb  a,#7
  cjne  a,#0ah,rx_st2_3
rx_st2_3
  jc  L127      ;if rx char is < 'A'  
  cjne  a,#0fh+1,rx_st2_4
rx_st2_4
  jnc  L127      ;if rx char > 'F'
L133
  anl  a,#0fh
  orl  a,@r1      ;'or' in the hi nibble
  mov  @r1,a    
  add  a,r5      ;get rx_lrc
  mov  r5,a      ;accumulate the lrc
  inc  r1      ;rx_ptr++
  inc  r7      ;rx_length++
  cjne  r7,#SIZEOF_MODBUS_BUFF,rx_st2_5
rx_st2_5
  jnc  L137      ;if rx packet is too large!  
  mov  r3,#1      ;otherwise next state = 1
  sjmp  L116_X
L137
  mov  r3,#0      ;next state = 0
L116_X
  pop  b
  pop  a
  pop  psw
  reti  
;
;
;       timer2 timeout comes here when an end of a modbus rtu packet is detected by 3 char timeout
;
;        
t2_isr        
        clr     TR2                     ;stop timer2 running
        clr     TF2                     ;reset the interrupt flag
        push    psw
        push    a
        mov     psw,#00001000b          ;select register bank#1  
        
        mov     r1,#modbus_buff
        mov     a,@r1                   ;get the first byte (modbus addr)
        xrl     a,our_addr              ;test with our address
        jnz     t2_1                    ;if not us
        setb    TASK0_RUN               ;if a good packet, activate the rx task
        mov     r3,#1                   ;set state for rx idle, when packet is processed, we are reset
        sjmp    t2_x
;
;       restart the RTU rx code
;
t2_1
        mov     r1,#modbus_buff         ;reset the rx->
        mov     r7,#0                   ;reset the byte count
        mov     r3,#0                   ;reset the rx state
t2_x
        pop     a
        pop     psw
        reti
;----------------------------------------------------------------------------
;
;
;  rom constant data
;
;  
;----------------------------------------------------------------------------
;  constant structure for the modbus registers. Has flags to determine if the register
;  is stored in ram or eeprom and the pointer to the ram/eeprom address where to register
;  contents are stored. Also has the default value that is loaded into the registers
;  on startup for ram based registers or when first programmed for eeprom based registers.
;  There is an entry for every modbus register in order of the modbus register number.
;
;
SIZEOF_MB       equ     4       ;structure size
MB_FLAGS        equ     0
MB_OFFSET       equ     1       ;offset value for index into eeprom OR internal ram (MB_EEPROM if set is eeprom)
MB_DEFAULT      equ     2       ;default value for init. 1 word
;
; bits in MB_FLAGS
;
MB_EEPROM       equ     0       ;bit 0 of the flags .1 = register read/written to eeprom, 0 =read/write to ram


modbus_options_table
                GLOBALS ON
;  0       Software Version Number
MB_VERS equ     ($-modbus_options_table)/SIZEOF_MB
        db      1.SHL.MB_EEPROM ;options
        db      <MBEE_VERS      ;ram/eeprom addr
        dw      VERSION         ;default value (loaded into eeprom)


modbus_buff     ds      SIZEOF_MODBUS_BUFF

stack    equ    $       ;stack starts from here- it grows upwards on a 8051
 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -