蓝桥杯单片机:基于超声波的使用模拟赛题

 

97c693d641d1469f9992624806e76729.jpeg0aa95c800e694ffd864492e1f74ff534.jpeg

main.c

#include <STC15F2K60S2.H>
#include "intrins.h"
#include "stdio.h"
#include "MCU_init.h"
#include "iic.h"
#include "key4.h"

#define SET_VALUE(X,Y) {P0=X;P2=(P2&=0X1F)|(Y<<5);P2&=0X1F;}	//宏定义
#define uint unsigned int
#define uchar unsigned char
	
extern unsigned char shift_state;	//外部变量
extern unsigned char mode;
int num[4]={15,0,30,26};	//定义显示初值
uint count=0;	//计时器计时
uchar value[9]={0},tran[8]={0},wei=0;
uchar light=0,temperature=0;	
uchar position=0;
bit adc_flag=0;	//adc开始标志位
bit light_flag=0,temperature_flag=0;	//LED亮灯标志位
bit blight_flag=0;	//数码管闪烁标志位
bit relay_flag=0;	//继电器亮标志位

void Delay5ms()		//@12.000MHz
{
	unsigned char i, j;

	i = 59;
	j = 90;
	do
	{
		while (--j);
	} while (--i);
}

void Delay500ms()		//@12.000MHz
{
	unsigned char i, j, k;
	_nop_();
	_nop_();
	i = 23;
	j = 205;
	k = 120;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

/******蜂鸣器函数******/
void bell_2times()
{
	SET_VALUE(0x40,5);
	Delay500ms();
	SET_VALUE(0x00,5);
	Delay500ms();
	SET_VALUE(0x40,5);
	Delay500ms();
	SET_VALUE(0x00,5);
	Delay500ms();
}

/******翻译函数******/
void translate(uchar *value,uchar *tran)
{
	uchar i,j,temp;	//temp用于保存中间量
	for(i=0,j=0;i<8;i++,j++)
	{
		switch(value[j])	//翻译value里的字符值
		{
			case '0':temp=0xc0;break;
			case '1':temp=0xf9;break;
			case '2':temp=0xa4;break;
			case '3':temp=0xb0;break;
			case '4':temp=0x99;break;
			case '5':temp=0x92;break;
			case '6':temp=0x82;break;
			case '7':temp=0xf8;break;
			case '8':temp=0x80;break;
			case '9':temp=0x90;break;
			case 'A':temp=0x88;break;
			case 'B':temp=0x83;break;
			case 'C':temp=0xc6;break;
			case 'D':temp=0xa1;break;
			case 'E':temp=0x86;break;
			case 'F':temp=0x8e;break;
			case 'H':temp=0x89;break;
			case 'L':temp=0xc7;break;
			case 'N':temp=0xc8;break;
			case 'P':temp=0x8c;break;
			case 'U':temp=0xc1;break;
			case '-':temp=0xbf;break;
			case ' ':temp=0xff;break;
			default:temp=0xff;break;
		}
		if(value[j+1]=='.')	//小数点显示
		{
			temp &= 0x7f;
			j++;
		}
		tran[i]=temp;	//将value保存字符串翻译后赋给tran数组保存
	}
}

/******显示函数******/
void display(uchar *tran,uchar wei)
{
	P0 = 0xff;	//将数码管段码清零
	P2 = P2 & 0x1f | 0xe0;	//选通Y7,赋予段码清零信号,消影
	P2 = P2 & 0X1f;	//关闭锁存器
	P0 = 0x01 << wei;	//位选左移1位
	P2 = P2 & 0x1f | 0xc0;	//选通Y6,赋予位选信号
	P2 = P2 & 0X1f;	//关闭锁存器
	P0 = tran[wei];	//
	P2 = P2 & 0x1f | 0xe0;	//打开Y7,赋予段码信号
	P2 = P2 & 0x1f;	//关闭锁存器
}

/******定时器1初始化******/
void Timer1Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0xBF;		//定时器时钟12T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0x18;		//设置定时初始值
	TH1 = 0xFC;		//设置定时初始值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	ET1 = 1;
	EA = 1;
}

