声明:代码确实写的不好,用的都是最笨的方法实现功能,不喜勿喷
第四届的题目明显和之前我写的那几届不同,难度也算有吧,但是不是很大。主要是这次的题目用到了AD转换和EEPROM,对于之前没有用过的东西,有一点困难就是要熟悉使用。这次我也是写了五个半小时,虽然也是写出来了,但是遗憾的是我没有缩短时间。
下面来看一下题目要求:
第一眼看这个题目把我下一跳,一下七条要求,平常的都是五条,没想到这个一下搞出了七条。其实仔细一看你就那个样子吧,没什么特别的地方。
下面说一下我自己的思路:
第一步:实现自动模式下的数码管显示和阈值比较以及L1的亮灭、继电器的开关
第二步:实现在手动模式下的数码管显示和阈值比较
第三步:实现在手动模式下各个按键的功能
第四步:实现自动模式下,阈值的设定以及保存至EEPROM
下面看一下代码:
第一:按键程序
#include "key.h"
uchar KeyS7_mode; //模式切换标志位
uchar KeyS6_buzzer;//蜂鸣器控制位
uchar KeyS5_relayo;//开继电器控制位
uchar KeyS4_relayc;//关继电器控制位
uchar KeyS6_set; //在自动模式下设置阈值标志位
uchar KeyS5_add; //在自动模式下阈值加一标志位
uchar KeyS4_duc; //在自动模式下阈值减一标志位
//独立按键扫描函数
void D_keyscan()
{
if(P30==0)
{
Delay5ms();
if(P30==0) //按键S7
{
KeyS7_mode += 1;
if(KeyS7_mode == 2)
KeyS7_mode = 0;
}
while(!P30);
}
else if(P31==0) //按键S6
{
Delay5ms();
if(P31==0)
{
KeyS6_set += 1;
KeyS6_buzzer += 1;
if(KeyS6_buzzer == 2)
KeyS6_buzzer = 0;
}
while(!P31);
}
else if(P32==0) //按键S5
{
Delay5ms();
if(P32==0)
{
KeyS5_add = 1;
KeyS5_relayo = 1;
}
while(!P32);
}
else if(P33==0) //按键S4
{
Delay5ms();
if(P33==0)
{
KeyS4_duc = 1;
KeyS4_relayc = 1;
}
while(!P33);
}
}
void Delay5ms() //@11.0592MHz
{
unsigned char i, j;
i = 54;
j = 199;
do
{
while (--j);
} while (--i);
}
第二:数码管程序
#include "shuma.h"
u8 shu_tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XC6,0XFF};//0XC6是英文C
uchar yi,er,san,si,wu,liu,qi,ba;
//第一和第二个数码管
void Display1_2(uchar yi,uchar er)
{
P2=0XC0;//打开位选573 U8
P0=0X01;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[yi];
Delay1ms();Delay1ms();
P2=0XC0;//打开位选573 U8
P0=0X02;//选择第二个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[er];
Delay1ms();Delay1ms();
}
//第四和第五个数码管
void Display4_5(uchar si,uchar wu)
{
P2=0XC0;//打开位选573 U8
P0=0X08;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[si];
Delay1ms();Delay1ms();
P2=0XC0;//打开位选573 U8
P0=0X10;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[wu];
Delay1ms();Delay1ms();
}
//第三和第六个数码管
void Display3_6(uchar san,uchar liu)
{
P2=0XC0;//打开位选573 U8
P0=0X04;//选择第三个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[san];
Delay1ms();Delay1ms();
P2=0XC0;//打开位选573 U8
P0=0X20;//选择第四个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[liu];
Delay1ms();Delay1ms();
}
//第七和第八个数码管
void Display7_8(uchar qi,uchar ba)
{
P2=0XC0;//打开位选573 U8
P0=0X40;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[qi];
Delay1ms();Delay1ms();
P2=0XC0;//打开位选573 U8
P0=0X80;//选择第一个数码管
P2=0XFF;//打开段选573 U7
P0=shu_tab[ba];
Delay1ms();Delay1ms();
}
void Delay1ms() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
第三:AD程序(AD转换是我第一次在省赛中遇到,也是自己写好的封装函数)
#include "ad.h"
#include "eeprom.h"
//AD开始函数
void IICAD_statrt(void)
{
SDA = 1;
_nop_();
SCL = 1;
_nop_();
SDA = 0;
_nop_();
SCL = 0;
}
//AD停止函数
void IICAD_stop(void)
{
SDA = 0;
_nop_();
SCL = 1;
_nop_();
SDA = 1;
}
//向AD写一个字节
void AD_writebyte(uchar dat)
{
uchar i;
for(i=0;i<8;i++)
{
SCL = 0;
_nop_();
SDA = dat&0x80;
_nop_();
SCL = 1;
dat<<=1;
}
SCL = 0;
_nop_();
}
//应答函数
uchar ACK_AD(void)
{
SCL = 1;
IICAD_delay(5);
if(SDA == 1)
{
SCL = 0;
Delay100us();
IICAD_stop();
return 0;
}
else
{
SCL = 0;
Delay100us();
return 1;
}
}
//从AD中读取数据
uchar IICAD_read(uchar add)
{
uchar temp;
IICAD_statrt();
AD_writebyte(0x90);
ACK_AD();
AD_writebyte(add);
ACK_AD();
IICAD_statrt();
AD_writebyte(0x91);
ACK_AD();
temp = IICAD_readbyte();
IICAD_stop();
//现在显示的是0-255,如果需要显示0-100可以加代码(temp = 0.39*temp;)
return temp;
}
//从AD中读取一个字节
uchar IICAD_readbyte()
{
uchar dat;
uchar i;
SCL = 0;
_nop_();
SCL = 1;
_nop_();
for(i=0;i<8;i++)
{
SCL = 1;
dat<<=1;
if(SDA)
{
dat |= 0x01;
}
SCL = 0;
}
return dat;
}
void IICAD_delay(uchar a)
{
do
{
_nop_();
}
while(a--);
}
void Delay100us() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
i = 2;
j = 15;
do
{
while (--j);
} while (--i);
}
第四:EEPROM程序(EEPROM转换是我第一次在省赛中遇到,也是自己写好的封装函数)
#include "eeprom.h"
//IIC开始函数
void IICEE_statrt(void)
{
SDA = 1;
_nop_();
SCL = 1;
_nop_();
SDA = 0;
_nop_();
SCL = 0;
}
//IIC停止函数
void IICEE_stop(void)
{
SDA = 0;
_nop_();
SCL = 1;
_nop_();
SDA = 1;
}
//将地址和数据写进IIC
void IICEE_write(uchar add ,uchar dat)
{
IICEE_statrt();
EE_writebyte(0xa0);
ACK_EE();
EE_writebyte(add);
ACK_EE();
EE_writebyte(dat);
ACK_EE();
IICEE_stop();
Delay10ms();Delay10ms();//一定要加
}
//向IIC写一个字节
void EE_writebyte(uchar dat)
{
uchar i;
for(i=0;i<8;i++)
{
SCL = 0;
_nop_();
SDA = dat&0x80;
_nop_();
SCL = 1;
dat<<=1;
}
SCL = 0;
_nop_();
}
void IICEE_delay(uchar a)
{
do
{
_nop_();
}
while(a--);
}
//应答函数
uchar ACK_EE(void)
{
SCL = 1;
IICEE_delay(5);
if(SDA == 1)
{
SCL = 0;
IICEE_stop();
return 0;
}
else
{
SCL = 0;
return 1;
}
}
//从IIC中读取数据
uchar IICEE_read(uchar add)
{
uchar temp;
IICEE_statrt();
EE_writebyte(0xa0);
ACK_EE();
EE_writebyte(add);
ACK_EE();
IICEE_statrt();
EE_writebyte(0xa1);
ACK_EE();
temp = IICEE_readbyte();
IICEE_stop();
Delay10ms();
return temp;
}
//从IIC中读取一个字节
uchar IICEE_readbyte()
{
uchar dat;
uchar i;
SCL = 0;
_nop_();
SCL = 1;
_nop_();
for(i=0;i<8;i++)
{
SCL = 1;
dat<<=1;
if(SDA)
{
dat |= 0x01;
}
SCL = 0;
}
return dat;
}
void Delay10ms() //@11.0592MHz
{
unsigned char i, j;
i = 108;
j = 145;
do
{
while (--j);
} while (--i);
}
AD的程序和EEPROM的程序非常相似,只是有两个地址不同而已。
第五:初始化程序(.c)
#include "system.h"
void Init(void)
{
P2=0XA0;//打开蜂鸣器,继电器控制端
P0=0X00;//关闭蜂鸣器,继电器
P2=0X80;//打开LED灯控制端
P0=0XFF;//关闭LED灯
P2=0XC0;//打开数码管片选控制端
P0=0XFF;//选择所有数码管
P2=0XFF;//打开数码管段选控制端
P0=0XFF;//关闭所有数码管段选
}
初始化程序(.h)
#ifndef __SYSTEM_H
#define __SYSTEM_H
#include "STC15F2K60S2.H"
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
typedef unsigned int u16;
typedef unsigned char u8;
void Init(void);
#endif
最后:主函数程序
#include "system.h"
#include "shuma.h"
#include "key.h"
#include "eeprom.h"
#include "ds1302.h"
#include "ad.h"
extern uchar yi,er,san,si,wu,liu,qi,ba;
extern uchar shijian[7];
extern uchar KeyS7_mode; //模式切换标志位
extern uchar KeyS6_buzzer;//蜂鸣器控制位
extern uchar KeyS5_relayo;//开继电器控制位
extern uchar KeyS4_relayc;//关继电器控制位
extern uchar KeyS6_set; //自动模式下湿度阈值调整控制位
extern uchar KeyS5_add; //自动模式下湿度阈值加标志位
extern uchar KeyS4_duc; //自动模式下湿度阈值减标志位
uchar AD_num; //读取AD数据
uchar Set_z1_flag; //完成两种模式按键的清零功能
uchar Set_z0_flag; //完成两种模式按键的清零功能
uchar ba_flag1; //实现在自动模式下按下S5加一
uchar qi_flag1; //实现在自动模式下按下S5当个位满十进一
uchar ba_flag2; //实现在自动模式下按下S4减一
uchar qi_flag2; //实现在自动模式下按下S4当个位不够减的时候向高位借位
uchar ba_num =1;
uchar qi_num;
uchar duc_flag;
uchar IIC_num; //读取EEPROM中的数据
uchar Set_qi; //将设定好的阈值保存
uchar Set_ba; //将设定好的阈值保存
void main(void)
{
Init();
DS13Init();
while(1)
{
Read_Time();//读取时间
D_keyscan();
if(KeyS7_mode == 0) //如果S7没有按下进入自动模式
{
if(Set_z0_flag == 0) //完成两种模式按键的清零功能
{
KeyS6_buzzer = 0;
KeyS5_relayo = 0;
KeyS4_relayc = 0;
Set_z0_flag = 1;
}
AD_num = IICAD_read(0x03);//读取滑动变阻器的值
if(AD_num <= 128) //模拟湿度,最大值255,小于等于百分之五十,继电器开,L1亮
{
P2=0XA0;P0=0X10;
P2=0X80;P0=0XFE;
}
else //模拟湿度,最大值255,大于百分之五十,继电器关,L1灭
{
P2=0XA0;P0=0X00;
P2=0X80;P0=0XFF;
}
if(KeyS6_set == 1) //在自动模式下按下S6进入湿度阈值设置界面
{
yi = 10;er = 10;san = 12;
si = 12;wu = 12;liu = 12;
if(KeyS5_add == 1) //如果S5按下实现阈值加一的功能
{
if((qi == 9) && (ba == 9)) //如果到达最大值就不再加一
{
KeyS5_add = 0;
}
else
{
ba_flag1++; //记录按键按下的次数
ba_num = (AD_num*100/256)%10 + ba_flag1;
if((ba_num >= 10) && (ba_num < 20)) //判断加上按键按下次数之后数值的范围
{
ba = ba_num - 10;
}
else if((ba_num >= 20) && (ba_num < 30))
{
ba = ba_num - 20;
}
else if((ba_num >= 30) && (ba_num < 40))
{
ba = ba_num - 30;
}
else if((ba_num >= 40) && (ba_num < 50))
{
ba = ba_num - 40;
}
else if((ba_num >= 50) && (ba_num < 60))
{
ba = ba_num - 50;
}
else if((ba_num >= 60) && (ba_num < 70))
{
ba = ba_num - 60;
}
else if((ba_num >= 70) && (ba_num < 80))
{
ba = ba_num - 70;
}
else if((ba_num >= 80) && (ba_num < 90))
{
ba = ba_num - 80;
}
else
{
ba = (AD_num*100/256)%10 + ba_flag1;
}
if(ba_num == 10) //实现满十进一
qi_flag1 = 1;
if(ba_num == 20)
qi_flag1 = 2;
if(ba_num == 30)
qi_flag1 = 3;
if(ba_num == 40)
qi_flag1 = 4;
if(ba_num == 50)
qi_flag1 = 5;
if(ba_num == 60)
qi_flag1 = 6;
if(ba_num == 70)
qi_flag1 = 7;
if(ba_num == 80)
qi_flag1 = 8;
if(ba_num == 90)
qi_flag1 = 9;
qi = (AD_num*100/256)/10 + qi_flag1;
}
KeyS5_add = 0;
}
if(KeyS4_duc == 1) //如果S4按下实现阈值减一的功能
{
if((qi == 0) && (ba == 0)) //如果减到最小值不再减一
{
KeyS4_duc = 0;
}
else
{
ba_flag2++; //记录按键S4按下的次数
if(ba_num != 0)
{
if(duc_flag == 1) //向十位借位之后的个位数值
{
ba_num = 9 - ba_flag2;
ba = ba_num;
}
else
{
ba_num = (AD_num*100/256)%10 - ba_flag2; //如果不需要借位就一直减一
ba = (AD_num*100/256)%10 - ba_flag2;
qi = (AD_num*100/256)/10 ;
}
}
else if(ba_num == 0) //个位已经减到零
{
qi_flag2 += 1;
ba_flag2 = 0; //将按键按下的次数清零,便于个位数字的计算
ba_num = 1;
duc_flag = 1;
qi = (AD_num*100/256)/10 - qi_flag2; //控制十位减被借位减一
ba = 9;
}
}
KeyS4_duc = 0;
}
Set_qi = qi; //保存设定好的湿度阈值,用于写进EEPROM
Set_ba = ba; //保存设定好的湿度阈值,用于写进EEPROM
}
else if(KeyS6_set == 2) //按键S6第二次按下,退出阈值设置模式
{
IICEE_write(0x00,0);//初始化
IICEE_write(0x00,(Set_qi*10+Set_ba)); //将保存的阈值写入EEPORM
IIC_num = IICEE_read(0x00);
KeyS6_set = 0;
}
else
{
yi = shijian[2]/10;er = shijian[2]%10; //显示时间
san = 10;si = shijian[1]/10;
wu = shijian[1]%10;liu = 12;
qi = (AD_num*100/256)/10;ba = (AD_num*100/256)%10; //显示模拟湿度
}
Display1_2(yi,er);
Display4_5(si,wu);
Display3_6(san,liu);
Display7_8(qi,ba);
}
else if(KeyS7_mode == 1) //进入手动模式
{
AD_num = IICAD_read(0x03);//读取滑动变阻器的值
if(AD_num <= 128) //模拟湿度,最大值255,小于等于百分之五十,继电器开,L1亮
{
if(Set_z1_flag == 0) //完成两种模式按键的清零功能
{
KeyS6_buzzer = 0;
KeyS5_relayo = 0;
KeyS4_relayc = 0;
Set_z1_flag = 1;
}
if(KeyS6_buzzer == 0)
{
P2=0XA0;P0=0X40;
}
else if(KeyS6_buzzer == 1) //在手动模式下,按下第一次S6蜂鸣器关闭,再次按下蜂鸣器开,依次循环
{
P2=0XA0;P0=0X00;
}
if(KeyS5_relayo == 1) //在手动模式下,按下S5继电器开,L2灯亮
{
P2=0XA0;P0=0X10;
P2=0X80;P0=0XFD;
if(KeyS4_relayc == 1) //在手动模式下,按下S4继电器关,L2灯灭
{
P2=0XA0;P0=0X00;
P2=0X80;P0=0XFF;
KeyS5_relayo = 0;
KeyS4_relayc = 0;
}
}
}
else //模拟湿度,最大值255,大于百分之五十,继电器关,L1灭
{
P2=0XA0;P0=0X00;
P2=0X80;P0=0XFF;
}
yi = shijian[2]/10;er = shijian[2]%10; //显示时间
san = 10;si = shijian[1]/10;
wu = shijian[1]%10;liu = 12;
qi = (AD_num*100/256)/10;ba = (AD_num*100/256)%10; //显示模拟湿度
Display1_2(yi,er);
Display4_5(si,wu);
Display3_6(san,liu);
Display7_8(qi,ba);
}
}
}
写这个题目只有一个点是比较值得注意的,就是在阈值设定的时候数的加减问题,要注意数字的边界值。
还是老样子我会把我的整个工程上传https://download.csdn.net/my