目录
1、(DS1302实时时钟)自动状态(L1亮),按下S6进入温度阈值设定界面。(按下可以 进入,但松开就返回实时时钟)
错误写法:(直接写在while里)
正确写法:(写在按键里)
2、继电器:手动状态(L2亮),按下S5,继电器打开;按下S4,继电器关闭。(按下S5 可以打开继电器,但松开就关闭)
存在问题的代码分析:(要同时操作蜂鸣器与继电器,一定要列出所有情况!!!)
注意:先把每个模块调通,再写逻辑程序!!!
问题自行解决:(自己写的过程中)
1、(DS1302实时时钟)自动状态(L1亮),按下S6进入温度阈值设定界面。(按下可以进入,但松开就返回实时时钟)
错误写法:
实时时钟显示不能写while循环里面!!!!
写在按键里面:(注意条件)
unsigned char key_num = 0, key_num2 = 0;(初始状态均为零)
key_num:0自动状态 / 1手动状态
key_num2:②进入界面 / ③控制蜂鸣器 / ④阈值+1 / ⑤打开灌溉 / ⑥阈值-1 / ⑦关闭灌溉
正确写法:
2、继电器:手动状态(L2亮),按下S5,继电器打开;按下S4,继电器关闭。(按下S5可以打开继电器,但松开就关闭)
错误写法:
①
②
③
正确写法:(与问题1相同)
(写在主函数while里面发出嗡嗡怪声?)
参考代码:
#include "reg52.h"
#include "ds1302.h"
#include "iic.h"
sbit S7 = P3^0;
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;
unsigned char SMG_duanma[19] = {
// 0 1 2 3 4 5 6 7
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
// 8 9 A10 B11 C12 D13 E14 F15
0x80,0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e,
// -16 .17
0xbf,0x7f,0xff}; //共阳数码管
unsigned char yi, er, san, si, wu, liu, qi, ba;
unsigned char DS1302_Read_add[7] = {0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};//DS1302读地址
unsigned char DS1302_Write_add[7] = {0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};//DS1302写地址
// 08时30分00秒
unsigned char Timer[7] = {0x00,0x30,0x08,0x14,0x02,0x01,0x22};
// 秒 分 时 日 月 星期 年
unsigned char Rb2;//阻值
unsigned char SD;//湿度
unsigned char YZ;//湿度阈值
unsigned char key7 = 0;//S7键值(0:自动状态 1:手动状态)
unsigned char key6 = 0;//S6键值(0:阈值调整 1:保存阈值)
unsigned char key5 = 0;//S5键值(1:阈值+1)
unsigned char key4 = 0;//S4键值(1:阈值-1)
unsigned char fmq = 1;//蜂鸣器功能默认打开(就是蜂鸣器可以开关)(0:功能关闭,蜂鸣器不能操作)
unsigned char jdq = 0;//继电器默认关闭
void eeprom_write(unsigned pos,unsigned char dat);
void InitHC138(unsigned char n)
{
switch (n)
{
case 4://LED
P2 = (P2 & 0x1f) | 0x80;
break;
case 5://蜂鸣器与继电器
P2 = (P2 & 0x1f) | 0xa0;
break;
case 6://数码管位置
P2 = (P2 & 0x1f) | 0xc0;
break;
case 7://数码管段码
P2 = (P2 & 0x1f) | 0xe0;
break;
case 0://不选
P2 = (P2 & 0x1f) | 0x00;
break;
}
}
void Delayms(unsigned int ms)//延时 ms
{
unsigned int i, j;
for (i = ms; i > 0; i--)
for (j = 845; j > 0; j--);
}
/*===================系统初始化==========================================
关闭LED、蜂鸣器与继电器
========================================================================*/
void InitSystem()
{
InitHC138(4);//上电后为自动状态L1亮
P0 = 0xfe;
InitHC138(5);
P0 = 0x00;
}
/*=================数码管单元==========================================
初始:08:30(DS1302)
=====================================================================*/
void SMG_Bit(unsigned pos, unsigned char dat)
{
InitHC138(7);
P0 = 0xff;//消影
InitHC138(6);
P0 = 0x01 << pos;
InitHC138(7);
P0 = dat;
}
void SMG_All(unsigned char dat)
{
InitHC138(6);
P0 = 0xff;
InitHC138(7);
P0 = dat;
}
void ShowSMG()
{
SMG_Bit(0, SMG_duanma[yi]);
Delayms(1);
SMG_Bit(1, SMG_duanma[er]);
Delayms(1);
SMG_Bit(2, SMG_duanma[san]);
Delayms(1);
SMG_Bit(3, SMG_duanma[si]);
Delayms(1);
SMG_Bit(4, SMG_duanma[wu]);
Delayms(1);
SMG_Bit(5, SMG_duanma[liu]);
Delayms(1);
SMG_Bit(6, SMG_duanma[qi]);
Delayms(1);
SMG_Bit(7, SMG_duanma[ba]);
Delayms(1);
SMG_All(0xff);//数码管最后一位太亮
}
/*=================按键单元============================================
S7:工作状态切换键 自动/手动
①手动工作状态下:
S6:按下关闭蜂鸣器提醒功能,再次按下打开功能。循环
S5:打开灌溉
S4:关闭灌溉
②自动工作状态下:
S6:按下进入湿度阈值调整界面:--,再次按下将阈值保存到EEPROM中,并退出设定界面
S5:阈值+1
S4:阈值-1
=====================================================================*/
void ScanKeys()
{
//按键S7
if (S7 == 0)//上电初始为自动状态
{
Delayms(5);
if (S7 == 0)
{//key7:0自动状态 1手动状态
if (key7 == 0)
{
key7 = 1;//手动状态L2
InitHC138(4);
P0 = 0xfd;
}
else if (key7 == 1)
{
key7 = 0;//自动状态L1
InitHC138(4);
P0 = 0xfe;
}
}
while(!S7)
{
ShowSMG();
}
}
//按键S6
if (S6 == 0)
{
Delayms(5);
if (S6 == 0)
{
if (key7 == 0)//自动状态
{
if (key6 == 0)//阈值调整界面
{key6 = 1;}
else if (key6 == 1)//阈值保存
{key6 = 0;}
}
else if (key7 == 1)//手动状态:开关蜂鸣器(蜂鸣器默认是打开状态)
{
if (fmq == 1)
{
fmq = 0;//(S6按下,蜂鸣器状态关闭,不可操作)
}
else if (fmq == 0)
{
fmq = 1;
}
}
}
while(!S6)
{
ShowSMG();
}
}
//按键S5
if (S5 == 0)//自动:+1 手动:打开继电器
{
Delayms(5);
if (S5 == 0)
{
if (key7 == 0)//自动状态
{
key5 = 1;//阈值+1
}
else if (key7 == 1)//手动状态
{
jdq = 1;//打开继电器
}
}
while(!S5)
{
ShowSMG();
}
}
//按键S4
if (S4 == 0)//自动:-1 手动:关闭继电器
{
Delayms(5);
if (S4 == 0)
{
if (key7 == 0)//自动状态
{
key4 = 1;//阈值-1
}
else if (key7 == 1)//手动状态
{
jdq = 0;//关闭继电器
}
}
while(!S4)
{
ShowSMG();
}
}
}
/*=================实时时钟DS1302======================================
初始:08:30(DS1302)
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302_Byte( unsigned char address );
=====================================================================*/
void DS1302_Init()//初始化时钟
{
unsigned char i;
Write_Ds1302_Byte(0x8e,0x00);//允许写(写保护)
for (i = 0; i < 7; i++)
{
Write_Ds1302_Byte(DS1302_Write_add[i],Timer[i]);
}
Write_Ds1302_Byte(0x8e,0x80);//禁止写
}
void DS1302_ReadTime()//读时间
{
unsigned char i;
for (i = 0; i < 7; i++)
{
Timer[i] = Read_Ds1302_Byte(DS1302_Read_add[i]);
}
}
/*=================AD湿度检测==========================================
void IIC_Start(void);
void IIC_Stop(void);
bit IIC_WaitAck(void);
void IIC_SendByte(unsigned char byt);
unsigned char IIC_RecByte(void);
=====================================================================*/
unsigned char ReadAD(unsigned char AIN)
{
unsigned char temp;//临时变量
IIC_Start();
IIC_SendByte(0x90);//允许写
IIC_WaitAck();
IIC_SendByte(AIN);//写通道
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0x91);//允许读
IIC_WaitAck();
temp = IIC_RecByte();
IIC_Stop();
return temp;
}
/*=================EEPROM存储器(读、写)===============================
void IIC_Start(void);
void IIC_Stop(void);
bit IIC_WaitAck(void);
void IIC_SendByte(unsigned char byt);
unsigned char IIC_RecByte(void);
=====================================================================*/
unsigned char eeprom_read(unsigned char add)//从某地址读数据
{
unsigned char dat;//数据
IIC_Start();
IIC_SendByte(0xa0);//允许写
IIC_WaitAck();
IIC_SendByte(add);//写通道
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0xa1);//允许读
IIC_WaitAck();
dat = IIC_RecByte();
IIC_Stop();
Delayms(5);//延时(防止连读、连写出错)
return dat;//数据
}
void eeprom_write(unsigned pos, unsigned char dat)//向某地址写数据
{
IIC_Start();
IIC_SendByte(0xa0);//允许写
IIC_WaitAck();
IIC_SendByte(pos);//写通道
IIC_WaitAck();
IIC_SendByte(dat);//写数据
IIC_WaitAck();
IIC_Stop();
Delayms(5);//延时(防止连读、连写出错)
}
//=========================主函数===================================================
void main()
{
InitSystem();
DS1302_Init();
yi = 0; er = 8; san = 16; si = 3;
wu = 0; liu = 18; qi = 0; ba = 0;
// eeprom_write(0x10,50);
/*初始阈值为50(写入存储器)但是写在这里有问题:每次上电初始化阈值都是50.
解决:上电一次,50存入后,注释掉,从此不再初始写入50,后续继续从此地址
读出更改后的阈值*/
YZ = eeprom_read(0x10);//从存储器读阈值(初始阈值=50)
while(1)
{
DS1302_ReadTime();//实时时钟
Rb2 = ReadAD(3);//(读滑动变阻器)123
SD = Rb2 * 0.39; // 0.39*255 = 99.45
ScanKeys();
if (key7 == 0)//自动状态
{
if (SD < YZ)//湿度<阈值
{
InitHC138(5); P0 = 0x10;//打开继电器
}
else if (SD >= YZ)//湿度>阈值
{
InitHC138(5); P0 = 0x00;//关闭继电器
}
if (key6 == 1)//阈值界面调整
{
if (key5 == 1)
{
key5 = 0;//释放状态
YZ = YZ + 1;
}
if (key4 == 1)
{
key4 = 0;//释放状态
YZ = YZ - 1;
}
yi = 16; er = 16; san = 18; si = 18; wu = 18; liu = 18;
qi = YZ / 10; ba = YZ % 10;
}
else if (key6 == 0)//阈值保存
{
eeprom_write(0x10,YZ);
yi = Timer[2]/16; er = Timer[2]%16; san = 16; //08时
si = Timer[1]/16; wu = Timer[1]%16; liu = 18; //30分
qi = SD / 10; ba = SD % 10; //湿度
}
}
else if (key7 == 1)//手动状态
{
//①湿度<阈值 蜂鸣器功能没开(手动关闭)
if ((SD < YZ) && (fmq == 0))
{
if (jdq == 1)//打开继电器(fmq没开)
{
InitHC138(5);
P0 = 0x10;
}
else if (jdq == 0)//关闭继电器(fmq没开)
{
InitHC138(5);
P0 = 0x00;
}
}
//②湿度<阈值 蜂鸣器功能打开(湿度小了,蜂鸣器打开)
if ((SD < YZ) && (fmq == 1))
{
if (jdq == 1)//打开继电器(fmq打开)
{
InitHC138(5);
P0 = 0x50;
}
else if (jdq == 0)//关闭继电器(fmq打开)
{
InitHC138(5);
P0 = 0x40;
}
}
//③湿度>阈值 蜂鸣器一定是关闭的
if (SD > YZ)
{
if (jdq == 1)//打开继电器(fmq关闭)
{
InitHC138(5);
P0 = 0x10;
}
else if (jdq == 0)//关闭继电器(fmq关闭)
{
InitHC138(5);
P0 = 0x00;
}
}
yi = Timer[2]/16; er = Timer[2]%16; san = 16;
si = Timer[1]/16; wu = Timer[1]%16; liu = 18;
qi = SD / 10; ba = SD % 10;
}
ShowSMG();
}
}
存在问题的代码分析:(要同时操作蜂鸣器与继电器,一定要列出所有情况!!!)
/*存在问题:继电器正常工作,蜂鸣器不正常工作
S6:控制蜂鸣器的开关
S5:打开继电器(打开后:P0=0x10; 按S6:P0=0xfmq 不可能同时工作)
S4:关闭继电器
所以:写出蜂鸣器与继电器的所有状态!!!!
①湿度>阈值 蜂鸣器一定是关闭的(继电器可开、关)
②湿度<阈值 蜂鸣器 功能打开(叫)(S6可关)/功能关闭(不叫);继电器可开、关
*/
else if (key7 == 1)//自动状态
{
if (fmq == 0)//蜂鸣器打开
{
InitHC138(5);
P0 = 0x40;
}
else if (fmq == 1)//蜂鸣器关闭
{
InitHC138(5);
P0 = 0x00;
}
if (jdq == 0)//继电器关闭
{
InitHC138(5);
P0 = 0x00;
}
else if (jdq == 1)//继电器打开
{
InitHC138(5);
P0 = 0x10;
}
}