蓝桥杯第四届单片机国赛--超声波测距报警实时时钟

题目要求

蓝桥杯第四届单片机国赛--超声波测距报警实时时钟_第1张图片

程序代码

主函数

#include "stc15f2k60s2.h"
#include "driver.h"
#include "ds1302.h"
#include "sonic.h"
#include "display.h"
#include "iic.h"

uchar code SMG_TAB[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
uchar SMG_WEI[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

uchar time_display[8];	 //时间显示
uchar wave_display[8];	 //超声波距离显示
uchar set_display[8];	 //时间设置显示
uchar setsonic_display[8];	  //报警距离显示

uchar key_value;		//键值
uchar display_mode;		//显示模式
uchar mode;			  //时间设置页面下,选择具体的设置变量
uchar sonic_mode;

uchar shi,fen,miao;	  //时、分、秒
uchar flag_24c02;

extern long sonic_distance;	//超声波距离/厘米
extern long lim_distance;			//报警距离

extern bit sonic_flag;
extern bit time_flag;		   //时间显示标志
bit blink_flag;			 //闪烁标志位

void Timer0Init();		//1毫秒@11.0592MHz
void Blink();			//数码管闪烁
void set_add();			//加函数
void set_subtract();	//减函数
void sonic_baojing();   //距离报警函数

void Delay500ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	_nop_();
	i = 22;
	j = 3;
	k = 227;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void main()
{
  Timer0Init();
  All_init();
  DS1302_init();
  init_set();

  flag_24c02=Read_24c02(0x11);
  if(flag_24c02==90)		  //保证第一次下载程序时,lim_distance是预设的初始值
  lim_distance=Read_24c02(0x01);
  else
  {
    lim_distance=30;
	Write_24c02(0x11,90);
  }
  while(1)
  {
	Timer_Display();
	Sonic_display();
	settime_display();
	Blink();
	sonic_baojing();
	
	key_value=key_init();
	switch(key_value)
	{
	  case 4:
	  set_subtract();
	  break;

	  case 5:
	  set_add();
	  break;

	  case 6:
	  if(display_mode==0)
	  display_mode=2;		   //时间设置界面

	  if(display_mode==1)
	  display_mode=3;		  //超声波报警距离调整界面

	  if(display_mode==2)
	  {
		mode++;
		if(mode==1)			 //读取当前时间
		{
		  shi=(TIME[2]/16)*10+TIME[2]%16;
		  fen=(TIME[1]/16)*10+TIME[1]%16;
		  miao=(TIME[0]/16)*10+TIME[0]%16;
		}

		if(mode==3)		  //将设置后的时间写入1302
		{
		  mode=0;
		  display_mode=0;
		  TIME[2]=shi/10*16+shi%10;
		  TIME[1]=fen/10*16+fen%10;
		  TIME[0]=miao/10*16+miao%10;
		  DS1302_init();
		}
	  }

	  if(display_mode==3)
	  {
		sonic_mode++;
		if(sonic_mode==2)
		{
		  sonic_mode=0;
		  display_mode=1;
		}
	  }
	  break;

	  case 7:
	  display_mode++;
	  if(display_mode==2)
	  display_mode=0;
	  break;
	}
  }
}

void sonic_baojing()
{
 if(display_mode==1)
 {
  if(sonic_distance<lim_distance)	   //距离小于报警距离
  {
    P2=(P2&0x1f)|0xa0;
    P06=1;	P04=0;		//蜂鸣器响
    P2=P2&0x1f;
  }
  else
  {
    P2=(P2&0x1f)|0xa0;
    P06=0;	P04=0;	
    P2=P2&0x1f;
  }

  if((lim_distance<sonic_distance)&&(sonic_distance<(1.2*lim_distance)))	//距离小于1.2倍报警距离,L1闪烁
  {
    ledlight(0xfe);
	Delay500ms();
	ledlight(0xff);
	Delay500ms();
  }
 }
}

void set_add()
{
  if(display_mode==2)	   //时间设置模式
  {
    if(mode==1)			   //小时加
	{
	 shi++;
	 if(shi==24)
	 shi=0;
	}

	if(mode==2)			//分钟加
	{
	 fen++;
	 if(fen==60)
	 fen=0;
	}
  }

  if(display_mode==3)	   //报警距离加
  {
	lim_distance++;
	Write_24c02(0x01,lim_distance);
  }
}

void set_subtract()
{
  if(display_mode==2)
  {
    if(mode==1)		 //小时减
	{		 
	 if(shi>0)
	 shi--;
	}

	if(mode==2)		//分钟减
	{		 
	 if(fen>0)
	 fen--;
	}
  }

  if(display_mode==3)
  {
    lim_distance--;		//报警距离减
	Write_24c02(0x01,lim_distance);
  }
}

void Blink()
{
  if(blink_flag)
	{
	  if(display_mode==2)
	  {
	    if(mode==1)
		{
		  set_display[0]=SMG_TAB[shi/10];
          set_display[1]=SMG_TAB[shi%10];
		}

		if(mode==2)
		{
		  set_display[3]=SMG_TAB[fen/10];
          set_display[4]=SMG_TAB[fen%10];
		}
	  }
	}
	else
	{
	  if(display_mode==2)
	  {
	    if(mode==1)
		{
		  set_display[0]=0x00;
          set_display[1]=0x00;
		}
		else
		{
		  set_display[0]=SMG_TAB[shi/10];
          set_display[1]=SMG_TAB[shi%10];
		}

		if(mode==2)
		{
		  set_display[3]=0x00;
          set_display[4]=0x00;
		}
		else
		{
		  set_display[3]=SMG_TAB[fen/10];
          set_display[4]=SMG_TAB[fen%10];
		}
	  }
	}
}

 
void Timer0Init()		//1毫秒@11.0592MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xCD;		//设置定时初值
	TH0 = 0xD4;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	EA=1;
	ET0=1;
}

void timer0() interrupt 1
{
  uchar smg_count;
  uchar i;
  uint sonic_count,init_count,blink_count;

  sonic_count++;
  smg_count++;
  init_count++;
  blink_count++;
  if(smg_count==3)
  {
    smg_count=0;

	P2=(P2&0X1F)|0XC0;		  //位选
	P0=SMG_WEI[i];
	P2=P2&0X1F;

	if(display_mode==0)
	{
	  P2=(P2&0X1F)|0XE0;
	  P0=~time_display[i];
	  P2=P2&0X1F;
	}

	if(display_mode==1)
	{
	  P2=(P2&0X1F)|0XE0;
	  P0=~wave_display[i];
	  P2=P2&0X1F;
	}

	if(display_mode==2)
	{
	  P2=(P2&0X1F)|0XE0;
	  P0=~set_display[i];
	  P2=P2&0X1F;
	}

	if(display_mode==3)
	{
	  P2=(P2&0X1F)|0XE0;
	  P0=~setsonic_display[i];
	  P2=P2&0X1F;
	}

	i++;
	if(i==8)
	i=0;
  }

  if(sonic_count==200)
  {
    sonic_count=0;
	sonic_flag=1;
  }

  if(init_count==1000)
  {
    init_count=0;
	time_flag=1;
  }

  if(blink_count==400)
  {
    blink_count=0;
	blink_flag=~blink_flag;
  }
}

驱动

#include "driver.h"


void All_init()
{
  P2=(P2&0X1F)|0XA0;
  P0=0X00;
  P2=P2&0X1F;

  P2=(P2&0X1F)|0X80;
  P0=0XFF;
  P2=P2&0X1F;
}

void ledlight(uchar led)
{
  P2=(P2&0X1F)|0X80;
  P0=led;
  P2=P2&0X1F;
}

#define key_state0 0
#define key_state1 1
#define key_state2 2

uchar key_init()
{
  static uchar key_state=0;
  uchar key_press, key_val=0;
  key_press=P3&0x0f;

  switch(key_state)
  {
    case key_state0:
	if(key_press!=0x0f)
	key_state=key_state1;
	break;

	case key_state1:
	if(key_press!=0x0f)
	{
	  if(key_press==0x0e)  	key_val=7;
	  if(key_press==0x0d)  	key_val=6;
	  if(key_press==0x0b)  	key_val=5;
	  if(key_press==0x07)  	key_val=4;
	  key_state=key_state2;
	}
	else
	key_state=key_state0;
	break;

	case key_state2:
	if(key_press==0x0f)
	key_state=key_state0;
	break;
  }
  return key_val;
}

DS1302模块

#include "ds1302.h"
/********************************************************************/ 
/*单字节写入一字节数据*/
unsigned char Write_addr[]={0x80,0x82,0x84};
unsigned char Read_addr[]={0x81,0x83,0x85};

unsigned char TIME[3]={0X59,0X50,0X11};

void Write_Ds1302_Byte(unsigned char dat) 
{
	unsigned char i;
	SCK = 0;
	for (i=0;i<8;i++) 
	{ 
		if (dat & 0x01) 	// 等价于if((addr & 0x01) ==1) 
		{
			SDA_SET;		//#define SDA_SET SDA=1 /*电平置高*/
		}
		else 
		{
			SDA_CLR;		//#define SDA_CLR SDA=0 /*电平置低*/
		}		 
		SCK_SET;
		SCK_CLR;		
		dat = dat >> 1; 
	} 
}
/********************************************************************/ 
/*单字节读出一字节数据*/
unsigned char Read_Ds1302_Byte(void) 
{
	unsigned char i, dat=0;	
	for (i=0;i<8;i++)
	{	
		dat = dat >> 1;
		if (SDA_R) 	  //等价于if(SDA_R==1)    #define SDA_R SDA /*电平读取*/	
		{
			dat |= 0x80;
		}
		else 
		{
			dat &= 0x7F;
		}
		SCK_SET;
		SCK_CLR;
	}
	return dat;
}

/********************************************************************/ 
/*向DS1302 单字节写入一字节数据*/
void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat)
{ 

	RST_CLR;			/*RST脚置低,实现DS1302的初始化*/
	SCK_CLR;			/*SCK脚置低,实现DS1302的初始化*/

	RST_SET;			/*启动DS1302总线,RST=1电平置高 */
	addr = addr & 0xFE;	 
	Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是写操作,写之前将最低位置零*/	
	Write_Ds1302_Byte(dat);	 /*写入数据:dat*/
	RST_CLR;				 /*停止DS1302总线*/
}