/******定时器1中断服务函数******/
void Timer1()	interrupt 3
{
	count++;
	display(tran,wei);
	if(++wei==8)
		wei=0;
	if(relay_flag==1)		//继电器开启
		P0=0x10;P2=P2&0x1f|0xa0;P2=P2&0x1f;
	if(relay_flag==0)		//继电器断开
		P0=0x00;P2=P2&0x1f|0xa0;P2=P2&0x1f;
	if(light_flag)	//LED点亮
	{
		light_flag=0;
		switch((uint)(light/28.0))
		{
			case 0:{P0=0x00;P2=P2&0x1f|0x80;P2 = P2&0x1f;}break;
			case 1:{P0=0x80;P2=P2&0x1f|0x80;P2 = P2&0x1f;}break;
			case 2:{P0=0xc0;P2=P2&0x1f|0x80;P2 = P2&0x1f;}break;
			case 3:{P0=0xe0;P2=P2&0x1f|0x80;P2 = P2&0x1f;}break;
			case 4:{P0=0xf0;P2=P2&0x1f|0x80;P2 = P2&0x1f;}break;
			case 5:{P0=0xf8;P2=P2&0x1f|0x80;P2 = P2&0x1f;}break;
			case 6:{P0=0xfc;P2=P2&0x1f|0x80;P2 = P2&0x1f;}break;
			case 7:{P0=0xfe;P2=P2&0x1f|0x80;P2 = P2&0x1f;}break;
			case 8:{P0=0xff;P2=P2&0x1f|0x80;P2 = P2&0x1f;}break;
		}
	}
	if(count%20==0)		//独立按键扫描
		key4();		
	if(count%200==0)	//adc读取
	{
		adc_flag=1;
	}
	if(count%300==0)	//数码管闪烁
		blight_flag=~blight_flag;
}

/******设置函数******/
void set()
{
	position=0;	//每次进入设置状态,位置从0开始
	while(!mode)	//当设置模式时
	{
		switch(shift_state)	//确定按键键值
		{
			case 2:{position++;if(position==4)position=0;shift_state=-1;}break;	//S6按下,向右移一位
			case 3:{num[position]++;shift_state=-1;}break;	//调参位加1
			case 4:{num[position]--;shift_state=-1;}break;	//调参位减1
			default:break;
		}
		switch(position)	//确认位置
		{
			case 0:{if(num[0]>25)num[0]=25;if(num[0]<15)num[0]=15;}break;	//第一页最高值在15-25之间
			case 1:{if(num[1]>10)num[1]=10;if(num[1]<0)num[1]=0;}break;	//第一页最低值在0-10之间
			case 2:{if(num[2]>50)num[2]=50;if(num[2]<30)num[2]=30;if(num[2]<num[3])num[2]=num[3];}break;	//第二页最高值在30-50之间且不能低于最低值
			case 3:{if(num[3]>32)num[3]=32;if(num[3]<26)num[3]=26;if(num[2]<num[3])num[3]=num[2];}break;	//第二页最低值在26-32之间且不能高于最高值
		}
		if(position/2==0)	//第一页
		{
			if(position%2==1)	//最低值闪烁
			{
				if(blight_flag==1)
				{
					sprintf(value,"1-H%2dL  ",num[0]);
					translate(value,tran);
				}
				if(blight_flag==0)
				{
					sprintf(value,"1-H%2dL%2d",num[0],num[1]);
					translate(value,tran);
				}
			}
			if(position%2==0)	//最高值闪烁
			{
				if(blight_flag==1)
				{
					sprintf(value,"1-H  L%2d",num[1]);
					translate(value,tran);
				}
				if(blight_flag==0)
				{
					sprintf(value,"1-H%2dL%2d",num[0],num[1]);
					translate(value,tran);
				}
			}
		}
		if(position/2==1)	//第二页
		{
			if(position%2==1)	//最低值闪烁
			{
				if(blight_flag==1)
				{
					sprintf(value,"2-H%2dL  ",num[2]);
					translate(value,tran);
				}
				if(blight_flag==0)
				{
					sprintf(value,"2-H%2dL%2d",num[2],num[3]);
					translate(value,tran);
				}
			}
			if(position%2==0)	//最高值闪烁
			{
				if(blight_flag==1)
				{
					sprintf(value,"2-H  L%2d",num[3]);
					translate(value,tran);
				}
				if(blight_flag==0)
				{
					sprintf(value,"2-H%2dL%2d",num[2],num[3]);
					translate(value,tran);
				}
			}
		}
	}
	AT24c02_W(0,num[0]);	//AT24C02保存
	Delay5ms();
	AT24c02_W(1,num[1]);
	Delay5ms();
	AT24c02_W(2,num[2]);
	Delay5ms();
	AT24c02_W(3,num[3]);
	Delay5ms();
}

