; Modbus Code for MCS51 on Max232 (RS232 interface) ; Demonstration of using Metalink CROSS ASSEMBLER ; Codde developed -2011 g kandasamy ; February ,2011 $MOD51 ; 8052 predefined ; ; ; CRC16_BYTE_1 equ 57h ; CRC16_BYTE_2 equ 58h ; slave_id equ 55h ; ; ; org 0000h ; The Hardware for this code shall be standard 8052 Processor with a serial interface. ajmp init ; P0,P1 & P2 ports can be used as Digital Input or Analog input suitably. ; ; org 0030h ; Program Starts here ; Init: mov SP,#0c0h ; Initialize Processor mov pcon,#080h ; mov P1,#0FFh ; P1 as Input Port mov p3,0ffh ; P3 remaining unused pins as Input mov 55h,#06h ; Set slave address to 6 ( any number) mov TH1,#0FAh ; Timer 1 Initialize for Serial port mov TMOD,#20h ; Baud 9600 , 8, N , 1 mov SCON,#50h ; setb TR1 ; ; ; ; start: nop ; mov r0,#014h ; Assign 20 Memory locations. 10 Words. Modbus address 40000 to 40009 mov r1,#061h ; User can design suitable hardware, ADC or SPI or any interface using mov @r1,#0h ; the IO ports & fill the data in the Memory Locations (RAM) 61h to 74h. inc r1 ; The code in this area fills some data for Modbus communication. mov @r1,p0 ; inc r1 ; mov @r1,#0h ;This code fills inc r1 ; mov @r1,p1 ; Modbus address Data inc r1 ; mov @r1,#0h ; inc r1 ; 40000 P0 data mov @r1,p2 ; 40001 P1 data inc r1 ; 40002 P2 data mov @r1,#0h ; 40003 3 (constant values) inc r1 ; 40004 4 (constant values) mov @r1,#03h ; 40005 5 (constant values) inc r1 ; 40006 6 (constant values) mov @r1,#0h ; 40007 7 (constant values) inc r1 ; 40008 8 (constant values) mov @r1,#04h ; 40009 9 (constant values) inc r1 ; mov @r1,#0h ; inc r1 ; mov @r1,#05h ; inc r1 ; mov @r1,#0h ; inc r1 ; mov @r1,#06h ; inc r1 ; mov @r1,#0h ; inc r1 ; mov @r1,#07h ; inc r1 ; mov @r1,#0h ; inc r1 ; mov @r1,#08h ; inc r1 ; mov @r1,#0h ; inc r1 ; mov @r1,#09h ; ; ; ; ; recevq: nop ; Receive 8 bytes from Modbus Master and mov r2,#08h ; stores the query at Memory Location mov r0,#0eAh ; eaH to f2H ; wait: jnb RI,wait ; Receive data from computer mov A,SBUF ; clr RI ; mov @r0, A ; inc r0 ; djnz r2, wait ; Receive data from computer ; chkq: nop ; Check query is correct? mov r0,#0eah ; Check Slave address First mov a,@r0 ; clr c ; xrl a,55h ; cjne a,#00h,start ; If slave address is not= dont ck any further inc r0 ; mov a,@r0 ; check command cjne a,#03h,invlcmd ; If not Holding Register read create exception response ; inc r0 ; Check Data Range. 10 words only inc r0 ; If no of data exceed 10. create mov a, @r0 ; exception response mov r6,a ; inc r0 ; inc r0 ; mov a,@r0 ; add a,r6 ; mov b,a ; mov a,#0ah ; clr c ; subb a,b ; jc datarnge ; Exception call ; ; Framing: nop ; Framing reply mov r1,#080h ; Response is created in address mov r0,#0eah ; starting from 080h of RAM ; ; mov a,@r0 ; mov @r1,a ; slave address in Location-1 inc r0 ; inc r1 ; mov a,@r0 ; mov @r1,a ; Function code in location-2 inc r0 ; inc r0 ; mov a,@r0 ; rl a ; mov r6,a ; inc r0 ; inc r0 ; ; mov a, @r0 ; No of data LSB rl a ; Twice LSB no of bytes as 16 bit register ; inc r1 ; mov @r1, a ; No of Data Bytes in Location-3 mov r2,a ; ; mov a,r6 ; add a, #061h ; mov r0, a ; ; movdata: inc r1 ; Filling data in Location-4..... mov a,@r0 ; mov @r1,a ; inc r0 ; djnz r2,movdata ; ; ; calccrc: acall CRC16_INIT ; Calculation of CRC for above data mov r0,#082h ; mov a,@r0 ; add a,#03h ; mov r4,a ; No of bytes for crc calculation mov a,r1 ; mov r5,a ; mov r1, #080h ; ; ; crcloop: mov a,@r1 ; Get Byte for crc calculation acall CRC16_CALC ; inc r1 ; djnz r4,crcloop ; mov a,r5 ; mov r1,a ; ; fillcrc: nop ; inc r1 ; mov @r1, CRC16_BYTE_1 ; inc r1 ; mov @r1, CRC16_BYTE_2 ;This Completes framing. ; ; mov r1,#082h ; CALCULATES NUMBER OF BYTES TO TRANSMIT mov a,@r1 ; add a,#05h ; No of Data + Slave ID+Fun code+CRC mov r1, a ; No of bytes to be transmitted ; Reply: nop ; mov r0,#080h ; Data to be transmitted starting address ; ; ; TX: mov a,@r0 ; inc r0 ; mov sbuf,A ; waittx: jnb TI,waittx ; clr ti ; djnz r1,tx ; ; ; Startagain: ljmp start ; ; ; invlcmd: nop ; Function code not supported by Modbus Slave ; Exception response mov r1,#080h ; mov r0,#0eah ; ; ; mov a,@r0 ; mov @r1,a ; slave address in Location-1 inc r0 ; inc r1 ; mov a,#081h ; Exception response mov @r1,a ; Command in Location-2 inc r1 ; mov @r1, #01 ; Type of Exception in location-3 ( Function code not supported) ; ; acall CRC16_INIT ; mov r4,#03h ; No of Bytes for CRC Calculation mov r1,#080h ; ; crcloop1: mov a,@r1 ; Get Byte for crc calculation acall CRC16_CALC ; inc r1 ; djnz r4,crcloop1 ; ; ; fillcrc1: nop ; mov r1, #083h ; mov @r1, CRC16_BYTE_1 ; inc r1 ; mov @r1, CRC16_BYTE_2 ; This Completes framing. ; mov r1,#05h ; NUMBER OF BYTES TO TRANSMIT ajmp reply ; ; ; datarnge: nop ; Data requested outside range of this slave ; Exception response mov r1,#080h ; mov r0,#0eah ; ; ; mov a,@r0 ; mov @r1,a ; slave address 1 inc r0 ; inc r1 ; mov a,#081h ; Exception response mov @r1,a ; Command 2 inc r1 ; mov @r1, #02 ; Invalid Data Range code ; ; acall CRC16_INIT ; mov r4,#03h ; No of Bytes for CRC Calculation mov r1,#080h ; ; crcloop2: mov a,@r1 ; Get Byte for crc calculation acall CRC16_CALC ; inc r1 ; djnz r4,crcloop2 ; ; ; fillcrc2: nop ; mov r1, #083h ; mov @r1, CRC16_BYTE_1 ; inc r1 ; mov @r1, CRC16_BYTE_2 ; This Completes framing. ; ; mov r1,#05h ; NUMBER OF BYTES TO TRANSMIT ; ajmp reply ; ; ; ; ; ; ; ; CRC16_INIT: mov CRC16_BYTE_1,#0FFh ; Clear CRC16 High mov CRC16_BYTE_2,#0FFh ; Clear CRC16 Low ret ; Return To Caller ; CRC16_CALC: nop ; mov r0,#08 ; 8 Times to shift xrl CRC16_BYTE_1,a ; High Byte XOR with Input crcp1: clr c ; 0 Into Low Bit mov a,CRC16_BYTE_2 ; D_CRC << 1 rrc a ; Shift Right Carry will become MSB mov CRC16_BYTE_2,a ; Store Back mov a,CRC16_BYTE_1 ; Get High Byte rrc a ; Shift Right thro carry mov CRC16_BYTE_1,a ; Store Back jnc crcp2 ; Skip If Shifted out bit Wasn't Set xrl CRC16_BYTE_1,#01h ; XOR In Polynomial High xrl CRC16_BYTE_2,#0a0h ; XOR In Polynomial Low crcp2: djnz r0,crcp1 ; Repeat 8 More Times ret ; Return from Routine ; ; end ;