/********************************************************************/ 
/*从DS1302单字节读出一字节数据*/
unsigned char Ds1302_Single_Byte_Read(unsigned char addr) 
{ 
	unsigned char temp;
	RST_CLR;			/*RST脚置低,实现DS1302的初始化*/
	SCK_CLR;			/*SCK脚置低,实现DS1302的初始化*/

	RST_SET;	/*启动DS1302总线,RST=1电平置高 */	
	addr = addr | 0x01;	 
	Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是读操作,写之前将最低位置高*/
	temp=Read_Ds1302_Byte(); /*从DS1302中读出一个字节的数据*/		
	RST_CLR;	/*停止DS1302总线*/

	SD=0;
	
	return temp;
}

void DS1302_init()
{
  unsigned char i;
  Ds1302_Single_Byte_Write(0x8e,0x00);
  for(i=0;i<3;i++)
  {
    Ds1302_Single_Byte_Write(Write_addr[i],TIME[i]);
  }
  Ds1302_Single_Byte_Write(0x8e,0x80);
}

void Read_time()
{
  unsigned char i;
  for(i=0;i<3;i++)
  {
  	TIME[i]=Ds1302_Single_Byte_Read(Read_addr[i]);
  }
}

超声波模块

#include "sonic.h"
#include "intrins.h"

