??? 09/28/06 09:26 Read: times |
#125265 - Modbus code Responding to: ???'s previous message |
Here is some modbus code written in assembler - it was originally written in 'c' but converted to assembler to fit into a small micro. However - the structure is much the same. Modbus sees everything as 16 bit registers or bits. This code only implements the 16 bit registers. These regsters may have configuration or process values. The config is stored in eeprom and the process values are stored in ram. The modbus_config_table structure is used by the routines read_modbus_reg and write_modbus_reg to find out where to read/write the values. This structure also has the initialisation values. The routine cold_init is used to initialise the ram based registers with the default value stored in the structure and tests for a token in the eeprom to see if it needs to be initialised. The serial interrupt code sends/receives the modbus packets. This code translates the ascii packets to/from RTU format. When a packet is received, a flag is set to activate a task that calls the routine process_modbus. This routine checks the received packet and forms the response. This code pretty much follows the logic in the modbus spec. You can add extra commands in here if required. Use the routines read_modbus_reg and write_modbus_reg to access the modbus registers. The CRC routine can be found in 'c' in the modbus spec. You can choose between two methods - looped as is done here - slow but small in code size or table driven - large but fast. Beware of atomicity issues - if you don't know what they are, you'd best learn as they apply here. This code ran under a co-operative tasker so modbus register accesses were mutually exclusive between the process_modbus code and the read/write_modbus_reg code. Ignore the above comments at your own peril. Apart from that, MODBUS is a very simple and widely supported protocol for instrumentation and control applications. Useless for anything else though. Have Fun. CHIP 8052 ; ; 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 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 |
Topic | Author | Date |
Modubus code... Russell Bull | 01/01/70 00:00 | |
Life's like that! | 01/01/70 00:00 | |
Tell me more... | 01/01/70 00:00 | |
commercial application... Yes! | 01/01/70 00:00 | |
Modbus code | 01/01/70 00:00 | |
Would have been great if it was in C | 01/01/70 00:00 | |
Free is what free gets | 01/01/70 00:00 | |
Thanks anyway | 01/01/70 00:00 | |
modbus in c | 01/01/70 00:00 | |
Read the above. | 01/01/70 00:00 | |
yes, but | 01/01/70 00:00 | |
I dont mind... | 01/01/70 00:00 | |
Happiness | 01/01/70 00:00 | |
Oh! yes great joy..... | 01/01/70 00:00 |