蓝桥杯单片机第十四届省赛代码(有注释)

蓝桥杯单片机第十四届省赛代码(有注释
首先对我的代码进行一下说明,由于现在官方对于底层驱动代码不再提供头文件,所以我对底层驱动代码的调用函数时直接写在对应的.c文件中的。都是在对应.c的最后面。
当然我的代码还有几处缺陷我会在最后面指出。

源代码

main.c

#include<reg52.h>
#include<ds1302.h>
#include<iic.h>
#include<onewire.h>
#include<smg.h>

sfr P4 = 0xc0;

sbit C3 = P3^2;
sbit C4 = P3^3;
sbit R1 = P4^4;
sbit R2 = P4^2;

sbit L1 = P0^0;
sbit L2 = P0^1;
sbit L3 = P0^2;
sbit L4 = P0^3;
sbit L5 = P0^4;
sbit L6 = P0^5;

unsigned int count_f = 0;//对NE555产生的信号进行计数
unsigned int Frequency = 0;//记录频率
unsigned char x = 0;//界面切换标志,0-2依次是时间、回显、参数
unsigned char y = 0;//回显界面切换标志,0-2依次是温度、湿度、时间
unsigned char time_flag;//长按计时标志

unsigned char time[3] = {0x13,0x03,0x05};//时间
unsigned char Temperature = 0;   //温度
unsigned char Humidity = 0;      //湿度
unsigned char Temperature_temp = 0;   //临时温度,用于记录采集的温度
unsigned char Humidity_temp = 0;      //临时湿度,用于记录采集的湿度
char Ad = 0;            //亮度
char Ad_Temp = 0;       //亮度临时值,用于判断是否进行挡光
unsigned char Par = 30;//温度参数

unsigned int T[2] = {0};   //温度采集记录T[0]为采集次数,T[1]为采集温度之和
unsigned int H[2] = {0};   //湿度采集记录,同上

unsigned char MaxTemp = 0;//最大温度
float AvgTemp = 0;        //平均温度
unsigned char MaxHum = 0;//最大湿度
float AvgHum = 0;        //平均温度

bit Ad_flag;     //1为亮度临时值更新
bit collection;  //1为进行一次采集
bit con_flag;    //1为进入温湿度界面
bit L4_flag;     //0为点亮L4

void InitSystem()
{
	SelectHC573(5);
	P0 = 0x00;//关闭蜂鸣器继电器
	SelectHC573(4);
	P0 = 0xff;//关闭led灯
	SelectHC573(0);
	
	TMOD = 0x16;
	TH0 = 0xff;//Timer0为计数器
	TL0 = 0xff;
	TH1 = (65536 - 1000) / 256;//Timer1为1ms定时器
	TL1 = (65536 - 1000) % 256;
	
	TR0 = 1;
	TR1 = 1;
	ET0 = 1;
	ET1 = 1;
	EA = 1;
}
//键盘去抖动的延时函数
void DelayKey(unsigned char t)  
{
	while(t--);
}
 //湿度读取
void Measure_Humidity()   
{
	if(Frequency < 200)
		Humidity = 0;
	else if(Frequency <= 2000)
		Humidity =(unsigned char)(((float)Frequency) * 0.044 + 1.111); 
	else 
		Humidity = 0;
}
//只更改某个led灯的函数
void Select_Lx(unsigned char Lx,n)
{
	if(n)
	{
		SelectHC573(4);
		P0 = P0 | 0x01 << (Lx - 1); 
		SelectHC573(0);
	}		
	else
	{
		SelectHC573(4);
		P0 = P0 & ~(0x01 << (Lx - 1));
		SelectHC573(0);
	}
}
//采集
void Gather()
{
	if(!con_flag)//防止多次采集
	{
		if(Ad_Temp - Ad > 50)         //进行一次采集标志
		{
			collection = 1;
			Ad_Temp = Ad_read();
			con_flag = 1;
		}
	}
	if(collection)                //采集
	{
		collection = 0;
		if(T[1] == 0)MaxTemp = Temperature;//第一次采集特殊处理
		else if(MaxTemp < Temperature)MaxTemp = Temperature;
		
		if(H[1] == 0)MaxHum = Humidity;
		else if(MaxHum < Humidity)MaxHum = Humidity;
		
		T[1] += Temperature;  //温度
		T[0] ++;
    if(Humidity > 0)            //湿度
		{
			H[1] += Humidity;
			H[0] ++;
		}
		AvgTemp = (float)T[1] / (float)T[0];
		AvgHum = (float)H[1] / (float)H[0];
		//采集无效
		if(Temperature > Temperature_temp && Humidity > Humidity_temp && H[0] > 1)
			Select_Lx(6,0);
		else 
			Select_Lx(6,1);
		//用于温湿度界面显示
		Temperature_temp = Temperature;
		if(Humidity  == 0)Humidity_temp = 1;//采集无效,用于区分没有采集
		else Humidity_temp = Humidity;
	}
	
		if(Ad_flag)        //0.4秒更新一次亮度临时值
	{
		Ad_flag = 0;              
		Ad_Temp = Ad_read();
	}
}
//防止上电85
void Delay750ms()	
{
	unsigned char data i, j, k;

	i = 35;
	j = 51;
	k = 182;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
//数码管显示
void Display()        
{
	if(con_flag)//温湿度界面
		Temperature_Humidity(Temperature_temp,Humidity_temp);
	else if(x == 0)
		Time(time);
	else if(x == 1)
		{
			if(y == 0)
				Echo_Temperature(MaxTemp,AvgTemp);
			else if(y == 1)
				Echo_humidity(MaxHum,AvgHum);
			else
				Echo_Time(T[0],time);
		}
		else
			Parameter(Par);
}
//键盘扫描
void KeyScan()        
{
	C3 = 0;C4 = 1;
	if(R1 == 0 && x == 1)      //S5
	{
		DelayKey(20);
		if(R1 == 0)
		{
			if(++y == 3)y = 0;
			while(R1 == 0)Display();
		}
	}
	if(R2 == 0)            //S9
	{
		DelayKey(20);
		if(R2 == 0)
		{
			time_flag = 1;//进行2s计时
			if(x == 2 && Par > 0)Par--;
			while(R2 == 0)
			{
				Display();
				if(time_flag == 2)//长按2秒,清除
				{
					time_flag = 0;
					MaxTemp = 0;AvgTemp = 0;
          MaxHum = 0;AvgHum = 0;
					T[0] = 0;T[1] = 0;
					H[0] = 0;H[1] = 0;
					Humidity_temp = 0;
					Temperature_temp = 0;
				}
			}
			if(time_flag == 1)time_flag = 0;
		}
	}

	C3 = 1;C4 = 0;
	if(R1 == 0)        //S4
	{
		DelayKey(20);
		if(R1 == 0)
		{
			if(++x == 3)x = 0;
			while(R1 == 0)Display();
		}
	}
	if(R2 == 0)       //S8
	{
		DelayKey(20);
		if(R2 == 0)
		{
			if(x == 2 && Par < 99)Par++;
			while(R2 == 0)Display();
		}
	}
}
//led灯状态改变
void led()
{
	if(x == 0 && con_flag == 0)  //L1
		Select_Lx(1,0);
	else 
		Select_Lx(1,1);
	
	if(x == 1 && con_flag == 0)  //L2
		Select_Lx(2,0);
	else 
		Select_Lx(2,1);
	
	if(con_flag)          //L3
		Select_Lx(3,0);
	else 
		Select_Lx(3,1);
	
	if(Temperature_temp > Par)  //L4
	{
		if(L4_flag)
	   	Select_Lx(4,0);
		else 
			Select_Lx(4,1);
	}
	
	if(Humidity_temp == 1)    //L5
		Select_Lx(5,0);
	else
		Select_Lx(5,1);
	
	Select_Lx(7,1);
	Select_Lx(8,1);
	
	//为了不在增加变量,将L6写在了采集函数中
}

void main()
{
	InitSystem();//
	Write_time(time);//初始化时间
	Ad_Temp = Ad_read();//初始化亮度
	Read_temperature();
	Delay750ms();//防止上电85
	while(1)
	{
		Temperature = (unsigned char)Read_temperature();//温度读取
		Read_time(time);                                //时间读取
		Measure_Humidity();                             //湿度读取
		Ad = Ad_read();                                 //光暗读取
		Gather();                                       //采集
	  KeyScan();                                      //键盘扫描
		Display();                                      //数码管显示
		led();                                          //led状态更改
	}
}
//计数器0
void Service_Timer0() interrupt 1
{
	count_f++;
}
//定时器1,定时1ms
void Service_Timer1() interrupt 3
{
	unsigned int i0,i1,i2,i3,i4;
	TH1 = (65536 - 1000) / 256;
	TL1 = (65536 - 1000) % 256;
	
	if(++i0 == 1000)//频率计时
	{
		Frequency = count_f;
		count_f = 0;
		i0 = 0;
	}
	
	if(++i1 == 400)//亮度临时值计时
	{
		i1 = 0;
		Ad_flag = 1;
	}
	if(con_flag)       //温湿度界面计时
	{
		if(++i2 == 3000)
		{
			con_flag = 0;
			i2 = 0;
		}
	}
	if(time_flag == 1)    //长按计时
	{
		if(++i3 == 2000)
		{
			i3 = 0;
			time_flag = 2;
		}
	}
	
	if(++i4 == 100)     //L4闪烁
	{
		i4 = 0;
		L4_flag = ~L4_flag;
	}
}

iic.c

#include<reg52.h>
#include<intrins.h>

sbit sda = P2^1;
sbit scl = P2^0;


#define DELAY_TIME	5

//
static void I2C_Delay(unsigned char n)
{
    do
    {
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();		
    }
    while(n--);      	
}

//
void I2CStart(void)
{
    sda = 1;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 0;
	I2C_Delay(DELAY_TIME);
    scl = 0;    
}

//
void I2CStop(void)
{
    sda = 0;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 1;
	I2C_Delay(DELAY_TIME);
}

//
void I2CSendByte(unsigned char byt)
{
    unsigned char i;
	
    for(i=0; i<8; i++){
        scl = 0;
		I2C_Delay(DELAY_TIME);
        if(byt & 0x80){
            sda = 1;
        }
        else{
            sda = 0;
        }
		I2C_Delay(DELAY_TIME);
        scl = 1;
        byt <<= 1;
		I2C_Delay(DELAY_TIME);
    }
	
    scl = 0;  
}

//
unsigned char I2CReceiveByte(void)
{
	unsigned char da;
	unsigned char i;
	for(i=0;i<8;i++){   
		scl = 1;
		I2C_Delay(DELAY_TIME);
		da <<= 1;
		if(sda) 
			da |= 0x01;
		scl = 0;
		I2C_Delay(DELAY_TIME);
	}
	return da;    
}

//
unsigned char I2CWaitAck(void)
{
	unsigned char ackbit;
	
    scl = 1;
	I2C_Delay(DELAY_TIME);
    ackbit = sda; 
    scl = 0;
	I2C_Delay(DELAY_TIME);
	
	return ackbit;
}

//
void I2CSendAck(unsigned char ackbit)
{
    scl = 0;
    sda = ackbit; 
	I2C_Delay(DELAY_TIME);
    scl = 1;
	I2C_Delay(DELAY_TIME);
    scl = 0; 
	sda = 1;
	I2C_Delay(DELAY_TIME);
}

unsigned char Ad_read()
{
	unsigned char temp;
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	I2CSendByte(0x01);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0x91);
	I2CWaitAck();
	temp = I2CReceiveByte();
	I2CSendAck(1);
	I2CStop();
	
	return temp;
}


iic.h

#ifndef _iic_h_
#define _iic_h_

unsigned char Ad_read();


#endif

###ds1302.c

#include<reg52.h>
#include<intrins.h>

sbit SCK = P1^7;
sbit SDA = P2^3;
sbit RST = P1^3;

//
void Write_Ds1302(unsigned  char temp) 
{
	unsigned char i;
	for (i=0;i<8;i++)     	
	{ 
		SCK = 0;
		SDA = temp&0x01;
		temp>>=1; 
		SCK=1;
	}
}   

//
void Write_Ds1302_Byte( unsigned char address,unsigned char dat )     
{
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1; 	_nop_();  
 	Write_Ds1302(address);	
 	Write_Ds1302(dat);		
 	RST=0; 
}

//
unsigned char Read_Ds1302_Byte ( unsigned char address )
{
 	unsigned char i,temp=0x00;
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1;	_nop_();
 	Write_Ds1302(address);
 	for (i=0;i<8;i++) 	
 	{		
		SCK=0;
		temp>>=1;	
 		if(SDA)
 		temp|=0x80;	
 		SCK=1;
	} 
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
	SCK=1;	_nop_();
	SDA=0;	_nop_();
	SDA=1;	_nop_();
	return (temp);			
}

void Write_time(unsigned char *Timer)
{
	Write_Ds1302_Byte(0x8e,0x80);
	Write_Ds1302_Byte(0x84,Timer[0]);
	Write_Ds1302_Byte(0x82,Timer[1]);
	Write_Ds1302_Byte(0x80,Timer[2]);
	Write_Ds1302_Byte(0x8e,0x00);
}

void Read_time(unsigned char *Timer)
{
	Timer[0] = Read_Ds1302_Byte(0x85);
	Timer[1] = Read_Ds1302_Byte(0x83);
	Timer[2] = Read_Ds1302_Byte(0x81);
}

ds1302.h

#ifndef _ds1302_h_
#define _ds1302_h_

void Write_time(unsigned char *Timer);
void Read_time(unsigned char *Timer);

#endif

onewore.c

#include<reg52.h>

sbit DQ = P1^4;

//
void Delay_OneWire(unsigned int t)  
{
	unsigned char i;
	while(t--){
		for(i=0;i<12;i++);
	}
}

//
void Write_DS18B20(unsigned char dat)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		DQ = 0;
		DQ = dat&0x01;
		Delay_OneWire(5);
		DQ = 1;
		dat >>= 1;
	}
	Delay_OneWire(5);
}

