蓝桥杯第四届初赛“模拟智能灌溉系统”设计任务书

本文档介绍了蓝桥杯第四届初赛的‘模拟智能灌溉系统’设计任务,包括自动和手动工作模式,湿度阈值控制及继电器模拟。作者提供了详细的代码实现,包括主函数main.c,IIC总线驱动iic.c和iic.h,以及DS1302时钟驱动ds1302.c和ds1302.h。代码实现了湿度检测、继电器控制以及按键交互等功能。
摘要由CSDN通过智能技术生成

蓝桥杯第四届初赛“模拟智能灌溉系统”设计任务书

Author:Luis
Time:2022-04-10
Version:v1.0

说明

​ 蓝桥杯系列的代码都是本人亲手写和调试,可能有时会有点错误,请见谅。此外,代码仅供大家学习,祝福各位在蓝桥杯比赛中能获得比较满意的成绩。

​ 忙着期中考试,今天就来“水”一下今天的博客。

​ 从第五届的题目开始,我就会开始一步步地分析题目并且写出代码。分析能力和思路更重要,代码只是实现手段,大家不能局限于代码。

功能简介

1.1 自动工作状态,根据湿度数据自动控制打开或关闭灌溉设备,以L1 点亮指示;
1.2 手动工作状态,通过按键控制打开或关闭灌溉设备,以L2 点亮指示;
1.3 系统上电后处于自动工作状态,系统初始湿度阈值为50%,此时若湿度低于
50%,灌溉设备自动打开,达到50%后,灌溉设备自动关闭;
1.4 灌溉设备打开或关闭通过继电器工作状态模拟。

具体代码

main.c

/*******************************************************************************
 * 目标:第四届题目 “模拟智能灌溉系统”设计任务书
 * 注意:J3跳线配置为IO方式,J5配置为BTN、J2配置为1-3和2-4
 *******************************************************************************/
#include <STC15F2K60S2.h>
#include "intrins.h"
#include "ds1302.h"
#include "iic.h"

unsigned char *time_ds1302;    // 时间
unsigned char ds1302_flag = 0; // 0 1

unsigned char key_value = 0;
unsigned char key_flag = 0;

unsigned char adc_flag = 0;
// 小数点是第8位为0 原本数字 - 0x80
unsigned char data_pros[] = {
    0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0xff, 0xbf};
unsigned char dspbuf[8] = {10, 10, 10, 10, 10, 10, 10, 10}; //显示缓冲区

// 初始化值
void close_init()
{
    P2 = 0xA0;
    P0 = 0x00;
    P2 = 0x80;
    P0 = 0xff;
    P2 = 0x00;
}

void Delay5ms() //@11.0592MHz
{
    unsigned char i, j;

    i = 54;
    j = 199;
    do
    {
        while (--j)
            ;
    } while (--i);
}

void Delay500ms() //@11.0592MHz
{
    unsigned char i, j, k;

    _nop_();
    _nop_();
    i = 22;
    j = 3;
    k = 227;
    do
    {
        do
        {
            while (--k)
                ;
        } while (--j);
    } while (--i);
}

// 显示函数 dspbuf为数码管的缓冲区
void display()
{
    static unsigned char dspnum = 0; // 数码管的位置
    P2 = 0xE0;
    P2 = 0xff; // 消影

    P2 = 0xc0;
    P0 = (1 << dspnum);

    P2 = 0xe0;
    P0 = data_pros[dspbuf[dspnum]];

    P2 = 0x00;
    if (++dspnum == 8)
        dspnum = 0;
}

void Timer0Init(void) // 1毫秒@11.0592MHz
{
    AUXR |= 0x80; //定时器时钟1T模式
    TMOD &= 0xF0; //设置定时器模式
    TL0 = 0xCD;   //设置定时初值
    TH0 = 0xD4;   //设置定时初值
    TF0 = 0;      //清除TF0标志
    TR0 = 1;      //定时器0开始计时

    // add
    TH1 = 0;
    TL1 = 0;
    ET0 = 1;
    EA = 1;
}