void Delay13us()		//@11.0592MHz
{
	unsigned char i;

	_nop_();
	_nop_();
	i = 33;
	while (--i);
}

unsigned int Rec_distance()
{
    long count=0;
	long UltraDistance=0;	   //最大距离
	long i;
	Echo=1;
	for (i=0;i<10;i++)
	{
		Trig=~Trig;		   //产生连续的方波
		Delay13us();
	}
	while(Echo)
	{
		count++;
		if(count>=1000)
		  break;
	}
	UltraDistance=count/7;
	return UltraDistance;
}

显示模块

#include "display.h"
#include "ds1302.h"
#include "driver.h"
#include "sonic.h"

bit time_flag;
bit sonic_flag;
long sonic_distance;
long lim_distance=30;

void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	_nop_();
	i = 43;
	j = 6;
	k = 203;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void settime_display()
{
  set_display[2]=0X40;
  set_display[5]=0X40;
  set_display[6]=SMG_TAB[miao/10];
  set_display[7]=SMG_TAB[miao%10];
}

void Timer_Display()
{
  if(time_flag)
  {
	  Read_time();
	  time_display[0]=SMG_TAB[TIME[2]/16];
	  time_display[1]=SMG_TAB[TIME[2]%16];
	  time_display[2]=0X40;
	  time_display[3]=SMG_TAB[TIME[1]/16];
	  time_display[4]=SMG_TAB[TIME[1]%16];
	  time_display[5]=0X40;
	  time_display[6]=SMG_TAB[TIME[0]/16];
	  time_display[7]=SMG_TAB[TIME[0]%16];
  } 
}