//
unsigned char Read_DS18B20(void)
{
	unsigned char i;
	unsigned char dat;
  
	for(i=0;i<8;i++)
	{
		DQ = 0;
		dat >>= 1;
		DQ = 1;
		if(DQ)
		{
			dat |= 0x80;
		}	    
		Delay_OneWire(5);
	}
	return dat;
}

//
bit init_ds18b20(void)
{
  	bit initflag = 0;
  	
  	DQ = 1;
  	Delay_OneWire(12);
  	DQ = 0;
  	Delay_OneWire(80);
  	DQ = 1;
  	Delay_OneWire(10); 
    initflag = DQ;     
  	Delay_OneWire(5);
  
  	return initflag;
}

float Read_temperature()
{
	unsigned char low,high;
	
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0x44);
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0xbe);
	low = Read_DS18B20();
	high = Read_DS18B20();
	
	return ((high << 8) | low) / 16.0;
}

onewire.h

#ifndef _onewire_h_
#define _onewire_h_

float Read_temperature();


#endif

smg.c(数码管相关代码)

#include<reg52.h>

code unsigned char Seg_Table[] = 
{
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0x88, //A
0x83, //b
0xc6, //C
0xa1, //d
0x86, //E
0x8e //F
};

code unsigned char Seg_point[] = 
{
0x40, //0.
0x79, //1.
0x24, //2.
0x30, //3.
0x19, //4.
0x12, //5.
0x02, //6.
0x78, //7.
0x00, //8.
0x10, //9.
};
//HC573芯片选择
void SelectHC573(unsigned char n)
{
	switch(n)
	{
		case 4:
			P2 = (P0 & 0x1f) | 0x80;
		break;
		case 5:
			P2 = (P0 & 0x1f) | 0xa0;
		break;
		case 6:
			P2 = (P0 & 0x1f) | 0xc0;
		break;
		case 7:
			P2 = (P0 & 0x1f) | 0xe0;
		break;
		case 0:
			P2 = (P0 & 0x1f) | 0x00;
		break;
	}
}