// 读取独立键值 J5为BTN模式
unsigned char read_key()
{
    static unsigned char key_press = 0; // 按下次数
    unsigned char key_temp;
    static bit key_re = 0;
    static unsigned char key_value = 0;

    key_temp = (P3 & 0x0f); // 取低位值
    /**************多次检测,可以可以防止抖动*********************/
    if (key_temp != 0x0f)
        key_press++;
    else
        key_press = 0;

    if (key_press == 5) // 连续5次按压
    {
        key_press = 0;
        key_re = 1; // 按下
        switch (key_temp)
        {
        case 0x0e:
            key_value = 1; // S7
            break;
        case 0x0d:
            key_value = 2; // S6
            break;
        case 0x0b:
            key_value = 3; // S5
            break;
        case 0x07:
            key_value = 4; // S4
            break;
        }
    }
    //连续5次检测到按键被按下,并且该按键已经释放
    if ((key_re == 1) && (key_temp == 0x0f))
    {
        key_re = 0;
        return key_value;
    }

    return 0xff; //无按键按下或被按下的按键未被释放
}

void main()
{
    unsigned char eeprom_value[2] = {5, 0};
    unsigned char eeprom_location[2] = {0x00, 0x01};
    unsigned char shidu = 0; // 湿度
    unsigned char i = 0;
    bit mode = 1;  // 模式 0 手动 1 自动
    bit mode6 = 0; // 模式 自动模式 调节页面
    unsigned char adc_pcf8591_value = 0;
    bit buzz_flag = 1; // 警报声
    bit guangai = 0;   // 是否打开灌溉系统
    close_init();
    Timer0Init();
    SetRTC();
    init_pcf8591();
    Delay5ms();
    // for (i = 0; i < 2; i++)
    // {
    //     Write_EEPROM(eeprom_location[i], eeprom_value[i]);
    //     Delay500ms();
    // }
    for (i = 0; i < 2; i++)
    {
        eeprom_value[i] = Read_EEPROM(eeprom_location[i]);
        Delay500ms();
    }
    shidu = 10 * eeprom_value[0] + eeprom_value[1];
    dspbuf[6] = shidu / 10;
    dspbuf[7] = shidu % 10;
    P2 = 0x80;
    P0 = 0xFE;
    P2 = 0x00;
    while (1)
    {
        if ((ds1302_flag == 1) && (mode6 == 0))
        {
            ds1302_flag = 0;
            time_ds1302 = ReadRTC();
            // 更新时间
            dspbuf[0] = time_ds1302[0];
            dspbuf[1] = time_ds1302[1];
            dspbuf[2] = 11;
            dspbuf[3] = time_ds1302[2];
            dspbuf[4] = time_ds1302[3];
        }

        if (key_flag == 1)
        {
            key_value = read_key();
            if (key_value != 0xff)
            {
                switch (key_value)
                {
                case 1:
                {
                    mode = !(mode);
                    if (mode == 0) // 手动模式必须 mode6=0
                    {
                        mode6 = 0;
                        P2 = 0x80;
                        P0 = 0xFD;
                        P2 = 0x00;
                    }
                    if (mode == 1)
                    {
                        mode6 = 0;
                        P2 = 0x80;
                        P0 = 0xFE;
                        P2 = 0x00;
                        P2 = 0xA0;
                        P0 = 0x00;
                        P2 = 0x00; // 关掉蜂鸣器
                    }
                }
                break;
                case 2:
                {
                    buzz_flag = 1;                   // 给检测权限
                    mode6 = !(mode6);                // mode=0 mode6=0是打开警报 mode=1 mode6=1 是开启状态
                    if ((mode == 1) && (mode6 == 1)) // 自动模式下调节S6
                    {
                        dspbuf[0] = 11;
                        dspbuf[1] = 11;
                        for (i = 2; i < 6; i++)
                            dspbuf[i] = 10;
                        dspbuf[6] = shidu / 10;
                        dspbuf[7] = shidu % 10;
                    }
                    if ((mode == 1) && (mode6 == 0))
                    {
                        Write_EEPROM(eeprom_location[0], dspbuf[6]);
                        Delay500ms();
                        Write_EEPROM(eeprom_location[1], dspbuf[7]);
                    }
                }
                break;
                case 3:
                {
                    if (mode == 0)
                        guangai = 1;
                    if (mode6 == 1)
                    {
                        shidu++;
                        if (shidu >= 100)
                            shidu = 99;
                        dspbuf[6] = shidu / 10;
                        dspbuf[7] = shidu % 10;
                    }
                }
                break;
                case 4:
                {
                    if (mode == 0)
                        guangai = 0;
                    if (mode6 == 1)
                    {
                        shidu--;
                        if (shidu <= 0)
                            shidu = 1;
                        dspbuf[6] = shidu / 10;
                        dspbuf[7] = shidu % 10;
                    }
                }
                break;
                }
            }
        }

        if ((mode == 0) && (adc_flag == 1) && (guangai == 1))
        {
            adc_flag = 0;
            adc_pcf8591_value = adc_pcf8591(); // 255 -->100
            shidu = (adc_pcf8591_value * 99 / (255.0));
            dspbuf[6] = shidu / 10;
            dspbuf[7] = shidu % 10;
        }
        if ((mode == 0) && (shidu < 50)) // 湿度检测 低于50 且 mode6模式为开响
        {
            if ((mode6 == 0) && (buzz_flag == 1))
            {
                buzz_flag = 0; // 防止鬼影
                P2 = 0xA0;
                P0 = 0x40;
                P2 = 0x00;
            }
            if ((mode6 == 1))
            {
                P2 = 0xA0;
                P0 = 0x00;
                P2 = 0x00;
            }
        }
        if ((mode == 0) && (shidu >= 50))
        {
            buzz_flag = 1;
            P2 = 0xA0;
            P0 = 0x00;
            P2 = 0x00;
        }
    }
}

