打印

51单片机串口通信问题

[复制链接]
6034|22
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
lp525110627|  楼主 | 2011-8-13 09:08 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我用51单片机串口与电脑通信,电脑用串口调试软件,结果发现当电脑发送的数据小于15时准确率很高,发送16时单片机接收到数据为32,而发送的数据大于32小于64时单片机接收到数据都加了32.
例如我发了个10(16进制)每次返回都是48。不知道为什么?哪位大哥能帮帮忙啊?
虽然我自己觉得源程序没问题还是附上程序,如下:
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit duan=P1^0;
sbit wei=P1^1;
int m=0;
uchar code table[]={
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40};
uchar code table2[8]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe}; //位选
void delay(uchar n)
{
   uchar  i,j;
   for(i=n;i>0;i--)
   for(j=0;j<85;j++);
}
void display()
{
   char a[3],temp=0,c=2;
   char b;
   a[0]=m/100;  //百位
   a[1]=m%100/10;  //十位
   a[2]=m%10;   //个位                                                               
   if(a[0])
      b=3;
   else if(a[1])
             b=2;
            else
               b=1;
    temp=0;
    c=2;
    for(b;b>0;b--)
    {
          wei=0;
          duan=1;
          P0=0x00;
          P0=table[a[c--]];
          duan=0;
          wei=1;
          P0=0xff;
          P0=table2[temp++];
          delay(1);  //延时
     }
     if(m<=8)
     {
        switch(m)
     {
            case 0x00: P2=255; break;
            case 0x01: P2=254; break;
            case 0x02: P2=252; break;
            case 0x03: P2=248; break;
            case 0x04: P2=240; break;
            case 0x05: P2=224; break;
            case 0x06: P2=192; break;
            case 0x07: P2=128; break;
            case 0x08: P2=0; break;
     }
     }
     if(m>10)
     {
        switch(m)
     {
            case 0x0b: P2 &=0xfe; break;
            case 0x0c: P2 |=0x01; break;
            case 0x0d: P2 &=0xfd; break;
            case 0x0e: P2 |=0x02; break;
            case 0x0f: P2 &=0xfb; break;
            case 0x10: P2 |=0x04; break;
            case 0x11: P2 &=0xf7; break;
            case 0x12: P2 |=0x08; break;
            case 0x13: P2 &=0xef; break;
            case 0x14: P2 |=0x10; break;
            case 0x15: P2 &=0xdf; break;
            case 0x16: P2 |=0x20; break;
            case 0x17: P2 &=0xbf; break;
            case 0x18: P2 |=0x40; break;
            case 0x19: P2 &=0x7f; break;
            case 0x1a: P2 |=0x80; break;
     }
     }  
   
}
main()
{
  SCON=0x50;  //设置串行口工作模式为方式一,允许接收
  PCON=0x00;  //设置波特率
  TMOD=0x20;  //设置波特率
  TH1=0xfd;   //设置波特率
  TL1=0xfd;   //设置波特率
  EA=1;
  TR1=1;
  RI=0;
  ES=1;   //打开串行口中断
  TI=1;
  while(1)
  {
         display();  
  }
  
}
void Chuankou(void) interrupt 4 //串口中断
{
    if(RI==1)   //若接收完毕则开始取数据
    {
        RI=0;
        m=0;
        m=SBUF;
        TI=0;
    SBUF=m;
    while(!TI);
    }
   
}

相关帖子

沙发
anqi0126| | 2011-8-13 10:44 | 只看该作者
程序的可读性不好

使用特权

评论回复
板凳
anqi0126| | 2011-8-13 10:51 | 只看该作者
能看出来你B 是位数,你c是啥啊?temp又代表啥啊?你这么长个程序注释还不到位,你自己看到行,别人一看就看不下去了,谁有时间给你慢慢找错误啊。你尽量让大家明白点

使用特权

评论回复
地板
草履虫| | 2011-8-15 12:00 | 只看该作者
main()中的ti=1?这有点小问题.
还有a[]你可以考滤用unsigned char ,而不是char.m用unsigned int.
另外c51的程序中最好不要用a, a[]做变量名.

使用特权

评论回复
5
xiaotann| | 2011-8-15 12:14 | 只看该作者
小于15时准确率很高

使用特权

