单片机串口发送字符串字符串问题

51单片机串口通信的发送与接收 字符串
> 51单片机串口通信的发送与接收 字符串
51单片机串口通信的发送与接收 字符串
51单片机的串口,是个全双工的串口,发送数据的同时,还可以接收数据。当串行发送完毕后,将在标志位 TI 置 1,同样,当收到了数据后,也会在 RI 置 1。无论 RI 或 TI 出现了 1,只要串口中断处于开放状态,单片机都会进入串口中断处理程序。在中断程序中,要区分出来究竟是发送引起的中断,还是接收引起的中断,然后分别进行处理。看到过一些书籍和文章,在串口收、发数据的处理方法上,很多人都有不妥之处。接收数据时,基本上都是使用&中断方式&,这是正确合理的。即:每当收到一个新数据,就在中断函数中,把 RI 清零,并用一个变量,通知主函数,收到了新数据。发送数据时,很多的程序都是使用的&查询方式&,就是执行 while(TI ==0); 这样的语句来等待发送完毕。这时,处理不好的话,就可能带来问题。看了一些网友编写的程序,发现有如下几条容易出错:1.有人在发送数据之前,先关闭了串口中断!等待发送完毕后,再打开串口中断。这样,在发送数据的等待期间内,如果收到了数据,将不能进入中断函数,也就不会保存的这个新收到的数据。这种处理方法,就会遗漏收到的数据。2.有人在发送数据之前,并没有关闭串口中断,当 TI = 1 时,是可以进入中断程序的。但是,却在中断函数中,将 TI 清零!这样,在主函数中的while(TI ==0);,将永远等不到发送结束的标志。3.还有人在中断程序中,并没有区分中断的来源,反而让发送引起的中断,执行了接收中断的程序。对此,做而论道发表自己常用的方法:接收数据时,使用&中断方式&,清除 RI 后,用一个变量通知主函数,收到新数据。发送数据时,也用&中断方式&,清除 TI 后,用另一个变量通知主函数,数据发送完毕。这样一来,收、发两者基本一致,编写程序也很规范、易懂。更重要的是,主函数中,不用在那儿死等发送完毕,可以有更多的时间查看其它的标志。实例:求一个PC与单片机串口通信的程序,要求如下:1、如果在电脑上发送以$开始的字符串,则将整个字符串原样返回(字符串长度不是固定的)。2、如果接收到1,则将P10置高电平,接收到0,P10置低电平。(用来控制一个LED)单片机是STC89C52RC/晶振11.0592/波特率要求是。谢谢!问题补充:可能会将【$ABCD,654ccc,aasdasd,aaaa,sssd,4D】这样的字符串(字符串长度约为50-150个字符)传送给单片机,只能能原样返回。本文引用地址:最佳答案:下列程序,已经调试成功。#includesbitLED=P1^0;unsignedcharUART_bitNew_rec=0,Send_ed=1,Money=0;//----------------------------------------------voidmain(void){SCON=0x50;//串口方式1,8-n-1,允许接收.TMOD=0x20;//T1方式2TH1=0xFD;[url=]//9600bps@11.0592MHz[/url]TL1=0xFD;TR1=1;ES=1;//开中断.EA=1;while(Money==0);//等着交费,呵呵,等着接收$.while(1){if((New_rec==1)&&(Send_ed==1)){//如果收到新数据及发送完毕SBUF=UART_//那就发送.New_rec=0;Send_ed=0;}}}//----------------------------------------------voidser_int(void)interrupt4{if(RI==1){//如果收到.RI=0;//清除标志.New_rec=1;UART_buff=SBUF;//接收.if(UART_buff==1)LED=1;if(UART_buff==0)LED=0;if(UART_buff==$)Money=1;}else{//如果送毕.TI=0;//清除标志.Send_ed=1;}}//----------------------------------------------串口接收程序是基于串口中断的,单片机的串口每次接收到一字节数据产生一次中断,然后再读取某个寄存器就可以得到串口接收的数据了。然而在实际应用当中,基本上不会有单字节接收的情况。一般都是基于一定串口通信协议的多字节通信。在422或者485通信中,还可能是一个主机(一般是计算机)带多个从机(相应的有单片机的板卡)。这就要求我们的单片机能够在连续接收到的串口数据序列中识别出符合自己板卡对应的通信协议,来进行控制操作,不符合则不进行任何操作。简而言之就是,单片机要在一串数据中找到符合一定规律的几个字节的数据。
先来说下怎样定串口协议吧。这个协议指的不是串口底层的协议,而是前面提到的数据帧协议。一般都是有帧头(2~3个字节吧),数据(长度根据需要),结束位(1位,有时候设计成校验字节,最简单的校验也就是前面所有数据求和)。
比如0xaa 0x55 +(数据部分省略)+校验和(除了aa 55 之外数据的和),如果要是多板卡的话有时候还要在帧头后面加一个板选字节(相当于3字节帧头了)。 第一次写串口接收程序的时候,我首先想到的就是定义一个全局变量(实际上最好是定义局部静态变量),初始值设置为0,然后每进一次中断+1,然后加到串口通信协议的长度的时候再清零。然后判断帧头、校验。写完了之后我自己都觉得不对,一旦数据错开了一位,后面就永远都接收不到数了。无奈看了一下前辈们的代码,跟我的思路差不多,只不过那个计数值跟接收到的数据时同时判断的,而且每次中断都要判断,一旦不对计数的那个变量就清零。 废话少说,直接上一段代码让大家看看就明白了。(通信协议姑且按照简单的aa 55 一个字节数据 一个字节校验,代码是基于51单片机的)。接收成功则在中断程序中把串口接收成功标志位置1。然后串口中断部分voidser()interrupt4{sta//串口接收计数的变量RI=0;//手动清某个寄存器,大家都懂的receive[count]=SBUF;if(count==0&&receive[count]==0xaa)//同时判断count跟收到的数据{count=1;}elseif(count==1&&receive[count]==0x55){count=2;}elseif(count==2){count++;}elseif(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字节数据,一个校验字节(除帧头外其他数据的和)。全局变量定义unsignedcharboardA//板选地址,通过检测几个io引脚,具体怎么得到的就不写了,很简单的unsignedcharg_DatRev[10]={0};//接收缓存bitretFlag=0;//为1代表串口接收到了一帧数据串口初始化函数,晶振22.1184voidinit_uart(){SCON=0x50;//串口方式1允许接收TMOD=0x21;//定时器1,方式2,8位自动重载,同时配置定时器0,工作方式1PCON=0x80;//波特率加倍TH1=0TL1=0//写入串口定时器初值TH0=()/256;//写入定时器0初值,串口传输一个字节时间为(1/19200)*10,计算得0.52msTL0=()%256;//定时器0定时大约1ms多EA=1;ET0=1;//波特率:4M初值:250(0xfa)IE|=0x90;TR1=1;}串口中断函数voidUART_INT(void)interrupt4{sta//串口接收计数的变量RI=0;g_DatRev[count]=SBUF;if(g_DatRev[count]==0xaa&&count==0)//帧头{count=1;}elseif(count==1&&g_DatRev[count]==0x55){count=2;}elseif(count==2&&g_DatRev[2]==boardAddr){CK=g_DatRev[count];count=3;}elseif(count>=3&&count<9){CK+=g_DatRev[count];count++;}elseif(count==9&&CK==g_DatRev[9]){ES=0;retFlag=1;count=0;}else{count=0;}resettimer();}//判断count不为0的话就启动定时器voidresettimer(){TR0=0;TH0=()/256;TL0=()%256;if(count!=0){TR0=1;}}定时器中断函数voidT0_time()interrupt1{TR0=0;TH0=()/256;TL0=()%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个字节的协议为例。voidser()interrupt4{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字节)全局变量bitret_unsignedcharreceive[256]={0};unsi中断函数voidser()interrupt4{staticunsignedchari=0;staticunsignedchartotal=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全局变量bitret_unsignedcharreceive[16]={0};//可以考虑在定义时加上idata,毕竟还可能是32//或者64长度的数组呢unsignedcharidatareceive[16]={0};unsi中断函数voidser()interrupt4{staticunsignedchari=0;staticunsignedchartotal=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++;}
分享给小伙伴们:
我来说两句……
最新技术贴
微信公众号二
微信公众号一字符和数据之间的转换
查看: 2640|
摘要:   我们学串口通信的应用主要是实现单片机和电脑之间的信息互发,可以用电脑控制单片机的一些信息,可以把单片机的一些信息状况发给电脑上的软件。下面我们就做一个简单的例程,实现单片机串口调试助手发送的数据, ...
  我们学串口通信的应用主要是实现和之间的信息互发,可以用电脑控制单片机的一些信息,可以把单片机的一些信息状况发给电脑上的软件。下面我们就做一个简单的例程,实现单片机串口调试助手发送的数据,在我们开发板上的数码管上显示出来。
#include&&reg52.h&
sbit&ADDR3&=&P1^3;&&&&&&//LED选择地址线3
sbit&ENLED&=&P1^4;&&&&&&//LED总使能引脚
unsigned&char&code&LedChar[]&=&{&&//数码管显示字符转换表
&&&&0xC0,&0xF9,&0xA4,&0xB0,&0x99,&0x92,&0x82,&0xF8,
&&&&0x80,&0x90,&0x88,&0x83,&0xC6,&0xA1,&0x86,&0x8E
unsigned&char&LedBuff[6]&=&{&&//数码管
&&&&0xFF,&0xFF,&0xFF,&0xFF,&0xFF,&0xFF
unsigned&char&T0RH&=&0;&&//T0重载值的高字节
unsigned&char&T0RL&=&0;&&//T0重载值的低字节
unsigned&char&RxdByte&=&0;&&//串口接收到的字节
void&ConfigTimer0(unsigned&int&ms);
void&ConfigUART(unsigned&int&baud);
void&main&()
&&&&P0&=&0xFF;&&//P0口初始化
&&&&ADDR3&=&1;&&//选择数码管
&&&&ENLED&=&0;&&//LED总使能
&&&&EA&=&1;&&&&&//开总中断
&&&&ConfigTimer0(1);&&&//配置T0定时1ms
&&&&ConfigUART(9600);&&//配置波特率为9600
&&&&while(1)
&&&&{&&&//将接收字节在数码管上以十六进制形式显示出来
&&&&&&&&LedBuff[0]&=&LedChar[RxdByte&&&0x0F];
&&&&&&&&LedBuff[1]&=&LedChar[RxdByte&&&&4];
void&ConfigTimer0(unsigned&int&ms)&&//T0配置函数
&&&&unsigned&long&
&&&&tmp&=&&/&12;&&&&&&//定时器计数频率
&&&&tmp&=&(tmp&*&ms)&/&1000;&&//计算所需的计数值
&&&&tmp&=&65536&-&&&&&&&&&//计算定时器重载值
&&&&tmp&=&tmp&+&31;&&&&&&&&&&&//修正中断响应延时造成的误差
&&&&T0RH&=&(unsigned&char)(tmp&&&&8);&&//定时器重载值拆分为高低字节
&&&&T0RL&=&(unsigned&char)
&&&&TMOD&&=&0xF0;&&&//清零T0的控制位
&&&&TMOD&|=&0x01;&&&//配置T0为模式1
&&&&TH0&=&T0RH;&&&&&//加载T0重载值
&&&&TL0&=&T0RL;
&&&&ET0&=&1;&&&&&&&&//使能T0中断
&&&&TR0&=&1;&&&&&&&&//启动T0
void&ConfigUART(unsigned&int&baud)&&//串口配置函数,baud为波特率
&&&&SCON&=&0x50;&&&//配置串口为模式1
&&&&TMOD&&=&0x0F;&&//清零T1的控制位
&&&&TMOD&|=&0x20;&&//配置T1为模式2
&&&&TH1&=&256&-&(/32)&/&&&//计算T1重载值
&&&&TL1&=&TH1;&&&&&//初值等于重载值
&&&&ET1&=&0;&&&&&&&//禁止T1中断
&&&&ES&&=&1;&&&&&&&//使能串口中断
&&&&TR1&=&1;&&&&&&&//启动T1
void&LedScan()&&//LED显示扫描函数
&&&&static&unsigned&char&index&=&0;
&&&&P0&=&0xFF;&&&&&&&&&&&&&&&&&//关闭所有段选位,显示消隐
&&&&P1&=&(P1&&&0xF8)&|&&&//位选索引值赋值到P1口低3位
&&&&P0&=&LedBuff[index];&&&&&&&//相应显示缓冲区的值赋值到P0口
&&&&if&(index&&&5)&&&&&&&&&&&&&//位选索引0-5循环,因有6个数码管
&&&&&&&&index++;
&&&&&&&&index&=&0;
void&InterruptTimer0()&interrupt&1&&//T0中断服务函数
&&&&TH0&=&T0RH;&&//定时器重新加载重载值
&&&&TL0&=&T0RL;
&&&&LedScan();&&&//LED扫描显示
void&InterruptUART()&interrupt&4
&&&&if&(RI)&&//接收到字节
&&&&&&&&RI&=&0;&&//手动清零接收中断标志位
&&&&&&&&RxdByte&=&SBUF;&&//接收到的数据保存到接收字节变量中
&&&&&&&&SBUF&=&RxdB&&//接收到的数据又直接发回,这叫回显-"echo",以提示用户输入的信息是否已正确接收
&&&&if&(TI)&&//字节发送完毕
&&&&&&&&TI&=&0;&&//手动清零发送中断标志位
  大家在做这个实验的时候,有个小问题要注意一下。因为我们STC89C52RC下载程序是使用了UART串口下载,下载完程序后,程序运行起来了,可是下载软件最后还会通过串口发送一些额外的数据,所以程序刚下载进去不是显示00,而可能是其他数据。大家只要把开关关闭,重新打开一次就好了。
  细心的同学可能会发现,在串口调试助手发送选项和接收选项处,还有个“字符格式发送”和“字符格式显示”,这是什么意思呢?
  先抛开我们使用的汉字不谈,那么我们常用的字符就包含了0~9的数字、A~Z/a~z的字母、还有各种标点符号等。那么在单片机系统里面我们怎么来表示它们呢?ASCII码(American&Standard&Code&for&Information&Interchange,即美国信息互换标准代码)可以完成这个使命:我们知道,在单片机中一个字节的数据可以有0~255共256个值,我们取其中的0~127共128个值赋予了它另外一层涵义,即让它们分别来代表一个常用字符,其具体的对应关系如下表。
  表1&ASCII表
  这样我们就在常用字符和字节数据之间建立了一一对应的关系,那么现在一个字节就既可以代表一个整数又可以代表一个字符了,但它本质上只是一个字节的数据,而我们赋予了它不同的涵义,什么时候赋予它那种涵义就看编程者的意图了。ASCII码在单片机系统中应用非常广泛,我们后续的课程也会经常使用到它,下面我们来对它做一个直观的认识,同学们一定要深刻理解其本质。
  对照上述表格,我们就可以实现字符和数字之间的转换了,比如还是这个程序,我们发送的时候改成字符格式发送,接收还是用十六进制接收,这样接收和数码管好做一下对比。
  我们用字符格式发送一个小写的a,返回一个十六进制的0x61,数码管上显示的也是61,ASCII码表里字符a对应十进制是97,等于十六进制的0x61;我们再用字符格式发送一个数字1,返回一个十六进制的0x31,数码管上显示的也是31,ASCII表里字符1对应的十进制是49,等于十六进制的0x31。这下大家就该清楚了:所谓的十六进制发送和十六进制接收,都是按字节数据的真实值进行的;而字符格式发送和字符格式接收,是按ASCII码表中字符形式进行的,但它实际上最终传输的还是一个字节数据。这个表格,当然不需要大家去记住,理解它,用的时候过来查就行了。
  通信的学习,不像前边控制部分那么直观了,通信部分我们的程序只能获得一个结果,而其过程我们却无法直接看到,所以慢慢的可能大家就会知道有和逻辑分析仪这类测量仪器。如果学校实验室或者公司里有示波器或者逻辑分析仪这类仪器,可以拿过来抓一下串口波形,直观的了解一下。如果暂时还没有这些仪器,先知道这么回事,有条件再说。因为工具类的东西有的比较昂贵,有条件可以尽量使用学校或者公司的。在这里我用一款简易的逻辑分析仪把串口通信的波形抓出来给大家看一下,大家了解一下即可,如图1所示。
图1&逻辑分析仪串口数据示意图
  分析仪和示波器的作用,就是把通信过程的波形抓出来进行分析。先大概说一下波形的意思。波形左边是低位,右边是高位,上边这个波形是电脑发送给单片机的,下边这个波形是单片机回发给电脑的。以上边的波形为例,左边第一位是起始位0,从低位到高位依次是,顺序倒一下,就是数据0x31,也就是ASCII码表里的‘1’。大家可以注意到分析仪在每个数据位都给标了一个白色的点,表示是数据,起始位和无数据的时候都没有这个白点。时间标T1和T2的差值在右边显示出来是0.102ms,大概是9600分之一,稍微有点偏差,在容许范围内即可。通过图11-7,我们可以清晰的了解了串口通信的收发的详细过程。
  那我们这里再来了解一下,如果我们使用串口调试助手,用字符格式直接发送一个“12”,我们在我们的数码管上应该显示什么呢?串口调试助手应该返回什么呢?经过试验发现,我们数码管显示的是32,而串口调试助手返回十六进制显示的是31、32两个数据,如图2所示。
图2&串口调试助手数据显示
  我们用逻辑分析仪把这个数据抓出来看一下,如图3所示。
图3&逻辑分析仪抓取数据
  对于ASCII码表来说,数字本身是字符而非数据,所以如果发送“12”的话,实际上是是分别发送了“1”和“2”两个字符,单片机呢,先收到第一个字符“1”,在数码管上会显示出31这个对应数字,但是瞬间马上就又收到了“2”这个字符,数码管瞬间从31变成了32,而我们视觉上呢,根本是没有办法发现这种快速变化的,所以我们感觉数码管直接显示的是32。
上一篇:下一篇:
Powered by &
这里是—这里可以学习 —这里是。
栏目导航:查看: 8164|回复: 6
(求助)51单片机串口接收字符串的问题
当通过串口向单片机发送不确定长度的字符串时,如何校验开始位和结束位,并且最终判断所接收到的字符串的长度?
比如: 开始位用2位”AE“来表示,结束位用2位”BF“来表示, 当向单片机发送如”AE...BF&类型的字符串时, 单片机如何将这一字符串保存到一个预设的数组中,并且正确判断这个字符串的长度?
哪位大虾能否帮忙贴段代码以参考?谢谢先
开始位何结束位这些都是由芯片的自动完成校验的,
/***************串口中断程序***************/& & & &
void&&com()&&interrupt 4& & using 2
& & & & & & & &&&uchar a=0,c=0;
& & & & & & & &&&uint&&b=65535;
& & & & & & & &&&ES=0;
& & & & & & & &&&while(b--)
& & & & & & & && &while(!RI);
& & & & & & & && &RI=0;
& & & & & & & && &c=SBUF;
& & & & & & & && &if(c==0x10||c==0x02||c==0x03)
& & & & & & & && &{
& & & & & & & & & & & && & & & & & if(a!=0)
& & & & & & & & & & & & & & & & {
& & & & & & & & & & & & & & & && &if(com_bus[a-1]==0x10) {com_bus[a-1]=c;}& & & && && && && & //若接收到的数据前面接收到了0X10 则过滤掉
& & & & & & & & & & & & & & & && &else{com_bus[a]=c; a++; if(c==0x03){bz=1;}}& & & & & & & & & & & & //若接收的数据前面没有0x10则送入缓冲区 若接收到0x03 则置接收完成标志
& & & & & & & & & & & & & & & && &&&
& & & & & & & & & & & & & & & && &}
& & & & & & & & & & & & & & & &&&else& &{com_bus[a]=c; a++; if(c!=0x02) {b=0;} }& & & && &&&//若接收数据帧头不对,则跳出接收& & & & & & & & & & & & & & & && &&&
& & & & & & & && &&&}
& & & & & & & && & else
& & & & & & & && &&&{
& & & & & & & & & & & && &com_bus[a]=c;& & & &&&a++;& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & //若接收数据帧头不对,则跳出接收
& & & & & & & & & & & && &if(com_bus[0]!=0x02)& & & &&&{b=0;}
& & & & & & & & & & & && &}
& & & & & & & && & if(com_bus[0]==0x02&&c==0x03&&bz==1)& & & & & & & &&&
& & & & & & & && &&&{
& & & & & & & & & & & && & b=0;
& & & & & & & & & & & && & bz=0;
& & & & & & & & & & & &&&}
& & & & & & & && &
& & & && && &}
& &&&& & & && &ES=1;& &
& & & && &}& && & & &
这个是我原来琢磨的,当时跟你的想法一样。这个接收长度可以不确定 ,接收帧头判断不对则退出,收到结尾也退出,数据送到缓冲区,希望对你有帮助
可是会出现数据的传送缺失的情况怎么弄呀比如123456可能变为12356少一些数据呀,这个怎么办呀
数据帧头--数据长度--数据区--数据和
有种方法! 首先发个校验,在发个字符长度,
然后 接受端就 循环取那个长度的个数!至于后面的问题可以 返回去学学 C语言的一些基础!
Powered by单片机接收字符串问题!!~!!!~!~_单片机吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:139,673贴子:
单片机接收字符串问题!!~!!!~!~收藏
用串口调试助手发送一串字符给单片机的时候
每次发的第一位都和上次发的最后一位是一样的
比如上次发的是 “abcd”
这次发的是“1234”
结果收到的就是“d123”.。这是怎么回事。。oid Send_and_Sin_Data (void){for (i=0;i&4;i++){//SBUF = table[i];//while (TI == 0);//等待发送结束//TI = 0;while (RI == 0);//发送和接受同步进行,发送结束后,等待接受结束RI = 0;table1[i] = SBUF;//接受端}}void E30 (){//inital ();//while (1)//{//for (i=0;i&6;i++)//table1[i] =//数组清空//if(K1 == 0)//{delayE (5);//if(K1 == 0)//{Send_and_Sin_Data ();//发送并接受数据/*Check_Data ();//验证接受的数据if (Error == 0)//判断接受的正确性{LED = 0;//亮delayE (50);LED = 1;//灭} *///}//}//}}
为用户提供各种低成本,低功耗,低能耗,功能强的微控制器解决方案.恩智浦微控制器,高性能,设计新颖,性能稳定,价格超低,欲购从速,欢迎垂询!
求帮忙~~!
登录百度帐号推荐应用

我要回帖

更多关于 单片机串口接收字符串 的文章

 

随机推荐