void isr_time_0() interrupt 1
{
    static unsigned char ds1302_time = 0;
    static unsigned char key_time = 0;
    static unsigned char adc_time = 0;
    display();
    if (++ds1302_time == 200) // 必须设置刷新时间,不然有问题
    {
        ds1302_time = 0;
        ds1302_flag = 1;
    }
    if (++key_time == 20)
    {
        key_time = 0;
        key_flag = 1;
    }
    if (++adc_time == 200)
    {
        adc_time = 0;
        adc_flag = 1;
    }
}

iic.c

/*
  程序说明: IIC总线驱动程序
  软件环境: Keil uVision 4.10
  硬件环境: CT107单片机综合实训平台 8051,12MHz
  日    期: 2011-8-9
*/

#include "reg52.h"
#include "intrins.h"

#define DELAY_TIME 5

#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1

//总线引脚定义
sbit SDA = P2 ^ 1; /* 数据线 */
sbit SCL = P2 ^ 0; /* 时钟线 */

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; // 0:应答,1:非应答
    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;
}

//通过I2C总线发送数据
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;
}

//从I2C总线上接收数据
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;
}

// add
// AT24C02
// 写数据
void Write_EEPROM(unsigned char addr, unsigned char dat)
{
    EA = 0;
    IIC_Start();
    IIC_SendByte(0xA0); // 看芯片手册Figure 7 -W为低电平有效
    IIC_WaitAck();

    IIC_SendByte(addr); // 0x00-0xff
    IIC_WaitAck();

    IIC_SendByte(dat);
    IIC_WaitAck();
    IIC_Stop();
    EA = 1;
}

