蓝桥杯单片机第十四届省赛代码(有注释)
首先对我的代码进行一下说明,由于现在官方对于底层驱动代码不再提供头文件,所以我对底层驱动代码的调用函数时直接写在对应的.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后储存,这样的话还要改很多地方。
第二就是这次试题的代码用到了太多的全局变量,导致很牛马,我的设想就是建立两个结构体分别是湿度结构体和温度结构体,将其相关变量都放到对应的结构体中。