资源描述
目录
一、Modbus 协议分析1
1。1两种传输方式2
1。2 Modbus消息帧3
1。3错误检测方法5
二、程序设计思想6
2。1总体设计6
2.2 硬件设计7
2.2.1单片机串行通信功能7
2.2。2 MAX232芯片8
2。2。3 整体电路设计9
2。3 软件设计10
2.3.1主机系统软件设计10
2.3。2 从机系统软件设计12
三、程序代码15
基于51单片机的双机串行通信设计
一、Modbus 协议分析
Modbus 协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络和其它设备之间可以通信.它已经成为一通用工业标准。有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控.
此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一控制器请求访问其它设备的过程,如何回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。
当在一Modbus网络上通信时,此协议决定了每个控制器须要知道它们的设备地址,识别按地址发来的消息,决定要产生何种行动。如果需要回应,控制器将生成反馈信息并用Modbus协议发出。在其它网络上,包含了Modbus协议的消息转换为在此网络上使用的帧或包结构.这种转换也扩展了根据具体的网络解决节地址、路由路径及错误检测的方法。
1) 在Modbus网络上转输
标准的Modbus口是使用一RS—232C兼容串行接口,它定义了连接口的针脚、电缆、信号位、传输波特率、奇偶校验。控制器能直接或经由Modem组网。
控制器通信使用主—从技术,即仅一设备(主设备)能初始化传输(查询)。其它设备(从设备)根据主设备查询提供的数据作出相应反应。典型的主设备:主机和可编程仪表。典型的从设备:可编程控制器.
主设备可单独和从设备通信,也能以广播方式和所有从设备通信.如果单独通信,从设备返回一消息作为回应,如果是以广播方式查询的,则不作任何回应。Modbus协议建立了主设备查询的格式:设备(或广播)地址、功能代码、所有要发送的数据、一错误检测域。
从设备回应消息也由Modbus协议构成,包括确认要行动的域、任何要返回的数据、和一错误检测域.如果在消息接收过程中发生一错误,或从设备不能执行其命令,从设备将建立一错误消息并把它作为回应发送出去.
2) 在其它类型网络上传输
在其它网络上,控制器使用对等技术通信,故任何控制都能初始和其它控制器的通信。这样在单独的通信过程中,控制器既可作为主设备也可作为从设备。提供的多个内部通道可允许同时发生的传输进程。
在消息位,Modbus协议仍提供了主—从原则,尽管网络通信方法是“对等”。如果一控制器发送一消息,它只是作为主设备,并期望从从设备得到回应。同样,当控制器接收到一消息,它将建立一从设备回应格式并返回给发送的控制器。
3) 查询-回应周期
(i)查询
查询消息中的功能代码告之被选中的从设备要执行何种功能.数据段包含了从设备要执行功能的任何附加信息.例如功能代码03是要求从设备读保持寄存器并返回它们的内容。数据段必须包含要告之从设备的信息:从何寄存器开始读及要读的寄存器数量。错误检测域为从设备提供了一种验证消息内容是否正确的方法。
(ii)回应
如果从设备产生一正常的回应,在回应消息中的功能代码是在查询消息中的功能代码的回应.数据段包括了从设备收集的数据:象寄存器值或状态。如果有错误发生,功能代码将被修改以用于指出回应消息是错误的,同时数据段包含了描述此错误信息的代码。错误检测域允许主设备确认消息内容是否可用。
1。1两种传输方式
控制器能设置为两种传输模式(ASCII或RTU)中的任何一种在标准的Modbus网络通信.用户选择想要的模式,包括串口通信参数(波特率、校验方式等),在配置每个控制器的时候,在一个Modbus网络上的所有设备都必须选择相同的传输模式和串口参数。
ASCII模式
:
地址
功能代码
数据数量
数据1
。..
数据n
LRC高字节
LRC低字节
回车
换行
RTU模式
地址
功能代码
数据数量
数据1
..。
数据n
CRC高字节
CRC低字节
所选的ASCII或RTU方式仅适用于标准的Modbus网络,它定义了在这些网络上连续传输的消息段的每一位,以及决定怎样将信息打包成消息域和如何解码。
在其它网络上(像MAP和Modbus Plus)Modbus消息被转成与串行传输无关的帧.
1)ASCII模式
当控制器设为在Modbus网络上以ASCII(美国标准信息交换代码)模式通信,在消息中的每个8Bit字节都作为两个ASCII字符发送.这种方式的主要优点是字符发送的时间间隔可达到1秒而不产生错误。
代码系统
十六进制,ASCII字符0..。9,A。.。F,消息中的每个ASCII字符都是一个十六进制字符组成每个字节的位.
•1个起始位
•7个数据位,最小的有效位先发送
•1个奇偶校验位,无校验则无
•1个停止位(有校验时),2个Bit(无校验时)
错误检测域
•LRC(纵向冗长检测)
2)RTU模式
当控制器设为在Modbus网络上以RTU(远程终端单元)模式通信,在消息中的每个8Bit字节包含两个4Bit的十六进制字符。这种方式的主要优点是:在同样的波特率下,可比ASCII方式传送更多的数据.
代码系统
•8位二进制,十六进制数0.。。9,A。.。F
•消息中的每个8位域都是一个两个十六进制字符组成
每个字节的位
•1个起始位
•8个数据位,最小的有效位先发送
•1个奇偶校验位,无校验则无
•1个停止位(有校验时),2个Bit(无校验时)
错误检测域
•CRC(循环冗长检测)
1.2 Modbus消息帧
两种传输模式中(ASCII或RTU),传输设备以将Modbus消息帧为有起点和终点的帧,这就允许接收的设备在消息起始处开始工作,读地址分配信息,判断哪一个设备被选中(广播方式则传给所有设备),判知何时信息已完成。部分的消息也能侦测到并且错误能设置为返回结果.
1) ASCII帧
使用ASCII模式,消息以冒号(:)字符(ASCII码 3AH)开始,以回车换行符结束(ASCII码 0DH,0AH)。
其它域可以使用的传输字符是十六进制的0.。.9,A.。。F。网络上的设备不断侦测“:”字符,当有一个冒号接收到时,每个设备都解码下个域(地址域)来判断是否发给自己的.
消息中字符间发送的时间间隔最长不能超过1秒,否则接收的设备将认为传输错误。一个典型消息帧如下所示:
起始位
设备地址
功能代码
数据
LRC校验
结束符
1个字符
2个字符
2个字符
n个字符
2个字符
2个字符
ASCII消息帧
2) RTU帧
使用RTU模式,消息发送至少要以3.5个字符时间的停顿间隔开始.在网络波特率下多样的字符时间,这是最容易实现的(如下图的T1—T2-T3-T4所示).传输的第一个域是设备地址。可以使用的传输字符是十六进制的0.。。9,A。。。F.网络设备不断侦测网络总线,包括停顿间隔时间内.当第一个域(地址域)接收到,每个设备都进行解码以判断是否发往自己的.在最后一个传输字符之后,一个至少3。5个字符时间的停顿标定了消息的结束。一个新的消息可在此停顿后开始。
整个消息帧必须作为一连续的流转输.如果在帧完成之前有超过1。5个字符时间的停顿时间,接收设备将刷新不完整的消息并假定下一字节是一个新消息的地址域。同样地,如果一个新消息在小于3。5个字符时间内接着前个消息开始,接收的设备将认为它是前一消息的延续。这将导致一个错误,因为在最后的CRC域的值不可能是正确的。一典型的消息帧如下所示:
起始位
设备地址
功能代码
数据
CRC校验
结束符
T1-T2—T3-T4
8Bit
8Bit
n个8Bit
16Bit
T1—T2—T3—T4
RTU消息帧
3)地址域
消息帧的地址域包含两个字符(ASCII)或8Bit(RTU)。可能的从设备地址是0.。.247 (十进制)。单个设备的地址范围是1.。.247。主设备通过将要联络的从设备的地址放入消息中的地址域来选通从设备。当从设备发送回应消息时,它把自己的地址放入回应的地址域中,以便主设备知道是哪一个设备作出回应。地址0是用作广播地址,以使所有的从设备都能认识。当Modbus协议用于更高水准的网络,广播可能不允许或以其它方式代替。
4)如何处理功能域
消息帧中的功能代码域包含了两个字符(ASCII)或8Bits(RTU).可能的代码范围是十进制的1。.。255。当然,有些代码是适用于所有控制器,有些是应用于某种控制器,还有些保留以备后用。
当消息从主设备发往从设备时,功能代码域将告之从设备需要执行哪些行为。例如去读取输入的开关状态,读一组寄存器的数据内容,读从设备的诊断状态,允许调入、记录、校验在从设备中的程序等。
当从设备回应时,它使用功能代码域来指示是正常回应(无误)还是有某种错误发生(称作异议回应)。对正常回应,从设备仅回应相应的功能代码.对异议回应,从设备返回一等同于正常代码的代码,但最重要的位置为逻辑1。
主设备应用程序得到异议的回应后,典型的处理过程是重发消息,或者诊断发给从设备的消息并报告给操作员。
5)数据域
数据域是由两个十六进制数集合构成的,范围00。..FF.根据网络传输模式,这可以是由一对ASCII字符组成或由一RTU字符组成。
从主设备发给从设备消息的数据域包含附加的信息:从设备必须用于进行执行由功能代码所定义的所为。这包括了象不连续的寄存器地址,要处理项的数目,域中实际数据字节数。
6)错误检测域
标准的Modbus网络有两种错误检测方法。错误检测域的内容视所选的检测方法而定。
ASCII
当选用ASCII模式作字符帧,错误检测域包含两个ASCII字符.这是使用LRC(纵向冗长检测)方法对消息内容计算得出的,不包括开始的冒号符及回车换行符。LRC字符附加在回车换行符前面.
RTU
当选用RTU模式作字符帧,错误检测域包含一16Bits值(用两个8位的字符来实现)。错误检测域的内容是通过对消息内容进行循环冗长检测方法得出的.CRC域附加在消息的最后,添加时先是低字节然后是高字节.故CRC的高位字节是发送消息的最后一个字节.
7)字符的连续传输
当消息在标准的Modbus系列网络传输时,每个字符或字节以如下方式发送(从左到右):
最低有效位。..最高有效位
使用ASCII字符帧时,位的序列是:
有奇偶校验
启始位
1
2
3
4
5
6
7
奇偶位
停止位
无奇偶校验
启始位
1
2
3
4
5
6
7
停止位
停止位
位顺序(ASCII)
使用RTU字符帧时,位的序列是:
有奇偶校验
启始位
1
2
3
4
5
6
7
8
奇偶位
停止位
无奇偶校验
启始位
1
2
3
4
5
6
7
8
停止位
停止位
位顺序(RTU)
1。3错误检测方法
标准的Modbus串行网络采用两种错误检测方法。奇偶校验对每个字符都可用,帧检测(LRC或CRC)应用于整个消息.它们都是在消息发送前由主设备产生的,从设备在接收过程中检测每个字符和整个消息帧。
用户要给主设备配置一预先定义的超时时间间隔,这个时间间隔要足够长,以使任何从设备都能作为正常反应.如果从设备测到一传输错误,消息将不会接收,也不会向主设备作出回应.这样超时事件将触发主设备来处理错误。发往不存在的从设备的地址也会产生超时。
1)奇偶校验
用户可以配置控制器是奇或偶校验,或无校验。这将决定了每个字符中的奇偶校验位是如何设置的.如果指定了奇或偶校验,“1"的位数将算到每个字符的位数中(ASCII模式7个数据位,RTU中8个数据位)。例如RTU字符帧中包含以下8个数据位:1 1 0 0 0 1 0 1,整个“1”的数目是4个。如果便用了偶校验,帧的奇偶校验位将是0,便得整个“1”的个数仍是4个。如果便用了奇校验,帧的奇偶校验位将是1,便得整个“1"的个数是5个。如果没有指定奇偶校验位,传输时就没有校验位,也不进行校验检测。代替一附加的停止位填充至要传输的字符帧中。
2)LRC检测
使用ASCII模式,消息包括了一基于LRC方法的错误检测域.LRC域检测了消息域中除开始的冒号及结束的回车换行号外的内容.
LRC域是一个包含一个8位二进制值的字节。LRC值由传输设备来计算并放到消息帧中,接收设备在接收消息的过程中计算LRC,并将它和接收到消息中LRC域中的值比较,如果两值不等,说明有错误。
LRC方法是将消息中的8Bit的字节连续累加,丢弃了进位。
3)CRC检测
使用RTU模式,消息包括了一基于CRC方法的错误检测域.CRC域检测了整个消息的内容。
CRC域是两个字节,包含一16位的二进制值。它由传输设备计算后加入到消息中。接收设备重新计算收到消息的CRC,并与接收到的CRC域中的值比较,如果两值不同,则有误。
CRC是先调入一值是全“1”的16位寄存器,然后调用一过程将消息中连续的8位字节各当前寄存器中的值进行处理。仅每个字符中的8Bit数据对CRC有效,起始位和停止位以及奇偶校验位均无效。
CRC产生过程中,每个8位字符都单独和寄存器内容相或(OR),结果向最低有效位方向移动,最高有效位以0填充。LSB被提取出来检测,如果LSB为1,寄存器单独和预置的值或一下,如果LSB为0,则不进行.整个过程要重复8次。在最后一位(第8位)完成后,下一个8位字节又单独和寄存器的当前值相或.最终寄存器中的值,是消息中所有的字节都执行之后的CRC值。
CRC添加到消息中时,低字节先加入,然后高字节。
二、程序设计思想
2.1总体设计
本文在MODBUS协议的基础上通过串行端口实现单片机和单片机的通讯,根据MODBUS协议,它有两种数据传输的方式:ASCII和RTU方式,由于RTU方式传输效率高,采用CRC校验方法,数据传输准确,所以本文采用了RTU方式。
硬件部分,使用两片89C4051,通过RS232进行双机通信。发送方的数据由串行口TXD段输出,经过电平转换芯片MAX232将TTL电平转换为RS232电平输出,经过传输线将信号传送到接收端.接收方也使用MAX232芯片进行电平转换后,信号到达接收方串行口的接收端。每个51从设备增加了一个I2C接口的ADC0831,主机通过协议来轮询各个从机的采样信号,解析后显示在主机的LCD屏的对应位置上。
软件部分,通过MODBUS协议进行发送接收,主机发送命令帧给从机,等待从机回应,等待超时则重新发送。从机收到命令帧后检查目的地址,确认后计算接收到数据的检验和,与主机发送来的检验和进行比较,若检验和相同则发送正常回应帧给主机;否则发送错误报告帧给主机,告知主机重新发送命令帧。
2.2 硬件设计
2.2.1单片机串行通信功能
图2—1 AT89C4051
计算机与外界的信息交换称为通信,常用的通信方式有两种:并行通信和串行通信。51单片机用4个接口与外界进行数据输入与数据输出就是并行通信,并行通信的特点是传输信号的速度快,但所用的信号线较多,成本高,传输的距离较近。串行通信的特点是只用两条信号线(一条信号线,再加一条地线作为信号回路)即可完成通信,成本低,传输的距离较远。
51单片机的串行接口是一个全双工的接口,它可以作为UART(通用异步接受和发送器)用,也可以作为同步移位寄存器用。51单片机串行接口的结构如下:
(1)数据缓冲器(SBUF)
接受或发送的数据都要先送到SBUF缓存。有两个,一个缓存,另一个接受,用同一直接地址99H,发送时用指令将数据送到SBUF即可启动发送;接收时用指令将SBUF中接收到的数据取出。
(2)串行控制寄存器(是SCON)
SCON用于串行通信方式的选择,收发控制及状态指示,各位含义如下:
SM0
SM1
SM2
REN
TB8
RB8
TI
RI
SM0,SM1:串行接口工作方式选择位,这两位组合成00,01,10,11对应于工作方式0、1、2、3。串行接口工作方式特点见下表。
SM0
SM1
工作方式
功能
波特率
0
0
0
8位同步移位寄存器(用于I/O扩展)
fORC/12
0
1
1
10位异步串行通信(UART)
可变(T1溢出率*2SMOD/32)
1
0
2
11位异步串行通信(UART)
fORC/64或fORC/32
1
1
3
11位异步串行通信(UART)
可变(T1溢出率*2SMOD/32)
SM2:多机通信控制位.
REN:接收允许控制位.软件置1允许接收;软件置0禁止接收。
TB8:方式2或3时,TB8为要发送的第9位数据,根据需要由软件置1或清0.
RB9:在方式2或3时,RB8位接收到的第9位数据,实际为主机发送的第9位数据TB8,使从机根据这一位来判断主机发送的时呼叫地址还是要传送的数据。
TI:发送中断标志.发送完一帧数据后由硬件自动置位,并申请中断.必须要软件清零后才能继续发送。
RI:接收中断标志。接收完一帧数据后由硬件自动置位,并申请中断。必须要软件清零后才能继续接收.
(3)输入移位寄存器
接收的数据先串行进入输入移位寄存器,8位数据全移入后,再并行送入接收SBUF中。
(4)波特率发生器
波特率发生器用来控制串行通信的数据传输速率的,51系列单片机用定时器T1作为波特率发生器,T1设置在定时方式。波特率时用来表示串行通信数据传输快慢程度的物理量,定义为每秒钟传送的数据位数。
(5)电源控制寄存器PCON
其最高位为SMOD。
(6)波特率计算
当定时器T1工作在定时方式的时候,定时器T1溢出率=(T1计数率)/(产生溢出所需机器周期).由于是定时方式,T1计数率= fORC/12。产生溢出所需机器周期数=模M—计数初值X。
2.2。2MAX232芯片
用8051串行接口通信,如果两台8051单片机之间的距离很近(不超过1.5m),可以采用直接将两台8051单片机的串行接口直接相连,利用其自身的TTL电平(0—5V)直接传输数据信息。如果传输距离较远(超过1.5m),由于传输线的阻抗与分布电容,会产生电平损耗和波形畸变,以至于检测不出数据或数据出错。此时可利用 RS232标准总线接口,将单片机输出的TTL电平转换为RS232标准电平(逻辑1为-15—-5V;逻辑0为+5-—+15V).用RS232可将传输距离提高到15m,如果想远距离传输,可以采用RS422或者RS485。
电平转换芯片MAX232是美信公司(MAXIM)生产,专用于进行将TTL电平转换为RS232电平的芯片,MAX232内部有泵电源,能将+5V电源电压在芯片内提高到RS232电平所需的+10V或者—10V电平。
图2—2电平转换芯片MAX232
2。2。3整体电路设计
最终设计电路如下图3所示,发送方的数据由串行口TXD段输出,经过电平转换芯片MAX232将TTL电平转换为RS232电平输出,经过传输线将信号传送到接收端.接收方也使用MAX232芯片进行电平转换后,信号到达接收方串行口的接收端。每个51从设备增加了一个I2C接口的ADC0831,主机通过MODBUS协议来轮询各个从机的采样信号,解析后显示在主机的LCD屏的对应位置上。主机和从机发送的数据通过VIRTUAL TERMINAL显示。
图2—3串行通信电路
2.3 软件设计
通过MODBUS协议进行发送接收,主机发送命令帧给从机,等待从机回应,等待超时则重新发送.从机收到命令帧后检查目的地址,确认后计算接收到数据的检验和,与主机发送来的检验和进行比较,若检验和相同则发送正常回应帧给主机;否则发送错误报告帧给主机,告知主机重新发送命令帧。
2。3。1主机系统软件设计
主机要对从机实施控制,首先要实现两者之间的通讯,按照MODBUS协议
的约定,在通讯中的信息数据中设置特定的代码,在通讯成功后,对信息数据进
行解析和提取,然后启动相应的中断程序进行处理。
本设计中,主机的通信过程如下:
(1)主程序:开始,打开串口,然后准备要发送的信号数据,调用CRC生
成程序获取信号数据的CRC校验码,组织命令报文,以MODBUS的RTU信息帧方式发送报文,发送完毕后进入侦听阶段,侦测帧头(T1.T2.T3.T4),通过判断,若符合MODBUS协议规定四个字符延时等待时间,等待中断服务服务,中断处理未完毕后返回中断等待,处理完毕,中断返回,返回主程序的数据准备阶段,继续进行侦听;若超时,进行超时处理,处理完毕返回主程序,进入数据准备.
(2)中断程序:响应中断后,进入中断服务程序,接收数据,进行CRC校验,若命令数据正确,进行命令报文解析,根据协议约定功能进行数据处理,处理完毕进入主程序;否则,重发报文,重发完毕,返回进入主程序。主机软件设计如主机主程序流程图2—4和主机中断服务子程序流程图2-5所示。
图2-4 主机主程序流程图
图2—5 主机中断服务子程序流程图
2。3。2 从机系统软件设计
从机的程序设计要实现五大功能:第一,要实现主机和从机之间的通讯功能
(接收报文和回报文);第二,要完成命令报文的解析和信息提取(设备地址、功能码,寄存器地址和数据等);第三,实现MODBUS协议规定的主要的功能(采集模拟量、从寄存器中取值、往寄存器写入数值以及向特定的单片机IO端口下置数字量);第四,通讯环节中的一些特定的中断程序的执行(接收和发生的启动、侦测报文开始位和结束位的启动中断等);第五,在通讯过程中保证信息数据的准确是非常重要的,所以从机软件的设计中要进行错误检测,其方法多种多样,在本设计中采用循环冗余检测(CRC),其优点是检验的效率比较高、准确率也比较高,实现五大功能程序设计,可以使从机完成MODBUS协议的相应功能。从机软件设计如从机主程序流程图2-6和从机中断子程序流程图2—7所示。
图2-6 从机主程序流程图
图2-7 从机中断子程序流程图
三、程序代码
/*******************************主机********************************/
#include 〈reg52.h〉
#include 〈intrins.h〉
#define Uint16 unsigned int
#define Uint32 unsigned long
#define uchar unsigned char
#define LCD_Data P1
#define Busy 0x80 //用于检测LCD状态字中的Busy标识
sbit reving=P3^5; //发送或接收指示灯,1:发送0:接收
sbit LCD_RS=P3^2;//定义引脚
sbit LCD_RW=P3^3;
sbit LCD_E=P3^4;
bit nodeok; //标志位
bit crcok; //校验标志位,1:校验正确0:校验错误
uchar asknode; // 轮询的当前节点
uchar asknode_save; //保存轮询的当前节点
uchar mtx[8],mrx[10];
uchar send101[]={0x01,0x04,0x00,0x00,0x00,0x03};
uchar timercnt; //定时
uchar revptr;
Uint16 delaycnt;
void InitUART(void);
void SendOneByte(unsigned);
void mdproc(uchar);
Uint16 Crc16(Uint16 *puchMsg, Uint16 usDataLen);
void WriteDataLCD(unsigned char WDLCD);
void WriteCommandLCD(unsigned char WCLCD,BuysC);
unsigned char ReadDataLCD(void);
unsigned char ReadStatusLCD(void);
void LCDInit(void);
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData);
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char *DData);
void Delay5Ms(void);
void Delay400Ms(void);
/* CRC 高位字节值表 */
const Uint16 code auchCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
} ;
/* CRC低位字节值表*/
const Uint16 code auchCRCLo[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
0x43, 0x83, 0x41, 0x81, 0x80, 0x40
} ;
void main(void)
{
unsigned char temp8;
Uint16 temp16,temp16_1,temp16_2;
unsigned char code row1[] = {”MODBUS FUNC:04H”};
unsigned char code row2[] = {"NOW GET START”};
uchar row3[]={" V1 V2 V3 "};
uchar row4[]={" 。 。 。 "};
int i;
reving=0;
nodeok=0;
timercnt=0x00;
asknode=0x00;
temp16_2=250;
for(i=0;i<10;i++){mrx[i]=0x00;}
for(i=0;i〈8;i++){mtx[i]=0x00;}
Delay400Ms(); //启动等待,等LCD讲入工作状态
LCDInit(); //LCD初始化
Delay5Ms(); //延时片刻(可不要)
DisplayListChar(1, 0, row1);
DisplayListChar(2, 1, row2);
ReadDataLCD();//测试用句无意义
delaycnt=0xffff;
while(delaycnt——){}
delaycnt=0xffff;
while(delaycnt-—){}
DisplayListChar(0, 0, row3);
InitUART();
crcok=1;
while(1)
{
if(crcok==1)
{
temp16_1=mrx[3];
temp16_1*=temp16_2;
temp16_1>〉=7;
switch(mrx[0])
{
case 0x01:{row4[1]=(temp16_1/100)+0x30;row4[3]=((temp16_1%100)/10)+0x30;row4[4]=(temp16_1%10)+0x30;break;}
case 0x02:{row4[6]=(temp16_1/100)+0x30;row4[8]=((temp16_1%100)/10)+0x30;row4[9]=(temp16_1%10)+0x30;break;}
case 0x03:{row4[11]=(temp16_1/100)+0x30;row4[13]=((temp16_1%100)/10)+0x30;row4[14]=(temp16_1%10)+0x30;break;}
default:{break;}
}
DisplayListChar(0, 1, row4); // 在指定位置显示从机发送来的数
展开阅读全文