323|1

130

帖子

0

TA的资源

一粒金砂(中级)

自动浇花系统第四帖之软件篇 [复制链接]

软件方面的实现了如下功能:

1.一周七天可以设置开启时间和关闭时间,只能通过串口设置;

2.手动开启和关闭,手动开始2分钟后自动关闭;

3.时间显示功能;

4.设置保存和读取功能,使用mcu自带的eeprom保存。

第三贴

/*
Automatic Watering System 2025.03.01
*/

#include <Ticker.h>
#include <RtcDS1302.h>
#include <EEPROM.h>
#include "TM1637.h"

#define VALVE_PIN1 8
#define VALVE_PIN2 9
#define KEY_PIN 2
#define MANUAL_5_min 300000         //5 minutes
#define MANUAL_10_min 120000        //2 minutes
#define DISPLAY_TIME_INTERVAL 5000  //5 second
#define DAYS 8                      //0 day is today, 1 day is tomorrow ...
#define NUMBEROFTIMES 2
#define CLK 11  //pins definitions for TM1637 and can be changed to other ports
#define DIO 10
#define KEY_DELAY 15

TM1637 tm1637(CLK, DIO);
ThreeWire myWire(4, 5, 3);  // IO, SCLK, CE
RtcDS1302<ThreeWire> Rtc(myWire);
const int ledPin = LED_BUILTIN;
const int valvePin[] = { VALVE_PIN1, VALVE_PIN2 };
const int on_time = 0;
const int off_time = 1;
const int days_of_plan = DAYS;
const int minutes_per_day = 1440;
const int minutes_per_hour = 60;

int interval_day = 0;
int interval_time_per_day = 10;
int day_work_complete = 0;
int valve_state = 0;  //0 open, 1 close
volatile int key_state = 0;

//the number of minutes since midnight
unsigned int onOffTimes[days_of_plan][NUMBEROFTIMES] = { { 1394, 1400 }, { 1394, 1400 }, { 1394, 1400 }, { 1390, 1400 }, { 1390, 1400 }, { 1390, 1400 }, { 1390, 1400 }, { 1390, 1400 } };
unsigned int onOffTimes_eeprom[days_of_plan][NUMBEROFTIMES] = {};
int8_t TimeDisp[] = { 0x00, 0x00, 0x00, 0x00 };

RtcDateTime now;
RtcDateTime start_time;

void close_all_valve();
void display_time();

Ticker timer_manual_10_min(close_all_valve, MANUAL_10_min, 1);
// Ticker timer_manual_5_min(close_all_valve, MANUAL_5_min);
Ticker timer_display_time(display_time, DISPLAY_TIME_INTERVAL);


void close_all_valve() {
  valve_close(0);
  valve_close(1);
  Serial.println("in close all function");
  // timer_manual_10_min.stop();
}

//  valve open
void valve_open(int i) {
  digitalWrite(valvePin[i], LOW);
  tm1637.displayStr("Open");
  valve_state = 1;
}
// valve close
void valve_close(int i) {
  digitalWrite(valvePin[i], HIGH);
  tm1637.displayStr("Clos");
  valve_state = 0;
}

