51单片机接收上位机发送的多个字节的串口通信

/*************************串口初始化*******************************************/
void Inituart()
{
IE=0x90; //打开中断总开关及串口中断开关
SCON = 0x50;//设定串行口工作方式1 允许接受
TMOD = 0x20; //定时器1,自动重载, 产生波特率
// PCON=0x80; // 加上他后波特率是19200 SMOD为1
TL1 = 0xfa;
TH1 = 0xfa; //波特率为9600 ,22.1184MHz
TR1 = 1;
}
/**************************接收上位机传送数据***************************************/
void uart_js() interrupt 4 //RI==1时执行串口中断
{
static uchar i = 0;
if(RI==1)
{
RX_BUF[i]=SBUF; //保存数据
RI=0;
i++;
}
if(i==10)
{
i=0;
RXend = 1;
LED0=0; //LED长亮
}

}
void main()
{
uchar j;
Inituart();

while(1)
{
while(RXend==0); //waiting receive end
RXend=0;
for(j=0;j<10;j++)
{
TxBuf[j] = RX_BUF[j]; //将需发送数据存入无线发送缓冲区
}
}
}
这个程序有什么问题么,为什么我用串口助手发送是个字节,接收不到呢?

具体程序可以参考楼下的例程

串口通信的概念非常简单,串口按位(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个逻辑高位。高位和低位不真正的检查数据,简单置位逻辑高或者逻辑低校验。这样使得接收设备能够知道一个位的状态,有机会判断是否有噪声干扰了通信或者是否传输和接收数据是否不同步。
温馨提示:内容为网友见解,仅供参考
第1个回答  2012-09-17
//试试以下程序
#include<reg51.h>
#define uchar unsigned char
uchar i,j;
unchar RX_BUF[10],TxBuf[10];
void Inituart()
{
IE=0x90; //打开中断总开关及串口中断开关
SCON = 0x50;//设定串行口工作方式1 允许接受
TMOD = 0x20; //定时器1,自动重载, 产生波特率
// PCON=0x80; // 加上他后波特率是19200 SMOD为1
TL1 = 0xfa;
TH1 = 0xfa; //波特率为9600 ,22.1184MHz
TR1 = 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 end
RXend=0;
for(j=0;j<10;j++)
{
TxBuf[j] = RX_BUF[j]; //将需发送数据存入无线发送缓冲区
}
}
}追问

不行啊,串口发十个字节,灯不亮,串口也接收不到发送的字节

追答

你可以试试,多发一个看看,是不是有数据丢失,没被接收到

追问

我用串口助手,一次发一个字节,连续发十次,单片机可以接收到十个字节,但是如果我一次性把十个字节都写入串口助手发送,就不行。而且如果我把串口助手设置为连续发送一个字节,连续十次也是ok,但就是不能一次发十个给串口助手

追答

刚才在另一个问题处我说过了这应该是数据丢失造成的,因为串口助手没有握手,很容易丢失数据的。不知道你用的是什么单片机,22.1184M晶振是不是高了点,如果是STC的话,不同的晶振,还要注意参数的设置是不同的。

追问

STC1104E的,晶振22.1184,设置的参数是9600波特的

追答

看看你程序下载时选择的是外部晶振还是内部晶振,实在不行你可以换一个晶振试试,比如换11.0592M的试试。

本回答被提问者和网友采纳
第2个回答  2012-09-17
#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; //总中断开
}
第3个回答  2012-09-17
大概看了一下,你这个程序问题可能就出在 static uchar i = 0; 这个i应该是全局变量吧,不然每次进入中断 i 都等于0,那都把数据赋值给数组的第一个元素了,所以最后只能得到发送的最后一个字节数据了追问

哦,我改为
static uchar i ;然后串口助手发十个字节,灯没亮

相似回答