51单片机串口485通讯程序
51单片机实现的485通讯程序
![51单片机实现的485通讯程序](https://img.taocdn.com/s3/m/bef06f3b83c4bb4cf7ecd162.png)
标签: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来执行帧处理。
手把手教你学51单片机之十八RS485通信与Modbus协议
![手把手教你学51单片机之十八RS485通信与Modbus协议](https://img.taocdn.com/s3/m/e468926f02d276a201292e4c.png)
在工业控制、电力通讯、智能仪表等领域,通常情况下是采用串口通信的方式进行数据交换。
最初采用的方式是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单片机的串口通信程序
![51单片机的串口通信程序](https://img.taocdn.com/s3/m/d74a2ac7453610661fd9f457.png)
单片机串口通信程序#include <reg52.h>#include<intrins.h>#include <stdio.h>#include <math.h>#define uchar unsigned char#define uint unsigned intsbit Key1 = P2^3;sbit Key2 = P2^2;sbit Key3 = P2^1;sbit Key4 = P2^0;sbit BELL = P3^6;sbit CONNECT = P3^7;unsigned int Key1_flag = 0;unsigned int Key2_flag = 0;unsigned int Key3_flag = 0;unsigned int Key4_flag = 0;unsigned char b;unsigned char code Num[21]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x40,0x79,0x24,0x30,0x19,0x12,0x 02,0x78,0x00,0x10,0x89};unsigned char code Disdigit[4] = {0x7F,0xBF,0xDF,0xEF};unsigned char Disbuf[4];void delayms(uint t){uint i;while(t--){/* 对于11.0592M时钟,约延时1ms */for (i=0;i<125;i++){}}}//-----------------------------------------------------void SendData(uchar Dat){uchar i=0;SBUF = Dat;while (1){if(TI){TI=0;break;}}}void ScanKey(){if(Key1 == 0){delayms(100);if(Key1 == 0){Key1_flag = 1;Key2_flag = 0;Key3_flag = 0;Key4_flag = 0;Key1 = 1;}else;}if(Key2 == 0){delayms(100);if(Key2 == 0){Key2_flag = 1;Key1_flag = 0;Key3_flag = 0;Key4_flag = 0;Key2 = 1;}else;}if(Key3 == 0){delayms(50);if(Key3 == 0){Key3_flag = 1;Key1_flag = 0;Key2_flag = 0;Key4_flag = 0;Key3 = 1;}else;}if(Key4 == 0){delayms(50);if(Key4 == 0){Key4_flag = 1;Key1_flag = 0;Key2_flag = 0;Key3_flag = 0;Key4 = 1;}else;}else;}void KeyProc(){if(Key1_flag){TR1 = 1;SendData(0x55);Key1_flag = 0;}else if(Key2_flag){TR1 = 1;SendData(0x11);Key2_flag = 0;}else if(Key3_flag){P1=0xff;BELL = 0; CONNECT = 1;Key3_flag = 0;}else if(Key4_flag){CONNECT = 0;BELL = 1;Key4_flag = 0;}else;}void Initdisplay(void){Disbuf[0] = 1;Disbuf[1] = 2;Disbuf[2] = 3;Disbuf[3] = 4;}void Display() //显示{unsigned int i = 0;unsigned int temp,count;temp = Disdigit[count];P2 =temp;temp = Disbuf[count];temp = Num[temp];P0 =temp;count++;if (count==4)count=0;}void time0() interrupt 1 using 2 {Display();TH0 = (65535 - 2000)/256;TL0 = (65535 - 2000)%256;}void main(){Initdisplay();TMOD = 0x21;TH0 = (65535 - 2000)/256;TL0 = (65535 - 2000)%256;TR0 = 1;ET0 = 1;TH1 = 0xFD; //11.0592MTL1 = 0xFD;PCON&=0x80;TR1 = 1;ET1 = 1;SCON = 0x40; //串口方式REN = 1;PT1 = 0;PT0 = 1;EA = 1;while(1){ScanKey();KeyProc();if(RI){Disbuf[0] = 0;Disbuf[1] = 20;Disbuf[2] = SBUF>>4;Disbuf[3] = SBUF&0x0f;RI = 0;}else;}}。
80C51单片机串口通信(含原程序)
![80C51单片机串口通信(含原程序)](https://img.taocdn.com/s3/m/b2178fefe009581b6bd9eb53.png)
buf=NUMCODETAB[num];
transbyte(buf);
buf=NUMCODETAB[num];
transbyte(buf);
buf=NUMCODETAB[num];
transbyte(buf);
buf=NUMCODETAB[num];
transbyte(buf);
void send(uchar dat)
{
SBUF=dat;
while(TI==0);
TI=0;
}
void delay(void)
{
uchar x,y;
for(x=0;x<220;x++)
for(y=0;y<250;Leabharlann ++);}
void main(void)
{
uchar i;
TMOD=0x20;
SCON=0x40;
并将这些代码用发光二极管在发送端显示(流水灯效果)。
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
uchar code tab[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
sbit DIPIN = P1^3;
uint num;
uchar receive (void)
{
uchar dat;
while(RI==0);
RI=0;
dat=SBUF;
SBUF=dat;
return dat;
}
unsigned char code NUMCODETAB[]={0xFC,0x60,0xDA,0xF2, //数字0,1,2,3
485通信程序(51单片机)
![485通信程序(51单片机)](https://img.taocdn.com/s3/m/048fc75049d7c1c708a1284ac850ad02df800770.png)
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单片机串口通信程序
![51单片机串口通信程序](https://img.taocdn.com/s3/m/1715ba0030126edb6f1aff00bed5b9f3f90f721e.png)
51单片机串口通信程序51单片机是我国自主研发的一款微控制器,在国内广泛应用于各种电子设备中。
在很多应用场景中,需要通过串口进行通信,以实现数据传输。
本文将介绍51单片机串口通信程序的编写方法。
一、串口介绍串口是一种通信接口,用于在电子设备之间传输数据。
其主要特点是一条通信线路同时只能传输一位数据,因此称为串口。
串口和并口属于不同的通信接口标准。
串口的优点是具有通信距离远、传输速率快、可靠性高等优点,因此广泛应用于各种场合中。
串口有两种工作模式:同步模式和异步模式。
在实际应用中,异步串口通信更为常见。
二、异步串口通信原理在异步串口通信中,数据的传输是通过发送端和接收端的时钟信号不同步实现的。
在发送数据时,发送端会发出一个起始位,接下来是数据位,最后是一个或多个停止位。
在接收端,当检测到起始位时,开始接收数据。
根据通信协议,在接收完数据位后,接收端会判断是否正确,然后再结束本次通信。
1. 硬件连接在51单片机和电脑之间进行串口通信,需要用到串口转USB线。
将串口转USB线的TxD接口与51单片机的P3.1接口相连,RxD接口与P3.0接口相连。
此外,需要一个5V的电源供给51单片机。
2. 准备工作在编写程序之前,需要进行一些准备工作:(1)将P3口设为外部中断P3口的最低2位是外部中断的2个输入端,需要将它们设为中断输入。
EA=1;EX0=1;(2)设置波特率串口通信需要设置波特率。
常见的波特率有9600、19200、38400等。
对应的波特率常数为0xFD、0xFA、0xF4等。
TH1=0xFD;//波特率9600(3)使能串口中断在发送和接收数据时,会不断产生中断,需要将中断使能。
ES=1;//允许串口中断3. 编写程序(1)发送数据void SendData(unsigned char SendBuff[],unsigned int ULength){unsigned int i;for(i=0;i<ULength;i++){SBUF=SendBuff[i];//发送数据while(TI==0); //等待,直到发送完成TI=0;}}(2)接收数据(3)主函数TMOD|=0x20;//定时器1工作方式2TH1=0xFD;//波特率9600TR1=1;//打开定时器1SCON=0x50;//串口方式1,8位数据,无校验,1停止位EA=1;//开总中断ES=1;//开串口中断while(1){SendData(pSendData,4);//发送数据 RecvData(pRecvData,4);//接收数据if(pRecvData[0]=='K'){P0=0x01;//点亮LED}else{P0=0x00;//关闭LED}}}四、总结。
51单片机串口485通讯程序
![51单片机串口485通讯程序](https://img.taocdn.com/s3/m/710ff77b27284b73f2425029.png)
/* 以下为单片机串口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/* 调试结果*/。
51单片机与RS485应用电路图
![51单片机与RS485应用电路图](https://img.taocdn.com/s3/m/06bb77175f0e7cd1842536af.png)
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通信程序案例)](https://img.taocdn.com/s3/m/c732165b6c85ec3a87c2c55f.png)
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。
51单片机的串口通信程序
![51单片机的串口通信程序](https://img.taocdn.com/s3/m/b31c77dca58da0116c17493f.png)
51单片机的串口通信程序(C语言)#include <reg52.h>#include<intrins.h>#include <stdio.h>#include <math.h>#define uchar unsigned char#define uint unsigned intsbit Key1 = P2^3;sbit Key2 = P2^2;sbit Key3 = P2^1;sbit Key4 = P2^0;sbit BELL = P3^6;sbit CONNECT = P3^7;unsigned int Key1_flag = 0;unsigned int Key2_flag = 0;unsigned int Key3_flag = 0;unsigned int Key4_flag = 0;unsigned char b;unsigned char code Num[21]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00, 0x10,0x89};unsigned char code Disdigit[4] = {0x7F,0xBF,0xDF,0xEF};unsigned char Disbuf[4];void delayms(uint t){uint i;while(t--){/* 对于11.0592M时钟,约延时1ms */for (i=0;i<125;i++){}}}//-----------------------------------------------------void SendData(uchar Dat){uchar i=0;SBUF = Dat;while (1){if(TI){TI=0;break;}}}void ScanKey(){if(Key1 == 0){delayms(100); if(Key1 == 0){Key1_flag = 1; Key2_flag = 0; Key3_flag = 0;Key4_flag = 0;Key1 = 1;}else;}if(Key2 == 0){delayms(100);if(Key2 == 0){Key2_flag = 1; Key1_flag = 0; Key3_flag = 0;Key4_flag = 0;Key2 = 1;}else;}if(Key3 == 0){delayms(50);if(Key3 == 0){Key3_flag = 1; Key1_flag = 0; Key2_flag = 0;Key4_flag = 0;Key3 = 1;}else;}if(Key4 == 0){delayms(50);if(Key4 == 0){Key4_flag = 1;Key1_flag = 0;Key2_flag = 0;Key3_flag = 0;Key4 = 1;}else;}else;}void KeyProc(){if(Key1_flag){TR1 = 1;SendData(0x55);Key1_flag = 0; }else if(Key2_flag){TR1 = 1;SendData(0x11); Key2_flag = 0;}else if(Key3_flag) {P1=0xff;BELL = 0;CONNECT = 1;Key3_flag = 0;}else if(Key4_flag){CONNECT = 0;BELL = 1;Key4_flag = 0;}else;}void Initdisplay(void){Disbuf[0] = 1;Disbuf[1] = 2;Disbuf[2] = 3;Disbuf[3] = 4;}void Display() //显示{unsigned int i = 0;unsigned int temp,count;temp = Disdigit[count]; P2 =temp;temp = Disbuf[count];temp = Num[temp];P0 =temp;count++;if (count==4)count=0;}void time0() interrupt 1 using 2 {Display();TH0 = (65535 - 2000)/256;TL0 = (65535 - 2000)%256;}void main(){Initdisplay();TMOD = 0x21;TH0 = (65535 - 2000)/256;TL0 = (65535 - 2000)%256;TR0 = 1;ET0 = 1;TH1 = 0xFD; //11.0592MTL1 = 0xFD;PCON&=0x80;TR1 = 1;ET1 = 1;SCON = 0x40; //串口方式REN = 1;PT1 = 0;PT0 = 1;EA = 1;while(1){ScanKey();KeyProc();if(RI){Disbuf[0] = 0;Disbuf[1] = 20;Disbuf[2] = SBUF>>4; Disbuf[3] = SBUF&0x0f; RI = 0;}else;}}。
基于51单片机RS485总线的远距离温度监控系统程序
![基于51单片机RS485总线的远距离温度监控系统程序](https://img.taocdn.com/s3/m/39d9573202d276a201292e98.png)
/等待初始化结束
delay(*DS18b20读一个字节*******************/uchar ReadOneChar(void)
{
uchar i=0; uchar dat=0; for (i=8;i>0;i--){
Ox3f,OxO6,Ox5b,Ox4f, Ox66,Ox6d,Ox7d,OxO7, Ox7f,Ox6f,Ox77,Ox7c, Ox39,Ox5e,Ox79,Ox71,
OxOO
DQ
//DS18B20接入口
//O~3
//4~7
//8~b //c~f
};uchar tem[7]; uchar T_num=200;/************************void delay(uint n);时函数void init_uart(void);始化void init_T0();定时器T0初始化void Init_DS18B20(void);始化函数uchar ReadOneChar(void);一个字节void WriteOneChar(uchar dat);一个字节int ReadTemperature(void);读取温度
}
delay(8);
}
/*****************DS18b20读取温度********************/int ReadTemperature(void)
{
uchar dat_L=0,dat_H=0;
int temper=0;
float temp1=0;
Init_DS18B20();
#include<reg52.h>
#define uchar unsigned char #define uint unsigned int sbit
[指南]51单片机串口通信程序(方式2)
![[指南]51单片机串口通信程序(方式2)](https://img.taocdn.com/s3/m/a9576975cbaedd3383c4bb4cf7ec4afe04a1b1b8.png)
51单片机串口通信程序(方式2)//应网要求而写//给89c2051单片机编程,用管脚控制其状态输出,即管脚1为高电平时单片机串行口输出十六进制“BBBB0000”的脉冲信号,如果是低电平时再由其他的管脚控制其输出“CCCC5555”和“AAAA1111”。
// 要求:1、单片机没隔40ms发送一组数据// 2、串行口工作是在模式2下进行输出的// 3、波特率是93.75k//此程序写2011年6月9日//特别声明,此程序还未在硬件上测试,请网友们帮忙测试,多提宝贵意见#include <reg51.h>sbit key1 = P1^0;sbit key2 = P1^1;sbit key3 = P1^2;code unsigned char senddata1[4 ]={0xBB,0xBB,0x00,0x00 };code unsigned char senddata2[4]={0xCC,0xCC,0x00,0x00 };code unsigned char senddata3[4 ]={0xAA,0xAA,0x00,0x00 };bit flagcomsend; //串口发送标志,void R_S_Byte(unsigned char R_Byte) //串发送程序{SBUF = R_Byte;while( TI == 0 );TI = 0;}void comsend(unsigned char *TxRxBuffer){unsigned char i;//ES=0;for(i=0;i<4;i++) // 只发送了实际的数据{R_S_Byte(TxRxBuffer[i]);}//ES=1;}void StartUARTT0( void ){ //波特率93.75晶振 6M 串口方式2TMOD = 0x01;SCON = 0x80; //串口方式2,不允许接收TH0 = 0xB1;// 定时器0,方式1,定时40MSTL0 = 0xE0;PCON = 0x00; //波特率不加倍ET0 = 1; PT0 = 1;TR0 = 1;EA = 1;ES = 0;}void intt0( void ) interrupt 1 using 1{ET0 = 0;TH0 = 0xB1;// 定时器0,方式1,定时40MS TL0 = 0xE0;flagcomsend=1; //串口发送标志ET0 = 1; TF0 = 0;}void main(){StartUARTT0( );TR0 = 0;while(1){key1 = 1; key2 = 1; key3 = 1;if( key1||key2||key3){TR0 = 1;}else{TR0 = 0;}if(flagcomsend){flagcomsend = 0;if( key1&&(!key2)&&(!key3)){comsend(senddata1 );}else if( key2&&(!key1)&&(!key3)) {comsend(senddata2 );}else if( key3&&(!key2)&&(!key1)) {comsend(senddata3 );}else{TR0 = 0;}}}}。
51单片机的串口通信程序(C语言)
![51单片机的串口通信程序(C语言)](https://img.taocdn.com/s3/m/715ea227482fb4daa58d4b0d.png)
#include <reg52.h>#include<intrins.h>#include <stdio.h>#include <math.h>#define uchar unsigned char#define uint unsigned intsbit Key1 = P2^3;sbit Key2 = P2^2;sbit Key3 = P2^1;sbit Key4 = P2^0;sbit BELL = P3^6;sbit CONNECT = P3^7;unsigned int Key1_flag = 0;unsigned int Key2_flag = 0;unsigned int Key3_flag = 0;unsigned int Key4_flag = 0;unsigned char b;unsigned char code Num[21]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00, 0x10,0x89};unsigned char code Disdigit[4] = {0x7F,0xBF,0xDF,0xEF};unsigned char Disbuf[4];void delayms(uint t){uint i;while(t--){/* 对于11.0592M时钟,约延时1ms */for (i=0;i<125;i++){}}}//-----------------------------------------------------void SendData(uchar Dat){uchar i=0;SBUF = Dat;while (1){if(TI){TI=0;break;}}}void ScanKey(){if(Key1 == 0){delayms(100); if(Key1 == 0){Key1_flag = 1; Key2_flag = 0; Key3_flag = 0;Key4_flag = 0;Key1 = 1;}else;}if(Key2 == 0){delayms(100);if(Key2 == 0){Key2_flag = 1; Key1_flag = 0; Key3_flag = 0;Key4_flag = 0;Key2 = 1;}else;}if(Key3 == 0){delayms(50);if(Key3 == 0){Key3_flag = 1; Key1_flag = 0; Key2_flag = 0;Key4_flag = 0;Key3 = 1;}else;}if(Key4 == 0){delayms(50);if(Key4 == 0){Key4_flag = 1;Key1_flag = 0;Key2_flag = 0;Key3_flag = 0;Key4 = 1;}else;}else;}void KeyProc(){if(Key1_flag){TR1 = 1;SendData(0x55);Key1_flag = 0; }else if(Key2_flag){TR1 = 1;SendData(0x11); Key2_flag = 0;}else if(Key3_flag) {P1=0xff;BELL = 0;CONNECT = 1;Key3_flag = 0;}else if(Key4_flag){CONNECT = 0;BELL = 1;Key4_flag = 0;}else;}void Initdisplay(void){Disbuf[0] = 1;Disbuf[1] = 2;Disbuf[2] = 3;Disbuf[3] = 4;}void Display() //显示{unsigned int i = 0;unsigned int temp,count;temp = Disdigit[count]; P2 =temp;temp = Disbuf[count];temp = Num[temp];P0 =temp;count++;if (count==4)count=0;}void time0() interrupt 1 using 2 {Display();TH0 = (65535 - 2000)/256;TL0 = (65535 - 2000)%256;}void main(){Initdisplay();TMOD = 0x21;TH0 = (65535 - 2000)/256;TL0 = (65535 - 2000)%256;TR0 = 1;ET0 = 1;TH1 = 0xFD; //11.0592MTL1 = 0xFD;PCON&=0x80;TR1 = 1;ET1 = 1;SCON = 0x40; //串口方式REN = 1;PT1 = 0;PT0 = 1;EA = 1;while(1){ScanKey();KeyProc();if(RI){Disbuf[0] = 0;Disbuf[1] = 20;Disbuf[2] = SBUF>>4;Disbuf[3] = SBUF&0x0f;RI = 0;}else;}}51单片机串口通信C语言程序2**************************************************************; 平凡单片机工作室;ckss.asm;功能:反复向主机送AA和55两个数;主机使用一个串口调试软件设置19200,n,8,1***************************************************************/#include "reg51.h"#define uchar unsigned char#define uint unsigned int//延时程序//////////////////由Delay参数确定延迟时间*/void mDelay(unsigned int Delay){ unsigned int i;for(;Delay>0;Delay--){ for(i=0;i<124;i++){;}}}//////////////////// 主程序////////////////////void main(){ uchar OutDat; //定义输出变量TMOD=0x20; //TMOD=0TH1=0xf3; //12MHZ ,BPS:4800,N,8,1TL1=0xf3;PCON=0x80; //方式一TR1=1; //?????????????????????????????SCON=0x40; //串口通信控制寄存器模式一OutDat=0xaa; //向串口发送固定数据值for(;;) //循环程序{SBUF=OutDat;//发送数据for(;;){ if(TI) //发送中断位当发送停止位时置1,表示发送完成break;}mDelay(500);TI=0; //清零中断位OutDat=~OutDat; //显示内容按位取反}}。
51单片机实现RS485
![51单片机实现RS485](https://img.taocdn.com/s3/m/19f62f090740be1e640e9a07.png)
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总线的远距离温度监控系统程序
![基于51单片机RS485总线的远距离温度监控系统程序](https://img.taocdn.com/s3/m/42f37ceefd0a79563c1e7283.png)
#include<reg52.h>#define uchar unsigned char#define uint unsigned intsbit DQ = P1^0; //DS18B20接入口sbit segd=P1^1; //段控制74573锁存使能sbit segw=P1^2; //位控制74573锁存使能uchar code tab[]={0x3f,0x06,0x5b,0x4f, //0~30x66,0x6d,0x7d,0x07, //4~70x7f,0x6f,0x77,0x7c, //8~b0x39,0x5e,0x79,0x71, //c~f0x00 //灭};uchar tem[7];uchar T_num=200;/************************函数声明***********************/void delay(uint n); //延时函数void init_uart(void); //串口初始化void init_T0(); //定时器T0初始化void Init_DS18B20(void); //DS18b20初始化函数uchar ReadOneChar(void); //DS18b20读一个字节void WriteOneChar(uchar dat); //DS18b20写一个字节int ReadTemperature(void); //DS18b20读取温度void disp_dat(uchar x,uchar y); //单个数码管显示函数void disp(void); //温度显示函数uchar sum(uchar *dat,uchar n); //求和校验函数uchar get_adress(void); //获取从机地址函数void change(void); //数据调整函数void send_dat(void); //串行数据发送函数/**********************主函数***********************/void main(){init_T0();init_uart(); //初始化串口while(1){change(); //调整数据disp();//进行显示}}/**********************延时函数**********************/void delay(uint n){while(n--) ;}/********************定时器T0初始化******************/void init_T0(){TMOD=0x01; //工作方式1定时50msTL0=0x00;ET0=1;//允许定时器T0中断EA=1; / /开总中断TR0=1;//启动定时器T0}/*********************串口初始化*********************/void init_uart(void){SCON=0x40; //工作方式1TMOD=TMOD|0x20; //T 1为工作方式2TH1=0xFD; //设置T1TL1=0xFD;TR1=1;//启动定时器T1}/*****************DS18b20初始化函数******************/void Init_DS18B20(void){uchar x=0;DQ=1; / /DQ复位delay(10); //延时DQ=0; / /将DQ拉低delay(80); //精确延时约480us/DQ线拉高总线delay(20);while(!DQ); / /等待初始化结束delay(30);}/****************DS18b20读一个字节*******************/uchar ReadOneChar(void){uchar i=0;uchar dat=0;for (i=8;i>0;i--){DQ=0;//给脉冲信号dat>>=1;DQ=1;//给脉冲信号if(DQ)dat|=0x80; //读入值是否为1delay(8);}return(dat);}/***************DS18b20写一个字节********************/void WriteOneChar(uchar dat){uchar i=0;for (i=8;i>0;i--){DQ=0;DQ=dat&0x01;delay(10);DQ=1;dat>>=1;}delay(8);}/*****************DS18b20读取温度********************/int ReadTemperature(void){uchar dat_L=0,dat_H=0;int temper=0;float temp1=0;Init_DS18B20();WriteOneChar(0xCC); //跳过读序号列号的操作WriteOneChar(0x44); //启动温度转换Init_DS18B20();WriteOneChar(0xCC); //跳过读序号列号的操作WriteOneChar(0xBE); //读取温度寄存器dat_L=ReadOneChar(); //低位dat_H=ReadOneChar(); //高位temper=dat_H;temper<<=8;temper=temper|dat_L;temp1=temper*0.0625;temper=temp1*10+0.5; //计算温度值return(temper);}/****************获取从机地址函数*******************/uchar get_adress(void){uchar ad;ad=P1;ad>>=4;//获取地址return(ad);}/******************求和校验函数**********************/uchar sum(uchar *dat,uchar n){uchar i;uchar s_dat=0x00;for(i=2;i<n+1;i++) //对十位、个位和小数位上的数据求和{s_dat+=dat[i];}return(s_dat); //返回求和值}/*******************数据调整函数********************/void change(void){int temp;temp=ReadTemperature(); //读温度tem[0]=0x24; //发送起始标志$tem[1]=get_adress(); //获取从机地址tem[2]=temp%1000/100; //存十位上的数据tem[3]=temp%100/10; //存个位上的数据tem[4]=temp%10; //存小数位上的数据tem[5]=sum(tem,3); //存校验和tem[6]=0x23; //发送结束标志#}/***************单个数码管显示函数*******************/void disp_dat(uchar x,uchar y){segw=1;//74HC573开锁存P0=~(0x01<<x); //送位选segw=0;segd=1;if(x==1)P0=tab[y]|0x80; //若是个位送显示小数点elseP0=tab[y]; //送显示数据segd=0;}/******************温度显示函数**********************/void disp(void){disp_dat(0,tem[2]); //显示十位上的数据delay(200);disp_dat(1,tem[3]); //显示个位上的数据delay(200);disp_dat(2,tem[4]); //显示小数点后第一位数据delay(200);disp_dat(3,16); //清零段位74HC573中的数据}/****************串行数据发送函数*******************/void send_dat(void){uchar i;for(i=0;i<7;i++){SBUF=tem[i];while(TI==0); //等待发送结束TI=0;}}/*******************定时T0中断程序*****************/void senddat_T0(void) interrupt 1{TH0=0x4c; //重载定时器初值TL0=0x00;if(--T_num==0){send_dat(); / /发送数据T_num=200; //恢复计数值}}文档已经阅读完毕,请返回上一页!。
手把手教你学51单片机之十八RS485通信与Modbus协议
![手把手教你学51单片机之十八RS485通信与Modbus协议](https://img.taocdn.com/s3/m/2180b0ffb9f3f90f76c61baf.png)
在工业控制、电力通讯、智能仪表等领域,通常情况下是采用串口通信的方式进行数据交换。
最初采用的方式是 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通信](https://img.taocdn.com/s3/m/90c21b3f3968011ca2009105.png)
本程序实现RS485多机通信步进机控制直流电机控制LED等控制开发环境keil4/***************************************************************************//******** main.c ***************//**************************************************************************/#include<reg52.h>#include<stdio.h>#include<stdlib.h>#include"CRC16.h"#define uint unsigned int#define uchar unsigned charsbit SENDMODE=P3^2; //收发控制sbit PWM=P2^4; //控制直流电机PWMsbit LED1=P2^5;sbit LED0=P2^6;uchar Rxbuf[12]; //数据接收缓冲区uchar PWMvalue=0;//控制直流电机转动速度uchar stmotorvalue=1;//控制步进机转动角度static unsigned int stmotor=0;static uchar Rxfinish=0; //接收完毕标志位void delay(uint n); //1ms延时函数static const char stepperForeward[8]={0x01,0x03,0x02,0x06,0x04,0x0c,0x08,0x09};//eigth pat Forewardstatic const char stepperRollback[8]={0x09,0x08,0x0c,0x04,0x06,0x02,0x03,0x01};//eigth pat Rollbackstatic const char stepperStop[8] ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};//eigth pat Pausechar stCtlFlag=2;//步进机direction contorlvoid inti() //波特率设计为9600{TMOD=0x21;TL1=250;TH1=250;TR1=1;PCON=0x80;SCON=0x50;EA=1;ES=1;TI=0;RI=0;TR0=1;ET0=1;TH0=(65535-100)/256;TL0=(65535-100)%256;SENDMODE=0;//485设计为接收模式LED0=1;LED1=1;}/*******************************************//*******************************************//****************************/void transmit(uint length,uchar *ptr) //发送函数目的当小车转弯时通知430单片机记录当前的方位,开始计算走过的路程{uint x=0;TI=0;SENDMODE=1;//把P3^2口拉高开始数据通信回复终端for(x=0;x<length;x++) //逐步把数据放到发送缓冲区{SBUF=ptr[x];while(!TI); //等待数据发送完成TI=0;}SENDMODE=0; //恢复接收模式sendOK=1;//发送完毕后把发送完毕标志位置1}void bzero(int length,uchar *ptr){int x;for(x=0;x<length;x++){*ptr++='\0';}}void UART0()interrupt 4{static unsigned char Rxnum=0;static unsigned char OK=0;if(RI==1){RI=0;LED0=1;if(OK==0){if(SBUF==0xff){Rxnum=0;OK=1;}}Rxbuf[Rxnum]=SBUF;Rxnum++;if(Rxnum==Rxbuf[1]||Rxbuf[Rxnum-1]==0xfe){if(Rxbuf[0]==0xff){Rxfinish=1;//一帧接收没错ES=0;//关中断}else{Rxfinish=0;//一帧接收出错}OK=0;Rxnum=0;}if(Rxnum>12){OK=0;Rxnum=0;}}}void time0()interrupt 1{static uchar count0=0;static int count1=0;static uchar stnum=0;TH0=(65535-100)/256;TL0=(65535-100)%256;count0++;if(count0<=PWMvalue){PWM=1;}else{PWM=0;if(count0>=10){count0=0;}}count1++;if(count1==10) //步进机控制{P2&=0xf0;count1=0;if(stCtlFlag==0){P2|=stepperForeward[stnum];}else if(stCtlFlag==1){P2|=stepperRollback[stnum];}else{P2|=stepperStop[stnum] ;}stnum++;if(stnum>=8){stnum=0;if(stmotor>=stmotorvalue*60){stCtlFlag=2;}else stmotor++;}}}void macontrol(int pwm,uchar ctldr,uchar stmotor)//电机控制函数{PWMvalue=pwm;stCtlFlag=ctldr;stmotorvalue=stmotor;}void main(){static uint CRC16value=0;static uchar temp=0;inti();while(1){if(Rxfinish!=0){Rxfinish=0;if((Rxbuf[1]-4)>0){CRC16value=crc16(&Rxbuf[1],Rxbuf[1]-4);//CRC16value=crc16(&Rxbuf[1],Rxbuf[1]-4);transmit(2,&CRC16value);if((CRC16value/256==Rxbuf[Rxbuf[1]-3])&&(CRC16value%256==Rxbuf[Rxbuf[1]-2])&&Rxb uf[2]==0x01&&Rxbuf[Rxbuf[1]-1]==0xfe&&Rxbuf[0]==0xff){LED0=(bit)(Rxbuf[3]&0x01);LED1=(bit)(Rxbuf[4]&0x01);stmotor=0;macontrol(Rxbuf[7],Rxbuf[5],Rxbuf[6]);temp=Rxbuf[7];}else PWMvalue=temp;}bzero(sizeof(Rxbuf),Rxbuf);ES=1; //开中断}else PWMvalue=temp;}}/*****************************************************************************/ /*******CRC16.h *****//***************************************************************************/ #ifndef __CRC16_H#define __CRC16_Hcode unsigned char const 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低位字节值表*/code unsigned char const 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} ;/***************************************************************************/ //计算CRC16程序/***************************************************************************/ unsigned short int crc16(unsigned char *puchMsg, unsigned short int usDataLen){unsigned char uchCRCHi = 0xFF ; /* 高CRC字节初始化*/unsigned char uchCRCLo = 0xFF ; /* 低CRC 字节初始化*/unsigned long uIndex ; /* CRC循环中的索引*/while (usDataLen--) /* 传输消息缓冲区*/{uIndex = uchCRCHi ^ *puchMsg++ ; /* 计算CRC */uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;uchCRCLo = auchCRCLo[uIndex] ;if(uchCRCHi==0xff||uchCRCHi==0xfe||uchCRCHi==0xfd||uchCRCHi==0xfc) uchCRCHi=0xfb;if(uchCRCLo==0xff||uchCRCLo==0xfe||uchCRCLo==0xfd||uchCRCLo==0xfc) uchCRCLo=0xfb;return (uchCRCHi << 8 | uchCRCLo) ;}#endif。
我的51单片机之 MAX485的 C语言与汇编的编程
![我的51单片机之 MAX485的 C语言与汇编的编程](https://img.taocdn.com/s3/m/79e47c871a37f111f1855bc3.png)
//与自制软件 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)。
/* 以下为单片机串口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使用工作方式2
TH1 = 250; // 设置初值
TL1 = 250;
TR1 = 1; // 开始计时
PCON = 0x80; // SMOD = 1
SCON = 0x50; // 工作方式1,波特率9600bps,允许接收
ES = 0; // 关闭串口中断
//IT0 = 0; // 外部中断0使用电平触发模式
//EX0 = 1; // 开启外部中断0
EA = 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表示0xdb
ecc = ecc^0xdb;
db = 0;
break;
case 0xdc:
data_buf[i] = 0xc0; // 0xdbdc表示0xc0
ecc = 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,发送0xdbdc
TI = 0;
SBUF = 0xdb;
while(!TI);
TI = 0;
SBUF = 0xdc;
while(!TI)
TI = 0;
break;
default: // 普通数据则直接发送
TI = 0;
SBUF = da;
while(!TI);
TI = 0;
}
}
#endif
/* 调试结果*/。