void display_time() {
  now = Rtc.GetDateTime();
  // Serial.println();
  // Serial.println();
  // printDateTime(now);
  // Serial.println();
  // printDateTime(start_time);
  // Serial.println();
  // Serial.print("Days from start:");
  // Serial.print(now.TotalDays() - start_time.TotalDays());
  // Serial.println();
  // Serial.print("Days of week is ");
  // Serial.println(now.DayOfWeek());
  if (!now.IsValid()) {
    // Common Causes:
    //    1) the battery on the device is low or even missing and the power line was disconnected
    Serial.println("RTC lost confidence in the DateTime!");
  }
  TimeDisp[0] = now.Hour() / 10;
  TimeDisp[1] = now.Hour() % 10;
  TimeDisp[2] = now.Minute() / 10;
  TimeDisp[3] = now.Minute() % 10;
  tm1637.display(TimeDisp);
  tm1637.point(now.Second() % 2);
  // Serial.println();
  // Serial.println();
  // Serial.print("Type 'P' to print settings or ");
  // Serial.println("'S2N13:45' to set valve 2 ON time to 13:34");
  // Serial.println("Please enter O to open valves");
  // Serial.println("Please enter C to close valves");
}
void setup() {
  //start serial connection
  Serial.begin(9600);
  //configure pin 2 as an input and enable the internal pull-up resistor
  pinMode(ledPin, OUTPUT);
  pinMode(valvePin[0], OUTPUT);
  pinMode(valvePin[1], OUTPUT);
  pinMode(KEY_PIN, INPUT_PULLUP);
  digitalWrite(valvePin[0], HIGH);  // close valve at begin
  digitalWrite(ledPin, LOW);        // LED off

  //RTC information display
  Serial.print("compiled: ");
  Serial.print(__DATE__);
  Serial.println(__TIME__);
  Rtc.Begin();

  RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
  printDateTime(compiled);
  Serial.println();

  if (!Rtc.IsDateTimeValid()) {
    // Common Causes:
    //    1) first time you ran and the device wasn't running yet
    //    2) the battery on the device is low or even missing
    Serial.println("RTC lost confidence in the DateTime!");
    Rtc.SetDateTime(compiled);
  }

  if (Rtc.GetIsWriteProtected()) {
    Serial.println("RTC was write protected, enabling writing now");
    Rtc.SetIsWriteProtected(false);
  }

  if (!Rtc.GetIsRunning()) {
    Serial.println("RTC was not actively running, starting now");
    Rtc.SetIsRunning(true);
  }

  now = Rtc.GetDateTime();
  if (now < compiled) {
    Serial.println("RTC is older than compile time!  (Updating DateTime)");
    Rtc.SetDateTime(compiled);
  } else if (now > compiled) {
    Serial.println("RTC is newer than compile time. (this is expected)");
  } else if (now == compiled) {
    Serial.println("RTC is the same as compile time! (not expected but all is fine)");
  }

  start_time = now;  // set system start time
  attachInterrupt(digitalPinToInterrupt(KEY_PIN), buttonPressed, CHANGE);
  timer_display_time.start();
  read_control_data();
  tm1637.set();
  tm1637.init();
}

void loop() {

  int sensorVal = digitalRead(KEY_PIN);  //read the pushbutton value into a variable
  timer_display_time.update();
  // timer_manual_5_min.update();
  timer_manual_10_min.update();
  checkUserInteraction();
  check_and_action();
  if (key_state == 1)
    control_by_key();
}

#define countof(a) (sizeof(a) / sizeof(a[0]))

void printDateTime(const RtcDateTime& dt) {
  char datestring[26];

  snprintf_P(datestring,
             countof(datestring),
             PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
             dt.Month(),
             dt.Day(),
             dt.Year(),
             dt.Hour(),
             dt.Minute(),
             dt.Second());
  Serial.print(datestring);
}

void buttonPressed() {
  if (key_state == 0)
    key_state = 1;
  return;
}

void control_by_key() {
  int buttonState = digitalRead(KEY_PIN);
  if (buttonState == LOW) {
    delay(KEY_DELAY);
    if (digitalRead(KEY_PIN) != LOW) {
      key_state = 0;
      return;
    }
    if (timer_manual_10_min.state() == STOPPED) {
      timer_manual_10_min.start();
      valve_open(0);
      valve_open(1);
      Serial.println("Valve open");
      key_state = 0;
      return;
    } else if (timer_manual_10_min.state() == RUNNING) {
      close_all_valve();
      Serial.println("Valve close");
      timer_manual_10_min.stop();
    }
  }
  key_state = 0;
  return;
}



void checkUserInteraction() {
  // Check for user interaction
  while (Serial.available() > 0) {

    // The first character tells us what to expect
    // for the rest of the line
    char temp = Serial.read();

    // If the first character is 'P' then
    // print the current settings
    // and break out of the while() loop
    if (temp == 'p') {
      // printSettings();
      print_eeprom();
      Serial.flush();
      break;
    }  // end of printing current settings

    // If first character is 'S' then the rest will be a setting
    else if (temp == 'S') {
      Serial.flush();
      expectValveSetting();
      save_control_data();
      Serial.flush();
      read_control_data();
      break;

    }
    // open valve
    else if (temp == 'o') {
      valve_open(0);
      valve_open(1);
      Serial.flush();
      break;
    }
    // close valve
    else if (temp == 'c') {
      valve_close(0);
      valve_close(1);
      Serial.flush();
      break;
    }
    // display control data
    else if (temp == 'd') {
      print_control_data();
      Serial.flush();
      break;
    }
    // Otherwise, it's an error.
    // Remind the user what the choices are
    // and break out of the while() loop
    else {
      printMenu();
      Serial.flush();
      break;
    }
  }  // end of processing user interaction
}