// 读数据
unsigned char Read_EEPROM(unsigned char addr)
{
    unsigned char da;

    EA = 0;
    IIC_Start();
    IIC_SendByte(0xA0);
    IIC_WaitAck();

    IIC_SendByte(addr);
    IIC_WaitAck();

    IIC_Start();
    IIC_SendByte(0xA1);
    IIC_WaitAck();

    da = IIC_RecByte();
    IIC_SendAck(1); // 非应答,停止读取
    IIC_Stop();

    EA = 1;
    return da;
}

// addd
// PCF8591
void init_pcf8591()
{
    EA = 0;
    IIC_Start();
    IIC_SendByte(0x90);
    IIC_WaitAck();

    IIC_SendByte(0X03); // 第一通道
    IIC_WaitAck();
    IIC_Stop();
    EA = 1;
}

// 通过I2C总线读取ADC结果
unsigned char adc_pcf8591()
{
    unsigned char da;

    EA = 0;
    IIC_Start();
    IIC_SendByte(0x91);
    IIC_WaitAck();

    da = IIC_RecByte();
    IIC_SendAck(1);

    IIC_Stop();

    EA = 1;
    return da;
}

iic.h

#ifndef __IIC_H
#define __IIC_H

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 Write_EEPROM(unsigned char addr, unsigned char dat);
unsigned char Read_EEPROM(unsigned char addr);

void init_pcf8591();         // 初始化pcf8591
unsigned char adc_pcf8591(); // 通过I2C总线读取ADC结果
#endif

ds1302.c

/*
  程序说明: DS1302驱动程序
  软件环境: Keil uVision 4.10
  硬件环境: CT107单片机综合实训平台 8051,12MHz
  日    期: 2011-8-9
*/

#include <reg52.h>
#include <intrins.h>

sbit SCK = P1 ^ 7;
sbit SDA = P2 ^ 3;
sbit RST = P1 ^ 3; // DS1302复位

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);
}

// 添加的
code unsigned char w_rtc_address[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c}; //秒分时日月周年
code unsigned char r_rtc_address[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};

unsigned char set[6] = {0, 8, 3, 0, 0, 0}; // 时间可以自己修改
unsigned char rtc[6];

// 设置时间
void SetRTC(void)
{
	Write_Ds1302_Byte(0x8E, 0X00); // WP=0,允许写操作

	Write_Ds1302_Byte(w_rtc_address[0], (set[4] << 4) | (set[5])); //秒分时 10进制转16进制 组合起来
	Write_Ds1302_Byte(w_rtc_address[1], (set[2] << 4) | (set[3]));
	Write_Ds1302_Byte(w_rtc_address[2], (set[0] << 4) | (set[1]));

	Write_Ds1302_Byte(0x8E, 0x80); // WP=1,禁止写操作
}

// 读取时间
unsigned char *ReadRTC(void)
{
	unsigned char i, *p;
	unsigned char tmp[3];

	p = (unsigned char *)r_rtc_address; //地址传递

	for (i = 0; i < 3; i++)
	{
		tmp[i] = Read_Ds1302_Byte(*p);
		p++;
	}

	rtc[0] = (tmp[2] >> 4); // 16进制转10进制
	rtc[1] = (tmp[2] & 0x0F);

	rtc[2] = (tmp[1] >> 4);
	rtc[3] = (tmp[1] & 0x0F);

	rtc[4] = (tmp[0] >> 4);
	rtc[5] = (tmp[0] & 0x0F);

	return rtc;
}

ds1302.h

#ifndef __DS1302_H
#define __DS1302_H

// void Write_Ds1302(unsigned char temp);
// void Write_Ds1302_Byte(unsigned char address, unsigned char dat);
// unsigned char Read_Ds1302_Byte(unsigned char address);

// add
void SetRTC(void);
unsigned char *ReadRTC(void); // unsigned char *p_rtc;读取
#endif
  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值