void Sonic_display()
{
  if(sonic_flag)
  {
    sonic_flag=0;			//200ms读取一次
    sonic_distance=Rec_distance();
  }
  wave_display[0]=0x00;
  wave_display[1]=0x00;
  wave_display[2]=0X00;
  wave_display[3]=0x00;
  wave_display[4]=0x00;
  wave_display[5]=SMG_TAB[sonic_distance%1000/100];
  wave_display[6]=SMG_TAB[sonic_distance%100/10];
  wave_display[7]=SMG_TAB[sonic_distance%10/1];

  setsonic_display[0]=0x00;
  setsonic_display[1]=0x00;
  setsonic_display[2]=0X00;
  setsonic_display[3]=0x40;
  setsonic_display[4]=0x40;
  setsonic_display[5]=SMG_TAB[lim_distance%1000/100];
  setsonic_display[6]=SMG_TAB[lim_distance%100/10];
  setsonic_display[7]=SMG_TAB[lim_distance%10/1];
}

void init_set()
{
  P2=(P2&0x1f)|0xa0;
  P06=1;	P04=0;		//蜂鸣器响
  P2=P2&0x1f;
  ledlight(0xfe);	  //L1亮
  time_display[0]=0xff; time_display[1]=0xff;
  time_display[2]=0Xff; time_display[3]=0xff;
  time_display[4]=0xff; time_display[5]=0xff;
  time_display[6]=0xff; time_display[7]=0xff;
  Delay1000ms();

  P2=(P2&0x1f)|0xa0;
  P06=0;  P04=0;		//蜂鸣器响
  P2=P2&0x1f;
  ledlight(0xfF);	  //L1亮
}

IIC模块

/*
  程序说明: IIC总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台(12MHz)
  日    期: 2011-8-9
*/

#include "iic.h"

//总线启动条件
void IIC_Start(void)
{
	SDA = 1;
	SCL = 1;
	somenop;
	SDA = 0;
	somenop;
	SCL = 0;	
}

//总线停止条件
void IIC_Stop(void)
{
	SDA = 0;
	SCL = 1;
	somenop;
	SDA = 1;
}
/*IIC总线协议规定,每传送一个字节数据后,都要有一个应答信号,以确定数据传送是否被对方收到,
应答信号由接收设备产生,在SCL为高电平期间,接收设备将SDA拉为低电平表示数据传输正确,即产生了应答。*/
//应答位控制
void IIC_Ack(unsigned char ackbit)	 //当ackbit为1时,表示单片机对从设备发送来数据的应答
                          //当ackbit为0时,表示主机接收了最后一个字节,因此不再应答,结束通信
{
	if(ackbit) 
	{	
		SDA = 0;
	}
	else 
	{
		SDA = 1;
	}
	somenop;
	SCL = 1;
	somenop;
	SCL = 0;
	SDA = 1; 
	somenop;
}

//等待应答
bit IIC_WaitAck(void)
{
	SDA = 1;
	somenop;
	SCL = 1;
	somenop;
	if(SDA)    //在SCL为高电平期间,因为接收设备未将SDA拉低,所以默认未接收到应答,结束IIC通信
	{   
		SCL = 0;
		IIC_Stop();
		return 0;
	}
	else  		//接收到应答,返回1,继续下一个数据字节的传输
	{ 
		SCL = 0;
		return 1;
	}
}

//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{   
		if(byt&0x80) 
		{	
			SDA = 1;
		}
		else 
		{
			SDA = 0;
		}
		somenop;
		SCL = 1;
		byt <<= 1;
		somenop;
		SCL = 0;
	}
}

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
	unsigned char da;
	unsigned char i;
	
	for(i=0;i<8;i++)
	{   
		SCL = 1;
		somenop;
		da <<= 1;
		if(SDA) 
		da |= 0x01;
		SCL = 0;
		somenop;
	}
	return da;
}

void Write_24c02(unsigned char addr,unsigned char dat)
{
  IIC_Start();
  IIC_SendByte(0xa0);
  IIC_WaitAck();
  IIC_SendByte(addr);
  IIC_WaitAck();
  IIC_SendByte(dat);
  IIC_WaitAck();
  IIC_Stop();
}

unsigned char Read_24c02(unsigned char dat)
{
  unsigned char temp;
  IIC_Start();
  IIC_SendByte(0xa0);
  IIC_WaitAck();
  IIC_SendByte(dat);
  IIC_WaitAck();

  IIC_Start();
  IIC_SendByte(0xa1);
  IIC_WaitAck();
  temp=IIC_RecByte();
  IIC_Ack(0);
  IIC_Stop();

  return temp;
}

你可能感兴趣的:(蓝桥杯)