2020-11-13

**

@蓝桥杯单片机设计第八届国赛超声波测距

题目
提取码:asdf

**

代码:

1、main.c

#include "STC15F2K60S2.H"
#include "key.h"
#include "ultrasonic.h"
#include "iic.h"


#define u8 unsigned char
#define u16 unsigned int


/*
	*@
	*@ 函 数 声 明 区 
	*@
*/
void system_init();
void timer_0_init();
void read_save_dat();
void key_processing();
void smg_display(unsigned char what[]);
void led_processing();
void Delay10ms();

/*
	*@
	*@ 变 量 定 义 区 
	*@
*/

u8 code smg_duan[]={                       //标准字库
//   0    1    2    3    4    5    6    7    8    9   
    0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,
    0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x00,0x40,0x39,0x71};    
   //0.    1.   2.   3.   4.  5.   6.    7.   8.  9.    灭   -   C	 01110001

u8 code smg_wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};      //位码
/*
test_display[] 是 测距显示的 第一个界面
dat_huixian[]  是 数据回显的 第二个界面
test_deadArray[] 是 盲区
the_distance_4[] 第一个元素没有用,1到4分别对应4次的测量、
smg_buff[] 是数码缓冲数组
key_vaule 是按下按键所返回的值 取值为 4,5,6,7 或者 0(见key.c文件的 void key_btn() )
menu_index 用于界面切换 ,本题共有三个界面要显示 取值为 0 1 2
Dis_index 所以测量的四次结果  yiwei 用于 当测量次数 超过4次,覆盖测量的数据
current_dis 当前测量的距离  last_dis 上一次测量的距离 
tes_dead 盲区距离
led1_count 测量完成后,每一秒加一,直到加到6(亮灭三次 共 6s)
count_1000ms 每1ms 从0开始加,加到1000 表示1s到	 , 初值为 1000 即 测量完成 led是 先 亮
flag_1s 用于测量完成后,led间隔1s 亮灭的使能控制 finish_En 每次测量完成的标志,
*/
u8 test_display[8] = {22,20,20,20,20,20,20,20} ;
u8 dat_huixian[8]  = {20,20,20,20,20,20,20,20} ;
u8 test_deadArray[8] = {23,20,20,20,20,20,20,20};

u8 the_distance_4[5] = {0,0,0,0,0};
u8 smg_buff[8];
u8 key_vaule = 0 ;
u8 menu_index = 0 ;
u8 Dis_index = 1 , yiwei = 0;
u8 current_dis = 0 , last_dis = 0 ;
u8 tes_dead = 20 ;
u8 led1_count = 0 ;
u16  count_1000ms = 1000 ;
bit flag_1s = 0 , finish_En = 0;

