看之前强烈建议先自己做一遍!!!
整个工程文件(有注释讲解)
网盘链接
先上演示效果
蓝桥杯单片机第五届模拟智能灌溉系统
首先依旧从赛题的系统框图开始讲起
首先需要做的是将系统框图里的各部分模块提前调试好,方便后续进行调试。使用IIC和DS1302的驱动,将他们复制在工程目录下,并调试好。
首先按照数码管显示要求显示时间和湿度。
顺便注意要求,湿度是由Rb2电位器产生的,时间是ds1302产生的。
主函数显示代码:
extern uchar time[7]; //ds1302.c中定义的存储时间的数组
uchar tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,\
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xff,0xbf};
uchar SMG[8]={20,20,20,20,20,20,20,20};//初始显示10,全息数码管
uchar SMG_mode=0,move; //数码管模式定义,滑动变阻器Rb2定义
void main(void)
{
init(); //初始开发板
ds1302_init(); //uchar time[7]={0,30,8,0,0,0,0}; 8:30:00
while(1)
{
get_time(); //时间获取
move=IIC_read(0x90,0x03); //读取Rb2电阻阻值
move=move*0.3921; //100/255 将255转换到100
if(SMG_mode==0)
{
SMG[0]=time[2]/10;SMG[1]=time[2]%10;SMG[2]=21; //时间显示
SMG[3]=time[1]/10;SMG[4]=time[1]%10;SMG[5]=20;
SMG[6]=move/10;SMG[7]=move%10; //显示湿度
}
SMG_output();
Dkey_scan();
}
}
然后接着看题目要求:
信息提取:
灌溉由继电器模拟
自动模式 | 手动模式 |
---|---|
L1点亮 | L2点亮 |
根据湿度自动灌溉 | 通过按键控制灌溉 |
低于设定阈值开启继电器,高于关闭继电器 | 低于阈值,蜂鸣器打开,使用按键s6关闭蜂鸣器 |
定义变量:
bit work_mode=0; //0为自动模式,1为手动模式
char threshold=50; //定义初始湿度阈值
uchar led=0xff,buzz=0x00; //定义led口和蜂鸣器继电器口,消除其他赋值干扰
手动模式与自动模式代码
if(work_mode==0) //自动模式
{
led |=0x02;led &=0xfe;P2=0X80;P0=led; //打开L1,关闭L2
if(move<threshold) //低于阈值
{
buzz|=0X10;P2=0XA0;P0=buzz; //打开继电器
}
else
{
buzz&=0XEF;P2=0XA0;P0=buzz; //关闭继电器
}
}
else //手动模式
{
led |=0x01;led &=0XFD;P2=0X80;P0=led; //打开L2,关闭L1
if(move<threshold) //低于阈值
{
buzz|=0X40;P2=0XA0;P0=buzz; //打开蜂鸣器
}
else
{
buzz&=0Xbf;P2=0XA0;P0=buzz; //关闭蜂鸣器
}
}
然后就可以开始写按键了:
S7:切换自动模式和手动模式
手动模式下:
S6:关闭和打开蜂鸣器提醒功能
S5:打开灌溉
S4:关闭灌溉
自动模式下:
S6:调整阈值,且数码管显示切换,再次按下退出,且保存湿度阈值到EEPROM之中
S5:阈值加一
S4:阈值减一
代码如下:
else if(SMG_mode==1)
{
SMG[0]=SMG[1]=21;SMG[3]=SMG[4]=SMG[5]=20;
SMG[6]=threshold/10;SMG[7]=threshold%10; //显示湿度
}
void Dkey_scan(void)
{
static uchar keybyte=0;
static uchar key;
if(((P3&0X0F)!=0X0F)&&(keybyte==0))
{
delay5ms();
if((P3&0X0F)!=0X0F)
{
keybyte=1;key=P3&0x0f;
}
}
if((keybyte==1)&&((P3&0X0F)==0X0F))
{
if((P3&0X0F)==0X0F)
{
switch(key)
{
case 0x0e:
if(work_mode==0)work_mode=1;
else work_mode=0;
break;
case 0x0d:
if(work_mode==1) //手动模式下
{
if(buzz_state==1){buzz_state=0;P2=0XA0;P0=0X00;} //关闭蜂鸣器
else {buzz_state=1;}//打开蜂鸣器使能
}
else //自动模式下
{
if(SMG_mode==0)SMG_mode=1; //切换数码管状态
else SMG_mode=0;
}
break;
case 0x0b:
if(work_mode==1) //手动模式
{
buzz|=0X10;P2=0XA0;P0=buzz; //打开灌溉
}
else //自动模式下
{
threshold++; //阈值加1
if(threshold>99)threshold=99; //范围
}
break;
case 0x07:
if(work_mode==1)//手动模式
{
buzz&=0XEF;P2=0XA0;P0=buzz; //关闭灌溉
}
else //自动模式下
{
threshold--; //阈值减1
if(threshold<0)threshold=0; //范围
}
break;
}
keybyte=0;
}
}
}
最后就做完了。
main.c
#include <stc15f2k60s2.h>
#include "intrins.h"
#include "iic.h"
#include "ds1302.h"
#define uchar unsigned char
#define uint unsigned int
void SMG_output(void);
void init(void);
void Delay1ms(void);
void delay5ms(void);
void Dkey_scan(void);
extern uchar time[7]; //ds1302.c中定义的存储时间的数组
uchar tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,\
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xff,0xbf};
uchar SMG[8]={20,20,20,20,20,20,20,20};//初始显示10,全息数码管
uchar SMG_mode=0,move; //数码管模式定义,滑动变阻器Rb2定义
bit work_mode=0; //0为自动模式,1为手动模式
char threshold=50; //定义初始湿度阈值
uchar led=0xff,buzz=0x00; //定义led口和蜂鸣器继电器口,消除其他赋值干扰
bit buzz_state=1; //为1打开蜂鸣器,为0关闭蜂鸣器
void main(void)
{
init(); //初始开发板
ds1302_init(); //uchar time[7]={0,30,8,0,0,0,0}; 8:30:00
threshold=IIC_read(0xA0,0x00); //上电读取EEPROM
while(1)
{
get_time(); //时间获取
move=IIC_read(0x90,0x03); //读取Rb2电阻阻值
move=move*0.3921; //100/255 将255转换到100
if(SMG_mode==0)
{
SMG[0]=time[2]/10;SMG[1]=time[2]%10;SMG[2]=21; //时间显示
SMG[3]=time[1]/10;SMG[4]=time[1]%10;SMG[5]=20;
SMG[6]=move/10;SMG[7]=move%10; //显示湿度
}
else if(SMG_mode==1)
{
SMG[0]=SMG[1]=21;SMG[3]=SMG[4]=SMG[5]=20;
SMG[6]=threshold/10;SMG[7]=threshold%10; //显示湿度
}
if(work_mode==0) //自动模式
{
led |=0x02;led &=0xfe;P2=0X80;P0=led; //打开L1,关闭L2
if(move<threshold) //低于阈值
{
buzz|=0X10;P2=0XA0;P0=buzz; //打开继电器
}
else
{
buzz&=0XEF;P2=0XA0;P0=buzz; //关闭继电器
}
}
else //手动模式
{
led |=0x01;led &=0XFD;P2=0X80;P0=led; //打开L2,关闭L1
if((move<threshold)&&(buzz_state==1)) //低于阈值且允许蜂鸣器打开
{
buzz|=0X40;P2=0XA0;P0=buzz; //打开蜂鸣器
}
else
{
buzz&=0Xbf;P2=0XA0;P0=buzz; //关闭蜂鸣器
}
}
SMG_output();
Dkey_scan();
}
}
void Dkey_scan(void)
{
static uchar keybyte=0;
static uchar key;
if(((P3&0X0F)!=0X0F)&&(keybyte==0))
{
delay5ms();
if((P3&0X0F)!=0X0F)
{
keybyte=1;key=P3&0x0f;
}
}
if((keybyte==1)&&((P3&0X0F)==0X0F))
{
if((P3&0X0F)==0X0F)
{
switch(key)
{
case 0x0e:
if(work_mode==0)work_mode=1;
else work_mode=0;
break;
case 0x0d:
if(work_mode==1) //手动模式下
{
if(buzz_state==1){buzz_state=0;P2=0XA0;P0=0X00;} //关闭蜂鸣器
else {buzz_state=1;}//打开蜂鸣器使能
}
else //自动模式下
{
if(SMG_mode==0)SMG_mode=1; //切换数码管状态
else {SMG_mode=0;IIC_write(0xA0,0x00,threshold);} //存取EEPROM
}
break;
case 0x0b:
if(work_mode==1) //手动模式
{
buzz|=0X10;P2=0XA0;P0=buzz; //打开灌溉
}
else //自动模式下
{
threshold++; //阈值加1
if(threshold>99)threshold=99; //范围
}
break;
case 0x07:
if(work_mode==1)//手动模式
{
buzz&=0XEF;P2=0XA0;P0=buzz; //关闭灌溉
}
else //自动模式下
{
threshold--; //阈值减1
if(threshold<0)threshold=0; //范围
}
break;
}
keybyte=0;
}
}
}
void SMG_output(void)
{
uchar i;
for(i=0;i<8;i++)
{
P2=(P2&0X1F)|0Xc0;
P0=(1<<i);
P2=(P2&0X1F)|0Xe0;
P0=tab[SMG[i]];
Delay1ms();
}
P2=(P2&0X1F)|0Xc0;
P0=0Xff;
P2=(P2&0X1F)|0Xe0;
P0=0Xff;
}
void init(void)
{
P2=(P2&0X1F)|0XA0;
P0=0X00;
P2=(P2&0X1F)|0X80;
P0=0Xff;
P2=(P2&0X1F)|0Xc0;
P0=0Xff;
P2=(P2&0X1F)|0Xe0;
P0=0Xff;
}
void Delay1ms(void) //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
void delay5ms(void) //@11.0592MHz
{
unsigned char i, j;
i = 54;
j = 199;
do
{
while (--j);
} while (--i);
}
iic.c
#include "iic.h"
#define DELAY_TIME 40
void IIC_write(uchar hw_address,uchar reg_address,uchar num)
{
IIC_Start();
IIC_SendByte(hw_address&0xfe);
IIC_WaitAck();
IIC_SendByte(reg_address);
IIC_WaitAck();
IIC_SendByte(num);
IIC_WaitAck();
IIC_Stop();
}
uchar IIC_read(uchar hw_address,uchar reg_address)
{
uchar num;
IIC_Start();
IIC_SendByte(hw_address&0xfe);
IIC_WaitAck();
IIC_SendByte(reg_address);
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(hw_address|0x01);
IIC_WaitAck();
num=IIC_RecByte();
IIC_WaitAck();
IIC_Stop();
return num;
}
//
void IIC_Delay(unsigned char i)
{
do{_nop_();}
while(i--);
}
//
void IIC_Start(void)
{
SDA = 1;
SCL = 1;
IIC_Delay(DELAY_TIME);
SDA = 0;
IIC_Delay(DELAY_TIME);
SCL = 0;
}
//
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
IIC_Delay(DELAY_TIME);
SDA = 1;
IIC_Delay(DELAY_TIME);
}
//
void IIC_SendAck(bit ackbit)
{
SCL = 0;
SDA = ackbit;
IIC_Delay(DELAY_TIME);
SCL = 1;
IIC_Delay(DELAY_TIME);
SCL = 0;
SDA = 1;
IIC_Delay(DELAY_TIME);
}
//
bit IIC_WaitAck(void)
{
bit ackbit;
SCL = 1;
IIC_Delay(DELAY_TIME);
ackbit = SDA;
SCL = 0;
IIC_Delay(DELAY_TIME);
return ackbit;
}
//
void IIC_SendByte(unsigned char byt)
{
unsigned char i;
for(i=0; i<8; i++)
{
SCL = 0;
IIC_Delay(DELAY_TIME);
if(byt & 0x80) SDA = 1;
else SDA = 0;
IIC_Delay(DELAY_TIME);
SCL = 1;
byt <<= 1;
IIC_Delay(DELAY_TIME);
}
SCL = 0;
}
//
unsigned char IIC_RecByte(void)
{
unsigned char i, da;
for(i=0; i<8; i++)
{
SCL = 1;
IIC_Delay(DELAY_TIME);
da <<= 1;
if(SDA) da |= 1;
SCL = 0;
IIC_Delay(DELAY_TIME);
}
return da;
}
iic.h
#ifndef _IIC_H
#define _IIC_H
#include "stc15f2k60s2.h"
#include "intrins.h"
#define uchar unsigned char
#define uint unsigned int
sbit SDA = P2^1;
sbit SCL = P2^0;
void IIC_Start(void);
void IIC_Stop(void);
bit IIC_WaitAck(void);
void IIC_SendAck(bit ackbit);
void IIC_SendByte(unsigned char byt);
unsigned char IIC_RecByte(void);
void IIC_write(uchar hw_address,uchar reg_address,uchar num);
uchar IIC_read(uchar hw_address,uchar reg_address);
#endif
ds1302.c
#include "ds1302.h"
uchar time[7]={0,30,8,0,0,0,0};
void ds1302_init(void)
{
uchar i,j=0x80;
Write_Ds1302_Byte(0x8e,0x00);
for(i=0;i<7;i++)
{
Write_Ds1302_Byte(j,time[i]);
j +=2;
}
Write_Ds1302_Byte(0x8e,0x80);
}
void get_time(void)
{
uchar i,j=0x81;
Write_Ds1302_Byte(0x8e,0x00);
for(i=0;i<7;i++)
{
time[i]=Read_Ds1302_Byte(j);
j +=2;
}
Write_Ds1302_Byte(0x8e,0x80);
}
//
void Write_Ds1302(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++)
{
SCK = 0;
IO = 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/10)<<4)|(dat%10));
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(IO)
temp|=0x80;
SCK=1;
}
RST=0; _nop_();
SCK=0; _nop_();
SCK=1; _nop_();
IO=0; _nop_();
IO=1; _nop_();
return (((temp/16)*10)+(temp%16));
}
ds1302.h
#ifndef __DS1302_H
#define __DS1302_H
#include <stc15f2k60s2.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit SCK = P1^7;
sbit IO = P2^3;
sbit RST = P1^3;
void Write_Ds1302(unsigned char temp);
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302_Byte( unsigned char address );
void get_time(void);
void ds1302_init(void);
#endif