微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > 两个51单片机485串口通信接收数据出错原因分析。大概发送三、五次会有一次全部接收正确。程序如下:

两个51单片机485串口通信接收数据出错原因分析。大概发送三、五次会有一次全部接收正确。程序如下:

时间:10-02 整理:3721RD 点击:
发送机程序:
#include <REGx52.H>
bit flagTxd = 0; //单字节发送完成标志,用来替代 TXD 中断标志位
sbit RS485_DIR = P2^7; //485收发控制端
unsigned char txdBuf[4]={0xfc,0xf3,0xcf,0x3f}; //发送数据缓存
sbit keyOk=P3^2; //发送按键
/* 串口配置函数,baud-通信波特率 */
void ConfigUART(unsigned int baud)
{
    RS485_DIR = 0; //RS485 设置为接收方向
    SCON = 0x50; //配置串口为模式 1
    TMOD &= 0x0F; //清零 T1 的控制位
    TMOD |= 0x20; //配置 T1 为模式 2
    TH1 = 256 - (11059200/12/32)/baud; //计算 T1 重载值
    TL1 = TH1; //初值等于重载值
    ET1 = 0; //禁止 T1 中断
    ES = 1; //使能串口中断
    TR1 = 1; //启动 T1
}
/* 延时程序 */
void Delay(unsigned int n)
{
  while(n)n--;
}
/* 串口数据写入,即串口发送函数,buf-待发送数据的指针,len-指定的发送长度 */
void UartWrite(unsigned char *buf, unsigned char len)
{        unsigned char i;
    RS485_DIR = 1; //RS485 设置为发送
    for(i=0;i<len;i++)
        { //循环发送所有字节
        flagTxd = 0; //清零发送标志
        SBUF = *buf; //发送一个字节数据
        buf++;
                while (!flagTxd); //等待该字节发送完成
    }
    Delay(50); //等待最后的停止位完成,延时时间由波特率决定
    RS485_DIR = 0; //RS485 设置为接收
}
/* 发送按键扫描 */
void Okkey(void)
{
   if(keyOk==0)
        {
                Delay(600);                   //延时防抖
                if(keyOk==0)
                {
                  UartWrite(txdBuf,4);        //发送数据
                  while(!keyOk);
                }
        }   
}
/* 主函数 */
void main(void)
{
        EA = 1; //开总中断
    ConfigUART(9600); //配置波特率为 9600
     while(1)
         {
                Okkey();  //发送按键扫描
         }
}
/* UART 中断服务函数 */
void InterruptUART() interrupt 4
{
    if (TI)
        { //字节发送完毕
        TI = 0; //清零发送中断标志位
        flagTxd = 1; //设置字节发送完成标志
    }
}
接收机程序:
#include <REGx52.H>
sbit RS485_DIR = P2^7;
unsigned char cntRxd = 0; //串口接收计数器
//unsigned char *ptrRxd; //串口发送指针
unsigned char RxdBuf[4]={0x00,0xff,0x00,0xff};         //接收缓存
/* 延时程序 */
void delay(void)
{
  unsigned char m,n,s;
  for(m=100;m>0;m--)
  for(n=20;n>0;n--)
  for(s=248;s>0;s--);
}
/* 串口配置函数,baud-通信波特率 */
void ConfigUART(unsigned int baud)
{        RS485_DIR=0;
    SCON = 0x50; //配置串口为模式 1
    TMOD &= 0x0F; //清零 T1 的控制位
    TMOD |= 0x20; //配置 T1 为模式 2
    TH1 = 256 - (11059200/12/32)/baud; //计算 T1 重载值
    TL1 = TH1; //初值等于重载值
    ET1 = 0; //禁止 T1 中断
    ES = 1; //使能串口中断
    TR1 = 1; //启动 T1
}
/* 把接收到的数据在P1口显示出来 */
void display(void)
{
        unsigned char i,j;
        unsigned char dispBuf[4];
        for(i=0;i<4;i++) dispBuf[i]=RxdBuf[i];
        for(j=0;j<4;j++)
        {
                P1=dispBuf[j];
                delay();
        }
}
/* 主函数 */
void main(void)
{        
    EA = 1; //开总中断
    ConfigUART(9600); //配置波特率为 9600
    cntRxd = 0;
        while(1)
        {
          display();
        }
}
/* UART 中断服务函数 */
void InterruptUART() interrupt 4
{
    if (RI)
        { //接收到字节
        RI = 0; //清零接收中断标志位
        if (cntRxd < 4)
                {  //放入缓存
                   RxdBuf[cntRxd] = SBUF;
                   cntRxd++;
        }
                else cntRxd=0;
    }
}

RxdBuf[cntRxd]定义大一点,比如100。
/* UART 中断服务函数 */
void InterruptUART() interrupt 4
{
    if (RI)
        { //接收到字节
        RI = 0; //清零接收中断标志位
   //     if (cntRxd < 4)
    //            {  //放入缓存
                   RxdBuf[cntRxd] = SBUF;
                   cntRxd++;
               if(cntRxd >99)
                   cntRxd = 0;
   //     }
         //       else cntRxd=0;                       这些注释掉
    }
}

试试把接收的BUF变量弄大一点!

建议发送程序里在发送过程不要使用指针,采用直接从数组取值的方法,另外如果可能的话,发送部分也加显示,把发送的内容显示出来。
接收程序建议在接收中断里做一个接收完成的标志,你现在接收部分采用的方法其实是不停的显示接收缓存,即使没有接收到任何数据,也在不停的显示,这样你是否能判断出正在显示的内容是发送的内容,还是其他的内容。

这个办法尝试过,但问题还是没有得到解决。谢谢你的提议。

我之前也试过,是串口中断没初始化对。

这是没有办法的,项目要求就是这样。设备按照设定的参数运行并显示对应参数;主机在远端通过串口通讯修改设备的参数。

在测试的时候可以做一个接收结束标志,而且对于实际应用来说,更是会有一个通讯协议,只有正确接收一个数据包时,接收到的数据才算是有效的,可以被执行的,所以一个正确的接收过程是确保设备正确工作的基本

谢谢你的建议。非常感谢!

void UartWrite(unsigned char c)
{   
    RS485_DIR = 1; //RS485 设置为发送
    flagTxd = 0; //清零发送标志
    SBUF = c; //发送一个字节数据
     while (!flagTxd); //等待该字节发送完成
    }
    Delay(50); //等待最后的停止位完成,延时时间由波特率决定
    RS485_DIR = 0; //RS485 设置为接收
}
按键函数里面发送用
for(i=0;i<4;i++)
    UartWrite(txdBuf[i]);
while(!keyok);

这是个不错的想法,下班回去就试试。

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top