📄 modbus.asm
字号:
;***********************************************************************************
;D331点胶机程序号选择及与运动控制卡通讯控件.
;编制: 洪天长 公司:特盈自动化 日期:06.01.12
;修改:彭铿 公司:特盈自动化 日期:07.07.19
;晶振选择11.0592M,采用波特率为19200,误差为0.00%.
;系统采用RS232通讯,MODBUS通讯协议,并进行CRC_16校验,字节不进行奇偶校验(但有校验位).
;主程序进行键盘扫描并通过查询方式与运动控制卡通讯.
;定时器T0中断程序进行LED数码显示器的查表扫描显示及状态指示灯的扫描显示.
;***********************************************************************************
ORG 0000H ;
AJMP START ;跳转到主程序.
ORG 30H ;
START:NOP
;系统初始化程序.
INITIALIZE1:MOV TMOD,#20H ;定时器T1工作于方式2,可自动重载8位串口用.
MOV TH1,#0FDH ;---------------串口波特率设定为19200-----------------
MOV TL1,#0FDH ;
MOV PCON,#80H ;波特率翻倍.
MOV SCON,#0DCH ;串行口工作于方式3,SM0=1,SM1=1,SM2=0.
;并允许接收REN=1,TB8=1,RB8=1,TI=0,RI=0.
SETB EA ;开总中断.
SETB EX0 ;允许中断0中断.
SETB PX0 ;外部中断设定为高优先级.
CLR IT0 ;外部中断0为电平触发.
SETB ET0 ;允许定时器T0中断.
CLR ET1 ;禁止定时器T1中断.
CLR ES ;禁止串行中断.
CLR TI ;清发送中断标志.
CLR RI ;清接收中断标志.
;以下为写8255控制字程序,
;其中PA口地址:7FFCH,PB口地址:7FFDH,PC口地址:7FFEH,控制口地址:7FFFH
PRINT: MOV DPTR,#7FFFH ;控制口地址
MOV A,#8BH ;控制字
MOVX @DPTR,A ;写入控制字
;以下为单片机从主机读取数据的程序段
;以下为发送数据的程序段.
READ_P:MOV 51H,#01H ;读单片机的地址
MOV 52H,#03H ;功能代码
MOV 53H,#00H ;
MOV 54H,#0BH ;选择十进制12号寄存器。
MOV 55H,#00H ;
MOV 56H,#01H ;需读的寄存器个数
MOV 50H,#06 ;写需要发送的数据个数(不包括CRC_16校验码).
LCALL SEND ;调用发送子程序.
;以下为接收数据的程序段.
MOV 50H,#08 ;需接收的数据位数赋值.
LCALL RECE ;调用接收子程序.
MOV A,42H ;
CJNE A,#100,READ_WRO ;通讯不成功则跳转.
AJMP READ_P_OK ;
READ_WRO:AJMP READ_WRONG
mov A,51H
CJNE A,#1,READ_P ;比较地址,若不是本单片机地址则重发
;以下为接收成功后的数据处理程序.接收的数据送PA口输出
READ_P_OK:
MOV 48H,55H ;保存读回低字节数值
MOV DPTR,#7FFCH ;PA口地址
MOV A,48H ;
MOVX @DPTR,A ;低字节数值由PA口输出
;以下为单片机发送数据到主机程序段
WRITE_STATE:MOV 51H,#01H ;写主机的就绪状态.
MOV 52H,#06H ;写单个寄存器.
MOV 53H,#00H ;写需要写的寄存器地址#25(十进制).
MOV 54H,#19H ;
MOV DPTR,#7FFEH ;C口地址→DPTR
MOVX A,@DPTR ;从C口读数据
MOV 55H,A ;写需要写入的数据PC读入的值.
MOV DPTR,#7FFDH ;B口地址→DPTR
MOVX A,@DPTR ;从B口读数据
MOV 56H,A ;写需要写入的数据PB读入的值.
MOV 50H,#06 ;写需要发送的数据个数(不包括CRC_16校验码).
LCALL SEND ;调用发送子程序.
;以下为接收数据的程序段.
MOV 50H,#08 ;需接收的数据位数赋值.
LCALL RECE ;调用接收子程序.
MOV A,42H ;
CJNE A,#100,WRITE_WRONG ;通讯不成功则跳转.
WRITE_WRONG:AJMP READ_WRONG ;写失败的程序与读失败的处理程序相同.
;以下为读参数失败后的处理程序段.
READ_WRONG: SETB P2.0 ;显示功能码A.
AJMP READ_P ;
;主程序结束.
;以下为单片机向主机发送数据的子程序,需要输入待发送的数据(51H地址为起始地址),
;以及需要发送的数据个数(存在50H,不包括CRC_16校验码).
;调用该子程序时会自动计算CRC_16结果并添加到数据块最后
;并发送;40H为已经发送的数据个数计算存储器.
SEND:LCALL CRC_16 ;根据待发送的内容及许发送的数据个数计算CRC_16.
MOV A,50H ;取出需发送的数据个数.
ADD A,#51H ;写入CRC_16结果的低字节.
MOV R1,A ;
MOV @R1,4DH ;
INC R1 ;写入CRC_16结果的高字节.
MOV @R1,4EH ;
INC 50H ;需要发送的数据个数加2.
INC 50H ;
MOV 40H,#00H ;已发送的数据清零.
SEND_LOOP: MOV A,40H ;计算待发送的数据地址.
ADD A,#51H ;
MOV R1,A ;
MOV A,@R1 ;
MOV SBUF,A ;发送数据.
SEND_WAIT:JNB TI,SEND_WAIT ;等待发送完毕.
CLR TI ;
INC 40H ;
MOV A,40H ;
CJNE A,50H,SEND_LOOP ;
RET ;
;发送子程序结束.
;以下为接收子程序.需要输入需接收的数据个数(存在50H中,不包含CRC_16的校验码),
;当接收到指定个数时(接收过程有超时控制),该子程序会自动
;计算其CRC_16是否为0(正确),并返回接收成功或失败标志
;(42H=100表示成功);41H用作已接收的数据个数计算.
RECE:MOV 42H,#100 ;置通讯成功标志.
MOV 41H,#00H ;已经接收的数据个数清零.
RECE_WAIT:MOV R7,#02 ;2006-09-19 21:00更改通讯超时为100ms,
RECE_L0: MOV R6,#200 ;
RECE_L1: MOV R5,#250 ;
RECE_L2: JB RI,RECE_NEXT ;
DJNZ R5,RECE_L2 ;
DJNZ R6,RECE_L1 ;
DJNZ R7,RECE_L0 ;
MOV 42H,#00 ;置超时通讯失败标志.
RECE_NEXT:CLR RI ;清接收中断标志.
MOV A,41H ;计算待接收的数据存放地址.
ADD A,#51H ;
MOV R1,A ;地址存放在R1中.
MOV A,SBUF ;读取接收到的数据.
MOV @R1,A ;
INC 41H ;已接收的数据个数加1.
MOV A,41H ;
CJNE A,50H,RECE_WAIT ;
LCALL CRC_16 ;
MOV A,4EH ;判断CRC_16结果中高字节是否位0.
CJNE A,#00H,RECE_WRONG ;
MOV A,4DH ;判断CRC_16结果中低字节是否位0.
CJNE A,#00H,RECE_WRONG ;
AJMP RECE_OUT ;
RECE_WRONG:MOV 42H,#00H ;置通讯失败标志.
RECE_OUT:RET ;子程序结束.
;接收子程序结束.
;以下为进行CRC-16校验的子程序.
;CRC_16校验模块使用的存储器如下:
;51H,52H,53H,......:为要进行CRC_16校验的数据块,并且进行校验程序时总是将51H的内容
;当第一字节,52H内容为第二字节,......
;50H:要进行CRC_16校验的数据块长度设定存储器.
;4FH:进行CRC_16校验时对已处理字节进行计数用存储器.
;4EH:CRC_16校验结果存储器的高字节.
;4DH:CRC_16校验结果存储器的低字节.
;4CH:进行CRC_16校验时对当前字节已移位次数进行记录的存储器.
CRC_16:MOV 4EH,#0FFH ;CRC_16检验结果存储器的高位字节置全1.
MOV 4DH,#0FFH ;CRC_16检验结果存储器的低位字节置全1.
MOV 4FH,#51H ;已进行CRC_16处理的数据地址初始化.
;以下为对逐个数据进行CRC_16检验.
CRC_LOOP1:MOV 4CH,#00H ;已对单字节进行移位的次数清零.
MOV R0,4FH ;将要处理的数据地址赋值给R0.
MOV A,@R0 ;以R0中的内容为地址,取出该地址中的数据到A.
XRL 4DH,A ;单字节数据与CRC_16检验结果存储器中的低位进行异或,
;结果存入CRC_16存储器的低字节.
CRC_LOOP2:CLR C ;进位标志清零.
MOV A,4EH ;取出CRC_16检验结果存储器中的高字节.
RRC A ;带进位标志右移一位.
MOV 4EH,A ;将移位后的数据回传给CRC_16检验结果存储器中的高位.
MOV A,4DH ;取出CRC_16检验结果存储器中的低字节.
RRC A ;带进位标志右移一位.
MOV 4DH,A ;将移位后的数据回传给CRC_16检验结果存储器中的低位.
INC 4CH ;移位次数存储器加1.
JC CRC_CAL ;如果移出的数为1则跳转到CRC_CAL.
AJMP CRC_NEXT ;跳转到移位次数判断.
CRC_CAL:XRL 4EH,#10100000B ;CRC_16存储器中高字节与多项式的高字节进行异或,
;结果存入CRC_16存储器的高字节.
XRL 4DH,#00000001B ;CRC_16存储器中低字节与多项式的低字节进行异或,
;结果存入CRC_16存储器的低字节.
CRC_NEXT:MOV A,4CH ;移位次数判断.
CJNE A,#08,CRC_LOOP2 ;移位次数不到8则转移.
INC 4FH ;已处理的数据地址加1.
MOV A,4FH ;取出已处理的数据地址.
SUBB A,#51H ;通过减法求实际已处理的数据个数.
CJNE A,50H,CRC_LOOP1 ;数据处理个数不到预定值则转移继续处理.
RET ;子程序返回.
;CRC_16子程序结束.
;以下为字型表:
; 0 1 2 3 4 5 6 7 8 9 P A
TABLE:DB 192,249,164,176,153,146,130,248,128,144,140,136
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -