找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2643|回复: 19
打印 上一主题 下一主题
收起左侧

问一个单片机串口通讯数据丢位的问题

  [复制链接]
跳转到指定楼层
楼主
问题说明:我设置的波特率是9600,然后这个程序就是笔记本发送数据给单片机,单片机马上原封不动地发送回去,但是在发送回来的时候发现缺位了,比如说我发送了一串数字2019060720055905,但是传回来的时候有时候就少了一位数字成了201906072055905,我想问下这是程序写的有什么问题吗,需要延时还是怎样?
  1. /*************************************************单纯串口通讯程序******************************************************/

  2. 先上程序
  3. #include <reg52.h>

  4. typedef unsigned char uchar;
  5. typedef unsigned int uint;

  6. void SendStr(uchar *s);
  7. void InitUART()

  8. void main()
  9. {
  10.         InitUART();
  11.         SendStr("UART test");
  12.         ES = 1
  13.         while(1)
  14.         {
  15.         }
  16. }

  17. void SendByte(uchar dat)
  18. {
  19.         SBUF = dat;
  20.         while(!TI)
  21.         TI=0;
  22. }

  23. void SendStr(uchar *s)
  24. {
  25.         while(*s != '\0')
  26.         {
  27.                 SendByte(*s);
  28.                 s++;
  29.         }               
  30. }

  31. void InitUART()
  32. {
  33.         SCON = 0x50
  34.         TMOD = 0x20;
  35.         TH1 = 0xFD;
  36.         TR1 = 1;
  37.         EA = 1;
  38. }

  39. void UART_SER() interrupt 4
  40. {
  41.         uchar temp;
  42.         if(RI)
  43.         {
  44.                 RI = 0;
  45.                 temp = SBUF;
  46.                 SBUF = temp;
  47.         }
  48.         if(TI)
  49.         {
  50.                 TI = 0;
  51.         }
  52. }
复制代码

/******************************************串口中断和定时器中断**********************************************/

我这里需要串口给单片机传时间数据,也需要定时器定时给数码管扫描显示数据,但是串口传给单片机的数据好像也不对,数码管显示的时间也不对,所以我觉得是不是两个中断会相互干扰,因为串口中断优先级比定时器0中断低,所以我特别设置了IP = 0x10,但是也没什么用,所以想来问下这其中到底有什么问题。下面是串口程序和定时器0程序。
  1. /**************串口程序***************/

  2. #include "UART.h"

  3. bit SetFlag;
  4. uchar time_buf2[16];

  5. void UART_Init()
  6. {
  7.         SCON = 0X50;// SCON:模式1, 8-bit UART,
  8.         TMOD |= 0x20;//TMOD: timer 1, mode 2, 8-bit
  9.         TH1  = 0xFD; // TH1:波特率 9600 2
  10.         TR1 = 1;
  11.         EA = 1;
  12.         ES = 1;
  13.         
  14. }


  15. void UART() interrupt 4
  16. {
  17.         uchar temp;
  18.         static uchar i;
  19.         if(RI)
  20.         {
  21.                 RI = 0;
  22.                 temp = SBUF;
  23.                 time_buf2[i] = temp;
  24.                 i++;
  25.                 if(i == 16)
  26.                 {
  27.                         i = 0;
  28.                         SetFlag = 1;
  29.                 }
  30.                 SBUF = temp;
  31.         }
  32.         if(TI)
  33.         {
  34.                 TI = 0;
  35.         }
  36. }

  37. /*************定时器0程序***************/

  38. #include "Display.h"
  39. #include "Delay.h"

  40. uchar code DuanMa[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
  41. uchar code WeiMa[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
  42. uchar TempData[8];

  43. void Display(uchar firstbit, uchar num)
  44. {
  45.         static uchar i = 0;
  46.         
  47.         DataPort=0;   //Çå¿Õ¶ÎËø′æÖDμÄêy¾Y£¬·àÖ1óD½»ìæÖØó°
  48.         Seg_Latch = 1;
  49.         Seg_Latch = 0;
  50.         
  51.         DataPort = WeiMa[i+firstbit];
  52.         Bit_Latch = 1;
  53.         Bit_Latch = 0;
  54.                
  55.         DataPort = TempData[i];
  56.         Seg_Latch = 1;
  57.         Seg_Latch = 0;
  58.         
  59.         i++;
  60.         if(i == num)
  61.         {
  62.                 i = 0;
  63.         }
  64. }

  65. void Init_Timer0()
  66. {
  67.         TMOD |= 0x01;
  68.         TH0 = (65535-2000)/256;
  69.         TL0 = (65535-2000)%256;
  70.         EA = 1;
  71.         ET0 = 1;
  72.         TR0 = 1;
  73. }

  74. void Timer0() interrupt 1
  75. {
  76.         static uchar  num;
  77.         TH0 = (65535-500)/256;
  78.         TL0 = (65535-500)%256;
  79.         Display(0,8);
  80.         num++;
  81.         
  82.         if(num == 50)
  83.         {
  84.                 num = 0;
  85.                 ReadTimeFlag = 1;
  86.         }
  87.         
  88. }
复制代码

下面就是串口通讯的错误结果


        


question.png (12.26 KB, 下载次数: 36)

question.png
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

来自 2#
ID:207421 发表于 2019-6-8 12:37 | 只看该作者
哪里抄的代码,代码中很多错误
串口通信注意的是:
1. 晶振的误差会导致数据发生错误
2. 发送速度的快慢, 一个巴掌扇过去,那个人还没来得及回复你,你又一个巴掌,他做哑巴得了,你白问了.
3. 没有对数据进行校验的函数
4. 接收或发送数据时,  没有进行ES或EA处理,不就存在BUG了么
回复

使用道具 举报

来自 3#
ID:557163 发表于 2019-6-8 22:57 | 只看该作者
这么改
1. 漏了个分号
void SendByte(uchar dat)
{
        SBUF = dat;
        while(!TI);  // 这里加上分号
        TI=0;
}

2.  中断服务程序的收发看似没问题,当单片机的波特率比电脑略低时,有一定的概率上一个字节发送还没完下一个字节就收到了,简单粗暴的改法是
把   SBUF=temp;
改为  SendByte(temp);
回复

使用道具 举报

地板
ID:523537 发表于 2019-6-7 20:36 | 只看该作者
下面就是串口通讯的错误结果
回复

使用道具 举报

5#
ID:523537 发表于 2019-6-8 06:14 | 只看该作者
恳请各位大佬指点
回复

使用道具 举报

6#
ID:94031 发表于 2019-6-8 08:35 | 只看该作者
发送双方都要给对方留出处理信息的时间。
回复

使用道具 举报

7#
ID:557425 发表于 2019-6-8 11:42 | 只看该作者

发送双方都要给对方留出处理信息的时间。



回复

使用道具 举报

8#
ID:259083 发表于 2019-6-8 17:09 | 只看该作者
可能是两个单片机的波特率误差导致的,你可以换几组波特率试试,如果还是不行,最好加CRC 校验等校验模式进行校验,也可以考虑采用纠错码来纠正误码!
回复

使用道具 举报

9#
ID:93224 发表于 2019-6-8 17:30 | 只看该作者
数码管用定时器0,串口的用定时器1
回复

使用道具 举报

10#
ID:523537 发表于 2019-6-8 19:14 | 只看该作者
lwh999995 发表于 2019-6-8 12:37
哪里抄的代码,代码中很多错误
串口通信注意的是:
1. 晶振的误差会导致数据发生错误

这个代码是我参照例子写的。首先我用的是11.0592MHz的晶振,波特率9600,我想问下需要延时要在哪里加_nop_()函数呢?另外我这个因为是电脑和单片机通讯,为了简单一点所以没有校验,最后接受和发送数据的时候要关闭总中断来避免多个中断干扰数据传输吗?
回复

使用道具 举报

11#
ID:523537 发表于 2019-6-8 19:15 | 只看该作者
xuyaqi 发表于 2019-6-8 08:35
发送双方都要给对方留出处理信息的时间。

那需要在哪里加延时函数呢?
回复

使用道具 举报

12#
ID:523537 发表于 2019-6-8 19:16 | 只看该作者
lele5211314 发表于 2019-6-8 17:30
数码管用定时器0,串口的用定时器1

我数码管确实用的是定时器0,串口用的是定时器1啊
回复

使用道具 举报

13#
ID:519141 发表于 2019-6-8 19:34 | 只看该作者
数据传输开始和完成都需要有确认语句,方可进行下一步的操作
回复

使用道具 举报

14#
ID:523537 发表于 2019-6-9 14:06 | 只看该作者
he_37 发表于 2019-6-8 22:57
这么改
1. 漏了个分号
void SendByte(uchar dat)

分号是我复制粘贴上来的时候不小心删掉了,不过我想了下你的改法应该是对的,后面我尝试了下也确实是对的,没有出现过一次丢包,不过我又有了一个新问题,我先把代码复制上来吧。void UART_SER() interrupt 4{
        uchar temp;
        if(RI)
        {
                RI = 0;
                temp = SBUF;
                SBUF = temp;
                /*下面两个语句就是SendByte(uchar dat)的功能*/
                while(!TI);
                TI = 0;
        }
}


我是这么想的,电脑发送了一个8位数据过来,单片机接收端的SBUF接收了,然后我把数据转给了发送端的SBUF,然后就是while(!TI);等待单片机发送完,但是我的串口中断还是开的,那么当单片机数据发送完TI置1,那么就会触发中断,然后又从中断函数开头uchar temp;开始,那么而且我也把TI=0;语句删了,那么按道理就是应该无限循环啊,为啥还会完整把整个数据接收完呢?我现在也搞不懂了。
回复

使用道具 举报

15#
ID:523537 发表于 2019-6-9 14:12 | 只看该作者
he_37 发表于 2019-6-8 22:57
这么改
1. 漏了个分号
void SendByte(uchar dat)

更有意思的是我整个串口中断程序没有把TI置0也可以进行串口通讯,只是也有丢位。
void UART_SER() interrupt 4
{
        uchar temp;
        if(RI)
        {
                RI = 0;
                temp = SBUF;
                SBUF = temp;
                /*下面两个语句就是SendByte(uchar dat)的功能*/
                while(!TI);
        }
}

回复

使用道具 举报

16#
ID:552783 发表于 2019-6-9 21:13 | 只看该作者
我觉得可以加个校验
回复

使用道具 举报

17#
ID:222006 发表于 2019-6-10 01:01 | 只看该作者
波特率和检验的问题,小老弟串口不要用人家的源码呀,bug多得吓死人哟,还占资源
回复

使用道具 举报

18#
ID:523537 发表于 2019-6-10 09:55 | 只看该作者
阔爱的钊钊 发表于 2019-6-10 01:01
波特率和检验的问题,小老弟串口不要用人家的源码呀,bug多得吓死人哟,还占资源

自己也是刚学,很多东西都不太懂,只好在源码上做简单修改
回复

使用道具 举报

19#
ID:243060 发表于 2019-6-10 11:39 | 只看该作者
串口通讯的时间是最主要的,要保证两个通讯的频率是一样的,其次对于发射和接受的延时等待时间也要一致
回复

使用道具 举报

20#
ID:523537 发表于 2019-6-11 00:03 | 只看该作者
yumer 发表于 2019-6-10 11:39
串口通讯的时间是最主要的,要保证两个通讯的频率是一样的,其次对于发射和接受的延时等待时间也要一致

嗯嗯,确实是这样,多谢指教了!
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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