评论回复
6
lp525110627|  楼主 | 2011-9-2 16:07 | 只看该作者
感谢各位的热心帮助,由于前段时间出去了,没能及时回复各位实在抱歉。
本人已将程序按照各位的建议做了改变,现粘贴如下
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit duan=P1^0;
sbit wei=P1^1;
unsigned int m=0;
uchar code table[]={
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40};  //段涎?
uchar code table2[8]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe}; //位选
/**************延时函数******************/
void delay(uchar n)
{
   uchar  i,j;
   for(i=n;i>0;i--)
    for(j=0;j<85;j++);
}
/**************显示函数******************/
void display()
{
   unsigned char post[3],temp=0,c=2;
   unsigned char b;
   post[0]=m/100;  //百位
   post[1]=m%100/10;  //十位
   post[2]=m%10;   //个位
   if(post[0])
      b=3;
   else if(post[1])
             b=2;
            else
               b=1;
    temp=0;
    c=2;
    for(b;b>0;b--)
    {
          wei=0;
          duan=1;
          P0=0x00;
          P0=table[post[c--]];
          duan=0;
          wei=1;
          P0=0xff;
          P0=table2[temp++];
          delay(1);  //延时
     }
     if(m<=8)
     {
        switch(m)
     {
            case 0x00: P2=255; break;
            case 0x01: P2=254; break;
            case 0x02: P2=252; break;
            case 0x03: P2=248; break;
            case 0x04: P2=240; break;
            case 0x05: P2=224; break;
            case 0x06: P2=192; break;
            case 0x07: P2=128; break;
            case 0x08: P2=0; break;
     }
     }
     if(m>10)
     {
        switch(m)
        {
            case 0x0b: P2 &=0xfe; break;
            case 0x0c: P2 |=0x01; break;
            case 0x0d: P2 &=0xfd; break;
            case 0x0e: P2 |=0x02; break;
            case 0x0f: P2 &=0xfb; break;
            case 0x10: P2 |=0x04; break;
            case 0x11: P2 &=0xf7; break;
            case 0x12: P2 |=0x08; break;
            case 0x13: P2 &=0xef; break;
            case 0x14: P2 |=0x10; break;
            case 0x15: P2 &=0xdf; break;
            case 0x16: P2 |=0x20; break;
            case 0x17: P2 &=0xbf; break;
            case 0x18: P2 |=0x40; break;
            case 0x19: P2 &=0x7f; break;
            case 0x1a: P2 |=0x80; break;
        }
     }  
   
}
/*************主函数******************/
main()
{
  SCON=0x50;  //设置串行口工作模式为方式一,允许接收
  PCON=0x00;  //设置波特率
  TMOD=0x20;  //设置波特率
  TH1=0xfd;   //设置波特率
  TL1=0xfd;   //设置波特率
  EA=1;   //开中断
  TR1=1;  //开定时器
  RI=0;
  ES=1;   //打开串行口中断
  while(1)
  {
         display();  
  }
  
}
/**************中断函数******************/
void Chuankou(void) interrupt 4 //串口中断
{
    if(RI==1)   //若接收完毕则开始取数据
    {
        RI=0;  //串口接收中断清零
        m=0;
        m=SBUF;        //接收数据
    }
   
}

按照4楼的建议改后,问题还是没解决。前面的显示函数不存在问题。只是主函数和中断函数不知是否有错误,所以对主函数也加了注释。希望高手们能多多指点。

使用特权

评论回复
7
ayb_ice| | 2011-9-2 16:41 | 只看该作者
首先要把程序搞规范
串口中断中不能先清零RI再读取SBUF,应该先读取SUBF再清RI,另外TI也要处理

使用特权

评论回复
8
lp525110627|  楼主 | 2011-9-2 17:03 | 只看该作者
多谢ls指导!以后多注意!TI也要处理?这个不理解。为什么呢?

使用特权

评论回复
9
dengm| | 2011-9-2 18:44 | 只看该作者
7楼: 不要误导菜鸟

一般先清零RI
     JBC RI, SUB_RX
     JBC TI, SUB_TX
        RETI
SUB_RX:
     PUSH ACC
     MOV A, SBUF
     '''''
     RETI

使用特权

评论回复
10
NE5532| | 2011-9-2 19:03 | 只看该作者
波特率准不?测过没?咋测的?

使用特权

评论回复
11
wxgxwhy| | 2011-9-2 23:03 | 只看该作者
还好:)

使用特权

评论回复
12
ayb_ice| | 2011-9-3 08:46 | 只看该作者
7楼: 不要误导菜鸟

一般先清零RI
     JBC RI, SUB_RX
     JBC TI, SUB_TX
        RETI
SUB_RX:
     PUSH ACC
     MOV A, SBUF
     '''''
     RETI
dengm 发表于 2011-9-2 18:44


好好看书吧

使用特权

评论回复
13
joyme| | 2011-9-3 09:53 | 只看该作者
楼主问题描述不是很清楚,你说的单片机收到的数据错误,是LED上显示错误,还是串口返回也是错的?
如你前面的程序,单片机接收一个自己会马上将其发回电脑
你设置串口发送接收都选一样的模式(如16进制,这两个设置不一致也会误导一些问题出来),看串口接收的内容是否正确,如正确则是显示部分的问题,如不正确则是串口部分问题

使用特权

评论回复
14
lp525110627|  楼主 | 2011-9-3 10:36 | 只看该作者
串口接收的内容也不正确。
在网上看到说如果单片机的晶振是12M的话波特率会有误差,我的单片机晶振是12M的。不知道是不是这个问题?

使用特权

评论回复
15
ayb_ice| | 2011-9-3 10:55 | 只看该作者
串口接收的内容也不正确。
在网上看到说如果单片机的晶振是12M的话波特率会有误差,我的单片机晶振是12M的。不知道是不是这个问题?
lp525110627 发表于 2011-9-3 10:36

你是真正的高手啊,
设计的时候都不计算波特率的,有没有误差,误差多少,有没有影响....

使用特权

评论回复
16
受不了了| | 2011-9-3 11:23 | 只看该作者
你用T2定时器做通讯波特率发生器好了,12兆晶振除非那种非主流的51用T1定时器才行

使用特权

评论回复
17
lp525110627|  楼主 | 2011-9-3 16:17 | 只看该作者
不好意思。我就没做硬件,直接在开发板上实验的。开发板上是12M的晶振,我还能怎么去设计波特率呢?

使用特权

评论回复
18
lp525110627|  楼主 | 2011-9-3 16:18 | 只看该作者
不好意思。我就没做硬件,直接在开发板上实验的。开发板上是12M的晶振,我还能怎么去设计波特率呢?

使用特权

评论回复
19
dengm| | 2011-9-3 17:22 | 只看该作者
换12M晶振 or 降低bps

使用特权

评论回复
20
草履虫| | 2011-9-5 23:09 | 只看该作者
12# ayb_ice

尽信书不如无书。支持8楼的说法。
什么时候清中断是和系统有关,开始清和最后清有时候和系统有关系。并非一定要开始就要清标志。

LZ的问题根本就不在清不清标志位这个问题上。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

23

帖子

1

粉丝