51单片机实现的485通讯程序
51单片机与RS485应用电路图
1 问题的提出在应用系统中,RS-485半双工异步通信总线是被各个研发机构广泛使用的数据通信总线,它往往应用在集中控制枢纽与分散控制单元之间。
系统简图如图1所示。
图1. RS-485系统示意图由于实际应用系统中,往往分散控制单元数量较多,分布较远,现场存在各种干扰,所以通信的可靠性不高,再加上软硬件设计的不完善,使得实际工程应用中如何保障RS-485总线的通信的可靠性成为各研发机构的一块心病。
在使用RS-485总线时,如果简单地按常规方式设计电路,在实际工程中可能有以下两个问题出现。
一是通信数据收发的可靠性问题;二是在多机通信方式下,一个节点的故障(如死机),往往会使得整个系统的通信框架崩溃,而且给故障的排查带来困难。
针对上述问题,我们对485总线的软硬件采取了具体的改进措施2 硬件电路的设计现以8031单片机自带的异步通信口,外接75176芯片转换成485总线为例。
其中为了实现总线与单片机系统的隔离,在8031的异步通信口与75176之间采用光耦隔离。
电路原理图如图2所示。
图2 改进后的485通信口原理图充分考虑现场的复杂环境,在电路设计中注意了以下三个问题。
2.1 SN75176 485芯片DE控制端的设计由于应用系统中,主机与分机相隔较远,通信线路的总长度往往超过400米,而分机系统上电或复位又常常不在同一个时刻完成。
如果在此时某个75176的DE端电位为“1”,那么它的485总线输出将会处于发送状态,也就是占用了通信总线,这样其它的分机就无法与主机进行通信。
这种情况尤其表现在某个分机出现异常情况下(死机),会使整个系统通信崩溃。
因此在电路设计时,应保证系统上电复位时75176的DE端电位为“0”。
由于8031在复位期间,I/O口输出高电平,故图2电路的接法有效地解决复位期间分机“咬”总线的问题。
2.2 隔离光耦电路的参数选取在应用系统中,由于要对现场情况进行实时监控及响应,通信数据的波特率往往做得较高(通常都在4800波特以上)。
单片机485烧程序方法
单片机485烧程序方法
1. 准备工作,首先,你需要准备一台支持单片机485烧录的编程器,以及单片机的开发板和对应的编程软件。
确保你有正确的单片机型号和对应的烧录工具。
2. 连接硬件,将编程器通过USB接口连接到计算机上,然后将编程器的接口与开发板上的对应接口相连。
确保连接的稳固性和正确性。
3. 打开编程软件,打开单片机的编程软件,一般来说,这些软件会提供一个界面,你可以在界面中选择单片机型号和相应的烧录方式。
4. 选择文件,在编程软件中选择你要烧录的程序文件,通常是一个.hex文件或者.bin文件。
5. 设置参数,根据你的需要,设置好烧录的参数,比如时钟频率、烧录方式等。
6. 烧录程序,点击软件界面上的烧录按钮,软件会开始向单片
机烧录程序。
在烧录过程中,要确保编程器和单片机的连接稳定,避免操作过程中的干扰。
7. 验证烧录,烧录完成后,一般软件会提示烧录成功。
此时可以进行一次验证,确认程序是否成功烧录到单片机中。
总的来说,单片机485烧程序方法需要准备好硬件设备、连接正确的硬件接口、选择正确的编程软件、设置好烧录参数,并且要确保烧录过程中的稳定性和正确性。
希望这些步骤能帮助到你。
51单片机实现的485通讯程序
51单片机实现的485通讯程序#ifndef __485_C__#define __485_C__#include <reg51.h>#include <string.h>#define unsigned char uchar#define unsigned int uint/* 通信命令 */#define __ACTIVE_ 0x01 // 主机询问从机是否存在#define __GETDATA_ 0x02 // 主机发送读设备请求#define __OK_ 0x03 // 从机应答#define __STATUS_ 0x04 // 从机发送设备状态信息#define __MAXSIZE 0x08 // 缓冲区长度#define __ERRLEN 12 // 任何通信帧长度超过12则表示出错uchar dbuf[__MAXSIZE]。
// 该缓冲区用于保存设备状态信息uchar dev。
// 该字节用于保存本机设备号sbit M_DE = P1^0。
// 驱动器使能,1有效sbit M_RE = P1^1。
// 接收器使能,0有效void get_status(>。
// 调用该函数获得设备状态信息,函数代码未给出void send_data(uchar type, uchar len, uchar *buf>。
// 发送数据帧bit recv_cmd(uchar *type>。
// 接收主机命令,主机请求仅包含命令信息void send_byte(uchar da>。
// 该函数发送一帧数据中的一个字节,由send_data(>函数调用void main(>{uchar type。
uchar len。
/* 系统初始化 */P1 = 0xff。
// 读取本机设备号dev = (P1>>2>。
TMOD = 0x20。
手把手教你学51单片机之十八RS485通信与Modbus协议
在工业控制、电力通讯、智能仪表等领域,通常情况下是采用串口通信的方式进行数据交换。
最初采用的方式是RS232接口,由于工业现场比较复杂,各种电气设备会在环境中产生比较多的电磁干扰,会导致信号传输错误.除此之外,RS232接口只能实现点对点通信,不具备联网功能,最大传输距离也只能达到几十米,不能满足远距离通信要求。
而RS485则解决了这些问题,数据信号采用差分传输方式,可以有效的解决共模干扰问题,最大距离可以到1200米,并且允许多个收发设备接到同一条总线上。
随着工业应用通信越来越多,1979年施耐德电气制定了一个用于工业现场的总线协议Modbus协议,现在工业中使用RS485通信场合很多都采用Modbus协议,本节课我们要讲解一下RS485通信和Modbus协议。
单单使用一块KST-51开发板是不能够进行RS485实验的,应很多同学的要求,把这节课作为扩展课程讲一下,如果要做本课相关实验,需要自行购买USB转485通信模块。
18.1 RS485通信实际上在RS485之前RS232就已经诞生,但是RS232有几处不足的地方:1、接口的信号电平值较高,达到十几V,容易损坏接口电路的芯片,而且和TTL电平不兼容,因此和单片机电路接起来的话必须加转换电路。
2、传输速率有局限,不可以过高,一般到几十Kb/s就到极限了。
3、接口使用信号线和GND与其他设备形成共地模式的通信,这种共地模式传输容易产生干扰,并且抗干扰性能也比较弱。
4、传输距离有限,最多只能通信几十米。
5、通信的时候只能两点之间进行通信,不能够实现多机联网通信。
针对RS232接口的不足,就不断出现了一些新的接口标准,RS485就是其中之一,他具备以下的特点:1、我们在讲A/D的时候,讲过差分信号输入的概念,同时也介绍了差分输入的好处,最大的优势是可以抑制共模干扰。
尤其工业现场的环境比较复杂,干扰比较多,所以通信如果采用的是差分方式,就可以有效的抑制共模干扰。
基于51 单片机的RS485 从机系统设计
题目:基于51单片机的RS485从机系统设计单片机接口电路设计及单片机资源配置:1.上电复位电路;2.晶振电路采用11.0592Mhz晶振;3.485接口电路(P3.7用于485芯片的收发控制,收发管脚接单片机的rxd和txd);4.P2口通过外部跳线接相应的高低电平,配置从机地址为学生学号(取值范围:0x01-0x80);5.P3.6外接一发光二极管(注意串联电阻进行限流);6.P3.2外接一按键,断开高电平,按下地电平;7.按键检测采用外部中断方式,下跳沿触发;8.单片机定时器0以模式1(16位模式)工作,产生50ms的定时中断,并在此基础上设计一单片机内部时钟(24小时制,能计量时、分、秒、50ms值);9.单片机串行通信采用模式1非多机通信方式,采用9600波特率以串行中断方式进行通信,主机地址为0xF0,广播地址为0xFF系统功能需求:1.系统自检功能:系统上电后,初始化时以每半秒闪烁一次的频率点亮发光二极管;按下按键触发外部中断过程中熄灭发光二极管,同时禁止外部中断防止按键重复触发;2.数据接收功能:在接收到主机发来的按键允许命令帧后开外部中断,允许按键按下产生外部中断,同时点亮发光二极管进行按键允许显示;此后按下按键产生外部中断并同时在程序的数组变量中记下当前的时钟数据(定时器的低8位、定时器的高8位、50ms值、秒、分、小时),并同时禁止外部中断防止按键重复触发;3.数据发送功能:接收到主机发来的时钟数据搜索命令帧后将前面记下的时钟数据按(定时器的低8位、定时器的高8位、50ms值、秒、分、小时)的顺序组成时钟数据返回帧回送给主机,同时熄灭发光二极管;4.校验和生成和检测功能:发送数据帧时自动生成校验和;接收数据帧时能检测校验和并判断接收数据是否正确;每帧数据在发送帧尾前,发送一字节的当前帧数据的校验和(校验和的计算不包含帧头和帧尾),另外帧长不包含帧头、帧尾和校验和字节。
附录:时钟数据搜索命令帧:时钟数据返回帧:帧结构头文件frame.h(内容如下)#define FRAME_HEAD 0xAA //帧头#define FRAME_TAIL 0x66 //帧尾#define FRAME_LEN 0x00 //帧长#define FRAME_DST_ADR 0x01 //目的地址#define FRAME_SRC_ADR 0x02 //源地址#define FRAME_CMD 0x03 //命令字#define FRAME_DATA 0x04 //帧数据起始#define READY 0x01 //按键允许命令#define TIME_SERCH 0x03 //时钟数据轮询命令#define TIME_BACK 0x07 //时钟数据返回命令#define BROAD_ADR 0xFF //广播地址#define MASTER_ADR 0xF0 //主机地址。
51单片机与RS485应用电路
--------以上部分请勿修改!-------------提高485总线的可靠性摘要:就485总线应用中易出现的问题,分析了产生的原因并给出解决问题的软硬件方案和措施。
关键词:RS-485总线、串行异步通信--------------------------------------------------------------------------------1 问题的提出在应用系统中,RS-485半双工异步通信总线是被各个研发机构广泛使用的数据通信总线,它往往应用在集中控制枢纽与分散控制单元之间。
系统简图如图1所示。
图1. RS-485系统示意图由于实际应用系统中,往往分散控制单元数量较多,分布较远,现场存在各种干扰,所以通信的可靠性不高,再加上软硬件设计的不完善,使得实际工程应用中如何保障RS-485总线的通信的可靠性成为各研发机构的一块心病。
在使用RS-485总线时,如果简单地按常规方式设计电路,在实际工程中可能有以下两个问题出现。
一是通信数据收发的可靠性问题;二是在多机通信方式下,一个节点的故障(如死机),往往会使得整个系统的通信框架崩溃,而且给故障的排查带来困难。
针对上述问题,我们对485总线的软硬件采取了具体的改进措施2 硬件电路的设计现以8031单片机自带的异步通信口,外接75176芯片转换成485总线为例。
其中为了实现总线与单片机系统的隔离,在8031的异步通信口与75176之间采用光耦隔离。
电路原理图如图2所示。
图2 改进后的485通信口原理图充分考虑现场的复杂环境,在电路设计中注意了以下三个问题。
2.1 SN75176 485芯片DE控制端的设计由于应用系统中,主机与分机相隔较远,通信线路的总长度往往超过400米,而分机系统上电或复位又常常不在同一个时刻完成。
如果在此时某个75176的DE端电位为“1”,那么它的485总线输出将会处于发送状态,也就是占用了通信总线,这样其它的分机就无法与主机进行通信。
51单片机与三菱PLC RS485通讯实例
我用的是天祥单片机实验板,由于没有RS485接口,我利用ADM485芯片自制了一个485接口,如图,但如果要进行半双工通讯,须将P3.0口到下载程序的RS232芯片的线断开可用一个跳线,用RS485的时候断开RS232,用RS232的时候插上跳线帽。硬件连接如图
PLC程序:
通讯我用单片机做主机(只发送指令),PLC做从机(只接收指令),单工单向,以便初学着掌握。
sbit led=P1^1;/*将RS485置为发送数据模式*/
unsigned char i;
void init()
{
SCON=0x50;/*串口中断开*/
TMOD=0x20;/*定时器设置*/
TH1=0xfd;/*定时时间的高位*/
TL1=0xfd;/*定时时间的低位,速度为9600BPS*/
TR1=1;/*定时器开*/
格式:1位启始,8位数据,一位停止。
所以PLC寄存器D8120:0C81.
plc程序很简单不懂的可以看下三菱PLC的通讯手册。如下图:
三:单片机程序:
#include<reg52.h>/*单片机的头文件*/
unsigned char code tab[]={0x17,0xff};/*PLC输出的Y点数,PLC输出Y灯0125678亮*/
QQ:79814563注明时工控交友
电话:15250151540
姓名:黄辉
2011年12月17日Saturday
51单片机与三菱PLC无协议通讯成功
我用了两个晚上的时间查阅一些资料,利用三菱PLC的扩展RS485通讯板与其51单片机连接通讯,可写PLC任意的地址。长度可达1000米,看见网上写的都很烦且对三菱和单片机不是很熟的朋友来说有一定的阅读难度,今天将它与大家分享。希望在此基础上大家能扩展出自己想要的功能,过些时间有空我在写个半双工的程序。
485通信程序(51单片机)
485通信程序(51单片机)什么是485通信?RS-485是一种串行通信协议,它使用差分信号传输数据。
485通信支持了在两个或以上设备之间传输数据的需求,比如用于电子计算机、通信设备、工业自动化等等。
RS-485已广泛应用于数控机床、自动化设备控制等领域中。
单纯的485通信包含四种通信模式:点对点、总线形、多主机和简介式通信。
其中,点对点通信指的是一对一的通信方式;总线形通信指的是一对多的群通信方式,所有设备都在同一条总线上发送和接收数据;多主机通信指的是多台主机的通信方式,多个设备都可以同时发送数据;简介式通信是一种用于仅需要发送少量数据的情况的通信方式。
下面介绍一下485通信的部分基本知识1.485通信的传输距离远,一般可以达到1200米。
2.485通信具有较强的抗干扰能力。
3.485通信使用差分信号进行传输,信号稳定,传输速率也比较快。
4.485通信可以支持多个设备同时进行通信,但是在同一时间内只有一个设备可发送数据。
5.在采用485通信时,一定要注意通讯端口的设置,如波特率、数据位、停止位等。
程序实现原理该程序使用了51单片机作为主控制器实现了基本的485通信,具体实现如下:1.通信模式的设置在程序开始时,需要设置通信模式。
如果通信模式为点对点通信,则可以直接使用UART通信模块进行通信;如果是多点通信,则需要使用485通信芯片。
2.通讯端口的配置在进行485通讯时,需要进行通讯端口的配置,包括波特率、数据位、停止位等参数的设定。
在485通信模式下,只有一个设备可为主设备,其他设备均为被设备。
在发送数据时,主设备的TXD口要与外部总线的D+口相连,而D-口不连接,从设备的TXD口要与D-口相连,而D+口不连接。
在接收数据时,主设备的RXD口要与D+口相连,而D-口不连接,从设备的RXD口要与D-口相连,而D+口不连接。
3.数据的发送和接收在发送和接收数据时,需要采用特定的方式进行报文的封装和解析。
51单片机串口485通讯程序
/* 以下为单片机串口485通讯程序,从机程序(当然也适用于主机程序),主机发送可以先用串口帮手软件来调试,经过Keil uVision4实际测试,测试效果如结尾图片所示, 大部分来自网络,只是改了两个地方: len = sizeof(dbuf),if(i >=( __ERRLEN+1)) // 帧超长,错误,返回,就可以实现了,其中的原因自已体会吧*/#ifndef __485_C__#define __485_C__#include <reg51.h>#include <string.h>#include <stdio.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned int/* 通信命令*/#define __ACTIVE_ 0x01 // 主机询问从机是否存在#define __GETDATA_ 0x02 // 主机发送读设备请求#define __OK_ 0x03 // 从机应答#define __STATUS_ 0x04 // 从机发送设备状态信息#define __MAXSIZE 0x08 // 缓冲区长度#define __ERRLEN 12 // 任何通信帧长度超过12则表示出错//uchar dbuf[__MAXSIZE]; // 该缓冲区用于保存设备状态信息uchar dbuf[__MAXSIZE];//={0,1,2,3,4,5,6,7}; // 该缓冲区用于保存设备状态信息uchar dev; // 该字节用于保存本机设备号sbit M_DE = P1^0; // 驱动器使能,1有效sbit M_RE = P1^1; // 接收器使能,0有效void get_status(); // 调用该函数获得设备状态信息,函数代码未给出void send_data(uchar type, uchar len, uchar *buf); // 发送数据帧bit recv_cmd(uchar *type); // 接收主机命令,主机请求仅包含命令信息void send_byte(uchar da); // 该函数发送一帧数据中的一个字节,由send_data()函数调用void main(){uchar type;uchar len;/* 系统初始化*/P1 = 0xff; // 读取本机设备号//dev = (P1>>2);dev = 0x01;TMOD = 0x20; // 定时器T1使用工作方式2TH1 = 250; // 设置初值TL1 = 250;TR1 = 1; // 开始计时PCON = 0x80; // SMOD = 1SCON = 0x50; // 工作方式1,波特率9600bps,允许接收ES = 0; // 关闭串口中断//IT0 = 0; // 外部中断0使用电平触发模式//EX0 = 1; // 开启外部中断0EA = 1; // 开启中断/* 主程序流程*/while(1) // 主循环{if(recv_cmd(&type) == 0) // 发生帧错误或帧地址与本机地址不符,丢弃当前帧后返回continue;switch(type){case __ACTIVE_: // 主机询问从机是否存在send_data(__OK_, 0, dbuf); // 发送应答信息,这里buf的内容并未用到break;case __GETDA TA_:// len = strlen(dbuf);//在C51中不能这个函数计算unsigned char型,这个函数只能计算char型len = sizeof(dbuf);// len =0x08;send_data(__STA TUS_, len, dbuf); // 发送设备状态信息break;default:break; // 命令类型错误,丢弃当前帧后返回}}}void READSTATUS() interrupt 0 using 1 // 产生外部中断0时表示设备状态发生改变,该函数使用寄存器组1{get_status(); // 获得设备状态信息,并将其存入dbuf指向的存储区,数据最后一字节置0表示数据结束}/* 该函数接收一帧数据并进行检测,无论该帧是否错误,函数均会返回* 函数参数type保存接收到的命令字* 当接收到数据帧错误或其地址位不为0时(非主机发送帧),函数返回0,反之返回1*/bit recv_cmd(uchar *type){bit db = 0; // 当接收到的上一个字节为0xdb时,该位置位bit c0 = 0; // 当接收到的上一个字节为0xc0时,该位置位uchar data_buf[__ERRLEN]; // 保存接收到的帧__ERRLEN=12;uchar tmp;uchar ecc = 0;uchar i;M_DE = 0; // 置发送禁止,接收允许M_RE = 0;/* 接收一帧数据*/i = 0;while(!c0) // 循环直至帧接收完毕{RI = 0;while(!RI);tmp = SBUF;RI = 0;if(db == 1) // 接收到的上一个字节为0xdb{switch(tmp){case 0xdd:data_buf[i] = 0xdb; // 0xdbdd表示0xdbecc = ecc^0xdb;db = 0;break;case 0xdc:data_buf[i] = 0xc0; // 0xdbdc表示0xc0ecc = ecc^0xc0;db = 0;break;default:return 0; // 帧错误,返回}i++;}switch(tmp) // 正常情况{case 0xc0: // 帧结束c0 = 1;break;case 0xdb: // 检测到转义字符db = 1;break;default: // 普通数据data_buf[i] = tmp; // 保存数据ecc = ecc^tmp; // 计算校验字节i++;}//if(i == __ERRLEN) // 帧超长,错误,返回if(i >=( __ERRLEN+1)) // 帧超长,错误,返回return 0;}/* 判断帧是否错误*/if(i<4) // 帧过短,错误,返回return 0;if(ecc != 0) // 校验错误,返回return 0;if(data_buf[0] != dev) // 非访问本机命令,错误,返回return 0;*type = data_buf[1]; // 获得命令字return 1; // 函数成功返回}/* 该函数发送一帧数据帧,参数type为命令字、len为数据长度、buf为要发送的数据内容*/void send_data(uchar type, uchar len, uchar *buf){uchar i;uchar ecc = 0; // 该字节用于保存校验字节M_DE = 1; // 置发送允许,接收禁止M_RE = 1;send_byte(dev); // 发送本机地址ecc = dev;send_byte(type); // 发送命令字ecc = ecc^type;send_byte(len); // 发送长度ecc = ecc^len;for(i=0; i<len; i++) // 发送数据{send_byte(*buf);ecc = ecc^(*buf);buf++;}send_byte(ecc); // 发送校验字节TI = 0; // 发送帧结束标志SBUF = 0xc0;while(!TI);TI = 0;}/* 该函数发送一个数据字节,若该字节为0xdb,则发送0xdbdd,若该字节为0xc0则,发送0xdbdc */void send_byte(uchar da){switch(da){case 0xdb: // 字节为0xdb,发送0xdbdd TI = 0;SBUF = 0xdb;while(!TI);TI = 0;SBUF = 0xdd;while(!TI)TI = 0;break;case 0xc0: // 字节为0xc0,发送0xdbdcTI = 0;SBUF = 0xdb;while(!TI);TI = 0;SBUF = 0xdc;while(!TI)TI = 0;break;default: // 普通数据则直接发送TI = 0;SBUF = da;while(!TI);TI = 0;}}#endif/* 调试结果*/。
485通信程序
本实验实现的功能和12.5节的完全相同,也是通过串行口接收上位机的启、停协议,然后根据协议来控制计数的启动和暂停,单片机每次计数过0向上位机返回过0消息。
本实验的主要代码如下:main.c源文件//main.c#include <reg51.h> //包含头文件#include "fun.h"void Timer0_interrupt() interrupt 1{TH0 = T0_50ms >> 8; //重装初值TL0 = T0_50ms;if ((++ count_in_T0) == 20) //count_in_T0自加到20,计时1s{count_in_T0 = 0;if ( (++ display_num) ==60){ //display_num自加1后判断是否等于60display_num = 0;//上发过0消息send(0xf0);send(0x01);send(0xf1);}}}void USART_interrupt() interrupt 4{char checkXOR;if (RI) //接收中断{RI = 0;reciev[rec_num] = SBUF;rec_num ++;if ((rec_num == 3) && (reciev[0] == 0x0f) )//接收到3字节,并且包头正确{checkXOR = reciev[0] ^ reciev[1];if (checkXOR == reciev[2] ) //如果异或校验正确,判断命令 {switch (reciev[1]){case 0x01:TR0 = 1; //启动rec_num = 0; //指令正确,清空缓冲区break;case 0x02:TR0 = 0; //暂停rec_num = 0; //指令正确,清空缓冲区break;default: //如果指令不正确,缓冲区左移reciev[0] = reciev[1];reciev[1] = reciev[2];rec_num --;break;}}}}if (TI){TI = 0;}}main(){unsigned char shi, ge; //定义十位、个位要输出的数据 ms_delay(100);init_port();init_usart();init_timer();dir = 0; //485接收数据rec_num = 0;display_num = 0;count_in_T0 = 0;//把两个数码管都关闭en2 = 1;en1 = 1;EA = 1; //开总中断while(1){shi = display_num / 10;ge = display_num % 10;display(shi,ge);}}fun.h头文件代码如下://fun.h//定义端口寄存器sfr P0M0 = 0X93;sfr P0M1 = 0X94;sfr P1M0 = 0X91;sfr P1M1 = 0X92;sfr P2M0 = 0X95;sfr P2M1 = 0X96;sfr P3M0 = 0Xb1;sfr P3M1 = 0Xb2;#define fosc 11059200L#define T0_50ms (65536 - (fosc/12/50000)) //50ms定时参数sbit en1 = P2^6;sbit en2 = P2^7;sbit dir = P3^2; //485方向控制unsigned char display_num,count_in_T0; //计数值、进入定时器的次数char reciev[3], rec_num; //保存接收到的数据/*共阴极数码管0~9的字形码"0" 3FH "5" 6DH"1" 06H "6" 7DH"2" 5BH "7" 07H"3" 4FH "8" 7FH"4" 66H "9" 6FH*/const unsigned char seg7[10] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f};void init_port(){P0M1 = 0xff;P0M0 = 0xff;P2M1 |= 0xc0;P2M0 |= 0xc0;P3M1 = 0x00; //P3.2准双向口模式P3M0 = 0x00;}void init_usart(){SM0 = 0;SM1 = 1;REN = 1;ES = 1;}void init_timer(){TMOD |= 0X01; //定时器0模式1,16bitTH0 = T0_50ms >> 8; //TH0 = T0_50ms / 256TL0 = T0_50ms; //TL0 = T0_50ms % 256ET0 = 1; //允许T0中断TMOD |= 0X20; //定时器1模式2,8bit自动重装 TH0 = 0xfd; //对应波特率9600TL0 = 0xfd;ET1 = 1; //允许T1中断TR1 = 1;}//定义延时函数void ms_delay(unsigned int t){unsigned int i;for (t; t > 0; t--) //外层循环t次for (i = 110;i > 0; i--) //内层循环110次;}void display(unsigned char c2, unsigned char c1) {P0 = seg7[c2]; //送入十位的段码en2 = 0; //显示DS2ms_delay(10);en2 = 1; //关闭DS2P0 = seg7[c1]; //送入个位的段码en1 = 0; //显示DS1ms_delay(10);en1 = 1; //关闭DS1}void send(char c){dir = 1; //485发送数据SBUF = c;while(!TI); //等待发完dir = 0; //485接收数据}讲解:本实验和12.5节的串行口收发实验基本相同,单片机串行口经由MAX1487芯片收发数据的过程对编程人员来说是完全透明的,我们只用跟平时操作串行口一样的方法来控制就可以了。
51单片机与RS485应用电路图
1 问题的提出在应用系统中,RS-485半双工异步通信总线是被各个研发机构广泛使用的数据通信总线,它往往应用在集中控制枢纽与分散控制单元之间。
系统简图如图1所示。
图1. RS-485系统示意图由于实际应用系统中,往往分散控制单元数量较多,分布较远,现场存在各种干扰,所以通信的可靠性不高,再加上软硬件设计的不完善,使得实际工程应用中如何保障RS-485总线的通信的可靠性成为各研发机构的一块心病。
在使用RS-485总线时,如果简单地按常规方式设计电路,在实际工程中可能有以下两个问题出现。
一是通信数据收发的可靠性问题;二是在多机通信方式下,一个节点的故障(如死机),往往会使得整个系统的通信框架崩溃,而且给故障的排查带来困难。
针对上述问题,我们对485总线的软硬件采取了具体的改进措施2 硬件电路的设计现以8031单片机自带的异步通信口,外接75176芯片转换成485总线为例。
其中为了实现总线与单片机系统的隔离,在8031的异步通信口与75176之间采用光耦隔离。
电路原理图如图2所示。
图2 改进后的485通信口原理图充分考虑现场的复杂环境,在电路设计中注意了以下三个问题。
2.1 SN75176 485芯片DE控制端的设计由于应用系统中,主机与分机相隔较远,通信线路的总长度往往超过400米,而分机系统上电或复位又常常不在同一个时刻完成。
如果在此时某个75176的DE端电位为“1”,那么它的485总线输出将会处于发送状态,也就是占用了通信总线,这样其它的分机就无法与主机进行通信。
这种情况尤其表现在某个分机出现异常情况下(死机),会使整个系统通信崩溃。
因此在电路设计时,应保证系统上电复位时75176的DE端电位为“0”。
由于8031在复位期间,I/O口输出高电平,故图2电路的接法有效地解决复位期间分机“咬”总线的问题。
2.2 隔离光耦电路的参数选取在应用系统中,由于要对现场情况进行实时监控及响应,通信数据的波特率往往做得较高(通常都在4800波特以上)。
485通讯协议程序怎么写(51单片机的485通信程序案例)
485通讯协议程序怎么写(51单片机的485通信程序案例)
RS-485总线接口是一种常用的串口,具有网络连接方便、抗干扰性能好、传输距离远等优点。
RS-485收发器采用平衡发送和差分接收,因此具有抑制共模干扰的能力,加上收发器具有高的灵敏度,能检测到低达200mv的电压,可靠通信的传输距离可达数千米。
使用RS-485总线组网,只需一对双绞线就可实现多系统联网构成分布式系统、设备简单、价格低廉、通信距离长。
51单片机的485通信程序
#ifndef __485_C__ #define __485_C__
#include 《reg51.h》
#include 《string.h》
#define unsigned char uchar
#define unsigned int uint
/* 通信命令*/
#define __ACTIVE_ 0x01 // 主机询问从机是否存在
#define __GETDATA_ 0x02 // 主机发送读设备请求
#define __OK_ 0x03 // 从机应答
#define __STATUS_ 0x04 // 从机发送设备状态信息
#define __MAXSIZE 0x08 // 缓冲区长度
#define __ERRLEN 12 // 任何通信帧长度超过12则表示出错
uchar dbuf[__MAXSIZE]; // 该缓冲区用于保存设备状态信息
uchar dev; // 该字节用于保存本机设备号
sbit M_DE = P1。
C8051F040的RS485收发程序
//交叉开关配置使能,UART0配置在P0.0-P0.1
P0MDOUT = 0Xff;
}
/*系统时钟初始化
-----------------------------------------------------------*/
void os_init()
{
int i = 0;
SFRPAGE = CONFIG_PAGE;
void time1_init()
{
SFRPAGE = TIMER01_PAGE;
TCON
= 0X40;
//TR1=1 定时器允许
TMOD
= 0x20;
//T1M1=1 T1M0=0 定时器工作在方式
CKCON = 0x10;
TH1
= 0xb8;
//装初值,波特率为
TL1
= 0xb8;
TR1=1;
i=0; for(i=0;i<50000;i++)
for(j=0;j<10;j++); }
SFRPAGE = UART0_PAGE;
gate = 0;
}
}
/*端口初始化-------------------------------------*/ void port_init() {
SFRPAGE = CONFIG_PAGE;
XBR0 = 0x04; XBR1 = 0x00; XBR2 = 0xd main()
{
WDTCN = 0x07;
//看门狗禁止
WDTCN = 0xDE;
WDTCN = 0xAD;
os_init();
port_init();
uart0_init();
51单片机实现RS485
default: // 普通数据则直接发送TI = 0;SBUF = da;while(!TI);TI = 0;}}#endifRS-232接口实现计算机和单片机通信程序作者:佚名来源:本站原创点击数:…更新时间:2008年07月10日【字体:大中小】//此程序通过RS-232接口来完成计算机和单片机通信(程序已用p1 8f458试验板上调试通过)//程序的调试可以用"串口调试助手V2.1"辅助完成,此程序可在htt p:// 下载//此程序首先发送测试数据55H,再通过中断实现数据的接收和发送#include "p18f458.h"void InterruptHandlerHigh(void);//初始化程序void initial(){SPBRG=0X19; //选择传输波特率为9600bpsTXSTA=0X04; //选择异步高速方式传输8位数据RCSTA=0X80; //允许同步串行口工作TRISC=0X80; //将RC7,RC6设置为输入,断绝与外接电路的连接 TXSTAbits.TXEN=1; //发送允许RCSTAbits.CREN=1; //接受数据允许PIE1bits.RCIE=1; //接收中断使能INTCON=0XC0; //总中断和外围中断允许}//高优先级中断向量#pragma code InterruptVectorHigh=0x08void InterruptVectorHigh (void){_asmgoto InterruptHandlerHigh //跳到中断程_endasm}//高优先级中断服务程序#pragma code#pragma interrupt InterruptHandlerHighvoid InterruptHandlerHigh (){while(PIR1bits.RCIF==1) //若接收中断标志不为1,则为误操作,返回{TXREG=RCREG; //将接收到的数据放入发送寄存器,并启动发送 }}//主程序main(){initial(); //系统初始化TXREG=0X55; //发送数据55H进行测试for(;;);}------------------------------------------汇编语言版本的RS-232接口实现计算机和单片机通信程序------------;此程序通过RS-232接口来完成计算机和单片机通讯(程序以在p18 f458试验板上调通);本单片机程序由提供;此程序首先发送测试数据55H,再通过中断实现数据的接收和发送;程序的调试可以用"串口调试助手V2.1"辅助完成LIST P=18f458INCLUDE "P18f458.INC"ORG 0x00GOTO MAINORG 0x08GOTO INTSERVEORG 0X30;**************中断服务子程序***************INTSERVEBTFSS PIR1,RCIF ;接收中断标志为1?GOTO ERR_RE ;误操作,返回MOVF RCREG,0 ;否则,将接收到的数据通过W寄存器MOVWF TXREG ;放入发送寄存器,并启动发送ERR_RE NOPRETFIE;****************初始化程序***************INITIAL NOPMOVLW 0X19 ;选择传输波特率为9600bpsMOVWF SPBRGMOVLW 0X04 ;选择异步高速方式传输8位数据MOVWF TXSTAMOVLW 0X80 ;允许同步串行口工作MOVWF RCSTAMOVLW 0X80 ;将RC7,RC6设置为输入,断绝与外接电路的连接MOVWF TRISCBSF TXSTA,TXEN ;发送允许BSF RCSTA,CREN ;接受数据允许BSF PIE1,RCIE ;接收中断使能MOVLW 0XC0 ;总中断和外围中断允许MOVWF INTCONRETURN;**********************主程序********************* MAIN NOPCLRWDTCALL INITIALMOVLW 0X55 ;发送数据55H进行测试MOVWF TXREGLOOPGOTO LOOPEND两片51单片机互相通信的串行通信程序(一个发送程序,一个接收程序)2007-05-27 08:27;系统晶振是 11.0592 MHz;51单片机发送单片机程序;此程序用Proteus仿真通过;此程序在硬件上测试通过;2007-05-27;附有简化电路图;为了使初学者能看懂,程序与图尽可能的简单扼要;实验现象为,发送端的P1口的哪个键被接下,接收端的哪个灯对应着亮;如果把两个单片机的T和R通过无线模块(如基于MCP2120芯片的模块)来扩充,便可做成无线通信ORG0000HAJMPSTARTORG0040HSTART:MOVSP,#60HMOVSCON,#50H;串口方式 1MOVTMOD,#20H;T1 方式2MOVTL1,#0FDH;波特率 9600 的常数MOVTH1,#0FDHSETBTR1movr5,#00hWAIT:movp1,#0ffhmova ,p1movr5,alcalldelay ;读键盘,这里去抖动,还要加几句话mova ,p1nopCJNEA,5,WAIT ;是否有键输入MOVSBUF,a;串口输出键盘输入的值NOPSS: JBCTI,WAIT;是否发送完毕SJMPSSDELAY:;延时子程序PUSH;保存现场PUSH1MOV0,#06HDELAY1: MOV 1,#0HDJNZ1,$DJNZ0,DELAY1POP1;恢复现场POPRETEND;系统晶振是 11.0592 MHz;51单片机接收单片机程序;此程序用Proteus仿真通过;此程序在硬件上测试通过;2007-05-27;附有简化电路图;为了使初学者能看懂,程序与图尽可能的简单扼要;实验现象为,发送端的P1口的哪个键被接下,接收端的哪个灯对应着亮;如果把两个单片机的T和R通过无线模块(如基于MCP2120芯片的模块)来扩充,便可做成无线通信ORG0000HAJMPSTARTORG0040HSTART:MOVSCON,#50H;串口方式 1MOVTMOD,#20H;T1 方式 2MOVTL1,#0FDH;波特率 9600 的常数MOVTH1,#0FDHSETBTR1WAIT:JBCRI,DIS_REC;是否接收到数据sjmpwaitDIS_REC:MOVA,SBUF;读串口接收到的数据movp1,aSJMPwaitend51单片机串行口通信程序设计例子时间:2009-03-06 17:13来源:未知作者:牛牛点击: 768次串行口方式0应用编程 8051单片机串行口方式0为移位寄存器方式,外接一个串入并出的移位寄存器,就能扩展一个并行口。
手把手教你学51单片机之十八RS485通信与Modbus协议
在工业控制、电力通讯、智能仪表等领域,通常情况下是采用串口通信的方式进行数据交换。
最初采用的方式是 RS232 接口,由于工业现场比较复杂,各种电气设备会在环境中产生比较多的电磁干扰,会导致信号传输错误。
除此之外,RS232 接口只能实现点对点通信,不具备联网功能,最大传输距离也只能达到几十米,不能满足远距离通信要求。
而 RS485 则解决了这些问题,数据信号采用差分传输方式,可以有效的解决共模干扰问题,最大距离可以到1200 米,并且允许多个收发设备接到同一条总线上。
随着工业应用通信越来越多, 1979 年施耐德电气制定了一个用于工业现场的总线协议 Modbus 协议,现在工业中使用RS485 通信场合很多都采用 Modbus 协议,本节课我们要讲解一下 RS485 通信和Modbus 协议。
单单使用一块KST-51 开发板是不能够进行RS485 实验的,应很多同学的要求,把这节课作为扩展课程讲一下,如果要做本课相关实验,需要自行购买USB 转 485 通信模块。
18.1 RS485通信实际上在 RS485 之前 RS232 就已经诞生,但是RS232 有几处不足的地方:1、接口的信号电平值较高,达到十几V ,容易损坏接口电路的芯片,而且和TTL 电平不兼容,因此和单片机电路接起来的话必须加转换电路。
2、传输速率有局限,不可以过高,一般到几十Kb/s 就到极限了。
3、接口使用信号线和GND 与其他设备形成共地模式的通信,这种共地模式传输容易产生干扰,并且抗干扰性能也比较弱。
4、传输距离有限,最多只能通信几十米。
5、通信的时候只能两点之间进行通信,不能够实现多机联网通信。
针对 RS232 接口的不足,就不断出现了一些新的接口标准,RS485 就是其中之一,他具备以下的特点:1、我们在讲A/D 的时候,讲过差分信号输入的概念,同时也介绍了差分输入的好处,最大的优势是可以抑制共模干扰。
尤其工业现场的环境比较复杂,干扰比较多,所以通信如果采用的是差分方式,就可以有效的抑制共模干扰。
485双机通信案例原理与测试说明
“485双机通信”功能实现说明1程序设计目标及程序运行效果说明程序设计目标:通过本例程理解RS485通信方式,实现双机通信。
程序运行效果:将两块带有485模块的51单片机通过485外接引脚A、B连接起来,单片机上电烧写程序后485模块的D/R引脚所对应的二极管均点亮,然后通过按键KEY3、KEY2控制数码管上的数值进行加减处理,两块单片机起始都默认为接收状态,最后按下KEY1发送键,将数据传送给另一块单片机,而此时接收方数码管上的数值发生相应的改变,与发送方数码管上的数值一致。
2程序相关电路及工作原理说明2.1 RS485通信原理RS232接口是1970年由美国电子工业协会(EIA)联合贝尔系统、调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准。
针对RS232的不足,于是不断出现了新的接口标准,RS485就是其中的一种。
RS485接口的最大传输距离标准值为4000英尺,实际上可达 3000米,另外RS232接口在总线上只允许连接1个收发器,即单站能力。
而RS485接口在总线上是允许连接多达128个收发器。
即具有多站能力,这样用户可以利用单一的RS485接口方便地建立起设备网络。
RS485属于半双工通信,数据可以在一个信号载体的两个方向上传输,但是不能同时进行传输。
电平转换采用差分电路方式,A、B两线的电压差大于0.2认为是逻辑“1”,小于-0.2认为是逻辑“0”,方便与TTL电路连接。
使用RS485进行通信与RS232通信的逻辑是一致的,但RS485抗干扰性更强,传输距离更远。
RS485广泛运用在工业自动化控制、视频监控、门禁对讲以及楼宇报警等各个领域。
图1 485模块电路原理图MAX485芯片的功能是将TTL电平转换为RS485电平,引脚功能如下:(1)485 D/R输出、接收信号控制引脚:当该引脚为低电平时,485为接收态,MAX485通过485_RXD把来自总线的信号输出给单片机;当该引脚为高电平时,485为发送态,来自485_TXD的输出信号通过A、B引脚加载到总线上。
我的51单片机之 MAX485的 C语言与汇编的编程
//与自制软件 ComTest 通信,设好通信口,按下软件中相应按钮,数码管显示相应值
//made by luqichao
//************************************************************************
#include <reg51.h>
;
{ 0 , 1, 2 , 3 , 4 , 5, 6, 7, 8, 9 }
MAIN:
MOV SCON,#50H; 串口工作于方式 1,充许接收
MOV PCON,#0H;
波特率不倍增
MOV TMOD,#20H; 定时器计数器 1 工作于方式 2;
MOV TH1,#0FDH;
MOV TL1,#0FDH; 波特率为 9600;
LEDCODE EQU P1 ComData EQU 40H; LED1 EQU P0.6; LED2 EQU P0.7; M485 EQU P0.5;
//作为收发数据的使能短,1 为发数据 0 为收数据
;字形码:0--f 及小数点
AscLed:DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H;
四、汇编程序: ;************************************************************************** ;与自制软件 ComTest 通信,设好通信口,按下软件中相应按钮,数码管显示相应值 ;made by luqichao ;************************************************************************** ORG 0000H AJMP MAIN ORG 001BH AJMP T1P ORG 0023H AJMP COMM ORG 0030H
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
标签:modbus8051源程序modbus协议--51端程序的实现RTU需要一个定时器来判断3.5个流逝时间。
#define ENABLE 1#define DISABLE 0#define TRUE 1#define FAULT 0#define RECEIVE_EN 0#define TRANSFER_EN 1#define MAX_RXBUF 0x20extern unsigned char emissivity;extern unsigned char tx_count,txbuf[15];extern unsigned char rx_count,rxbuf[15];extern unsigned char tx_number,rx_number;extern bit rx_ok;unsigned char rx_temp;void InitTimer1() //针对标准8051{TMOD=(TMOD|0xf0)&0x1f; //将T1设为16位定时器TF1=0;TH1=0x62; //设T1位3.5位的接收时间35bit/9600bit/s=3.646msTL1=0x80;//晶振为11.0592MHz,T=65535-3.646ms*11.0592MHz/12=0xf2df//0x6280是22.1184M下LPC9XX下的值。
ET1=1;//允许T1中断TR1=1;//T1开始计数}void timer1() interrupt 3 using 2 //定时器中断{TH1=0x62; //3.646ms interruptTL1=0x80;if(rx_count>=5) //超时后,若接收缓冲区有数则判断为收到一帧{rx_ok=TRUE;}}void scomm() interrupt 4 using 3 //modbus RTU模式{if(TI){TI = 0;if(tx_count < tx_number) //是否发送结束{SBUF = txbuf[tx_count];}tx_count++;}if(RI){rx_temp=SBUF;if(rx_ok==FAULT) //已接收到一帧数据,在未处理之前收到的数舍弃{if(rx_countrxbuf[rx_count]=rx_temp;rx_count++;}TH1=0x62; //timer1 reset,count againTL1=0x80;RI=0;}}在主循环中判断标志rx_ok来执行帧处理。
if(rx_ok){ParseFrame();KB0=1;REN=0;tx_count=0;TI=1; //启动发送响应帧rx_count=0;rx_ok=0;}WORD MAKEWORD(a, b){int_byte itemp;itemp.items.high=a;itemp.items.low=b;return (itemp.item);// 解析帧并发送响应帧 (在帧完整的前提下调用)bit ParseFrame(){unsigned char byAddr ; // 地址unsigned char byFunCode ; // 功能代码int_byte wCRC;wCRC.item = MAKEWORD(rxbuf[rx_count-1], rxbuf[rx_count-2]);if(wCRC.item != CRC(rxbuf, rx_count-2)) // 判断校验是否正确return FALSE;// 正式解析byAddr = rxbuf[0]; // 地址byFunCode = rxbuf[1]; // 功能代码// 如果地址不对if( (byAddr != m_byAddress) && (byAddr != 0) )return FALSE;if(byAddr == m_byAddress){AddSendByte(m_byAddress) ; // 地址switch( byFunCode ){case 3: // 读保持寄存器Fun3(3);break;....// 添加命令散转......default:ErroRespond(1);return FALSE;break;}}wCRC.item = CRC(txbuf,tx_number);AddSendByte(wCRC.items.low);AddSendByte(wCRC.items.high);return TRUE;// 根据接收帧模式发送相应,模式的数据BOOL AddSendByte(const BYTE byData){txbuf[tx_number]=byData;tx_number++;if(tx_number>30)return FALSE;return TRUE;}// 异常响应描述响应解释// 01 无效功能变送器不允许执行收到的功能// 02 无效地址数据栏中的地址是不允许的// 03 无效数据数据栏中的数据是不允许的// 06 忙收到的消息没错,但从机正在执行一个长的程序命令bit ErroRespond(const unsigned char byErroCode){// printf("\nErroRespond%02X \n", byErroCode);if( !AddSendByte(rxbuf[1] | 0x80) )return FALSE;return AddSendByte(byErroCode);}//***CRC Calculation for MODBUS Protocol for VC++***////数组snd为地址等传输字节,num为字节数//unsigned int CRC(unsigned char *snd, unsigned char num){unsigned char i, j;unsigned int c,crc=0xFFFF;for(i = 0; i < num; i ++){c = snd[i] & 0x00FF;crc ^= c;for(j = 0;j < 8; j ++){if (crc & 0x0001){crc>>=1;crc^=0xA001;}else crc>>=1;}}return(crc);}51单片机实现的485通讯程序单片机2009-08-31 14:17:48 阅读722 评论0 字号:大中小订阅#ifndef __485_C__#define __485_C__#include <reg51.h>#include <string.h>#define unsigned char uchar#define unsigned int uint/* 通信命令*/#define __ACTIVE_ 0x01 // 主机询问从机是否存在#define __GETDATA_ 0x02 // 主机发送读设备请求#define __OK_ 0x03 // 从机应答#define __STATUS_ 0x04 // 从机发送设备状态信息#define __MAXSIZE 0x08 // 缓冲区长度#define __ERRLEN 12 // 任何通信帧长度超过12则表示出错uchar dbuf[__MAXSIZE]; // 该缓冲区用于保存设备状态信息uchar dev; // 该字节用于保存本机设备号sbit M_DE = P1^0; // 驱动器使能,1有效sbit M_RE = P1^1; // 接收器使能,0有效void get_status(); // 调用该函数获得设备状态信息,函数代码未给出void send_data(uchar type, uchar len, uchar *buf); // 发送数据帧bit recv_cmd(uchar *type); // 接收主机命令,主机请求仅包含命令信息void send_byte(uchar da); // 该函数发送一帧数据中的一个字节,由send_data()函数调用void main(){uchar type;uchar len;/* 系统初始化*/P1 = 0xff; // 读取本机设备号dev = (P1>>2);TMOD = 0x20; // 定时器T1使用工作方式2TH1 = 250; // 设置初值TL1 = 250;TR1 = 1; // 开始计时PCON = 0x80; // SMOD = 1SCON = 0x50; // 工作方式1,波特率9600bps,允许接收ES = 0; // 关闭串口中断IT0 = 0; // 外部中断0使用电平触发模式EX0 = 1; // 开启外部中断0EA = 1; // 开启中断/* 主程序流程*/while(1) // 主循环{if(recv_cmd(&type) == 0) // 发生帧错误或帧地址与本机地址不符,丢弃当前帧后返回continue;switch(type){case __ACTIVE_: // 主机询问从机是否存在send_data(__OK_, 0, dbuf); // 发送应答信息,这里buf的内容并未用到break;case __GETDATA_:len = strlen(dbuf);send_data(__STATUS_, len, dbuf); // 发送设备状态信息break;default:break; // 命令类型错误,丢弃当前帧后返回}}}void READSTATUS() interrupt 0 using 1 // 产生外部中断0时表示设备状态发生改变,该函数使用寄存器组1{get_status(); // 获得设备状态信息,并将其存入dbuf指向的存储区,数据最后一字节置0表示数据结束}/* 该函数接收一帧数据并进行检测,无论该帧是否错误,函数均会返回* 函数参数type保存接收到的命令字* 当接收到数据帧错误或其地址位不为0时(非主机发送帧),函数返回0,反之返回1*/bit recv_cmd(uchar *type)bit db = 0; // 当接收到的上一个字节为0xdb时,该位置位bit c0 = 0; // 当接收到的上一个字节为0xc0时,该位置位uchar data_buf[__ERRLEN]; // 保存接收到的帧uchar tmp;uchar ecc = 0;uchar i;M_DE = 0; // 置发送禁止,接收允许M_RE = 0;/* 接收一帧数据*/i = 0;while(!c0) // 循环直至帧接收完毕{RI = 0;while(!RI);tmp = SBUF;RI = 0;if(db == 1) // 接收到的上一个字节为0xdb{switch(tmp){case 0xdd:data_buf[i] = 0xdb; // 0xdbdd表示0xdbecc = ecc^0xdb;db = 0;break;case 0xdcdata_buf[i] = 0xc0; // 0xdbdc表示0xc0ecc = ecc^0xc0;db = 0;break;defaultreturn 0; // 帧错误,返回}i++;}switch(tmp) // 正常情况{case 0xc0: // 帧结束c0 = 1;break;case 0xdb: // 检测到转义字符break;default: // 普通数据data_buf[i] = tmp; // 保存数据ecc = ecc^tmp; // 计算校验字节i++;}if(i == __ERRLEN) // 帧超长,错误,返回return 0;}/* 判断帧是否错误*/if(i<4) // 帧过短,错误,返回return 0;if(ecc != 0) // 校验错误,返回return 0;if(data_buf[0] != dev) // 非访问本机命令,错误,返回return 0;*type = data_buf[1]; // 获得命令字return 1; // 函数成功返回}/* 该函数发送一帧数据帧,参数type为命令字、len为数据长度、buf为要发送的数据内容*/ void send_data(uchar type, uchar len, uchar *buf){uchar i;uchar ecc = 0; // 该字节用于保存校验字节M_DE = 1; // 置发送允许,接收禁止M_RE = 1;send_byte(dev); // 发送本机地址ecc = dev;send_byte(type); // 发送命令字ecc = ecc^type;send_byte(len); // 发送长度ecc = ecc^len;for(i=0; i<len; i++) // 发送数据{send_byte(*buf);ecc = ecc^(*buf);buf++;}send_byte(ecc); // 发送校验字节TI = 0; // 发送帧结束标志while(!TI);TI = 0;}/* 该函数发送一个数据字节,若该字节为0xdb,则发送0xdbdd,若该字节为0xc0则,发送0xdbdc */void send_byte(uchar da){switch(da){case 0xdb: // 字节为0xdb,发送0xdbddTI = 0;SBUF = 0xdb;while(!TI);TI = 0;SBUF = 0xdd;while(!TI)TI = 0;break;case 0xc0: // 字节为0xc0,发送0xdbdcTI = 0;SBUF = 0xdb;while(!TI);TI = 0;SBUF = 0xdc;while(!TI)TI = 0;break;default: // 普通数据则直接发送TI = 0;SBUF = da;while(!TI);TI = 0;}}#endif关于CT极性的若干相关问题看到旺友leilin0902关于线圈极性测试方法的帖子,有一小小想法,开新贴讨论CT极性的相关问题,我会慢慢提问,欢迎大家讨论。