void work()	//工作模式
{
		if(adc_flag)
		{
			light=ADC(0x03);	//读取光敏值
			light_flag=1;
			temperature=ADC(0x01);	//读取温度
			if(temperature==255)
				temperature-=1;
			adc_flag=0;
		}
			sprintf(value,"C-%2dL-%02d",(uint)(temperature/5.0),(uint)(light/28.0));
			translate(value,tran);
		if(temperature>=num[1]*5&&temperature<=num[0]*5)	//温度在最大值和最小值之间,模拟电压
			DAC((unsigned char)(255/(num[0]-num[1])*(num[0]-temperature/5)));
		else if(temperature>num[0]*5)	//温度超过最大值输出5V
			DAC(0);
		else if(temperature<num[1]*5)	//温度低于最小值输出0V
			DAC(255);
		if((temperature/5)>num[2])	//温度大于第二页最高值继电器打开
			relay_flag=1;
		else		//低于时继电器断开
			relay_flag=0;
}

void main()
{
	MCU_init();	//单片机初始化函数
	bell_2times();	//蜂鸣器响2次
	Timer1Init();	//定时器1初始化
	num[0]=AT24c02_R(0);	//AT24C02上电读取
	Delay5ms();
	num[1]=AT24c02_R(1);
	Delay5ms();
	num[2]=AT24c02_R(2);
	Delay5ms();
	num[3]=AT24c02_R(3);
	Delay5ms();
	while(1)
	{
		switch(mode)	//扫描模式
		{
			case 0:set();break;	//设置参数模式
			case 1:work();break;	//工作模式
			default:break;
		}
	}
}

MCU_init.c

#include <STC15F2K60S2.H>

void MCU_init()
{
	P2 = P2 & 0x1f | 0x80;P0 = 0xff;		//打开锁存器Y4,关闭LED灯
	P2 = P2 & 0x1f;
	P2 = P2 & 0x1f | 0xa0;P0 = 0x00;		//打开锁存器Y5,关闭继电器和蜂鸣器
	P2 = P2 & 0x1f;
	P2 = P2 & 0x1f | 0xc0;P0 = 0x00;		//打开锁存器Y6,清楚锁存器中数码管位选信号
	P2 = P2 & 0x1f;
	P2 = P2 & 0x1f | 0xe0;P0 = 0xff;		//打开锁存器Y7,清楚锁存器中数码管段码信号
	P2 = P2 & 0x1f;
}

 key4.c

#include <STC15F2K60S2.H>
#include "key4.h"

sbit S7 = P3^0;
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;

unsigned char shift_state=0;
unsigned char key4_scan=0;
unsigned char shift_times=0;
unsigned char mode=1;
void key4()
{
	if(key4_scan==0)	//第一次扫描
	{
	  if((P3&0x0f) != 0x0f)
		{			
		key4_scan=1;
		}
  }
	else if(key4_scan==1)	//第二次扫描
	{
		if((P3&0x0f) != 0x0f) 
		{
			if(S7==0)
			{
				shift_times++;
				switch(shift_times%2)
				{
					case 0:{mode=1;};break;
					case 1:{mode=0;};break;
				}
				if(shift_times>=100)
					shift_times=0;
				key4_scan=2;
			}		
			else if(S6==0)
			{
				shift_state=2;
				key4_scan=2;
			}		
			else if(S5==0)
			{
				shift_state=3;
				key4_scan=2;
			}	
			else if(S4==0)
			{
				shift_state=4;
				key4_scan=2;
		  }
			else
			{
				shift_state=4;
				key4_scan=0;
			}			
	 }
 }
  else if(key4_scan==2)	//第三次扫描
	{
		if((P3&0x0f)==0x0f)
		{
			key4_scan=0;
		}
	}
}

 iic.c

#include <STC15F2K60S2.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;    
}

unsigned char ADC(unsigned char Ain)
{
	unsigned char dat;
	IIC_Start();
	IIC_SendByte(0x90); //写
	IIC_WaitAck();
	IIC_SendByte(Ain|0x40);
	IIC_WaitAck();
	IIC_Stop();
	
	IIC_Start();
	IIC_SendByte(0x91); //读
	IIC_WaitAck();
//	IIC_RecByte();
//	IIC_SendAck(0);
	dat=IIC_RecByte();
	IIC_SendAck(1);
	IIC_Stop();
	
	return dat;
}

void DAC(unsigned char dat)
{
	IIC_Start();
	IIC_SendByte(0x90); //写
	IIC_WaitAck();
	IIC_SendByte(0x43);
	IIC_WaitAck();
	IIC_SendByte(dat);
	IIC_WaitAck();
	IIC_Stop();
}

void AT24c02_W(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 int AT24c02_R(unsigned char addr)
{
	unsigned int dat;
	IIC_Start();
	IIC_SendByte(0xa0); //写
	IIC_WaitAck();
	IIC_SendByte(addr);
	IIC_WaitAck();
	
	IIC_Start();
	IIC_SendByte(0xa1); //读
	IIC_WaitAck();
	dat=IIC_RecByte();
	IIC_SendAck(1);
	IIC_Stop();
	
	return dat;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值