void printMenu() {
  Serial.println(
    "Please enter p to print the current settings");
  Serial.println(
    "Please enter S2N13:45 to set 2 day of week ON time to 13:34");
  Serial.println("Please enter o to open valves");
  Serial.println("Please enter c to close valves");
  Serial.println("Please enter d to display control data");
  Serial.println("Please enter p to display eeprom data");
}

void print_eeprom() {
  Serial.println("EEPROM content is:");
  for (int i = 0; i < EEPROM.length()/10; i++) {
    Serial.print(EEPROM.read(i));
    Serial.print(" ");
    if ((i+1) % 10 == 0 )
      Serial.println();
  }
  Serial.println();
}

void save_control_data() {
  noInterrupts();
  EEPROM.put(0, onOffTimes);
  delay(5);
  interrupts();
}

void read_control_data() {
  EEPROM.get(0, onOffTimes_eeprom);
}

void print_control_data() {
  Serial.println("Control data is:");
  for (int i = 0; i < days_of_plan; i++)
    for (int j = 0; j < NUMBEROFTIMES; j++) {
      Serial.print(onOffTimes[i][j]);
      Serial.print(" ");
    }
  Serial.println();
}

void check_and_action() {
  if (now.Hour() * minutes_per_hour + now.Minute() >= onOffTimes[now.DayOfWeek()][0] && now.Hour() * minutes_per_hour + now.Minute() < onOffTimes[now.DayOfWeek()][1] && valve_state == 0) {
    valve_open(0);
    valve_open(1);
  }
  if (now.Hour() * minutes_per_hour + now.Minute() >= onOffTimes[now.DayOfWeek()][0] && now.Hour() * minutes_per_hour + now.Minute() >= onOffTimes[now.DayOfWeek()][1] && valve_state == 1) {
    valve_close(0);
    valve_close(1);
    valve_close(0);
    valve_close(1);
  }
}


void expectValveSetting() {

  // The first integer should be the day of week, only have one valve
  int day_of_week = Serial.parseInt();

  // the next character should be either N or F
  char onOff = Serial.read();

  // next should come the hour
  int desiredHour = Serial.parseInt();

  // the next character should be ':'
  if (Serial.read() != ':') {
    Serial.println("no : found");  // Sanity check
    Serial.flush();
    return;
  }

  // next should come the minutes
  int desiredMinutes = Serial.parseInt();

  // finally expect a newline which is the end of
  // the sentence:
  if (Serial.read() != '\n') {  // Sanity check
    Serial.println(
      "Make sure to end your request with a Newline");
    Serial.flush();
    return;
  }

  // Convert the desired hour and minute time
  // to the number of minutes since midnight
  int desiredMinutesSinceMidnight = (desiredHour * 60 + desiredMinutes);

  // Now that we have all the information set it into the array
  // in the correct row and column

  if (onOff == 'N') {  // it's an ON time
    onOffTimes[day_of_week][on_time] = desiredMinutesSinceMidnight;
  } else if (onOff == 'F') {  // it's an OFF time
    onOffTimes[day_of_week][off_time] = desiredMinutesSinceMidnight;
  } else {  // user didn't use N or F
    Serial.print("You must use upper case N or F ");
    Serial.println("to indicate ON time or OFF time");
    Serial.flush();
    return;
  }

}  // end of expectValveSetting()

 

最新回复

浇花系统是不是成品快弄好了呀   详情 回复 发表于 2025-3-10 09:34

回复
举报

1万

帖子

202

TA的资源

管理员

浇花系统是不是成品快弄好了呀

加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
个人签名玩板看这里:
https://bbs.eeworld.com.cn/elecplay.html
EEWorld测评频道众多好板等你来玩,还可以来频道许愿树许愿说说你想要玩的板子,我们都在努力为大家实现!

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网 14

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表