/*
	*@
	*@ 主 程 序
	*@
*/
void main()
{
	read_save_dat();
	system_init();
	timer_0_init();

	while(1)
	{
		 // 界面0 测量数据 界面
		 test_display[2] = 	current_dis / 100; test_display[3] = 	current_dis / 10 % 10; test_display[4] = 	current_dis % 10;
		 test_display[5] = 	last_dis / 100;    test_display[6] = 	last_dis / 10 % 10;    test_display[7] = 	last_dis % 10;
		
		 // 界面1 数据回显
		 dat_huixian[0] = Dis_index ;  
		 
		 /*
		  以下的 5 - Dis_index ,关于是否有 5 - 看是想显示第一次测量、第二次测量.......
		  	还是显示 最近一次测量、最近第二次测量............
		 */
		 dat_huixian[5] = the_distance_4[5-Dis_index] / 100 ;dat_huixian[6] = the_distance_4[5-Dis_index] / 10 % 10 ;
		 dat_huixian[7] = the_distance_4[5-Dis_index] % 10 ;
		 
		 // 界面2 盲区
		 test_deadArray[6] =  tes_dead / 10;   test_deadArray[7] =  tes_dead % 10;
		 
	}
}
/*
	*@
	*@ 定 时 器 0 中 断 服 务 子  程 序 
	*@
*/
void timer_0_processing() interrupt 1
{
	static int count_2ms = 0 , count_10ms = 0  ; 
	count_2ms++; count_10ms++;	

	if(finish_En == 1)
	{
		if(count_1000ms >= 1000)
		{
			led1_count++;
			count_1000ms = 0 ;
			flag_1s = !flag_1s ;
		} 
		count_1000ms++ ;
	}

	if(count_2ms == 2)
	{
		count_2ms = 0 ;
		smg_display(smg_buff); // 2ms 扫面一次数码管
		led_processing();	   // led 显示
	}
	if(count_10ms == 10)	 // 10ms 扫描一次按键函数 , 写 DA  
	{
		count_10ms = 0 ;
		key_processing();

		if(current_dis <= tes_dead )
		{
			write_dac(0);
		}
		else
		{
			if( ( (current_dis - tes_dead)*0.02 + 0.04) * 51 > 255) 
			{
				write_dac(255);
			}
			write_dac(( (current_dis - tes_dead)*0.02 + 0.04)*51);
		}
	}
	
}
/*
	*@
	*@ 按 键  子  程 序
	*@
*/
void key_processing()
{
	u8 EEPROM_index = 0 ;
	key_vaule = key_btn();
	switch(key_vaule)
	{
		case(4):last_dis = 	current_dis ;	// 将本次数据给上次数据 然后再次测量获得本次数据
				current_dis = sonic_wave();
				finish_En = 1 ;led1_count = 0 ;	// 测量完成 ,相应的控制位 赋值 ,
				count_1000ms = 1000 ;
				// 实 现 数 据 覆 盖
				for(yiwei = 3 ; yiwei > 0 ; yiwei--)
				{
					the_distance_4[yiwei + 1] = the_distance_4[yiwei] ;
				}

				the_distance_4[1] = current_dis ;

				// 将 数 据 保 存 到 ROM
				for(EEPROM_index = 1 ; EEPROM_index < 5 ; EEPROM_index++)
		 		{
		 			write_24c02(EEPROM_index,the_distance_4[EEPROM_index]);
					Delay10ms();
				}
				 
				break;
		case(5):if(menu_index == 0)
				{	
					Dis_index = 1 ; // 每次界面从 测量进入回显 ,都从第一个下标开始
					menu_index = 1;
				}
				else if(menu_index == 1)
						menu_index = 0 ;		 
				break;
		case(6):if(menu_index != 2 )
				{
					menu_index = 2 ;
				}
				else
				{
					menu_index = 0 ;	
				}
				break;
		case(7):if(menu_index == 1)
				{
					Dis_index++;
					if(Dis_index == 5)Dis_index = 1 ;
				}
				if(menu_index == 2)
				{
					tes_dead += 10 ;
					if(tes_dead >= 40)tes_dead = 0 ;

					write_24c02(5,tes_dead);
					Delay10ms();
				}
				break;
	}
}
/*
	*@
	*@ 显 示子 程 序
	*@
*/
void smg_display(unsigned char what[])
{
	static int where = 0 ;
	u8 i ;
	// 根据当前的界面 匹配相应的段码
	for(i = 0 ; i < 8 ; i++)
	{
		switch(menu_index)
		{
			case(0):what[i] = ~smg_duan[test_display[i]];break;
			case(1):what[i] = ~smg_duan[dat_huixian[i]];break;
			case(2):what[i] = ~smg_duan[test_deadArray[i]];break;
		}
	}

	P2 = 0X00 ; P0 = 0 ; P2 = 0XC0;
	P2 = 0X00 ; P0 = smg_wei[where] ; P2 = 0XC0 ;
	P2 = 0X00 ; P0 = what[where] ; P2 = 0XE0 ;
	where++;if(where == 8)where = 0 ;
}

/*
	*@
	*@ led 指示 
	*@
*/
void led_processing()
{
	if(menu_index == 0)
	{ 
		if(led1_count < 6)
		{
		 	if(flag_1s == 1)
			{
				P2 = 0X00 ; P0 = 0Xfe ; P2 = 0X80 ;
			}
			else
			{
				P2 = 0X00 ; P0 = 0xff ; P2 = 0X80 ;	
			}
		}
		else
		{
			led1_count = 0 ;
			finish_En = 0 ; flag_1s = 0 ;
			P2 = 0X00 ; P0 = 0xff ; P2 = 0X80 ;	
		}
	}
	else if(menu_index == 1)
	{
		P2 = 0X00 ; P0 = 0xbf ; P2 = 0X80 ;
	}
	else
	{
		P2 = 0X00 ; P0 = 0x7f ; P2 = 0X80 ;
	}	
}
/*
	*@
	*@  初 始 化
	*@
*/
void timer_0_init()
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x20;		//设置定时初值
	TH0 = 0xD1;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时

	ET0 = 1 ;
	EA = 1 ;
}
void system_init()
{
	
	P2 = 0X00 ; P0 = 0XFF ; P2 = 0X80 ;
	P2 = 0X00 ; P0 = 0X00 ; P2 = 0XA0 ;
}

void read_save_dat()
{
	tes_dead = read_24c02(5);
	the_distance_4[1] = read_24c02(1);
	the_distance_4[2] = read_24c02(2);
	the_distance_4[3] = read_24c02(3);
	the_distance_4[4] = read_24c02(4);
}
void Delay10ms()		//@12.000MHz
{
	unsigned char i, j;

	i = 117;
	j = 184;
	do
	{
		while (--j);
	} while (--i);
}