void Delay(unsigned int t)
{
	while(t--);
}
//关闭所有数码管,防止某个数码管过亮
void ShutDown()
{
	SelectHC573(6);
	P0 = 0xff;
	SelectHC573(7);
	P0 = 0xff;
}
//数码管位选和段选
void ShowSMG_byte(unsigned char pos,value)
{
	SelectHC573(7);
	P0 = 0xff;
	SelectHC573(6);
	P0 = 0x01 << pos;
	SelectHC573(7);
	P0 = value;
	
	Delay(200);
}

void Time(unsigned char *Timer)    //时间显示界面
{
	ShowSMG_byte(0,Seg_Table[Timer[0] / 16]);
	ShowSMG_byte(1,Seg_Table[Timer[0] % 16]);
	ShowSMG_byte(2,0xbf);
	
	ShowSMG_byte(3,Seg_Table[Timer[1] / 16]);
	ShowSMG_byte(4,Seg_Table[Timer[1] % 16]);
	ShowSMG_byte(5,0xbf);
	
	ShowSMG_byte(6,Seg_Table[Timer[2] / 16]);
	ShowSMG_byte(7,Seg_Table[Timer[2] % 16]);

	ShutDown();
}

void Echo_Temperature(unsigned char MaxTemp,float AvgTemp)   //温度回显界面
{
	ShowSMG_byte(0,0xc6);
	ShowSMG_byte(1,0xff);
	ShowSMG_byte(2,Seg_Table[MaxTemp / 10]);
	ShowSMG_byte(3,Seg_Table[MaxTemp % 10]);	
	ShowSMG_byte(4,0xbf);

	ShowSMG_byte(5,Seg_Table[(int)AvgTemp / 10]);
	ShowSMG_byte(6,Seg_point[(int)AvgTemp % 10]);
	ShowSMG_byte(7,Seg_Table[(int)(AvgTemp * 10) % 10]);

	ShutDown();
}

