过完年,一到公司主管就催我赶紧把这个项目的PC和单片机的RS485通信给调通。这几天,一直在实验室度过的。开始我从单片机简单发送一串数据,用串口调试助手测试。上位机根本没有接收到数据,用示波器测了发送管脚和接收管脚都没有波形,查看了下波特率也是对的。所以初步断定是否硬件电路有问题,检查了ADM2483的DE端初始化时是低电平,我在程序里把这个位置为高电平,再用万用表测量还是低电平。原来DE和RE和地线是连到一块的,问其他同事,原来他们前面把这个地方拉低为了让485模块一直处于接收状态,测试测试能否接收到上位机数据。把这个地方改过来后,继续测试。还是用简单的串口收发数据测试通信,上位机发送数据,下位机接收到数据后紧接着把接收到的数据发给上位机。测试的时候,发送55和00是正确的,但是其他数据都发生了改变。后面用示波器测试单片机TXD2和RXD2的波形,发现下位机发出的数据在RXD2上显示波形,初步断定是否设计原理图的时候这两个引脚是否反了,把电路板割线,重新跳线调换两个引脚后再测试下位机往上位机发送数据,上位机接收正常。紧接着,发送和接收一起测,发送和接收都正常了。调了几天,原来电路板出问题了,可主管一来就说硬件是没有问题的,让我检查软件。哎,干软件的就是弱势群体,特别在我们公司真是这样。所以搞嵌入式开发的最好要软硬件都懂。最后,我把我以前写的程序下载到板子上,发现仍然和上位机不能通信。最后我想是不是在接收中断函数里通信协议解析不对,通过查阅资,改用另一种方式解析,结果可以通过上位机控制下位机输出显示了。最后把自己些调试用的程序附上:
简单的串口2收发程序
#include <reg52.h>
/*******************宏定义***********************/
#define uchar unsigned char
#define uint unsigned int
/*****************串口2特殊功能的声明*************/
sfr AUXR=0x8e; // 辅助寄存器,用于设定串口2工作波特率、独立波特率发生器的选择
sfr S2CON=0x9a; //串口2串行控制器
sfr S2BUF=0x9b; //串口2数据缓冲寄存器
sfr BRT=0x9c; //独立波特率产生器,重装数
sfr IE2=0xaf; //串口2中断寄存器
sfr AUXR1=0xa2;// 辅助寄存器1,用于切换端口。以后用,切记!
#define S2RI 0x01 // 串口2接收标志位
#define S2TI 0x02 // 串口2发送标志位
sfr WDT_CONTR = 0xc1;//看门狗
/*******************位定义声明*****************/
sbit EN1=P3^3;//485通信使能端
bit flag = 0;
/********************数据存储、数据缓冲器声明*************/
/**************************************************************/
//++++++++++++++++++++++++++++++++++++++++//
//名称:delay_ms
//作用:延时time毫秒
//说明:延时函数
//输入参数:time
//输出参数:
//++++++++++++++++++++++++++++++++++++++++//
void delay_ms(unsigned int time)
{
unsigned int i,j;
for(i=time;i>0;i--)
for(j=112;j>0;j--)
{;}
}
uint num;
void UartInit(void) //9600bps@11.0592MHz
{
AUXR &= 0xf7; //波特率不倍速
S2CON = 0x50; //8位数据,可变波特率
BRT = 0xFD; //设定独立波特率发生器重装值
AUXR &= 0xfb; //独立波特率发生器时钟为Fosc/12,即12T
AUXR |= 0x10; //启动独立波特率发生器
EA=1;
IE2=0x01;
}
void send(uint ch)
{
EN1 = 1;
IE2=0x00;
S2CON&=~S2TI;
S2BUF=ch;
while(!(S2CON&S2TI));
S2CON &=~S2TI;
IE2=0x01;
EN1 = 0;
}
void main()
{
EN1 = 0;
UartInit();
send(0x55);
delay_ms(1);
send(0xaa);
delay_ms(1);
send(0xff);
delay_ms(1);
while(1);
}
void Uart2() interrupt 8
{
if(S2CON&S2RI)
{
S2CON&=~S2RI;
delay_ms(1);
num=S2BUF;
send(num);
}
}通信协议解析部分程序
void Data_analysis(void)
{
static unsigned int check_sum = 0; //存放校验和
static unsigned char lencnt = 0; //数据长度计数器
switch (state_flag)
{
case 0:
{
if(recdata == 0xaa) // 是否帧头第一个数据
state_flag = 1;
else
state_flag = 0; // 标志复位
break;
}
case 1:
{
if(recdata == 0x55) //是否帧头第二个数据
state_flag = 2;
else
state_flag = 0; // 标志复位
break;
}
case 2:
{
if(recdata == addr) //判断目的地址是否正确
{
state_flag = 3;
check_sum = recdata;
}
else
state_flag = 0; // 标志复位
break;
}
case 3:
{
state_flag = 4;
cmd = recdata; //指令码
check_sum ^= recdata; //校验和累加
break;
}
case 4:
{
lencnt = 0; //数据长度计数器清零
data_count = recdata; //存储数据长度
check_sum ^= recdata; //累加
if(data_count != 0) //后面有数据码
state_flag = 5;
else
state_flag = 7;
break;
}
case 5:
case 6:
{
dat[lencnt++] = recdata; //存储数据码
check_sum ^= recdata; //累加
if(lencnt == data_count)
{
state_flag = 7;
lencnt = 0;
}
else
state_flag = 6;
break;
}
case 7:
{
if(check_sum == recdata) //数据校验,判断累加和是否正确
state_flag = 8;
else
{
retval = 1; //置错误标志,数据传输不正确
state_flag=0;
}
check_sum=0;//累加和清0
break;
}
case 8:
{
if (recdata==0x0d)
{
retval = 2; //置接收一帧数据成功标志
state_flag=0;
}
else
state_flag=0;
break;
}
default:
break;
}
// if(timeOutFlag == 1) //超时判断
// {
// timeOutFlag = 0;
// state_flag=0;
// retval = 1; //置错误标志,数据传输不正确
// recdata = 0x00;
// }
}

本文记录了作者解决RS485通信问题的过程,包括电路板问题排查、软件调试及通信协议解析等步骤,最终实现了PC与单片机之间的稳定通信。
8733





