找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 15743|回复: 18
收起左侧

单片机串口通信有的时候接收数据不正确

  [复制链接]
ID:183242 发表于 2017-4-7 12:11 | 显示全部楼层 |阅读模式
我在串口助手中输入0123456789(后面加一个回车转行)然后发送数据,有的时候接收数据不是正确的,有的时候接收数据正确。

代码如下:


#include <reg52.h>            
#define uchar unsigned char
#define uint unsigned int
unsigned char flag,a,i;
void init()
{
        TMOD=0x20;
        TH1=0xfd;
        TL1=0xfd;
        TR1=1;
        REN=1;
        SM0=0;
        SM1=1;        
        EA=1;
        ES=1;        
}
void main()
{
        init();
        while(1)
        {
                if(flag==1)
                {
                        ES=0;
                        SBUF=a;
                        while(!TI);
                        TI=0;
                        ES=1;
                        flag=0;
                }
        }
}

void ser() interrupt 4
{
        RI=0;
        a=SBUF;
        flag=1;
}

现象如图所示:
0.png

回复

使用道具 举报

ID:123289 发表于 2017-4-8 00:51 | 显示全部楼层
当你收到一个字节后,做了一件事“禁止串口中断ES=0”,偏偏这个时刻,下一个数据又发来了,怎么办?
而且关的时间还不短(有一个字节的发送时间,发完后才开),在这个时间里,另一个数据会冲掉前一个数据!这就丢一个了。
而且PC发来的数据流,不能保证时间间隔是均匀的(指发了一个字节再发一个字节之间的间隔时间,这个时间取决于PC的工作任务的多寡,pc机是多用户系统,不是只做发送串口数据一件事,你无法撑控)。
运气好,PC数据流与你合拍,OK!
运气差,丢几个数据。
最差,我也说不清了。

评分

参与人数 1黑币 +50 收起 理由
admin + 50 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:151348 发表于 2017-4-7 14:02 | 显示全部楼层
收发太快,接收完之后加个延时,a=SBUF;delay();flag=1;
也可加个判断,要是收发的数据不同,那请求重发

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:82765 发表于 2017-4-7 15:27 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

ID:183242 发表于 2017-4-7 15:49 | 显示全部楼层
imxuheng 发表于 2017-4-7 14:02
收发太快,接收完之后加个延时,a=SBUF;delay();flag=1;
也可加个判断,要是收发的数据不同,那请求重发

加了延时也不行
回复

使用道具 举报

ID:180800 发表于 2017-4-7 16:15 | 显示全部楼层
可能是晶振频率和波特率方面的原因,要注意计算出来的波特率和理论值差值不要太大,超过3%可能就会有问题,推荐用11.0592和9600

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:185829 发表于 2017-4-7 17:20 | 显示全部楼层
加入CRC校验,误码率会低,另外TTL电平转为RS232没有?

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:185829 发表于 2017-4-7 17:21 | 显示全部楼层
TTL的输出线不要太长了

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:7485 发表于 2017-4-7 19:22 | 显示全部楼层
晶振是多少的?
回复

使用道具 举报

ID:187303 发表于 2017-4-7 23:09 | 显示全部楼层
估计是速度没控制好,加延时

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:187303 发表于 2017-4-7 23:10 | 显示全部楼层
使用同步字,接收端进行字符截取

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:150133 发表于 2017-4-7 23:48 | 显示全部楼层
12MHZ晶振时,bps4800收发正常,bps9600收发极容易出错。你用的应该是12MHZ吧?

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:148552 发表于 2017-4-8 10:18 | 显示全部楼层
#include <reg52.h>            
#define uchar unsigned char
#define uint unsigned int
unsigned char flag,a,i;
void init()
{
        TMOD=0x20;
        TH1=0xfd;
        TL1=0xfd;
        TR1=1;
        REN=1;
        SM0=0;
        SM1=1;        
        EA=1;
        ES=1;        
}
void main()
{
        init();
        while(1)
        {
                if(flag==1)
                {
                        flag=0;
                        ES=0;
                        SBUF=a;
                        while(!TI);
                        TI=0;
                        ES=1;
                               //flag=0
                }
        }
}

void ser() interrupt 4
{
        RI=0;
        a=SBUF;
        flag=1;
}



我把你程序改成这样就可以了;

原因是:原来的程序flag=0,写在了最后一句,要把它写在ES=1前面,否则开串口中断的一瞬间程序被中断了,也就是下一个数据收到了,但是程序不会从if()条件那里开始执行,而是从断点开始执行,所以就有数据丢失了

评分

参与人数 1黑币 +3 收起 理由
kaixinjiuhao + 3 很给力!

查看全部评分

回复

使用道具 举报

ID:183242 发表于 2017-4-8 20:54 | 显示全部楼层
本帖最后由 kaixinjiuhao 于 2017-4-8 21:02 编辑
你像风儿来了 发表于 2017-4-8 10:18
#include            
#define uchar unsigned char
#define uint unsigned int

那如果用数组的形式来装载输入的字符,那应该怎么编写呢?

比如:

#include <reg52.h>            
#define uchar unsigned char
#define uint unsigned int
unsigned char flag,a[4],i,j;
void init()
{
        TMOD=0x20;
        TH1=0xfd;
        TL1=0xfd;
        TR1=1;
        REN=1;
        SM0=0;
        SM1=1;        
        EA=1;
        ES=1;        
}
void main()
{
        init();
        while(1)
        {
                if(flag==1)
                {
                        flag=0;
                        ES=0;
                        SBUF=a[j++];
                        while(!TI);
                        TI=0;
                        ES=1;
                               //flag=0
                }
        }
}

void ser() interrupt 4
{
        RI=0;
        a[i++]=SBUF;
        if(i==4)
        flag=1;
}




我将interrupt 4中的a变为数组a,我只输入四个字符,我在interrupt 4中将SBUF中的四个字符全部放到数组中,然后在主函数中显示数组中数值。
这种方法应该怎样实现呢?

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:187614 发表于 2017-4-9 17:44 | 显示全部楼层
建议先接收数据,再清中断位,试试
回复

使用道具 举报

ID:188051 发表于 2017-4-10 14:29 | 显示全部楼层
建议先接收数据,再清中断位,试试
回复

使用道具 举报

ID:188077 发表于 2017-4-10 15:27 | 显示全部楼层
void uart() interrupt 4
{
        unsigned char date;
       
        date = SBUF;//取出接收到的数据
        RI = 0;//清除接收中断标志位       
        SBUF = date;//将接收到的数据放回发送缓存器
        while(!TI);//等待发送数据完成
        TI = 0;//清除发送中断标志位
}
回复

使用道具 举报

ID:188319 发表于 2017-4-11 00:20 来自手机 | 显示全部楼层
ser中断函数,加一个判断RI的语句?
回复

使用道具 举报

ID:188365 发表于 2017-4-11 10:14 | 显示全部楼层
第一,有可能是你的ttl线接触不好,第二,有可能是你波特率设置太高,通讯造成数据丢失,第三,晶振使用的不合理,造成计算出来的波特率误差较大。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表