⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 485-slave2.c

📁 用485实现单片机之间的串行通信。 从机部分一直等待主机的命令
💻 C
字号:
/*--------RS485通信程序从机部分----------*/

#include<reg52.h>
#include<string.h>

#define uchar unsigned char
#define uint  unsigned int
#define   comm  0                 //液晶命令
#define   dat   1                 //液晶数据

/* 以下为程序协议中使用的握手信号 */
#define __SUCC_ 0x0f    // 数据传送成功
#define __ERR_ 0xf0    // 数据传送错误
#define __RDY_ 0x06    // 主机开始通信时发送的呼叫信号
#define __BUSY_ 0x15    // 从机忙应答
#define __OK_ 0x00    // 从机准备好

/*以下为所用的从机地址 */
#define  addr1 0x01
#define  addr2 0x02

sbit    cs_lcd   = P2^7;
sbit    std  = P2^6;
sbit    sclk = P2^5;
sbit    re_de   = P3^7;

void init_serial();    // 串口初始化
unsigned char recv_data(unsigned char *buf);    // 接收数据
void wr_lcd (uchar dat_comm,uchar content);      //向液晶写数据
void chn_disp (uchar code *chn,uint k);
void delay (uint us);

uchar  buf[16];
uchar code tab1[]={"开始接收"};
uchar code tab2[]={"收到命令"};
uchar code tab3[]={"好数据"};


/*------------------初始化液晶-----------------*/
void init_lcd (void)
{

  wr_lcd (comm,0x30);  /*30---基本指令动作*/
  wr_lcd (comm,0x01);  /*清屏,地址指针指向00H*/
  delay (100);
  wr_lcd (comm,0x06);  /*光标的移动方向*/
  wr_lcd (comm,0x0c);  /*开显示,关游标*/
}
/*------------------向LCD发送数据-------------------*/

void wr_lcd (uchar dat_comm,uchar content)
{
  uchar a,i,j;
  delay (50);
  a=content;
  cs_lcd=1;
  sclk=0;
  std=1;
  for(i=0;i<5;i++)
  {
    sclk=1;
    sclk=0;
  }
  std=0;
  sclk=1;
  sclk=0;
  if(dat_comm)
    std=1;   //data
  else
    std=0;   //command
  sclk=1;
  sclk=0;
  std=0;
  sclk=1;
  sclk=0;
  for(j=0;j<2;j++)
  {
    for(i=0;i<4;i++)
    {
      a=a<<1;
      std=CY;
      sclk=1;
      sclk=0;
    }
    std=0;
    for(i=0;i<4;i++)
    {
      sclk=1;
      sclk=0;
    }
  }
}
/*--------------清DDRAM------------------*/
void clrram (void)
{
  wr_lcd (comm,0x30);
  wr_lcd (comm,0x01);
  delay (180);
}
/*-----------------------------------*/
void delay (uint us)   //delay time 微妙
{
  while(us--);
}


/*---------------显示汉字或字符----------------*/
void chn_disp (uchar code *chn,uint k)
{
  uchar i;
  wr_lcd (comm,0x30);
  wr_lcd (comm,0x80);

  for (i=0;i<k;i++)
  wr_lcd (dat,chn[i]);

}

/* 初始化串口 */
void init_serial()
{
	TMOD = 0x20;	//定时器T1使用工作方式2
	TH1 = 250;    // 设置初值
	TL1 = 250;
	TR1 = 1;    // 开始计时
	PCON =0x00; // 0x80;    // SMOD = 1
	SCON = 0x50; //0xd0;	//工作方式3,9位数据位,波特率9600bps,允许接收
        // re_de=0;    //485允许接受
}

/* 接收数据,注意该函数使用buf指向的缓冲区保存数据,在数据末尾使用'\0'表示数据结束
 返回值为0,数据校验成功,返回值为0xfe,接受过程中接收到地址帧,返回值为0xff,数据校验失败*/

unsigned char recv_data(unsigned char *buf)
{
	//unsigned char len;    // 该字节用于保存数据长度
	//unsigned char ecc;    // 该字节用于保存校验字节
	unsigned char i,tmp;
	/* 接收数据长度 */
	//RI = 0;
	//while(!RI);
	//if(RB8 == 1)    // 若当前接收为地址帧则返回0xfe
	//	return 0xfe;
	//len = SBUF;
	RI = 0;
	/* 使用len的值为校验字节ecc赋初值 */
	//ecc = len;
	/* 接收数据 */
	for(i=0; i<16; i++)
	{
		while(!RI);
	//	if(RB8 == 1)    // 若当前接收为地址帧则返回0xfe
	//		return 0xfe;
		*buf[i] = SBUF;    // 接收数据
		//ecc = ecc^(*buf);    // 进行字节校验
		RI = 0;
		buf++;
	}
	//*buf = 0;    // 表示数据结束
	/* 接收校验字节 */
	//while(!RI);
	//if(RB8 == 1)    // 若当前接收为地址帧则返回0xfe
	//	return 0xfe;
	//tmp = SBUF;
	//RI = 0;
	/* 进行数据校验 */
	//ecc = tmp^ecc;
	//if(ecc != 0)    // 校验失败
	//{
	//	*(buf-len) = 0;    // 清空数据缓冲区
	//	TI = 0;    // 发送校验失败信号
	//	TB8 = 0;
	//	SBUF = __ERR_;
	//	while(!TI);
	//	TI = 0;
	//	return 0xff;    // 返回0xff表示校验错误
	//}
	TI = 0;    // 校验成功
	TB8 = 0;
	SBUF = __SUCC_;
	while(!TI);
	TI = 0;
	return 0;    // 校验成功,返回0
}
/*------------主程序---------------*/

void main()
{

	unsigned char i = 0;
	unsigned char tmp = 0xff;
	unsigned char addr;    // 保存本机地址

	addr =addr1;       /*读取本机地址 */

          cs_lcd=1;
          SP=0x5f;

	/* 串口初始化 */
	init_serial();    // 初始化串口
	EA = 0;    // 关闭所有中断

         init_lcd ();                  //初始化液晶
        chn_disp (tab1,8);

	/* 进入设备应答阶段 */
	while(1)
	{
		//SM2 = 1;    // 只接收地址帧
		/* 如果接收到的地址帧不是本机地址,则继续等待 */
		//tmp = addr-1;
		while(tmp !=__RDY_)
		{
			RI = 0;
			while(!RI);
			tmp = SBUF;
			RI = 0;
		}
                wr_lcd (comm,0x86);
                chn_disp (tab2,8);
		/* 发送应答信号,并做好接收数据的准备 */
		TI = 0;
		//TB8 = 0;    // 主机不检测该位
		SBUF =__OK_;
		while(!TI);
		TI = 0;
                chn_disp (tab3,6);
		//SM2 = 0;    // 允许接收数据信息
		/* 数据接收 */
		tmp = 0xff;
		while(tmp == 0xff)    // 如果数据校验失败则重新接收数据
		{
			tmp = recv_data(buf);    // 校验失败返回0xff,检测到地址帧则返回0xfe,接收成功则返回0
		}
		if(tmp == 0xfe)    // 在数据接收过程中,如果发现地址帧,则重新开始整个接收过程
			continue;

                wr_lcd (comm,0x90);           //置显示位置
		chn_disp (buf,16) ;   //显示表示数据接收成功
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -