【附报告 51单片机多机通信】主机控制从机1步进电机、从机2超声波测距(主机可集中显示步进电机的转速、转向、启停状态以及超声波测距结果)

一、设计目标

    使用三个51单片机,实现多机通信。

二、实现功能

    1号单片机可遥控2、3号单片机、超声波测距等;

    1号单片机可集中显示步进电机的转速、转向、启停状态以及超声波测距结果。

三、硬件原理

    51单片机,超声波测距模块,四相双极步进电机,导线,静态数码管,动态数码管,独立按键,74HC245芯片,74HC138芯片。

        5460d38d3c864746851f84ac52e3c071.png

 图1   

 

3eb589ddcfcd44d68535ccd3f95ba7eb.png

图2

 

455801d074444c8097fc8d250fd8239a.png

图3

 

7f89457d0aa7486faab68dd705b11ebb.png

图4

 

3c5529e346d14dc1821ac61db95af7ec.png

图5

6f528dbb348446cb8c12bbe522063d6d.png

图6

 

09133c9243cb4976860770b4600377d5.png

图7

 

90f029f2c9144f47bfa20e0591e991fc.png

图8

 

542c6b4c53844d65802626d82e35ff54.png

图9

 

81b125d4c9ad42c9adeaea8b14d458c3.png

图10

 

b318b09ec4594c6a898d957509019028.png

图11 

 

5010f1a6c98545e381d0acd73daaf882.png

图12

    图1为超声波测距模块的内部电路图。

    图2为超声波测距的输出和接收声波的时序逻辑图。

    图3、图5为动态数码管的控制。使用51单片机的P0_0、P0_1、P0_2端连接74HC138芯片的A、B、C引脚,从而控制哪一个数码管被点亮。

    图6为静态数码管的内部电路图;

    图7为控制步进电机的部分的内部电路图;

    图4为独立按键设置;

    图8为四线双极性步进电机内部原理图;

    图9为步进电机转动的原理图:

①A加正极,A-加负极,B加负极,B-加负极(电机状态,N极朝上)。

②A加负极,A-加负极,B加正极,B-加负极(电机状态,N极朝右,旋转90度)。

③A加负极,A-加正极,B加负极,B-加负极(电机状态,N极朝下)。

④A加负极,A-加负极,B加负极,B-加正极(电机状态,N极朝左)。

    只要依次给相应引脚相应的电平就可以使得电机转动,转动的最小角度为90度。为了实现更加小角度的供电,本次设计中的供电顺序:A、AB、B、BA-、A-、A-B-、B-、B-A,转动的最小角度为45°。

    图10、图11、图12为多机通信工作原理。

    在多机通信中,主机必须要能对各个从机进行识别,在51系列单片机中可以通过SCON寄存器的SM2位来实现。当串口以方式2或方式3发送数据时,每一帧信息都是11位,第9位是数据可编程位,通过给TB8置1或置0来区别地址帧和数据帧,当该位为1时,发送地址帧;该位为0时,发送数据帧。

四、程序流程图

cd35b7baaad34204800defa0a0e2f4bb.png

五、代码说明

    主机的代码由主程序、握手子程序、判断按键抬起子程序、延时程序、发送数字程序、同步电机程序、校验速度程序、清零程序、测距程序、显示中断程序组成。

    1号从机代码由主程序、延时程序、通信中断程序、调速程序、速度校验程序、显示程序组成。

    2号从机代码由主程序、延时程序、通信中断程序、测距程序组成。

1.主函数

①主机

/**********************主函数*************************/
void main()
{
  zjcsh();
  key();
  lian();
  return 0;
}

 

②从机1

/*************************主函数**********************************************************/
void main()
{
  csh();
  Int0Init();//声明加速的中断
  Int1Init();//声明减速的中断
  while(1)
  {
    mode(key());//先按键扫描,后选择模式
  }	
}

 

③从机2

/*************************主函数*******************************/
void main()
{
 unsigned int time = 0;
 csh();
 while(1)
 {  
  time = RunOnce();//传感器接收到高电平的时间
  distance = GetDistance(time);
  xianshi(distance);
 }
}

 

2.子函数1

    主机的延时函数。

/**********************延时函数*************************/
void delay(unsigned int t)//调节给电机供电的时间,从而调速	
{
  while(t--);

 

3.子函数2

    主机的动态数码管显示函数。用于动态数码管显示超声波测距的结果。

}/*********************动态数码管显示*************************/
void shumaguan(unsigned char wei,num)//第几位(wei)显示
{
 switch(wei)
 {
  case 1:P3_5=0;P3_6=0;P3_7=0;break;
  case 2:P3_5=0;P3_6=0;P3_7=1;break;
  case 3:P3_5=0;P3_6=1;P3_7=0;break;
  case 4:P3_5=0;P3_6=1;P3_7=1;break;
  case 5:P3_5=1;P3_6=0;P3_7=0;break;
  case 6:P3_5=1;P3_6=0;P3_7=1;break;
  case 7:P3_5=1;P3_6=1;P3_7=0;break;
  case 8:P3_5=1;P3_6=1;P3_7=1;break;
 }
 P1=shuzi[num];
 delay(1);
}

 

4.子函数3

    主机的测距显示函数。用于控制动态数码管显示超声波测距的结果。

/**********************测距显示*************************/
void xianshi(int d)
{
  int k=8,m;
  while(d!=0)
  {
    m=(d%10);//在数码管上显示个位,从后往前显示
    shumaguan(k,m);
    k--;//数码管向前移位
    d=d/10;
  }
}

5.子函数4

    主机的初始化函数。定义工作方式3,定义SM2的初态。定义波特率9600。

/**********************主机初始化*************************/
void zjcsh()
{
  TMOD=0x20;
  SCON=0xd0;
  TH1=TL1=0xfd;
  PCON=0X00;;
  TR1=1;
  ES=1;
  EA=1;
}

 

6.子函数5

    主机与从机建立联系的函数,并且发地址用于呼叫。

/**********************建立联系——发地址*************************/
void lian(date)
{
  TB8=1;//发送的地址
  if(date==1&&2&&3&&4&&5&&6)
  {
    SBUF=0xA1;//从机1 步进电机
  }
  else
  {
    SBUF=0xA2;//从机2 超声波测距
  }
  while(!TI);
  TI=0;
}

 

7.子函数6

    主机的中断接受及发数据函数。判断收到的从机反馈信息,判断是哪个从机发来的,并给两个从机分别发送不同的指令信息用于控制。若收到的是从机反馈的数据,则分别通过不同方式进行显示。动态数码管显示超声波测距结果,静态数码管显示步进电机的转速。

/**********************中断接收——发数据*************************/
void zd()interrupt 4
{
  RI=0;
  addr=SBUF;
  if(RB8==1)//判断是否为地址
  {
	if(addr==0xA1)
	{
	  TB8=0;//发送的是数据
	  SBUF=date;//给从机1发数据
	  while(!TI);
	  TI=0;
	}
	if(addr==0xA2)
	{
	  TB8=0;//发送的是数据
	  SBUF=date;//给从机2发数据
	  while(!TI);
	  TI=0;
	}
  }
  else
  {
    if(RB8==0)//判断是否为数据
	{
	  dat=SBUF; 
	  if(addr==0xA1)
	  {
	    P0=smg[dat];//显示电机速度
	  }
	  else
	  {
	    xianshi(dat);//显示测距结果
	  }  
	}
  }
}

 

8.子函数7

    主机的按键判断函数。用于生成对步进电机的控制指令。

/**********************按键判断*************************/
void key()
{
  if(P2_0==0) date=1;//顺时针
  if(P2_1==0) date=2;//逆时针
  if(P2_2==0) date=3;//启动
  if(P2_3==0) date=4;//停机
  if(P2_4==0) date=5;//加速
  if(P2_5==0) date=6;//减速
  if(P2_6==0) date=7;//超声波测距
  if(P2_7==0) date=8;
}

 

9.子函数8

    从机1的延时函数。

/***************************延时函数*******************************/
void delay(unsigned int t)//调节给电机供电的时间,从而调速	
{
  while(t--);
}

 

10.子函数9

    从机1的按键扫描函数。用于在从机端控制步进电机。

/***************************按键扫描***************************************/
int key()
{
  if(P0_0==0) i=1;//顺时针
  if(P0_1==0) i=2;//逆时针
  if(P0_2==0) i=3;//启动/回到初速度
  if(P0_3==0) i=4;//停机
  return i;
}  

 

11.子函数10

    从机1的模式判断函数。用于控制步进电机。

/****************************模式判断**************************************/  
void mode(int i)//由按键扫描返回值判断 
{
  switch(i)
  {
/****************模式1 正转****************/
	case 1:
	  while(1)
	  {
	    for(n=0;n<8;n++)//循环供电
		{
		  P2=SSZ[n];//供电
		  delay(V);//延时
		  P1=~smg[D];//显示速度档
		}
		break;
	  }  
	 break; 	 
/****************模式2 反转****************/
	case 2:
	  while(1)
	  {
	    for(n=0;n<8;n++)//循环供电
		{
		  P2=NSZ[n];//供电
		  delay(V);//延时
		  P1=~smg[D];//显示速度档
		}
		break;
	  }
	  break;     
/****************启动/重启****************/ 
	case 3:
	  V=500;//启动的速度/初速度
	  D=1;//速度1档,自动进入模式1
/****************停机****************/
	case 4:
	  P2=0X00;//不给电机供电
	  P1=~smg[0];//数码管显示0 共阳极 取反供电 
	  break;  	       
  }
}

 

 

12.子函数11

    从机1的中断初始化函数。

/*************************中断初始化*****************************/
void Int0Init()//加速
{
  IT0=1;//下降沿有效 
  EX0=1;//IT0中断允许 
  EA=1;//总开关打开 
}

void Int1Init()//减速
{
  IT1=1;
  EX1=1;
  EA=1;
}

 

13.子函数12

    从机1的调速函数。

/*************************调速函数****************************/
void Int0() interrupt 0	 //加速
{
  if(P3_2==0)//判断加速键是否被按下
  {
    delay(2000);//消抖
    if(P3_2==0)//消抖后再次判断
	{
      V=V-50;//延时时间减少,所以速度增加
	  D=D+1;//速度档加1
	}
  }
}

void Int1() interrupt 2	 //减速
{
  if(P3_3==0)//判断减速键是否被按下
  {
    delay(2000);//消抖
    if(P3_3==0)//消抖后再次判断
	{
      V=V+50;//延时时间增加,所以速度减少
	  D=D-1;//速度档减1
	}
  }
}

 

14.子函数13

    从机1 的通信初始化函数。

/*************************初始化*******************************/
void csh()
{
  TMOD=0x20; //定时器工作方式2 
  REN=1;
  SM0=1;
  SM1=1;
  SM2=1;//主机置0 从机置1
  TH1=TL1=0xfd; //9600波特率
  SCON=0X00;
  TR1=1;//开定时
  TI=0;
  RI=0;
  ES=1;//开串口中断
  EA=1;//串口总开关
}

15.子函数14

    从机1的中断收函数。

/*************************中断收*******************************/
void zd() interrupt 4
{
  RI=0;
  if(RB8==1)//再判断接受数据=地址
  {
    if(addr==SBUF)
	{
	  SM2=0;
	  P2_0=0;
	  TB8=1;
	  SBUF=0XA1;
	  while(!TI);
	  TI=0;
	}
  }
  else
  {
    date=SBUF;
	P2_1=0;
	mode(date);
	TB8=1;
	SBUF=D;
	while(!TI);
	TI=0;
	SM2=1;
  }
}

16.子函数15

    从机2的延时函数。

/******************************************延时函数***************************************/
void delay(unsigned int xms)//延时x毫秒 
{
  unsigned int i,j;
  for(i=xms;i>0;i--)
    for(j=112;j>0;j--);
return;
}

 

17.子函数16

    从机2的数码管显示函数。

/******************************************数码管控制函数***************************************/
unsigned char shuzi[]={0x3f/*0*/,0x06/*1*/,0x5b/*2*/,0x4f/*3*/,0x66/*4*/,0x6d/*5*/,0x7d/*6*/,0x07/*7*/,0x7f/*8*/,0x6f/*9*/};//显示的数字(num)的数组
 
void shumaguan(unsigned char wei,num)//第几位(wei)显示
{
 switch(wei)
 {
  case 1:P0_2=0;P0_1=0;P0_0=0;break;
  case 2:P0_2=0;P0_1=0;P0_0=1;break;
  case 3:P0_2=0;P0_1=1;P0_0=0;break;
  case 4:P0_2=0;P0_1=1;P0_0=1;break;
  case 5:P0_2=1;P0_1=0;P0_0=0;break;
  case 6:P0_2=1;P0_1=0;P0_0=1;break;
  case 7:P0_2=1;P0_1=1;P0_0=0;break;
  case 8:P0_2=1;P0_1=1;P0_0=1;break;
 }
 P3=shuzi[num];
 delay(1);
}

 

18.子函数17

    从机2的定时器函数。用于产生方波。

/**********************************定时器函数 延时10us*************************************/
void Delay10us()
{
 TMOD |= 0x01;//16位定时器/计数器
 TH0 = 0xFF;//赋初值
 TL0 = 0xF6;//赋初值
 TR0 = 1;//启动
 
 while(!TF0);//溢出
 
 TF0 = 0;//清溢出
}

 

19.子函数18

    从机2的算距离函数。

/******************************************算距离函数***************************************/
float GetDistance(unsigned int time)  
{
 float distance;
 distance = (float)time * 0.017;//cm    距离=高电平时间×声速/2        0.017cm/us
 
 return distance;//将距离返回主函数
}

 

20.子函数19

    从机2的测时间函数。

/******************************************测时间函数***************************************/
unsigned int RunOnce()  
{
 unsigned int time;
 
/******************发送10us高电平信号*************/
 Trig = 0;
 Trig = 1;
 Delay10us();
 Trig = 0;
/**************等待高电平信号接收*****************/
 while(!Echo);
/*********T0清0重新计数(高电平持续时间)*********/
 TH0 = 0;
 TL0 = 0;
 TR0 = 1;
/*********等待高电平信号接收结束******************/
 while(Echo);
/*******************关闭T0计数********************/
 TR0 = 0;
/**********高电平时间赋值,单位us*****************/
 time = TH0*256 + TL0; 
 TH0 = 0;
 TL0 = 0;
 
 return time;
}

 

21.子函数20

    从机2的动态数码管显示结果函数。用于处理数据后交给数码管函数显示结果。

/**************************************动态数码管显示结果***********************************/
void xianshi(int d)
{
  int k=8,m;
  while(d!=0)
  {
    m=(d%10);//在数码管上显示个位,从后往前显示
    shumaguan(k,m);
 k--;//数码管向前移位
 d=d/10;
  }
}

 

22.子函数21

    从机2的通信初始化函数。

/*************************初始化*******************************/
void csh()
{
  TMOD=0x20; //定时器工作方式2 
  REN=1;
  SM0=1;
  SM1=1;
  SM2=1;//主机置0 从机置1
  TH1=TL1=0xfd; //9600波特率
  SCON=0X00;
  TR1=1;//开定时
  TI=0;
  RI=0;
  ES=1;//开串口中断
  EA=1;//串口总开关
}

 

23.子函数22

    从机2的中断接收函数。

/*************************中断收*******************************/
void zd() interrupt 4
{
  RI=0;
  if(RB8==1)//再判断接受数据=地址
  {
    if(addr==SBUF)
	{
	  SM2=0;
	  P2_0=0;
	  TB8=1;
	  SBUF=0XA2;
	  while(!TI);
	  TI=0;
	}
  }
  else
  {
    date=SBUF;
	P2_1=0;
	TB8=0;
	SBUF=distance;
	while(!TI);
	TI=0;
	SM2=1; 
  }
}

六、源代码 

1.主机

#include <REGX51.H>
int addr;
int date,dat;
int num;
int D=1;//V在延时函数中,用于调速;D用来控制数码管显示的数字
smg[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//用于显示档速 0-f 
unsigned char shuzi[]={0x3f/*0*/,0x06/*1*/,0x5b/*2*/,0x4f/*3*/,0x66/*4*/,0x6d/*5*/,0x7d/*6*/,0x07/*7*/,0x7f/*8*/,0x6f/*9*/};//显示的数字(num)的数组
/**********************延时函数*************************/
void delay(unsigned int t)//调节给电机供电的时间,从而调速	
{
  while(t--);
}/*********************动态数码管显示*************************/
void shumaguan(unsigned char wei,num)//第几位(wei)显示
{
 switch(wei)
 {
  case 1:P3_5=0;P3_6=0;P3_7=0;break;
  case 2:P3_5=0;P3_6=0;P3_7=1;break;
  case 3:P3_5=0;P3_6=1;P3_7=0;break;
  case 4:P3_5=0;P3_6=1;P3_7=1;break;
  case 5:P3_5=1;P3_6=0;P3_7=0;break;
  case 6:P3_5=1;P3_6=0;P3_7=1;break;
  case 7:P3_5=1;P3_6=1;P3_7=0;break;
  case 8:P3_5=1;P3_6=1;P3_7=1;break;
 }
 P1=shuzi[num];
 delay(1);
}
/**********************测距显示*************************/
void xianshi(int d)
{
  int k=8,m;
  while(d!=0)
  {
    m=(d%10);//在数码管上显示个位,从后往前显示
    shumaguan(k,m);
    k--;//数码管向前移位
    d=d/10;
  }
}
/**********************主机初始化*************************/
void zjcsh()
{
  TMOD=0x20;
  SCON=0xd0;
  TH1=TL1=0xfd;
  PCON=0X00;;
  TR1=1;
  ES=1;
  EA=1;
}
/**********************建立联系——发地址*************************/
void lian(date)
{
  TB8=1;//发送的地址
  if(date==1&&2&&3&&4&&5&&6)
  {
    SBUF=0xA1;//从机1 步进电机
  }
  else
  {
    SBUF=0xA2;//从机2 超声波测距
  }
  while(!TI);
  TI=0;
}
/**********************中断接收——发数据*************************/
void zd()interrupt 4
{
  RI=0;
  addr=SBUF;
  if(RB8==1)//判断是否为地址
  {
	if(addr==0xA1)
	{
	  TB8=0;//发送的是数据
	  SBUF=date;//给从机1发数据
	  while(!TI);
	  TI=0;
	}
	if(addr==0xA2)
	{
	  TB8=0;//发送的是数据
	  SBUF=date;//给从机2发数据
	  while(!TI);
	  TI=0;
	}
  }
  else
  {
    if(RB8==0)//判断是否为数据
	{
	  dat=SBUF; 
	  if(addr==0xA1)
	  {
	    P0=smg[dat];//显示电机速度
	  }
	  else
	  {
	    xianshi(dat);//显示测距结果
	  }  
	}
  }
}
/**********************按键判断*************************/
void key()
{
  if(P2_0==0) date=1;//顺时针
  if(P2_1==0) date=2;//逆时针
  if(P2_2==0) date=3;//启动
  if(P2_3==0) date=4;//停机
  if(P2_4==0) date=5;//加速
  if(P2_5==0) date=6;//减速
  if(P2_6==0) date=7;//超声波测距
  if(P2_7==0) date=8;
}
/**********************主函数*************************/
void main()
{
  zjcsh();
  key();
  lian();
  return 0;
}

2.从机一 (步进电机)

#include <REGX51.H>
int addr=0xA1;
int date;
unsigned char SSZ[] = {0x08,0x0a,0x02,0x06,0x04,0x05,0x01,0x09};//顺时针数组
unsigned char NSZ[] = {0x09,0x01,0x05,0x04,0x06,0x02,0x0a,0x08};//逆时针数组
smg[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//用于显示档速 0-f 
int V=500,D=1;//V在延时函数中,用于调速;D用来控制数码管显示的数字
int i=4;//先使电机处于停机状态
int n=0;//用于循环给电机通电
/*************************步进电机******************************************************************************/
/***************************延时函数*******************************/
void delay(unsigned int t)//调节给电机供电的时间,从而调速	
{
  while(t--);
}
/***************************按键扫描***************************************/
int key()
{
  if(P0_0==0) i=1;//顺时针
  if(P0_1==0) i=2;//逆时针
  if(P0_2==0) i=3;//启动/回到初速度
  if(P0_3==0) i=4;//停机
  return i;
}  
/****************************模式判断**************************************/  
void mode(int i)//由按键扫描返回值判断 
{
  switch(i)
  {
/****************模式1 正转****************/
	case 1:
	  while(1)
	  {
	    for(n=0;n<8;n++)//循环供电
		{
		  P2=SSZ[n];//供电
		  delay(V);//延时
		  P1=~smg[D];//显示速度档
		}
		break;
	  }  
	 break; 	 
/****************模式2 反转****************/
	case 2:
	  while(1)
	  {
	    for(n=0;n<8;n++)//循环供电
		{
		  P2=NSZ[n];//供电
		  delay(V);//延时
		  P1=~smg[D];//显示速度档
		}
		break;
	  }
	  break;     
/****************启动/重启****************/ 
	case 3:
	  V=500;//启动的速度/初速度
	  D=1;//速度1档,自动进入模式1
/****************停机****************/
	case 4:
	  P2=0X00;//不给电机供电
	  P1=~smg[0];//数码管显示0 共阳极 取反供电 
	  break;  	       
  }
}
/*************************中断初始化*****************************/
void Int0Init()//加速
{
  IT0=1;//下降沿有效 
  EX0=1;//IT0中断允许 
  EA=1;//总开关打开 
}

void Int1Init()//减速
{
  IT1=1;
  EX1=1;
  EA=1;
}
/*************************调速函数****************************/
void Int0() interrupt 0	 //加速
{
  if(P3_2==0)//判断加速键是否被按下
  {
    delay(2000);//消抖
    if(P3_2==0)//消抖后再次判断
	{
      V=V-50;//延时时间减少,所以速度增加
	  D=D+1;//速度档加1
	}
  }
}

void Int1() interrupt 2	 //减速
{
  if(P3_3==0)//判断减速键是否被按下
  {
    delay(2000);//消抖
    if(P3_3==0)//消抖后再次判断
	{
      V=V+50;//延时时间增加,所以速度减少
	  D=D-1;//速度档减1
	}
  }
}
/*************************初始化*******************************/
void csh()
{
  TMOD=0x20; //定时器工作方式2 
  REN=1;
  SM0=1;
  SM1=1;
  SM2=1;//主机置0 从机置1
  TH1=TL1=0xfd; //9600波特率
  SCON=0X00;
  TR1=1;//开定时
  TI=0;
  RI=0;
  ES=1;//开串口中断
  EA=1;//串口总开关
}
/*************************中断收*******************************/
void zd() interrupt 4
{
  RI=0;
  if(RB8==1)//再判断接受数据=地址
  {
    if(addr==SBUF)
	{
	  SM2=0;
	  P2_0=0;
	  TB8=1;
	  SBUF=0XA1;
	  while(!TI);
	  TI=0;
	}
  }
  else
  {
    date=SBUF;
	P2_1=0;
	mode(date);
	TB8=1;
	SBUF=D;
	while(!TI);
	TI=0;
	SM2=1;
  }
}

/*************************主函数**********************************************************/
void main()
{
  csh();
  Int0Init();//声明加速的中断
  Int1Init();//声明减速的中断
  while(1)
  {
    mode(key());//先按键扫描,后选择模式
  }	
}

3.从机二 (超声波测距)

#include <REGX51.H>
int addr=0xA2;
int date;
float distance;
sbit Trig = P1^0;
sbit Echo = P1^1;
/******************************************延时函数***************************************/
void delay(unsigned int xms)//延时x毫秒 
{
  unsigned int i,j;
  for(i=xms;i>0;i--)
    for(j=112;j>0;j--);
return;
}
/******************************************数码管控制函数***************************************/
unsigned char shuzi[]={0x3f/*0*/,0x06/*1*/,0x5b/*2*/,0x4f/*3*/,0x66/*4*/,0x6d/*5*/,0x7d/*6*/,0x07/*7*/,0x7f/*8*/,0x6f/*9*/};//显示的数字(num)的数组
 
void shumaguan(unsigned char wei,num)//第几位(wei)显示
{
 switch(wei)
 {
  case 1:P0_2=0;P0_1=0;P0_0=0;break;
  case 2:P0_2=0;P0_1=0;P0_0=1;break;
  case 3:P0_2=0;P0_1=1;P0_0=0;break;
  case 4:P0_2=0;P0_1=1;P0_0=1;break;
  case 5:P0_2=1;P0_1=0;P0_0=0;break;
  case 6:P0_2=1;P0_1=0;P0_0=1;break;
  case 7:P0_2=1;P0_1=1;P0_0=0;break;
  case 8:P0_2=1;P0_1=1;P0_0=1;break;
 }
 P3=shuzi[num];
 delay(1);
}
/**********************************定时器函数 延时10us*************************************/
void Delay10us()
{
 TMOD |= 0x01;//16位定时器/计数器
 TH0 = 0xFF;//赋初值
 TL0 = 0xF6;//赋初值
 TR0 = 1;//启动
 
 while(!TF0);//溢出
 
 TF0 = 0;//清溢出
}
/******************************************算距离函数***************************************/
float GetDistance(unsigned int time)  
{
 float distance;
 distance = (float)time * 0.017;//cm    距离=高电平时间×声速/2        0.017cm/us
 
 return distance;//将距离返回主函数
}
/******************************************测时间函数***************************************/
unsigned int RunOnce()  
{
 unsigned int time;
 
/******************发送10us高电平信号*************/
 Trig = 0;
 Trig = 1;
 Delay10us();
 Trig = 0;
/**************等待高电平信号接收*****************/
 while(!Echo);
/*********T0清0重新计数(高电平持续时间)*********/
 TH0 = 0;
 TL0 = 0;
 TR0 = 1;
/*********等待高电平信号接收结束******************/
 while(Echo);
/*******************关闭T0计数********************/
 TR0 = 0;
/**********高电平时间赋值,单位us*****************/
 time = TH0*256 + TL0; 
 TH0 = 0;
 TL0 = 0;
 
 return time;
}
/**************************************动态数码管显示结果***********************************/
void xianshi(int d)
{
  int k=8,m;
  while(d!=0)
  {
    m=(d%10);//在数码管上显示个位,从后往前显示
    shumaguan(k,m);
 k--;//数码管向前移位
 d=d/10;
  }
}
/*************************初始化*******************************/
void csh()
{
  TMOD=0x20; //定时器工作方式2 
  REN=1;
  SM0=1;
  SM1=1;
  SM2=1;//主机置0 从机置1
  TH1=TL1=0xfd; //9600波特率
  SCON=0X00;
  TR1=1;//开定时
  TI=0;
  RI=0;
  ES=1;//开串口中断
  EA=1;//串口总开关
}
/*************************中断收*******************************/
void zd() interrupt 4
{
  RI=0;
  if(RB8==1)//再判断接受数据=地址
  {
    if(addr==SBUF)
	{
	  SM2=0;
	  P2_0=0;
	  TB8=1;
	  SBUF=0XA2;
	  while(!TI);
	  TI=0;
	}
  }
  else
  {
    date=SBUF;
	P2_1=0;
	TB8=0;
	SBUF=distance;
	while(!TI);
	TI=0;
	SM2=1; 
  }
}
/*************************主函数*******************************/
void main()
{
 unsigned int time = 0;
 csh();
 while(1)
 {  
  time = RunOnce();//传感器接收到高电平的时间
  distance = GetDistance(time);
  xianshi(distance);
 }
}

 

猜你喜欢

转载自blog.csdn.net/m0_57007304/article/details/130144460