51单片机串口通信
////////////////////////////////////////////////////////////////////////////////////////////////// //E51Pro.c//Easy 51Pro编程器主程序,负责通讯,管理编程操作///////////////////////////////////////////////////////////////////////////////////////////////////#include BYTE ComBuf[18];//串口通讯数据缓存,发送和接收都使用UINT nAddress;//ROM中地址计数UINT nTimeOut;//超时计数ProWork pw;//编程器一般操作void Delay_us(BYTE nUs)//微秒级延时<255us{TH0=0;TL0=0;TR0=1;while(TL010000)//后17个字节都有超时限制return 0;}ComBuf[n]=SBUF;RI=0;}return 1;}BOOL WaitResp()//等待上位机回应,1字节,有超时限制{nTimeOut=0;RI=0;while(!RI){nTimeOut++;if(nTimeOut>50000){return 0;}}RI=0;ComBuf[0]=SBUF;return 1;}BOOL WaitData()//写器件时等待上位机数据,18字节,有超时限制{BYTE n;RI=0;for(n=0;n<=17;n++){nTimeOut=0;while(!RI){nTimeOut++;if(nTimeOut>10000){return 0;}}RI=0;ComBuf[n]=SBUF;}return 1;}void SendData()//发送数据或回应操作完成,18字节{BYTE n=0;for(n;n<=17;n++){TI=0;SBUF=ComBuf[n];while(!TI){}TI=0;}}void SendResp()//回应上位机1个字节,在写器件函数中使用{TI=0;SBUF=ComBuf[0];while(!TI){}TI=0;}void SetVpp5V()//设置Vpp为5v{P3_4=0;P3_3=0;}void SetVpp0V()//设置Vpp为0v{P3_3=0;P3_4=1;}void SetVpp12V()//设置Vpp为12v{P3_4=0;P3_3=1;}void RstPro()//编程器复位{pw.fpProOver();//直接编程结束SendData();//通知上位机,表示编程器就绪,可以直接用此函数因为协议号(ComBuf[0])还没被修改,下同}void ReadSign()//读特征字{pw.fpReadSign();SendData();//通知上位机,送出读出器件特征字}void Erase()//擦除器件{pw.fpErase();SendData();//通知上位机,擦除了器件}void Write()//写器件{BYTE n;pw.fpInitPro();//编程前的准备工作SendData();//回应上位机表示进入写器件状态,可以发来数据while(1){if(WaitData())//如果等待数据成功{if(ComBuf[0]==0x07)//判断是否继续写{for(n=2;n<=17;n++)//ComBuf[2~17]为待写入数据块{if(!pw.fpWrite(ComBuf[n]))//<<<<<<<<<<<<<<<<<<<调用写该器件一个单元的函数{pw.fpProOver();//出错了就结束编程ComBuf[0]=0xff;SendResp();//回应上位机一个字节,表示写数据出错了WaitData();//等待上位机的回应后就结束return;}nAddress++;//下一个单元}ComBuf[0]=1;//回应上位机一个字节,表示数据块顺利完成,请求继续SendResp();}else if(ComBuf[0]==0x00)//写器件结束break;else//可能是通讯出错了{pw.fpProOver();return;}}else//等待数据失败{pw.fpProOver();return;}}pw.fpProOver();//编程结束后的工作Delay_ms(50);//延时等待上位机写线程结束ComBuf[0]=0;//通知上位机编程器进入就绪状态SendData();}void Read()//读器件{BYTE n;pw.fpInitPro();//先设置成编程状态SendData();//回应上位机表示进入读状态while(1){if(WaitResp())//等待上位机回应1个字节{if(ComBuf[0]==0)//ComBuf[0]==0表示读结束{break;}else if(ComBuf[0]==0xff)//0xff表示重发{nAddress=nAddress-0x0010;}for(n=2;n<=17;n++)//ComBuf[2~17]保存读出的数据块{ComBuf[n]=pw.fpRead();//<<<<<<<<<<<<<<<<<<<调用写该器件一个单元的函数nAddress++;//下一个单元}ComBuf[0]=6;//向上位机发送读出的数据块SendData();}elsebreak;//等待回应失败}pw.fpProOver();//操作结束设置为运行状态ComBuf[0]=0;//通知上位机编程器进入就绪状态SendData();}void Lock()//写锁定位{pw.fpLock();SendData();}/////////////////////////////////////////////////////////////////////////////////////////////////////所支持的FID,请在这里继续添加///////////////////////////////////////////////////////////////////////////////////////////////////extern void PreparePro00();//FID=00:AT89C51编程器extern void PreparePro01();//FID=01:AT89C2051编程器extern void PreparePro02();//FID=02:AT89S51编程器void main(){SP=0x60;SetVpp5V();//先初始化Vpp为5vSCON=0x00;TCON=0x00;//PCON=0x00;//波特率*2IE=0x00;//TMOD: GATE|C/!T|M1|M0|GATE|C/!T|M1|M0//00 10 00 01TMOD=0x21;//T0用于延时程序TH1=0xff;TL1=0xff;//波特率28800*2,注意PCON//SCON: SM0|SM1|SM2|REN|TB8|RB8|TI|RI//0 1 0 1 0 000SCON=0x50;TR1=1;Delay_ms(1000);//延时1秒后编程器自举ComBuf[0]=0;SendData();while(1)//串口通讯采用查询方式{if(!WaitComm())//如果超时,通讯出错{Delay_ms(500);ComBuf[0]=0;//让编程器复位,使编程器就绪}switch(ComBuf[1])//根据FID设置(ProWork)pw中的函数指针{case 0://at89c51编程器PreparePro00();break;case 1://at89c2051编程器PreparePro01();break;case 2://at89s51编程器PreparePro02();break;//case 3:支持新器件时,请继续向下添加// break;//case 4:// break;default:ComBuf[0]=0xff;ComBuf[1]=0xff;//表示无效的操作break;}switch(ComBuf[0])//根据操作ID跳到不同的操作函数{case 0x00:RstPro();//编程器复位break;case 0x01:ReadSign();//读特征字break;case 0x02:Erase();//擦除器件break;case 0x03:Write();//写器件break;case 0x04:Read();//读器件break;case 0x05:Lock();//写锁定位break;default:SendData();break;}} }
// 单片机串行口发送/接收程序,每接收到字节即发送出去 // 和微机相接后键入的字符回显示在屏幕上// 可用此程序测试//#include #define XTAL 11059200// CUP 晶振频率#define baudrate 9600// 通信波特率void main(void){unsigned char c;TMOD = 0x20; // 定时器1工作于8位自动重载模式, 用于产生波特率TH1=(unsigned char)(256 - (XTAL / (32L * 12L * baudrate)));TL1=(unsigned char)(256 - (XTAL / (32L * 12L * baudrate)));// 定时器0赋初值SCON = 0x50;PCON = 0x00;TR1 = 1;IE = 0x00;// 禁止任何中断while(1){while(RI == 0);RI = 0;c = SBUF;// 从缓冲区中把接收的字符放入c中SBUF = c;// 要发送的字符放入缓冲区while(TI == 0);TI = 0;} }
void InitSerial(void) {TMOD = 0x20; // T1 方式2PCON=0x00;// PCON=00H,SMOD=0 PD = PCON.2 = 1 进入掉电模式TH1 = TL1 = BAUD_9600;// BAUD: 9600SCON = 0x50; // 串行通信方式1 REN=1 允许接收ET1 = 0;// 不允许中断TR1 = 1;// 开启定时器1IE = 0; // 关闭所有中断允许位memset(&SerialBuf, 0x00, SERIAL_BUF_LEN); // 初始化SerialBuf[SERIAL_BUF_LEN]}/**********************************************************名称:SendByte()**功能:串口发送一个字节**输入:ucData**返回:无**说明:无********************************************************/void SendByte(unsigned char ucData){SBUF = ucData;while(!TI){_CLRWDT_;}TI = 0; }
#include #include unsigned char ch;bit read_flag= 0 ;void init_serialcom( void ) //串口通信初始设定{SCON = 0x50 ; //UART为模式1,8位数据,允许接收TMOD |= 0x20 ; //定时器1为模式2,8位自动重装PCON |= 0x80 ; //SMOD=1;TH1 = 0xFD ; //Baud:19200 fosc="11".0592MHzIE |= 0x90 ; //Enable Serial InterruptTR1 = 1 ; // timer 1 runTI=1;}//向串口发送一个字符void send_char_com( unsigned char ch){SBUF=ch;while (TI== 0);TI= 0 ;}//串口接收中断函数void serial () interrupt 4 using 3{if (RI){RI = 0 ;ch=SBUF;read_flag= 1 ; //就置位取数标志}}main(){init_serialcom(); //初始化串口while ( 1 ){if (read_flag) //如果取数标志已置位,就将读到的数从串口发出{read_flag= 0 ; //取数标志清0send_char_com(ch);}} }

关于51单片机的串口通信,为什么要用rs232电平
所谓的RS-232通信标准,就是对插件样式、信号名称和意义以及所谓的驱动器/接收器的电气模式这种硬件作出规定。一般的都是9针的接口,其中包括CD接口:数据通道接收载波的检测;RD接口:接收数据;SD接口:发送数据;ER接口:数据终端就绪;SG接口:信号用接地;DR接口:数据集就绪;RS接口:请求发送;CS接口:允许发送;CI接口:被呼表示。用以上接口进行数据通信,还有对电平的要求。当然与51单片机进行通信方式很简单,首先要解决的是电平标准,51的I/O口最大输出5V电压,而RS-232要求电压在±10V,为达到电平匹配,需用到MAX232CPF电平转换芯片,将0~5V电平转换为±10V电平,从而实现电平匹配;然后,数据接口只用到了数据发送与接收2个端口,还有数据的请求发送与允许发送,共4个端口,MAX232CPF还有其他一些外围电路接口,但比较简单,都是些电容接口,从而实现单片机与RS232接口的通信。我这儿还有RS232通信接口的相关资料,需要的话我可以给你。

单片机串口通信是否必须要建立通信协议?单片机之间通信是否也必须建立通信协议?
单片机进行串口通信,需要设置波特率和一些电气参数(一般定义1BIT起始位,8BIT数据位,1BIT停止位,无奇偶校验位)这些就属于通信协议的范畴。再则,单片机接收的数据,需要进行处理,所以你必须要知道接收的数据代表的意义,这也是通信协议,只是不太严格的通信协议。而比较严格的通信协议则一般会定义起始字节,数据字节,校验字节,结束字节等等,这点对单片机来说到不是必须的,你只要知道接收到相应的数据,能够进行处理就好了。
51单片机的话可以通过外接一个max232与电脑通信通信的协议都是硬件弄好了的,用户只需要用就行了;如果是51单片机之间的通讯可以直接把两块单片机的RXD和TXD交叉连接就可以 但是这样的传输距离比较近而且容易受到干扰,想要远距离传输还是需要用到232或者是422、485传输协议。说明:232的软件协议是单片机内部固化好的,硬件协议需要用到232芯片。
不要协议收到的是一系列的数据流。但你对数据流的处理,必须有最简单的定义,如数据流的起始字节,数据流的长度,数据流的CRC检验。这就是协议。 如果两个单片机之间的通信内容能用一个字节来表达清楚,则不需要任何协议;就相当于两个单片机之间定义了255种状态而忆。 谢谢!
双方必须约定:波特率、位数、奇偶校验的方式。 这些是最基本的串口通信协议。
那是必须的,没有协议怎么知道收到的数是什么意思?

51单片机接收上位机发送的多个字节的串口通信
具体程序可以参考楼下的例程 串口通信的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。它很简单并且能够实现远距离通信。比如IEEE488定义并行通行状态时,规定设备线总长不得超过20米,并且任意两个设备间的长度不得超过2米;而对于串口而言,长度可达1200米。典型地,串口用于ASCII码字符的传输。通信使用3根线完成:(1)地线,(2)发送,(3)接收。由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。其他线用于握手,但是不是必须的。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通信的端口,这些参数必须匹配:a,波特率:这是一个衡量通信速度的参数。它表示每秒钟传送的bit的个数。例如300波特表示每秒钟发送300个bit。当我们提到时钟周期时,我们就是指波特率例如如果协议需要4800波特率,那么时钟是4800Hz。这意味着串口通信在数据线上的采样率为4800Hz。通常电话线的波特率为14400,28800和36600。波特率可以远远大于这些值,但是波特率和距离成反比。高波特率常常用于放置的很近的仪器间的通信,典型的例子就是GPIB设备的通信。b,数据位:这是衡量通信中实际数据位的参数。当计算机发送一个信息包,实际的数据不会是8位的,标准的值是5、7和8位。如何设置取决于你想传送的信息。比如,标准的ASCII码是0~127(7位)。扩展的ASCII码是0~255(8位)。如果数据使用简单的文本(标准 ASCII码),那么每个数据包使用7位数据。每个包是指一个字节,包括开始/停止位,数据位和奇偶校验位。由于实际数据位取决于通信协议的选取,术语“包”指任何通信的情况。c,停止位:用于表示单个包的最后一位。典型的值为1,1.5和2位。由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。d,奇偶校验位:在串口通信中一种简单的检错方式。有四种检错方式:偶、奇、高和低。当然没有校验位也是可以的。对于偶和奇校验的情况,串口会设置校验位(数据位后面的一位),用一个值确保传输的数据有偶个或者奇个逻辑高位。例如,如果数据是011,那么对于偶校验,校验位为0,保证逻辑高的位数是偶数个。 如果是奇校验,校验位位1,这样就有3个逻辑高位。高位和低位不真正的检查数据,简单置位逻辑高或者逻辑低校验。这样使得接收设备能够知道一个位的状态,有机会判断是否有噪声干扰了通信或者是否传输和接收数据是否不同步。
//试试以下程序 #include#define uchar unsigned charuchar i,j;unchar RX_BUF[10],TxBuf[10];void Inituart(){IE=0x90;//打开中断总开关及串口中断开关SCON = 0x50;//设定串行口工作方式1 允许接受TMOD = 0x20;//定时器1,自动重载, 产生波特率//PCON=0x80;// 加上他后波特率是19200SMOD为1TL1 = 0xfa;TH1 = 0xfa; //波特率为9600 ,22.1184MHzTR1 = 1;}/**************************接收上位机传送数据***************************************/void uart_js() interrupt 4//RI==1时执行串口中断{if(RI==1){RX_BUF[i]=SBUF; //保存数据RI=0;i++;}if(TI)TI=0;if(i==10){i=0;RXend = 1;LED0=0;//LED长亮}}void main(){Inituart();i=j=0;while(1){while(RXend==0);//waiting receive endRXend=0;for(j=0;j<10;j++){TxBuf[j] =RX_BUF[j];//将需发送数据存入无线发送缓冲区}} }
#define FOSC 110592 //晶振频率 #define Baud 96//波特率void IE_INIT() //初始化串口{//IPH=PSH; //串口中断优先级控制PCON &= 0x7f; //波特率不倍速//PCON |= 0X80; //波特率倍速SCON= 0x50; //8位数据,可变波特率/*使用定时器1作为波特率发生器并赋值 */TMOD &= 0x0f; //清除定时器1模式位TMOD |= 0x20; //设定定时器1为8位自动重装方式TL1=TH1=256-(FOSC/Baud/32/12);//设定定时初值 设定定时器重装值ET1 = 0; //禁止定时器1中断TR1 = 1; //启动定时器1/*使用定时器2作为波特率发生器并赋值 *///TL2=RCAP2L=(65535-FOSC/(32*Baud)); //设定定时初值//TH2=RCAP2H=(65535-FOSC/(32*Baud))>>8;//设定定时器重装值// RCLK=1; //接收时钟标志,0:使用定时器1作为串口接收发生器 1:使用定时器2作为串口接收发生器// TCLK=1; //发送时钟标志,0:使用定时器1作为串口发送发生器 1:使用定时器2作为串口发送发生器// TR2=1; //启动定时期2/*启动串口中断 总中断*/ES=1;//串口使能EA=1;//总中断开 }
大概看了一下,你这个程序问题可能就出在 static uchar i = 0; 这个i应该是全局变量吧,不然每次进入中断 i 都等于0,那都把数据赋值给数组的第一个元素了,所以最后只能得到发送的最后一个字节数据了

51单片机串口通信,和I2C串口通信协议有什么区别和相同
串口通信准确的说叫RS232通信,串口通信和I2C都是串行通信,但串口通信是RS232协议,I2C通信是遵循I2C协议,举个简单例子,从A到B有条路,一个人走路过去,一个人坐车过去。串行通信就是相当于路,RS232和I2C协议相当于走路和坐车两种不同的方式 赞同
方式1时,SM2一般设置为 0SM2=1,则只有收到有效的停止位时才激活RI。我知道的就这些了,你可以参考一下以上内容来自“飘仙建站论坛”追问 这个我也知道,不过还是谢谢

本文由 在线网速测试 整理编辑,转载请注明出处,原文链接:https://www.wangsu123.cn/news/82960.html。