void Echo_humidity(unsigned char MaxHum,float AvgHum)   //湿度回显界面
{
	ShowSMG_byte(0,0x89);
	ShowSMG_byte(1,0xff);
	ShowSMG_byte(2,Seg_Table[MaxHum / 10]);
	ShowSMG_byte(3,Seg_Table[MaxHum % 10]);	
	ShowSMG_byte(4,0xbf);

	ShowSMG_byte(5,Seg_Table[(int)AvgHum / 10]);
	ShowSMG_byte(6,Seg_point[(int)AvgHum % 10]);
	ShowSMG_byte(7,Seg_Table[(int)(AvgHum * 10) % 10]);

	ShutDown();
}

void Echo_Time(unsigned char n,unsigned char *Timer)  //时间回显
{
	ShowSMG_byte(0,Seg_Table[15]);
	ShowSMG_byte(1,Seg_Table[n / 10]);
	ShowSMG_byte(2,Seg_Table[n % 10]);
	
	ShowSMG_byte(3,Seg_Table[Timer[0] / 16]);
	ShowSMG_byte(4,Seg_Table[Timer[0] % 16]);
	ShowSMG_byte(5,0xbf);
	ShowSMG_byte(6,Seg_Table[Timer[1] / 16]);
	ShowSMG_byte(7,Seg_Table[Timer[1] % 16]);

	ShutDown();
}

void Parameter(unsigned char parameter)     //参数界面
{
	ShowSMG_byte(0,0x8c);
	ShowSMG_byte(1,0xff);
	ShowSMG_byte(2,0xff);
	ShowSMG_byte(3,0xff);
	ShowSMG_byte(4,0xff);
	ShowSMG_byte(5,0xff);
	ShowSMG_byte(6,Seg_Table[parameter / 10]);
	ShowSMG_byte(7,Seg_Table[parameter % 10]);
	ShutDown();
}

void Temperature_Humidity(unsigned char Temperature,Humidity )//温湿度界面
{
	ShowSMG_byte(0,0x86);
	ShowSMG_byte(1,0xff);
	ShowSMG_byte(2,0xff);
	ShowSMG_byte(3,Seg_Table[Temperature / 10]);
	ShowSMG_byte(4,Seg_Table[Temperature % 10]);
	ShowSMG_byte(5,0xbf);

	if(Humidity < 5)//采集湿度无效
	{
		ShowSMG_byte(6,Seg_Table[10]);
		ShowSMG_byte(7,Seg_Table[10]);
	}
	else//采集湿度有效
	{
		ShowSMG_byte(6,Seg_Table[Humidity / 10 % 10]);
		ShowSMG_byte(7,Seg_Table[Humidity % 10]);
	}
	ShutDown();
}