2 、key.c

#include "key.h"


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

unsigned char key_btn()
{
	static char key_state =  key_state0 ;
	unsigned char key_press,key_return = 0 ;

	if(P33 == 0)key_press = 0X07 ;
	else if(P32 == 0)key_press = 0X0b ;
	else if(P31 == 0)key_press = 0X0d ;
	else if(P30 == 0)key_press = 0X0e ;
	else key_press = 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 == 0x07)key_return = 4 ;
							if(key_press == 0x0b)key_return = 5 ;
							if(key_press == 0x0d)key_return = 6 ;
							if(key_press == 0x0e)key_return = 7 ;

							key_state = key_state2 ;

						 }
						 else
						 {
						 	key_state = key_state0 ;
						 }
						 break;
		case(key_state2):if(key_press == 0x0f)
						 {
						 	key_state = key_state0 ;
						 }
						 break ;
	}

	return key_return ;

}

3 、iic.c

#include "iic.h"
#include "intrins.h"

#define DELAY_TIME 5

#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1

//总线引脚定义
sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */

void IIC_Delay(unsigned char i)
{
    do{_nop_();}
    while(i--);        
}
//总线启动条件
void IIC_Start(void)
{
    SDA = 1;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 0;
    IIC_Delay(DELAY_TIME);
    SCL = 0;	
}

//总线停止条件
void IIC_Stop(void)
{
    SDA = 0;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}
/*
//发送应答
void IIC_SendAck(bit ackbit)
{
    SCL = 0;
    SDA = ackbit;  					// 0:应答,1:非应答
    IIC_Delay(DELAY_TIME);
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SCL = 0; 
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}
*/

//等待应答
bit IIC_WaitAck(void)
{
    bit ackbit;
	
    SCL  = 1;
    IIC_Delay(DELAY_TIME);
    ackbit = SDA;
    SCL = 0;
    IIC_Delay(DELAY_TIME);
    return ackbit;
}

//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
    unsigned char i;

    for(i=0; i<8; i++)
    {
        SCL  = 0;
        IIC_Delay(DELAY_TIME);
        if(byt & 0x80) SDA  = 1;
        else SDA  = 0;
        IIC_Delay(DELAY_TIME);
        SCL = 1;
        byt <<= 1;
        IIC_Delay(DELAY_TIME);
    }
    SCL  = 0;  
}

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

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

unsigned char read_24c02(unsigned char address)
{
	unsigned char temp = 0 ;

	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	IIC_SendByte(address);
	IIC_WaitAck();

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

}

void write_dac(unsigned char dat)
{
	unsigned char temp = 0 ;

	IIC_Start();
	IIC_SendByte(0x90);
	IIC_WaitAck();
	IIC_SendByte(0x40);
	IIC_WaitAck();
	IIC_SendByte(dat);
	IIC_WaitAck();
	IIC_Stop();
}

4、ultrasonic.c

#include "ultrasonic.h"
#include "intrins.h"

void Delay12us()		//@12.000MHz
{
	unsigned char i;

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


void send_wave(unsigned char how_many)
{
	unsigned char i;

	TX = 0 ;

	for(i = 0 ; i < how_many ; i++)
	{
		TX = !TX ;
		Delay12us();
	}
}

unsigned char sonic_wave()
{
	unsigned char DIS ;

	AUXR &= 0XBF ;	// 1011 1111
	TMOD &= 0X0F;
	TF1 = 0 ;
	TR1 = 0 ;
	TH1 = 0 ;
	TL1 = 0 ;
	ET1 = 0; 

	send_wave(4);
	TR1 = 1 ;
	EA = 0 ;
	while((RX == 1)&&(TF1 == 0));
	TR1 = 0 ;
	EA = 1 ;
	if(TF1 == 1)
	{
		TF1 = 0;
		DIS = 255;
	}
	else
	{
		DIS = ( (TH1<<8) | TL1 )* 0.017 ;
	}

	return DIS;
}

注:相应的头文件就是把需要用到的函数声明一下,头文件的格式就是
#如果没有定义 xxx
#那就定义 xxx
#include “STC15F2K60S2.H”
包含需要调用的函数

#endif
这里空一行
另外超声波里定义了引脚
见下:

#ifndef _ULTRESONIC_H
#define	_ULTRESONIC_H


#include "STC15F2K60S2.H"

sbit TX = P1^0 ;
sbit RX = P1^1 ;

unsigned char sonic_wave();

#endif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值