单片机串口接收多字节数据

http://bbs.elecfans.com/jishu_409918_1_1.html

各位大侠看一下,我下面的程序为什么不能接收两个字节的数据呢?
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
void rs232_init();
uchar flag,i,g,d;
uchar code table[]="I get ";
//sbit led=P1^0;
main()
{
        rs232_init();
        while(1)
        {
                if(flag==1)
                {
                        ES=0;
                        for(i=0;i<6;i++)
                        {
                                SBUF=table[i];
                                while(!TI);
                                TI=0;
                        }
                        SBUF=g;
                        while(!TI);
                        TI=0;
                        SBUF=d;
                        while(!TI);
                        TI=0;
                        ES=1;
                        flag=0;
                }                
        }
}
void rs232_init()
{
        TMOD=0x20;
        TH1=0xfd;
        TL1=0xfd;
        TR1=1;
        REN=1;
        SM0=0;
        SM1=1;
        EA=1;
        ES=1;        
}
void ser()interrupt 4
{
        RI=0;
        g=SBUF;
        d=SBUF;
        flag=1;
}

我用串口调试助手调试时,上位机给单片机发送两个字节的数据,例如发送ck两个字母时,只接收到cc两个字母呢?


//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

首先数据发送是一位一位发送的,串口接收也是一位一位接收的,当接收8位数据后,申请中断。

你的程序中,程序进入中断后,你用了g=SBUF,d=SBUF,程序之所以进入中断是因为串口接收到了八位数据,是八位数据,不是十六位数据,也就是你发送的字母ck中的c,k还没有发送完呢,所以g和d都被赋值了c,打印结果当然是cc了。

你要了解串口是接收八位数据后申请中断,你必须在下一个八位数据接收完(下一次中断到来前)以前取走这个数据,不然这个数据将会丢失。

我给你改 的程序如下,我定义一个宏N,N就是你每次发送的数据个数,然后一个数组,数组有N个元素,用于存储串口接受的数据。

当串口有中断时,我立即把这个数据存储到数组中,同时将数组指针指向下一位,然后当下一个中断来时重复上面步骤,直到接收数据个数到达N。

这里中断中程序不能太长,如果程序很长,我本次数据还没存储好,下一个数据已经到了,会丢失数据。

  1. #include<reg51.h>
  2. #define uchar unsigned char
  3. #define uint unsigned int
  4. #define N 2                                                        //可一次接收数据量
  5. void rs232_init();
  6. uchar flag,i;                                                       //删除无用变量                           
  7. uchar code table[]="I get ";
  8. uchar table1[N];                                              //接收缓存数组
  9. uchar j=0;                                                             //接收计数器
  10. //sbit led=P1^0;
  11. main()
  12. {
  13.          rs232_init();
  14.          while(1)
  15.          {
  16.                  if(flag==1)
  17.                  {
  18.                          ES=0;
  19.                          for(i=0;i<6;i++)
  20.                          {
  21.                                  SBUF=table[i];
  22.                                  while(!TI);
  23.                                  TI=0;
  24.                          }
  25.                          for(j=0;j<N;j++)                        //发送接收数组
  26.                                                  {
  27.                                                          SBUF=table1[j];
  28.                                  while(!TI);
  29.                                  TI=0;
  30.                                                 }
  31.                          j=0;                                           //清零接收计数器
  32.                          ES=1;
  33.                          flag=0;
  34.                  }                
  35.          }
  36. }
  37. void rs232_init()
  38. {
  39.          TMOD=0x20;
  40.          TH1=0xfd;
  41.          TL1=0xfd;
  42.          TR1=1;
  43.          SM0=0;
  44.          SM1=1;
  45.                  REN=1;                                                        //先设定号工作方式,在打开允许接收
  46.          EA=1;
  47.          ES=1;        
  48. }
  49. void ser()interrupt 4
  50. {                 
  51.                 RI=0;
  52.                 table1[j++]=SBUF;                                //存数据到接收缓存
  53.                 if(j==N)                                                //数组满时,允许发送
  54.                 flag=1;
  55. }
复制代码


受此贴启发,Starsky项目中,串口中断接收更改如下成功接收多字节:

/*    串口接收数据中断服务函数    */
#pragma vector = 0x14              //设置串口接收中断向量号 = 0X14 = 20
__interrupt void UART1_RX_RXNE(void)
{          
  static int cnt=0;


  UART1_SR_RXNE = 1;    //清除中断标志
  
  if(cnt == (COMBUFNUM-1))  //receive data done
  {    
    bufRec[cnt]= UART1_DR;  //last byte
    recCmd = bufRec[1];
    dutyPwm = (int) bufRec[2];
    cnt =0;
  }
  else{
    bufRec[cnt]= UART1_DR;
    cnt++;
  }
}

其中bufRec为接收buffer;

UART1_DR为STM8S003F6 UART接收数据寄存器。



串口是计算机上一种非常通用设备通信的协议(不要与通用串行总线Universal Serial Bus或者USB混淆)。大多数计算机包含两个基于RS232的串口。串口同时也是仪器仪表设备通用的通信协议;很多GPIB兼容的设备也带有RS- 232口。同时,串口通信协议也可以用于获取远程采集设备的数据串口通信的概念非常简单,串口按位(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个逻辑高位。高位和低位不真正的检查数据,简单置位逻辑高或者逻辑低校验。这样使得接收设备能够知道一个位的状态,有机会判断是否有噪声干扰了通信或者是否传输和接收数据是否不同步。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值