单片机串口数据接收程序_stm32单片机的串口数据接收程序 - CSDN
  • 各位大侠看一下,我下面的程序为什么不能接收两个字节的数据呢? #include #define uchar unsigned char #define uint unsigned int void rs232_init(); uchar flag,i,g,d; uchar code table

    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接收数据寄存器。



    展开全文
  • 51系列单片机 单片机串口通信接收发送数据程序
  • 基于STC单片机串口接收发送程序/**************************************************************************** * 程序名称:STC89C52RC单片机串口发送接收程序 * 实验条件:11.0592的晶振频率
  • 单片机串口接收的几种常用的数据处理方法 一、为什么串口接收数据需要处理 我们在做项目的时候经常会用到串口,当我们用串口和别的设备通讯的时候就需要严格遵循通讯协议,然而,仅仅是遵循通讯协议是不够的,因为...

    单片机串口接收的几种常用的数据处理方法

    一、为什么串口接收的数据需要处理
    我们在做项目的时候经常会用到串口,当我们用串口和别的设备通讯的时候就需要严格遵循通讯协议,然而,仅仅是遵循通讯协议是不够的,因为单片机串口受到别的信号干扰的时候,容易出现数据错误,特别是串口发送的第一个字节和最后一个字节。一旦出现这种情况,设备之间的通讯可能会受到影响,甚至会导致系统瘫痪。另外,串口收到数据的时候,我们也需要判断一帧数据的长度,特别是指令发送比较频繁的时候。因此,串口在接收到数据之后应该先进行数据处理,再执行命令,这样能够增强产品的稳定性。

    二、串口接收重点关注的几个标志
    为了保证通讯的稳定性,一般的通讯协议会加入帧头、帧尾、数据长度、校验这四个标志中的一个或多个。它们的作用如下:
    1、帧头:串口发送数据的第一个字节是最容易出错的,如果你把重要的指令放在第一个字节,一旦出现错误,可能会使从机执行错误的操作。而帧头能够有效规避这个问题。
    2、帧尾:和帧头类似,帧尾也能避免最后一个字节出错,同时,它也可以作为接收端接收完成的标志。
    3、数据长度:它可以作为接收端接收完成的标志。有时也能作为判断数据是否正确的标志。
    4、校验:能够有效避免校验以外的所有数据的错误,但是校验正确不代表数据一定没有出错,每种校验方式都有一定的缺陷。
    帧头、帧尾、数据长度和校验,这四种标志加起来之后能够大大的增强数据传输的稳定性,但不是每个通讯协议都会包含以上四个标志,可能只会用到其中的一两个。因为如果要发送的主要数据本身就比较长,加上这个几个标志之后会更长,这对于那种传输速度慢、传输数据时间长、传输指令频繁处理速度慢的设备来说,较长的指令可能会影响工作效率。具体我就不多说了,我今天主要讲的是接收数据的处理方法,大家根据自己的协议选择合适的处理方法就行了。

    三、常用的几种数据处理方法
    1、判断帧头:串口接收到第一个数据之后先判断是否是帧头,如果帧头正确就存起来继续收,反之则丢掉继续等帧头。示例代码片段如下:

    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断
    {
    	Res = USART_ReceiveData(USART1);//读取接收到的数据,同时也清除了中断标志位
    		   
    	USART_RX_BUF[USART_RX_STA ++] = Res;
    	if(USART_RX_BUF[0] != 0xA5 && USART_RX_STA == 1)
    	{//帧头错误
    	     USART_RX_STA = 0;//重新接收
    	}
    	if(USART_RX_STA >= USART_RX_Len)
    	{//接收完成
    	    USART_RX_STA = 0;
    	    USART_RXHANDLE_FLAG = 1;
    	}
    }
    

    这种处理方法能够有效避免第一个字节出错的问题,我就试过一次主设备那边传过来的数据帧头前面多了一个字节(可能是刚开始传输的时候电压不稳定产生的纹波),用这种方法就能够之间把第一个错误的数据丢掉,从正确的帧头开始接收。但是这种方法不能够检查帧头后面的数据是否正确。
    2、判断帧尾:可以把帧尾作为一帧数据接收完成的标志。另外,当接收缓存存了多个指令的时候,帧尾能够帮助我们在一堆数据中区分出哪些数据是同一个指令的。当然,如果仅仅是区分数据用帧头也可以。不过这种办法必须保证帧尾和其他数据不一样,不然就会出现错误的判断。所以有些人为了避免这个问题会用两个字节作为帧尾,不过这样一来,数据长度就更大了,影响通讯效率。
    3、根据数据长度判断是否完成接收:可以通过数据长度判断接收是否完成。如果协议里面的指令长度不是统一的,我们就不能根据固定的长度来接收数据。这个时候在一帧数据里面加入数据长度这个标志,就能够给单片机一个判断的准则,单片机接收到数据长度这个标志之后,根据这个长度来接收剩下的数据。示例代码片段如下:

    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断
    {
    	Res = USART_ReceiveData(USART1);//读取接收到的数据,同时也清除了中断标志位
    		   
    	USART_RX_BUF[USART_RX_STA ++] = Res;
    	if(USART_RX_BUF[0] != 0xA5 && USART_RX_STA == 1)
    	{//帧头错误
    	     USART_RX_STA = 0;//重新接收
    	}
    	If(USART_RX_STA == 4)
    	{
    	USART_RX_Len = USART_RX_BUF[3];//数据长度
    	}
    	if(USART_RX_STA >= (USART_RX_Len + 4))
    	{//接收完成
    	    USART_RX_STA = 0;
    	    USART_RXHANDLE_FLAG = 1;
    	}
    }
    

    4、根据接收时间判断一帧数据的长度。根据波特率计算出两个字节传输的时间间隔,接收到数据之后定时器开始计时,在定时器中断触发之前收到数据就清空,重新计时,超过两个字节的间隔时间,就认为是一帧数据接收完成。具体的程序我就不写了,这个网上能找到很多例程。这种方法适合接收长度不定的情况,在这个方法的基础上还可以加上帧头帧尾等标志,增强稳定性。
    5、校验处理:校验一般是在接收完成之后进行,校验是很必要的,因为它包含一帧数据的所有字节,通过校验能够大大的减少出错的概率。

    四、总结
    其实串口接收数据处理主要要注意两点,第一点是单片机如何确定一帧数据接收完成,第二点是单片机如果判断接收到的数据是正确的指令。第一点可以通过帧尾,数据长度等标志确定接收完成。第二点可以先通过帧头初步判断指令的正确性,再通过校验二次处理,判断指令是否正确接收。

    关于串口接收数据处理的相关内容就介绍到这里,如果还有什么问题,可以留言,如果文章有哪里写的不对,欢迎指正,谢谢!

    展开全文
  • 在用单片机接收串口数据时,当接收数据不定长时 ,需要判断出何时接收完成,之前我写的一个文章是在QT中处理如何判断接收完成的,在单片机中的思路其实是一样的,只不过在QT中实例化了一个定时器,在未超时接收到...

    在用单片机接收串口数据时,当接收数据不定长时 ,需要判断出何时接收完成,之前我写的一个文章是在QT中处理如何判断接收完成的,在单片机中的思路其实是一样的,只不过在QT中实例化了一个定时器,在未超时接收到数据时再重新定时,到接收完成不再接收时,达到超时时间,之后去处理相关的数据包,可以参考这个链接:
    https://blog.csdn.net/snowmcu20132514/article/details/100739937。
    在单片机中,我在STM32的单片机中这样做,有点问题,因为我用的是库开发,我并未找到怎么重新加载计数器的计数值。因此,我将定时的计数更新中断设置成了1ms,我的数据帧的长度是10个字节,115200的波特率,接收完成大概在1ms,我把超时时间设置为5ms,5ms没更新超时就认为接收完成了,之后就可以去解析数据包,从数据包中的数据正确的数据帧。主要是两个部分:
    其一:串口中断,设置接收一个字节就进入中断一次,如果进入中断就重新设置超时时间为5ms,这样只要进入接收中断,那么超时时间就一直为5ms,并将接收的数据放入缓存,可以是数据或者队列,并设置一个全局变量设置串口在接收状态;
    其二 :定时器更新中断,设置为1ms更新一次,如果串口在接收状态,每次将超时时间递减一,如果递减到0,说明已经超时,认为串口接收完成了,将前面设置的的全局变量设置为非接收状态,此时,就可以将这个数据包拿去解析了。

    展开全文
  • 转自:http://bbs.ednchina.com/BLOG_ARTICLE_3007162.HTM ... 串口接收程序是基于串口中断的,单片机串口每次接收到一字节数据产生一次中断,然后再读取某个寄存器就可以得到串口接收的数...

    转自:http://bbs.ednchina.com/BLOG_ARTICLE_3007162.HTM

      感觉串口多字节接收部分的逻辑相对于配置寄存器跟串口回复来说,是有点难度的——寄存器配置基本上都是死的,串口回复多字节跟回复一字节只是多了一个循环。

     

            串口接收程序是基于串口中断的,单片机的串口每次接收到一字节数据产生一次中断,然后再读取某个寄存器就可以得到串口接收的数据了。然而在实际应用当中,基本上不会有单字节接收的情况。一般都是基于一定串口通信协议的多字节通信。在422或者485通信中,还可能是一个主机(一般是计算机)带多个从机(相应的有单片机的板卡)。这就要求我们的单片机能够在连续接收到的串口数据序列中识别出符合自己板卡对应的通信协议,来进行控制操作,不符合则不进行任何操作。简而言之就是,单片机要在一串数据中找到符合一定规律的几个字节的数据。

     

            先来说下怎样定串口协议吧。这个协议指的不是串口底层的协议,而是前面提到的数据帧协议。一般都是有帧头(2~3个字节吧),数据(长度根据需要),结束位(1位,有时候设计成校验字节,最简单的校验也就是前面所有数据求和)。

            比如0xaa 0x55 +(数据部分省略)+校验和(除了aa 55 之外数据的和),如果要是多板卡的话有时候还要在帧头后面加一个板选字节(相当于3字节帧头了)。

     

           第一次写串口接收程序的时候,我首先想到的就是定义一个全局变量(实际上最好是定义局部静态变量),初始值设置为0,然后每进一次中断+1,然后加到串口通信协议的长度的时候再清零。然后判断帧头、校验。写完了之后我自己都觉得不对,一旦数据错开了一位,后面就永远都接收不到数了。无奈看了一下前辈们的代码,跟我的思路差不多,只不过那个计数值跟接收到的数据时同时判断的,而且每次中断都要判断,一旦不对计数的那个变量就清零。

     

           废话少说,直接上一段代码让大家看看就明白了。(通信协议姑且按照简单的aa 55 一个字节数据 一个字节校验,代码是基于51单片机的)。接收成功则在中断程序中把串口接收成功标志位置1。

     

    下面是全局变量定义

    unsigned char receive[4]={0,0,0,0};//接收缓存

    bit uart_flag;//串口接收成功标志

     

    然后串口中断部分

    void ser()interrupt 4

    {

    static unsigned char count;//串口接收计数的变量

      RI=0;//手动清某个寄存器,大家都懂的

      receive[count]=SBUF;

      if(count==0&&receive[count]==0xaa)//同时判断count跟收到的数据

      {

           count=1;

      }

      else if(count==1&&receive[count]==0x55)

      {

         count=2;

      }

      else if(count==2)

      {

           count++;

      }

      else if(count==3&&receive[count]== receive [2])//判断校验和,数据多的话是求//和,或者其他的校验方法,也可能是固定的帧尾

      {

        count=0;

         uart_flag =1;//串口接收成功标志,为1时在主程序中回复,然后清零

       ES=0;      //关中断,回复完了再ES=1;

      }

      else

      {

         count=0;//判断不满足条件就将计数值清零

      }

    }

     

            第一次做的串口大概就按照这个方法写完了(我后来看过其他的代码,有人用switch语句写的,逻辑跟这个也差不多,不过我还是感觉用if else来写清晰一些),

            不过在测试的时候发现了bug,如果数据帧发送一半,然后突然停止,再来重新发,就会丢失一帧的数据。比如先接受到aa 55,然后断了,再进来aa 55 01 01,就不受控制了。后来我也想到一个bug,如果在多设备通信中,属于其他设备的的帧数据最后一位是aa(或者最后两位为aa 55 ,或者最后3位为aa 55 板选),下一次通信的数据就接收不到了。

     

            当时对于数据突然中断的bug,没有想到很好的解决办法,不过这种情况几率极小,所以一直用这个方法写也没有问题。多设备通信最后一位恰好是aa的几率也很小,出问题的可能也很小。当时项目里面的控制数据跟校验恰好不可能出现aa,于是我把if(count==0&&receive[count]==0xaa)改成了if(receive[count]==0xaa)其他都没变,解决了,没有bug了。

     

            后来我又写了几次单片机程序,才想到了一些解决问题的方法——不过改天再接着写吧,太累了,明天还要上班呢。

     

            在后来的项目中,真的遇到了数据位跟校验位都可能出现aa的情况。我考虑到每次数据都是连续发送的(至少我们用labwindows做的上位机程序是这样的),成功接收到了一帧数据是要有一定时间回复的,也就是说如果接收到一半,但是很长时间没接收到数据,把计数值count清零就ok啦。涉及时间的问题自然要用定时器来实现啦。

    这次的通信协议如下,串口波特率19200,2个帧头aa 55 ,一个板选,6字节数据,一个校验字节(除帧头外其他数据的和)。

     

    全局变量定义

    unsigned char boardAddr;//板选地址,通过检测几个io引脚,具体怎么得到的就不写了,很简单的

    unsigned char g_DatRev [10]={0};//接收缓存

    bit retFlag=0;//为1代表串口接收到了一帧数据

     

     

    串口初始化函数,晶振22.1184

     

    void init_uart()

    {

           SCON = 0x50;                 //串口方式1允许接收

           TMOD = 0x21;                //定时器1,方式2,8位自动重载,同时配置定时器0,工作方式1

           PCON = 0x80;                // 波特率加倍

           TH1 = 0xfa;

           TL1 = 0xfa;               //写入串口定时器初值

           TH0=(65536-2000)/256;    //写入定时器0初值,串口传输一个字节时间为(1/19200)*10,计算得0.52ms

           TL0=(65536-2000)%256;   //定时器0定时大约1ms多

        EA=1;

        ET0=1;                  //波特率:19200    22.1184M  初值:250(0xfa)

           IE |= 0x90;           

        TR1 = 1;                   

    }

     

    串口中断函数

     

    void UART_INT(void) interrupt 4

           static unsigned char count;//串口接收计数的变量

     

                  RI = 0;

                  g_DatRev[count] = SBUF;

                  if(g_DatRev[count]==0xaa&&count==0)             //帧头

               {

                       count=1;                                                 

                }

                   else if(count==1&&g_DatRev[count]==0x55) 

                {  

                             count=2;          

                }

     

                    else if (count==2&&g_DatRev[2] == boardAddr)

                   { 

                      CK = g_DatRev[count];

                       count=3;

                     

                   }

         

                   else if(count>=3&&count<9)

                  {     

                    

                         CK += g_DatRev[count];

                        count ++;

                }

                 

               else if(count == 9&&CK==g_DatRev[9])

                         {     

                             ES = 0; 

                            retFlag = 1;

                             count=0;            

                         }            

                  else

                   {

                        count=0;

                   } 

                 resettimer();

     

    }

     

    //判断count不为0的话就启动定时器

    void resettimer()

    {

           TR0=0;

           TH0=(65536-2000)/256;

           TL0=(65536-2000)%256;

           if(count!=0)

           {

                  TR0=1;

           }

    }

     

    定时器中断函数

    void T0_time()interrupt 1

    {     

        TR0=0;

           TH0=(65536-2000)/256;

           TL0=(65536-2000)%256;

           count=0;

     

    }

     

            这种方法的确是本人自己想出来的,别人可能也这样做过,但我这个绝对不是抄袭或者模仿来的。这样写的确可以避免前面提到过的bug,不过代价是多用了一个定时器的资源,而且中断函数里的内容更多了,占用了更多的时间。

     

            要是能把第一种方法改进一下就好了,主要是那个校验不能为aa的那个bug,因为毕竟传输到一半突然断了的可能性是非常小的。后来我想第一个判断if(count==0&&receive[count]==0xaa)好像有点太严格了,考虑到第二字节的帧头,跟板选地址不可能为aa,于是把这个改写为if(count>=0&&count<=2&& receive[count]==0xaa),这样就把bug出现的几率降到了非常小,也只是在前一帧结尾数据恰好为 aa 55 板选 的时候才出现,几率是多少大家自己算一下吧,呵呵。这样我自己觉得,昨天写的那种方法改进到这个程度,应该算可以啦,反正我是很满意了。

     

            实际上我还想过其他的方法,比如缓存的数组采用移位寄存的方式。拿前面的4个字节的协议为例。

     

    void ser()interrupt 4

    {

     unsigned char i;

      RI=0;

     

      for(i=0;i<3;i++)

      {

         receive[i]=receive[i+1];

      }

      receive[3]=SBUF;

      if(reveive[0]==0xaa&&receive[1]==0x55&&receive[2]==receive[3])

      {

         ret_flag=1;

           ES = 0;  

      }

     

    }

            这段代码看上去可是简单明了,这样判断可是不错啊,同时判断帧头跟校验不会产生前面提到的bug。说实话当时我刚想出这种方法并写出来的时候,马上就被我给否了。那个for循环可真是很占时间的啊,延时函数都是这样写的。每次都循环一下,这延时太长,通信速度太快的话就不能接收到下一字节数据了。最要命的是这个时间的长度是随着通信协议帧的字节数增加而增加的,如果一次要接收几十个字节,肯定就玩完了。这种方法我一次都没用过。

     

            不过我居然又想出来了这种方法的改良措施,是前两天刚想出来的,呵呵,还没有实践过呢。

    下面代码的协议就按第二段程序(定时器清零的那个协议,一共10字节)

     

    全局变量

     

    bit ret_flag;

    unsigned char receive[256]={0};

    unsigned char boardaddress;

     

    中断函数

     

    void ser()interrupt 4

    {

     

     

      static unsigned char i=0;

      static unsigned char total=0;

      RI=0;

      receive[i]=SBUF;

      total=total-receive[i-7]+receive[i-1];

     

      if(receive[i-9]==0xaa&&receive[i-8]==0x55

      &&receive[i-7]==boardaddress&&receive[i]==total

      )

      {

         ret_flag=1;

           ES = 0;  

      }

      i++;

     

    }

            之所以要定义256个长度的数组,就是为了能够让数组“首尾相接”。因为0 -1 = 255 , 255+1 = 0。而且我在计算校验的时候也改进了算法,不会因为数据长度的增加而增加计算校验值的时间。这种方法也是我不久前才想出来的,所以还没有经过实际的验证。上面的代码可能会有逻辑上的错误,如果真有错误,有网友看出来的话,请在下面留言告诉我。这个方法也是我原创的哦,别人也肯能会想到,不过我这个绝对不是抄袭别人的。

     

            上面的代码最大的缺点就是变量定义的太多了,太占ram资源了,编译的时候可能会出现错误,毕竟51单片机才128字节的ram(有的资源也很丰富的,比如c8051系列的),这一下子就是256字节的变量。不过对于资源多一些的单片机,这样写还是可以的。要是能有4bit在一起的数据类型就好了,呵呵,verilog代码里面是可以的,C语言里貌似不行啊。

     

            要想能在例如51单片机上运行,只能按照下面的折中方式了,也就是把i相关的量都与一个0x0f

     

    全局变量

     

    bit ret_flag;

    unsigned char receive[16]={0};// 可以考虑在定义时加上idata,毕竟还可能是32

    //或者64长度的数组呢unsigned char idata receive[16]={0};

     

    unsigned char boardaddress;

     

    中断函数

     

    void ser()interrupt 4

    {

     

     

      static unsigned char i=0;

      static unsigned char total=0;

      RI=0;

      receive[i&0x0f]=SBUF;

      total=total-receive[(i-7)&0x0f]+receive[(i-1)&0x0f];

     

      if(receive[(i-9)&0x0f]==0xaa&&receive[(i-8)&0x0f]==0x55

      &&receive[(i-7)&0x0f]==boardaddress&&receive[i&0x0f]==total

      )

      {

         ret_flag=1;

           ES = 0;  

      }

      i++;

     

    }

     

        这样就可以了。等我有机会试一下吧,呵呵。我写了这么多,想必大家都能搞定串口接收了吧。

    PS:字体有点小,大家凑合看吧,编辑字体的话就显示字数超了,真的不是我犯懒哦。

    展开全文
  • 程序功能:接收上位机发过来的一个字符串,然后把该字符串发送给上位机, 字符串必须以!结尾 **********************/ #include #define uchar unsigned char #define uint unsigned int sbit LED = P2^7; uchar ...
    作者:李大闯
    
    
    /*********************
    程序功能:接收上位机发过来的一个字符串,然后把该字符串发送给上位机,
      字符串必须以!结尾
    **********************/
    #include <reg52.h>
    #define uchar unsigned char
    #define uint unsigned int
    sbit LED = P2^7;
    uchar flag = 0;
    uchar index = 0;
    uchar data c[100];
    void Delay_ms(uint n)
    {
     uchar i;
     while(n--)
         for(i = 0;i < 120;i++);
    }
    void Send_string(uchar *c)
    {
     while(*c != '!')
     {
      SBUF=*c;
      c++;
      while(TI==0);
      TI=0;
     }
    }
    void main()
    {
     SCON=0x50;	//串口模式1,允许接收
     TMOD=0x20;	//T1工作模式2
     TH1=0xF3;	//波特率4800
     TL1=0xF3;
     PCON=0x80;	//波特率倍增
     EA = 1;//开总中断
     ES = 1;//开串口中断
     TR1=1;//开定时器1中断
     while(1)
     {
      if((SBUF == '!')&&(flag == 1))
      {
        Send_string(c);
       LED = ~LED;
       index = 0;
       flag = 0;
      }
      /*
      需要理解虽然 读取SBUF和写入SBUF所用的SBUF是不同的,这里可以理解为有两个SBUF,
      一个SBUF_read和一个SBUF_write,当往SBUF中写数据时SBUF_read不变。
     */
     }
    }
    //串口接收中断函数
    void Serial_INT() interrupt 4
    {
     if(RI==0) return;
     ES=0;	//关闭串口中断
     RI=0;	//清接收中断标志
     c[index++]=SBUF;
        if(SBUF == '!')
       flag = 1;
     ES=1;
    }
    

    展开全文
  • /******************************串口1的波特率********************************/ //T1作波特率发生器 //在波特率加倍情况下  #define BAUD_57600 256 - (OSC_FREQ/192L)/57600L // 254 FF #define BAUD_28800 256...
  • 51单片机串口多字节接收
  • 51单片机串口,是个全双工的串口,发送数据的同时,还可以接收数据。 当串行发送完毕后,将在标志位 TI 置 1,同样,当收到了数据后,也会在 RI 置 1。 无论 RI 或 TI 出现了 1,只要串口中断处于开放状态,...
  • 主要解决51单片机串口通讯中的数据出错,或数据保存在SBUF中影响接下来的数据接收
  • 大多数51单片机用的都是11m晶振而只有少部分用的是奇葩的12m(楼主的就是),在12m晶振进行串口通信时切忌要将波特率设置为4800以下,应为12m晶振的波特率在9600以上误差很大容易丢失数据,动手能力强的可以折腾一下用...
  • /******************************串口1的波特率********************************/ //T1作波特率发生器 //在波特率加倍情况下  #define BAUD_57600 256 - (OSC_FREQ/192L)/57600L // 254 FF #defin...
  • 单片机串口数据发送与接收程序,已调试过啦
  • /******************************串口1的波特率********************************///T1作波特率发生器//在波特率加倍情况下 #define BAUD_57600 256 - (OSC_FREQ/192L)/57600L // 254 FF#define BAUD_28800 ...
  • 51单片机串口,是个全双工的串口,发送数据的同时,还可以接收数据。 当串行发送完毕后,将在标志位 TI 置 1,同样,当收到了数据后,也会在 RI 置 1。 无论 RI 或 TI 出现了 1,只要串口中断处于开放状态,单片机...
  • 转自:http://bbs.ednchina.com/BLOG_ARTICLE_3007162.HTM  工作了一年多,写了不少单片机串口程序。...  串口接收程序是基于串口中断的,单片机的串口每次接收到一字节数据产生一次中断,然后再读取某个寄...
  • 用汇编语言编写的51单片机串口和模拟串口收发多个数据程序。单片机自带串口作为串口1,与上位机通讯。用外部中断模拟串口作为串口2,与现场仪表通讯。从单片机初始化到各个单元子程序均有。方便开发者使用。改程序...
1 2 3 4 5 ... 20
收藏数 9,240
精华内容 3,696
关键字:

单片机串口数据接收程序