smg.h

#ifndef _smg_h_
#define _smg_h_

void SelectHC573(unsigned char n);
void Time(unsigned char *Timer);                               //时间显示界面
void Echo_Temperature(unsigned char MaxTemp,float AvgTemp);   //温度回显界面
void Echo_humidity(unsigned char MaxHum,float AvgHum);        //湿度回显界面
void Echo_Time(unsigned char n,unsigned char *Timer);         //时间回显
void Parameter(unsigned char parameter);                       //参数界面
void Temperature_Humidity(unsigned char Temperature,Humidity );//温湿度界面


#endif

以上就是完整的代码了。
对于iic和onewire我就不多说了,要说的是ds1302中我的写的函数传入的数组;其中Timer[0]、Timer[1]和Timer[2]分别储存的是时分秒,也就是说在main.c文件中的时间数组也是这样储存的。
还有就是数码管相关的代码我都是写在smg.c中的,重点讲的时main.c文件
因为要频繁更改某个led灯且只更改该led灯的状态,所以我就直接写了一个对应的函数,如下

在main.c中我是将每个功能都是单独分开的,这取决于我用的几个flag标志,只要你写过几个蓝桥杯的真题,相信你也有在最后面哪怕是添加一个led灯以0.1s为间隔闪烁的简单功能就会出问题,并且怎么就找不到且不会改。
就拿数码管显示和键盘扫描来说,我用了x和y就基本已经将这两个模块完全分离;即使出错也很好改正。

不过在本次试题中体现不是很明显,但是在第十三届的试题中就异常明显了,后续我会发出来

还有就是对于定时器1的使用我也是在网上学的,只需要一个定时器就可以完成很多功能的计时。

最后就是我的代码的缺点,
第一就是湿度读取函数
在这里插入图片描述
就是第80行,我将湿度计算出来后就直接强制转换为unsigned char类型,这样会导致如果我的湿度如果是12.9的时候会直接变成12,误差很大,当然也有解决办法,就是将湿度乘100后储存,这样的话还要改很多地方。
第二就是这次试题的代码用到了太多的全局变量,导致很牛马,我的设想就是建立两个结构体分别是湿度结构体和温度结构体,将其相关变量都放到对应的结构体中。

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值