前言
今天刷了第十四届的省赛,不得不说这个难度确实比之前的几届都要高,就比如说平常省赛不会考的555出现在了省赛中,逻辑性也很强。其次还有很多小陷阱。并且很多外设同时考察,一不小心就会陷入陷阱之中。本人第一次尝试2个小时以为差不多完成的时侯发现题意理解错了,重新写了一次用了大概快到5个小时了。所以大家动手之前一定要深刻理解题意,其次再去码。
笔者应该是全部实现了,如有需要者可点赞收藏找我下载源代码。同时欢迎大家指正发现错误。
main.c(主文件)
#include "reg52.h"
#include "user.h"
#include "ds1302.h"
#include "iic.h"
#include "ds18b20.h"
sfr P4=0xc0;
sbit R1=P3^0;
sbit R2=P3^1;
sbit R3=P3^2;
sbit R4=P3^3;
sbit C1=P4^4;
sbit C2=P4^2;
sbit C3=P3^5;
sbit C4=P3^4;
void Display_info();
unsigned char flq;//数据是否有效
unsigned char ui=1;//默认时间显示界面(系统界面选择)
unsigned char Wr_time[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
unsigned char Re_time[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
unsigned char Timer[7]={0x50,0x03,0x13,0x03,0x04,0x03,0x24};
unsigned int count_f=0;//频率产生
unsigned int dat_f=0;//一秒总频率
unsigned char count_t=0;//1秒计时
unsigned int count_flag=0;//3秒计时
unsigned int temp_x;//温度转换取得温度
unsigned char hot=30;//参数
unsigned char sun;//初始正常光照
unsigned char stat_led=0xff;//led状态
unsigned char flag=0;//亮暗状态检测
unsigned char cnt=0;//采集次数
unsigned char temp_new_display[100]=0;//实时采集温度
unsigned int temp_old[100]=0;
unsigned char i;//最大值平均值循环计数
unsigned int sum=0;//总值
unsigned int sum_junzhi=0;//温度平均值
unsigned int wet_junzhi=0;//湿度平均值
unsigned int wet_sum=0;//湿度总值
unsigned char temp_max=0;//温度最大值
unsigned char wet_max=0;//湿度最大值
unsigned char wet_new[100]=0;//实时采集湿度
unsigned int temp_new_noeffect=0;
unsigned char hour,min=0;
unsigned char count_long=0;
unsigned char S9_flag=0;
unsigned char stat_led4=0;
unsigned char count_led=0;
/************************电压采集********************/
unsigned char Get_Pcf8591()
{
unsigned int x;
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(0x41);
I2CWaitAck();
I2CStart();
I2CSendByte(0x91);
I2CWaitAck();
x=I2CReceiveByte();
I2CSendAck(1);
I2CStop();
return x;
}
void Time555()
{
TMOD=0x16;
TH0=0xff;
TL0=0xff;
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
EA=1;
ET0=1;
ET1=1;
TR0=1;
TR1=1;
}
void Service_count()interrupt 1
{
count_f++;
}
void Service_timer()interrupt 3
{
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
count_t++;
if(count_t==20)
{
dat_f=count_f;
count_t=0;
count_f=0;
}
if(S9_flag==1)//S9按下
{
count_long++;//开始计数
}
if(flag==1)//定时器内检测状态,开始3秒计时。
{
count_flag++;
if(count_flag==60)
{
flag=0;
count_flag=0;
}
}
if(stat_led4==1)
{
count_led++;
stat_led&=~0x08;
if(count_led==2)
{
count_led=0;
stat_led|=0x08;
}
select573(4,stat_led);
}
}
/************************时间采集********************/
void Write_1302()
{
unsigned char i;
Write_Ds1302_Byte(0x8e,0x00);
for(i=0;i<7;i++)
{
Write_Ds1302_Byte(Wr_time[i],Timer[i]);
}
Write_Ds1302_Byte(0x8e,0x80);
}
void Read_1302()
{
unsigned char i;
for(i=0;i<7;i++)
{
Timer[i]=Read_Ds1302_Byte(Re_time[i]);
}
}
/*************************初次温度读取**************/
void Initds18b20()
{
unsigned char LSB,MSB;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
do
{
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
LSB=Read_DS18B20();
MSB=Read_DS18B20();
MSB=(MSB<<4)|(LSB>>4);
}
while(MSB==85);
}
/************************温度采集********************/
void Get_ds18b20()
{
unsigned char LSB,MSB;
unsigned int temp;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
Display_info();
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
LSB=Read_DS18B20();
MSB=Read_DS18B20();
temp=(MSB<<8)|LSB;
if((temp&0xf800)==0x0000)
{
temp_x=temp*0.0625;
}
}
/************************时间界面********************/
void UI_time()
{
Read_1302();
Display_Bit(0,SMGNoDot_CA[Timer[2]/16]);
Display_Bit(1,SMGNoDot_CA[Timer[2]%16]);
Display_Bit(2,0xbf);
Display_Bit(3,SMGNoDot_CA[Timer[1]/16]);
Display_Bit(4,SMGNoDot_CA[Timer[1]%16]);
Display_Bit(5,0xbf);
Display_Bit(6,SMGNoDot_CA[Timer[0]/16]);
Display_Bit(7,SMGNoDot_CA[Timer[0]%16]);
}
/************************温度回显********************/
void UI_temp_HUIXIAN()
{
Display_Bit(0,0xc6);
if(cnt!=0)
{
Display_Bit(2,SMGNoDot_CA[temp_max/10]);
Display_Bit(3,SMGNoDot_CA[temp_max%10]);
Display_Bit(4,0xbf);
Display_Bit(5,SMGNoDot_CA[(sum/cnt)/100]);
Display_Bit(6,SMGDot_CA[(sum/cnt)/10%10]);
Display_Bit(7,SMGNoDot_CA[(sum/cnt)%10]);
}
}
/************************湿度回显********************/
void UI_wet_HUIXIAN()
{
Display_Bit(0,0x89);
wet_junzhi=wet_sum/cnt;
if(cnt!=0)
{
Display_Bit(2,SMGNoDot_CA[wet_max/10]);
Display_Bit(3,SMGNoDot_CA[wet_max%10]);
Display_Bit(4,0xbf);
Display_Bit(5,SMGNoDot_CA[wet_junzhi/100]);
Display_Bit(6,SMGDot_CA[wet_junzhi/10%10]);
Display_Bit(7,SMGNoDot_CA[wet_junzhi%10]);
}
}
/************************时间回显********************/
void UI_time_HUIXIAN()
{
Display_Bit(0,0x8e);
Display_Bit(1,SMGNoDot_CA[cnt/10]);
Display_Bit(2,SMGNoDot_CA[cnt%10]);
if(cnt!=0)
{
Display_Bit(3,SMGNoDot_CA[hour/16]);
Display_Bit(4,SMGNoDot_CA[hour%16]);
Display_Bit(5,0xbf);
Display_Bit(6,SMGNoDot_CA[min/16]);
Display_Bit(7,SMGNoDot_CA[min%16]);
}
}
/************************参数界面********************/
void UI_set()
{
Display_Bit(0,0x8c);
Display_Bit(6,SMGNoDot_CA[hot/10]);
Display_Bit(7,SMGNoDot_CA[hot%10]);
}
/************************温湿度界面********************/
void UI_3sDisplay()
{
stat_led&=~0x04;
select573(4,stat_led);
Display_Bit(0,0x86);
if(flq==1)
{
Display_Bit(3,SMGNoDot_CA[temp_new_display[cnt]/10]);
Display_Bit(4,SMGNoDot_CA[temp_new_display[cnt]%10]);
Display_Bit(6,SMGNoDot_CA[wet_new[cnt]/10]);
Display_Bit(7,SMGNoDot_CA[wet_new[cnt]%10]);
}
else
{
Display_Bit(3,SMGNoDot_CA[temp_new_noeffect/10]);
Display_Bit(4,SMGNoDot_CA[temp_new_noeffect%10]);
Display_Bit(6,0x88);
Display_Bit(7,0x88);
}
}
/************************显示函数********************/
void Display_info()
{
if(flag==0)
{
switch(ui)
{
case 1: UI_time(); break;//时间
case 2: UI_temp_HUIXIAN();break;//回显(温度)
case 3: UI_set(); break;//参数
case 4: UI_wet_HUIXIAN();break;//湿度回显
case 5: UI_time_HUIXIAN(); break;//时间回显
}
}
else
{
UI_3sDisplay();
}
}
/************************按键扫描********************/
void Scankennys()
{
if(ui==5)
{
R3=0;
R1=R2=R4=C1=C2=C3=C4=1;
if(C2==0)
{
delay(500);
if(C2==0)
{
S9_flag=1;
}
while(C2==0)
{
Display_info();
}
S9_flag=0;
if(count_long>40)
{
cnt=0;
count_long=0;
temp_new_display[100]=0,temp_old[100]=0,sum_junzhi=0,wet_junzhi=0,wet_sum=0,temp_max=0,wet_max=0,wet_new[100]=0,hour,min=0,sum=0;
}
}
}
if(ui==3)
{
R4=0;
R1=R2=R3=C1=C2=C3=C4=1;
if(C2==0)
{
delay(500);
if(C2==0&&hot<=98)
{
hot++;
}
while(C2==0)
{
Display_info();
}
}
R3=0;
R1=R2=R4=C1=C2=C3=C4=1;
if(C2==0)
{
delay(500);
if(C2==0&&hot>=1)
{
hot--;
}
while(C2==0)
{
Display_info();
}
}
}
R4=0;
R1=R2=R3=C1=C2=C3=C4=1;
if(C1==0)
{
delay(500);
if(C1==0)
{
switch(ui)
{
case 1:ui=2;break;
case 2:ui=3;break;
case 3:ui=1;break;
case 4:ui=3;break;
case 5:ui=3;break;
}
}
while(C1==0)
{
Display_info();
}
}
if(ui==2||ui==4||ui==5)
{
R3=0;
R1=R2=R4=C1=C2=C3=C4=1;
if(C1==0)
{
delay(500);
if(C1==0)
{
switch(ui)
{
case 2:ui=4;break;
case 4:ui=5;break;
case 5:ui=2;break;
}
}
while(C1==0)
{
Display_info();
}
}
}
}
/*************************数据采集******************/
void Caiji()
{
sun=Get_Pcf8591();
if(sun<120)
{
flag=1;//亮状态
if(flag==1&&flq==1)//有效数据
{
Get_ds18b20();
cnt++;
hour=Timer[2];//传入此时时间
min=Timer[1];//~
temp_new_display[cnt]=temp_x;//显示温度
if(temp_new_display[cnt]>temp_new_display[cnt-1])
{
temp_max=temp_new_display[cnt];
}
temp_old[cnt]=temp_x*10;
sum+=temp_old[cnt];//以上为采集温度
wet_new[cnt]=(dat_f-200)*0.044+10;
wet_sum+=wet_new[cnt]*10;
if(wet_new[cnt]>wet_new[cnt-1])
{
wet_max=wet_new[cnt];
}
while(sun<120)
{
sun=Get_Pcf8591();
Display_info();
}
}
else if(flag==1&&flq==0)//无效数据,读但不存
{
Get_ds18b20();
temp_new_noeffect=temp_x;//记录无效数据
while(sun<120)
{
sun=Get_Pcf8591();
Display_info();
}
}
}
}
/*************************检测是否有效******************/
void Scaneffect()
{
if(dat_f>200&&dat_f<2000)
{
flq=1;
}
else
{
flq=0;
}
}
/*************************led函数******************/
void led()
{
if(temp_new_display[cnt]>hot||temp_new_noeffect>hot)
{
stat_led4=1;
}
else
{
stat_led4=0;
stat_led|=0x08;
}
if(ui==1)
{
stat_led&=~0x01;
stat_led|=0x06;
}
if(ui==2||ui==4||ui==5)
{
stat_led&=~0x02;
stat_led|=0x05;
}
if(flag==1&&flq==0)
{
stat_led&=~0x10;
}
else if(flag==1&&flq==1)
{
stat_led|=0x10;
}
if(cnt>=2)
{
if(temp_new_display[cnt]>temp_new_display[cnt-1]&&wet_new[cnt]>wet_new[cnt-1])
{
stat_led&=~0x20;
}
else
{
stat_led|=0x20;
}
}
select573(4,stat_led);
}
/*************************主函数******************/
void main()
{
initsystem();
Time555();
Write_1302();
Initds18b20();
while(1)
{
Scaneffect();
Display_info();
Scankennys();
Caiji();
led();
}
}
-
ds1302.c
/* # DS1302代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
//
#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);
}
iic.c
/* # I2C代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
#define DELAY_TIME 10
#include "reg52.h"
#include "intrins.h"
#define SlaveAddrW 0xA0;
#define SlaveAddrR 0xA1;
sbit sda=P2^1;
sbit scl=P2^0;
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);
}
onewire.c
/* # 单总线代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
//
#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;
}
关于我的逻辑我想讲给大家的
/*************************数据采集******************/
void Caiji()
{
sun=Get_Pcf8591();
if(sun<120)
{
flag=1;//亮状态
if(flag==1&&flq==1)//有效数据
{
Get_ds18b20();
cnt++;
hour=Timer[2];//传入此时时间
min=Timer[1];//~
temp_new_display[cnt]=temp_x;//显示温度
if(temp_new_display[cnt]>temp_new_display[cnt-1])
{
temp_max=temp_new_display[cnt];
}
temp_old[cnt]=temp_x*10;
sum+=temp_old[cnt];//以上为采集温度
wet_new[cnt]=(dat_f-200)*0.044+10;
wet_sum+=wet_new[cnt]*10;
if(wet_new[cnt]>wet_new[cnt-1])
{
wet_max=wet_new[cnt];
}
while(sun<120)
{
sun=Get_Pcf8591();
Display_info();
}
}
else if(flag==1&&flq==0)//无效数据,读但不存
{
Get_ds18b20();
temp_new_noeffect=temp_x;//记录无效数据
while(sun<120)
{
sun=Get_Pcf8591();
Display_info();
}
}
}
}
我觉得最让我头疼的就是数据采集这里,我首先通过判断亮暗,如果亮转暗,则需要判断是不是有效数据。在有效数据的情况下,让采集次数cnt++。同时因为我们的函数在主函数中,会不断的执行,很容易陷入cnt无限++的情景,这个时候其实只用在后面加上一个while循环就可以避免,当光照转为暗的时候,cnt++,此时进入循环,同时放入显示函数,防止cnt无限++。那么如何退出循环呢,就是在再次转为亮的时候,退出循环,所以我在while循环中放入了光照值的变化,同时while循环的条件就是当再次转为亮。这样的话就很好实现了,这道赛题基本上就可以解决了。不断存数组,存入新的温度和湿度用来显示采集数据。显示的时候显示cnt位置的数组即最新采集数据。当采集到无效数据时我们只需要拿一个对总体数据无影响的值存放温度展示在数码管上3秒就可以了,给一个标志就ok。我这个写法的好处就是在这里面采集不会冲突,每次取一个放一个。数据会处理的比较清晰调理。在这里面也可以不断地更新时间,题目要求的是最近的时间,那就再采集的时候取走时间就可以了。希望大家可以理解。
大家记得上电的时候写一个避免温度为85的函数。
/*************************初次温度读取**************/
void Initds18b20()
{
unsigned char LSB,MSB;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
do
{
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
LSB=Read_DS18B20();
MSB=Read_DS18B20();
MSB=(MSB<<4)|(LSB>>4);
}
while(MSB==85);
}