- 2025-03-22
-
回复了主题帖:
用了一年的休息时间给我女儿设计的电动车
这不是电动自行车吗?为什么要用电动车的接口?
-
回复了主题帖:
自动浇花系统第四帖之软件篇
本帖最后由 serialworld 于 2025-3-22 07:07 编辑
上一版的代码存储开关阀门时间的部分有Bug,这一版更新了一下。另外,还加入输入控制参数的正确性检查。目前手动控制还以有个Bug,待后面完善。
/*
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] = { { 600, 604 }, { 600, 604 }, { 600, 604 }, { 600, 604 }, { 600, 604 }, { 600, 604 }, { 600, 604 }, { 600, 604 } };
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());
Serial.println();
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!");
return;
}
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);
EEPROM.get(0, onOffTimes);
}
void print_control_data() {
Serial.println("Control data is:");
char timetring[26];
for (int i = 0; i < days_of_plan - 1; i++) {
Serial.print(i);
Serial.print(" day of week, on off time is: ");
for (int j = 0; j < NUMBEROFTIMES; j++) {
snprintf_P(timetring,
countof(timetring),
PSTR("%02u:%02u"),
onOffTimes[i][j] / 60,
onOffTimes[i][j] % 60);
Serial.print(timetring);
Serial.print(" ");
}
Serial.println();
}
Serial.println();
}
void check_and_action() {
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!");
valve_close(0);
valve_close(1);
valve_close(0);
valve_close(1);
tm1637.displayStr("Rtc Error!");
return;
}
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 (desiredMinutes < 0 || desiredMinutes > 59) {
Serial.print("You must input correct minutes >0 and < 59 ");
Serial.flush();
return;
}
if (desiredHour < 0 || desiredHour > 23) {
Serial.print("You must input correct hours >0 and < 24 ");
Serial.flush();
return;
}
if (day_of_week < 0 || day_of_week > 7) {
Serial.print("You must input correct day of week, 0 Sunday, 1 Monday, ... ");
Serial.flush();
return;
}
if (onOff == 'N' && desiredMinutesSinceMidnight < minutes_per_day && desiredMinutesSinceMidnight >= 0) { // it's an ON time
onOffTimes[day_of_week][on_time] = desiredMinutesSinceMidnight;
} else if (onOff == 'F' && desiredMinutesSinceMidnight < minutes_per_day && desiredMinutesSinceMidnight > 0 && desiredMinutesSinceMidnight > onOffTimes[day_of_week][on_time]) { // 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-03-21
-
回复了主题帖:
【新年花灯】STM32 F030 点亮WS2812流水灯
本帖最后由 serialworld 于 2025-3-22 06:53 编辑
具体实现的原理是借鉴了帖子WS2812灯珠的STM32驱动
是用DMA+PWM相结合实现的。具体代码如下,供大家参考。
硬件使用的是STM32F0开发板,外壳使用的是一个开关面板的暗盒。
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @File : main.c
* @brief : Main program body
******************************************************************************
** This notice applies to any and all portions of this file
* that are not between comment pairs USER CODE BEGIN and
* USER CODE END. Other portions of this file, whether
* inserted by the user or by software development tools
* are owned by their respective copyright owners.
*
* COPYRIGHT(c) 2019 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#define led_num 8
#define led_buffer_len 192
#define led_ctr_len 8
#ifdef USE_COLOR_RGB565
#define C_MAROON 0x8000
#define C_DARK_RED 0x8800
#define C_BROWN 0xA145
#define C_FIREBRICK 0xB104
#define C_CRIMSON 0xD8A7
#define C_RED 0xF800
#define C_TOMATO 0xFB09
#define C_CORAL 0xFBEA
#define C_INDIAN_RED 0xCAEB
#define C_LIGHT_CORAL 0xEC10
#define C_DARK_SALMON 0xE4AF
#define C_SALMON 0xF40E
#define C_LIGHT_SALMON 0xFD0F
#define C_ORANGE_RED 0xFA20
#define C_DARK_ORANGE 0xFC60
#define C_ORANGE 0xFD20
#define C_GOLD 0xFEA0
#define C_DARK_GOLDEN_ROD 0xB421
#define C_GOLDEN_ROD 0xDD24
#define C_PALE_GOLDEN_ROD 0xEF35
#define C_DARK_KHAKI 0xBDAD
#define C_KHAKI 0xEF31
#define C_OLIVE 0x8400
#define C_YELLOW 0xFFE0
#define C_YELLOW_GREEN 0x9E66
#define C_DARK_OLIVE_GREEN 0x5346
#define C_OLIVE_DRAB 0x6C64
#define C_LAWN_GREEN 0x7FC0
#define C_CHART_REUSE 0x7FE0
#define C_GREEN_YELLOW 0xAFE6
#define C_DARK_GREEN 0x0320
#define C_GREEN 0x07E0
#define C_FOREST_GREEN 0x2444
#define C_LIME 0x07E0
#define C_LIME_GREEN 0x3666
#define C_LIGHT_GREEN 0x9772
#define C_PALE_GREEN 0x97D2
#define C_DARK_SEA_GREEN 0x8DD1
#define C_MEDIUM_SPRING_GREEN 0x07D3
#define C_SPRING_GREEN 0x07EF
#define C_SEA_GREEN 0x344B
#define C_MEDIUM_AQUA_MARINE 0x6675
#define C_MEDIUM_SEA_GREEN 0x3D8E
#define C_LIGHT_SEA_GREEN 0x2595
#define C_DARK_SLATE_GRAY 0x328A
#define C_TEAL 0x0410
#define C_DARK_CYAN 0x0451
#define C_AQUA 0x07FF
#define C_CYAN 0x07FF
#define C_LIGHT_CYAN 0xDFFF
#define C_DARK_TURQUOISE 0x0679
#define C_TURQUOISE 0x46F9
#define C_MEDIUM_TURQUOISE 0x4E99
#define C_PALE_TURQUOISE 0xAF7D
#define C_AQUA_MARINE 0x7FFA
#define C_POWDER_BLUE 0xAEFC
#define C_CADET_BLUE 0x64F3
#define C_STEEL_BLUE 0x4C16
#define C_CORN_FLOWER_BLUE 0x64BD
#define C_DEEP_SKY_BLUE 0x05FF
#define C_DODGER_BLUE 0x249F
#define C_LIGHT_BLUE 0xAEBC
#define C_SKY_BLUE 0x867D
#define C_LIGHT_SKY_BLUE 0x867E
#define C_MIDNIGHT_BLUE 0x18CE
#define C_NAVY 0x0010
#define C_DARK_BLUE 0x0011
#define C_MEDIUM_BLUE 0x0019
#define C_BLUE 0x001F
#define C_ROYAL_BLUE 0x435B
#define C_BLUE_VIOLET 0x897B
#define C_INDIGO 0x4810
#define C_DARK_SLATE_BLUE 0x49F1
#define C_SLATE_BLUE 0x6AD9
#define C_MEDIUM_SLATE_BLUE 0x7B5D
#define C_MEDIUM_PURPLE 0x939B
#define C_DARK_MAGENTA 0x8811
#define C_DARK_VIOLET 0x901A
#define C_DARK_ORCHID 0x9999
#define C_MEDIUM_ORCHID 0xBABA
#define C_PURPLE 0x8010
#define C_THISTLE 0xD5FA
#define C_PLUM 0xDD1B
#define C_VIOLET 0xEC1D
#define C_MAGENTA 0xF81F
#define C_ORCHID 0xDB9A
#define C_MEDIUM_VIOLET_RED 0xC0B0
#define C_PALE_VIOLET_RED 0xDB92
#define C_DEEP_PINK 0xF8B2
#define C_HOT_PINK 0xFB56
#define C_LIGHT_PINK 0xFDB7
#define C_PINK 0xFDF9
#define C_ANTIQUE_WHITE 0xF75A
#define C_BEIGE 0xF7BB
#define C_BISQUE 0xFF18
#define C_BLANCHED_ALMOND 0xFF59
#define C_WHEAT 0xF6F6
#define C_CORN_SILK 0xFFBB
#define C_LEMON_CHIFFON 0xFFD9
#define C_LIGHT_GOLDEN_ROD_YELLOW 0xF7DA
#define C_LIGHT_YELLOW 0xFFFB
#define C_SADDLE_BROWN 0x8A22
#define C_SIENNA 0x9A85
#define C_CHOCOLATE 0xD344
#define C_PERU 0xCC28
#define C_SANDY_BROWN 0xF52C
#define C_BURLY_WOOD 0xDDB0
#define C_TAN 0xD591
#define C_ROSY_BROWN 0xBC71
#define C_MOCCASIN 0xFF16
#define C_NAVAJO_WHITE 0xFEF5
#define C_PEACH_PUFF 0xFED6
#define C_MISTY_ROSE 0xFF1B
#define C_LAVENDER_BLUSH 0xFF7E
#define C_LINEN 0xF77C
#define C_OLD_LACE 0xFFBC
#define C_PAPAYA_WHIP 0xFF7A
#define C_SEA_SHELL 0xFFBD
#define C_MINT_CREAM 0xF7FE
#define C_SLATE_GRAY 0x7412
#define C_LIGHT_SLATE_GRAY 0x7453
#define C_LIGHT_STEEL_BLUE 0xAE1B
#define C_LAVENDER 0xE73E
#define C_FLORAL_WHITE 0xFFDD
#define C_ALICE_BLUE 0xEFBF
#define C_GHOST_WHITE 0xF7BF
#define C_HONEYDEW 0xEFFD
#define C_IVORY 0xFFFD
#define C_AZURE 0xEFFF
#define C_SNOW 0xFFDE
#define C_BLACK 0x0000
#define C_DIM_GRAY 0x6B4D
#define C_GRAY 0x8410
#define C_DARK_GRAY 0xAD55
#define C_SILVER 0xBDF7
#define C_LIGHT_GRAY 0xD69A
#define C_GAINSBORO 0xDEDB
#define C_WHITE_SMOKE 0xF7BE
#define C_WHITE 0xFFFF
#endif
#ifdef USE_COLOR_RGB888
#define C_MAROON 0x800000
#define C_DARK_RED 0x8B0000
#define C_BROWN 0xA52A2A
#define C_FIREBRICK 0xB22222
#define C_CRIMSON 0xDC143C
#define C_RED 0xFF0000
#define C_TOMATO 0xFF6347
#define C_CORAL 0xFF7F50
#define C_INDIAN_RED 0xCD5C5C
#define C_LIGHT_CORAL 0xF08080
#define C_DARK_SALMON 0xE9967A
#define C_SALMON 0xFA8072
#define C_LIGHT_SALMON 0xFFA07A
#define C_ORANGE_RED 0xFF4500
#define C_DARK_ORANGE 0xFF8C00
#define C_ORANGE 0xFFA500
#define C_GOLD 0xFFD700
#define C_DARK_GOLDEN_ROD 0xB8860B
#define C_GOLDEN_ROD 0xDAA520
#define C_PALE_GOLDEN_ROD 0xEEE8AA
#define C_DARK_KHAKI 0xBDB76B
#define C_KHAKI 0xF0E68C
#define C_OLIVE 0x808000
#define C_YELLOW 0xFFFF00
#define C_YELLOW_GREEN 0x9ACD32
#define C_DARK_OLIVE_GREEN 0x556B2F
#define C_OLIVE_DRAB 0x6B8E23
#define C_LAWN_GREEN 0x7CFC00
#define C_CHART_REUSE 0x7FFF00
#define C_GREEN_YELLOW 0xADFF2F
#define C_DARK_GREEN 0x006400
#define C_GREEN 0x00FF00
#define C_FOREST_GREEN 0x228B22
#define C_LIME 0x00FF00
#define C_LIME_GREEN 0x32CD32
#define C_LIGHT_GREEN 0x90EE90
#define C_PALE_GREEN 0x98FB98
#define C_DARK_SEA_GREEN 0x8FBC8F
#define C_MEDIUM_SPRING_GREEN 0x00FA9A
#define C_SPRING_GREEN 0x00FF7F
#define C_SEA_GREEN 0x2E8B57
#define C_MEDIUM_AQUA_MARINE 0x66CDAA
#define C_MEDIUM_SEA_GREEN 0x3CB371
#define C_LIGHT_SEA_GREEN 0x20B2AA
#define C_DARK_SLATE_GRAY 0x2F4F4F
#define C_TEAL 0x008080
#define C_DARK_CYAN 0x008B8B
#define C_AQUA 0x00FFFF
#define C_CYAN 0x00FFFF
#define C_LIGHT_CYAN 0xE0FFFF
#define C_DARK_TURQUOISE 0x00CED1
#define C_TURQUOISE 0x40E0D0
#define C_MEDIUM_TURQUOISE 0x48D1CC
#define C_PALE_TURQUOISE 0xAFEEEE
#define C_AQUA_MARINE 0x7FFFD4
#define C_POWDER_BLUE 0xB0E0E6
#define C_CADET_BLUE 0x5F9EA0
#define C_STEEL_BLUE 0x4682B4
#define C_CORN_FLOWER_BLUE 0x6495ED
#define C_DEEP_SKY_BLUE 0x00BFFF
#define C_DODGER_BLUE 0x1E90FF
#define C_LIGHT_BLUE 0xADD8E6
#define C_SKY_BLUE 0x87CEEB
#define C_LIGHT_SKY_BLUE 0x87CEFA
#define C_MIDNIGHT_BLUE 0x191970
#define C_NAVY 0x000080
#define C_DARK_BLUE 0x00008B
#define C_MEDIUM_BLUE 0x0000CD
#define C_BLUE 0x0000FF
#define C_ROYAL_BLUE 0x4169E1
#define C_BLUE_VIOLET 0x8A2BE2
#define C_INDIGO 0x4B0082
#define C_DARK_SLATE_BLUE 0x483D8B
#define C_SLATE_BLUE 0x6A5ACD
#define C_MEDIUM_SLATE_BLUE 0x7B68EE
#define C_MEDIUM_PURPLE 0x9370DB
#define C_DARK_MAGENTA 0x8B008B
#define C_DARK_VIOLET 0x9400D3
#define C_DARK_ORCHID 0x9932CC
#define C_MEDIUM_ORCHID 0xBA55D3
#define C_PURPLE 0x800080
#define C_THISTLE 0xD8BFD8
#define C_PLUM 0xDDA0DD
#define C_VIOLET 0xEE82EE
#define C_MAGENTA 0xFF00FF
#define C_ORCHID 0xDA70D6
#define C_MEDIUM_VIOLET_RED 0xC71585
#define C_PALE_VIOLET_RED 0xDB7093
#define C_DEEP_PINK 0xFF1493
#define C_HOT_PINK 0xFF69B4
#define C_LIGHT_PINK 0xFFB6C1
#define C_PINK 0xFFC0CB
#define C_ANTIQUE_WHITE 0xFAEBD7
#define C_BEIGE 0xF5F5DC
#define C_BISQUE 0xFFE4C4
#define C_BLANCHED_ALMOND 0xFFEBCD
#define C_WHEAT 0xF5DEB3
#define C_CORN_SILK 0xFFF8DC
#define C_LEMON_CHIFFON 0xFFFACD
#define C_LIGHT_GOLDEN_ROD_YELLOW 0xFAFAD2
#define C_LIGHT_YELLOW 0xFFFFE0
#define C_SADDLE_BROWN 0x8B4513
#define C_SIENNA 0xA0522D
#define C_CHOCOLATE 0xD2691E
#define C_PERU 0xCD853F
#define C_SANDY_BROWN 0xF4A460
#define C_BURLY_WOOD 0xDEB887
#define C_TAN 0xD2B48C
#define C_ROSY_BROWN 0xBC8F8F
#define C_MOCCASIN 0xFFE4B5
#define C_NAVAJO_WHITE 0xFFDEAD
#define C_PEACH_PUFF 0xFFDAB9
#define C_MISTY_ROSE 0xFFE4E1
#define C_LAVENDER_BLUSH 0xFFF0F5
#define C_LINEN 0xFAF0E6
#define C_OLD_LACE 0xFDF5E6
#define C_PAPAYA_WHIP 0xFFEFD5
#define C_SEA_SHELL 0xFFF5EE
#define C_MINT_CREAM 0xF5FFFA
#define C_SLATE_GRAY 0x708090
#define C_LIGHT_SLATE_GRAY 0x778899
#define C_LIGHT_STEEL_BLUE 0xB0C4DE
#define C_LAVENDER 0xE6E6FA
#define C_FLORAL_WHITE 0xFFFAF0
#define C_ALICE_BLUE 0xF0F8FF
#define C_GHOST_WHITE 0xF8F8FF
#define C_HONEYDEW 0xF0FFF0
#define C_IVORY 0xFFFFF0
#define C_AZURE 0xF0FFFF
#define C_SNOW 0xFFFAFA
#define C_BLACK 0x000000
#define C_DIM_GRAY 0x696969
#define C_GRAY 0x808080
#define C_DARK_GRAY 0xA9A9A9
#define C_SILVER 0xC0C0C0
#define C_LIGHT_GRAY 0xD3D3D3
#define C_GAINSBORO 0xDCDCDC
#define C_WHITE_SMOKE 0xF5F5F5
#define C_WHITE 0xFFFFFF
#endif
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
uint32_t led_buffer[192] = { 13, 13, 13, 26, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 26, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 26, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13,
13, 13, 13, 26, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 26, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 26, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13,
13, 13, 13, 26, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13,
13, 13, 13, 26, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13,
13, 13, 13, 26, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 26, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 26, 13, 13, 13, 13 };
uint16_t count = 0;
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
RTC_HandleTypeDef hrtc;
TIM_HandleTypeDef htim1;
TIM_HandleTypeDef htim3;
DMA_HandleTypeDef hdma_tim1_ch2;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_TIM1_Init(void);
static void MX_RTC_Init(void);
static void MX_TIM3_Init(void);
/* USER CODE BEGIN PFP */
void led_clear();
void led_fill(uint16_t value, uint16_t col, uint16_t color);
void led_set_color(uint16_t index, uint8_t r, uint8_t g, uint8_t b);
void led_play();
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void) {
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_TIM1_Init();
MX_RTC_Init();
MX_TIM3_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) {
if (HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_2, led_buffer, 384)
!= HAL_OK) {
/* Starting Error */
Error_Handler();
}
HAL_Delay(1000);
HAL_TIM_PWM_Stop_DMA(&htim1, TIM_CHANNEL_2);
switch (count % 4) {
case 0:
led_fill(26, 5, 1);
break;
case 1:
led_fill(26, 4, 2);
break;
case 3:
led_clear();
break;
case 2:
led_fill(26, 3, 3);
default:
break;
}
switch (count % 9) {
case 6:
led_fill(26, 6, 1);
break;
case 7:
led_fill(26, 7, 2);
break;
case 8:
led_play();
break;
default:
break;
}
count++;
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };
RCC_PeriphCLKInitTypeDef PeriphClkInit = { 0 };
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI
| RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL4;
RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) {
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
Error_Handler();
}
}
/**
* @brief RTC Initialization Function
* @param None
* @retval None
*/
static void MX_RTC_Init(void) {
/* USER CODE BEGIN RTC_Init 0 */
/* USER CODE END RTC_Init 0 */
/* USER CODE BEGIN RTC_Init 1 */
/* USER CODE END RTC_Init 1 */
/** Initialize RTC Only
*/
hrtc.Instance = RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 127;
hrtc.Init.SynchPrediv = 255;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
if (HAL_RTC_Init(&hrtc) != HAL_OK) {
Error_Handler();
}
/* USER CODE BEGIN RTC_Init 2 */
/* USER CODE END RTC_Init 2 */
}
/**
* @brief TIM1 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM1_Init(void) {
/* USER CODE BEGIN TIM1_Init 0 */
/* USER CODE END TIM1_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = { 0 };
TIM_MasterConfigTypeDef sMasterConfig = { 0 };
TIM_OC_InitTypeDef sConfigOC = { 0 };
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = { 0 };
/* USER CODE BEGIN TIM1_Init 1 */
/* USER CODE END TIM1_Init 1 */
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 41;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim1) != HAL_OK) {
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK) {
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK) {
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig)
!= HAL_OK) {
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2)
!= HAL_OK) {
Error_Handler();
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 0;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig)
!= HAL_OK) {
Error_Handler();
}
/* USER CODE BEGIN TIM1_Init 2 */
/* USER CODE END TIM1_Init 2 */
HAL_TIM_MspPostInit(&htim1);
}
/**
* @brief TIM3 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM3_Init(void) {
/* USER CODE BEGIN TIM3_Init 0 */
/* USER CODE END TIM3_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = { 0 };
TIM_MasterConfigTypeDef sMasterConfig = { 0 };
/* USER CODE BEGIN TIM3_Init 1 */
/* USER CODE END TIM3_Init 1 */
htim3.Instance = TIM3;
htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 0;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK) {
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK) {
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig)
!= HAL_OK) {
Error_Handler();
}
/* USER CODE BEGIN TIM3_Init 2 */
/* USER CODE END TIM3_Init 2 */
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void) {
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE()
;
/* DMA interrupt init */
/* DMA1_Channel2_3_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel2_3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = { 0 };
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOF_CLK_ENABLE()
;
__HAL_RCC_GPIOA_CLK_ENABLE()
;
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4,
GPIO_PIN_RESET);
/*Configure GPIO pins : PA1 PA2 PA3 PA4 */
GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
/* USER CODE BEGIN 4 */
void led_clear() {
for (int i = 0; i < led_buffer_len; i++)
led_buffer[i] = 13;
}
void led_fill(uint16_t value, uint16_t col, uint16_t color) {
for (int i = 0; i < led_buffer_len / led_ctr_len / 3; i++) {
led_buffer[(i * 3 + color - 1) * led_ctr_len + col] = value;
}
}
void led_set_color(uint16_t index, uint8_t r, uint8_t g, uint8_t b) {
for (int i = 0; i < 8; i++) {
if ((r >> i) & 0x01) {
led_buffer[index * 24 + 7 - i] = 26;
} else {
led_buffer[index * 24 + 7 - i] = 13;
}
if ((g >> i) & 0x01) {
led_buffer[index * 24 + 8 + 7 - i] = 26;
} else {
led_buffer[index * 24 + 8 + 7 - i] = 13;
}
if ((b >> i) & 0x01) {
led_buffer[index * 24 + 16 + 7 - i] = 26;
} else {
led_buffer[index * 24 + 16 + 7 - i] = 13;
}
}
}
void led_play() {
led_clear();
uint8_t colors [24]={
10,10,0,
6,4,10,
10,10,0,
6,4,10,
10,10,20,
6,40,10,
10,20,0,
6,10,30
};
for (int i = 0; i < 8; i++) {
led_set_color(i, colors[i*3], colors[i*3+1], colors[i*3+2]);
if (HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_2, led_buffer, 384)
!= HAL_OK) {
/* Starting Error */
Error_Handler();
}
HAL_Delay(200);
HAL_TIM_PWM_Stop_DMA(&htim1, TIM_CHANNEL_2);
}
for (int i = 0; i < 8; i++) {
led_set_color(i, 0x00, 0x00, 0x00);
if (HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_2, led_buffer, 384)
!= HAL_OK) {
/* Starting Error */
Error_Handler();
}
HAL_Delay(500);
HAL_TIM_PWM_Stop_DMA(&htim1, TIM_CHANNEL_2);
}
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void) {
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
HAL_Delay(50);
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_2);
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(char *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
- 2025-03-09
-
发表了主题帖:
自动浇花系统第四帖之软件篇
软件方面的实现了如下功能:
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-03-08
-
回复了主题帖:
拆套湾湾制造的门禁系统1
好复杂,信号标识都放在亚克力,看着就不便宜。
-
回复了主题帖:
自动浇花系统第三帖之硬件完善
本帖最后由 serialworld 于 2025-3-8 17:25 编辑
秦天qintian0303 发表于 2025-3-7 07:12 总感觉这种自动浇水系统如果不应用在大规模上就有点浪费了
我看了一下网上卖的自动浇花的基本都是家用的,当然体积都比我这个DIY小不少。一般也不用电磁阀,用小水泵供水。这个体积大,主要是使用了现成的模块。尤其是用了arduino uno开发板,要是换成其他开发板体积会小一些。
-
回复了主题帖:
自动浇花系统第三帖之硬件完善
本帖最后由 serialworld 于 2025-3-8 17:16 编辑
kit7828 发表于 2025-3-8 14:55 潜水泵寿命不长吗?有具体的测试数据吗?
这确实没有测试,只是一般的小水泵都是有刷电机。电机寿命受电刷寿命的影响。不过如果只是浇花的,不会长时间运行,寿命也不是太大的问题。鱼缸用的潜水泵,寿命应该是很长的,用的应该是无刷电机。
- 2025-03-07
-
回复了主题帖:
【树莓派Pico 2 RP2350开发板】环境搭建
wangerxian 发表于 2025-2-26 21:20
VS Code都有Raspberry Pi Pico插件了?
节省成本!使用上便利性不如Type C.
- 2025-03-05
-
发表了主题帖:
自动浇花系统第三帖之硬件完善
本帖最后由 serialworld 于 2025-3-5 21:13 编辑
在之前的基础上增加了物理按键,LED数码管。按键用于手动控制,而LED数码管用来显示电磁阀的状态和时间。
完善后的硬件照片如下。软件方面也正在完善,目前已经可以显示时间了。硬件方面,考虑到电磁阀发热较大,担心因为单片机死机或继电器故障而导致电磁阀长时间通电,使得电磁阀温度温度过高,导致损坏,可以增加温度保护功能。目前,考虑使用温度开关进行保护。
目前制作的优点和不足:
优点:
1..基本使用可以直接外购的模块,制作比较方便;
2..使用Arduino uno开发板开发速度快;
3.交流供电不用考虑电池更换问题.;
4.不使用电动水泵,寿命长。
缺点:
1.体积大,使用模块和电磁阀,体积比较大;
2.不使用电动水泵,浇花的水流量小;
3.使用交流供电,需要附近有电源;
4.模块之间使用杜邦线连接可靠性差;
5.制作成本高,主要是arduino开发板比较贵。
软件方面的计划实现如下功能:
一周七天可以设置开启时间和关闭时间;
手动开启和关闭,手动开始2分钟后自动关闭;
时间显示功能;
第二帖
第一帖
- 2025-02-24
-
回复了主题帖:
自动浇花系统第二帖之硬件连接
walker2048 发表于 2025-2-24 01:19
如果你需要管理的植物用的水不多,直接买二手茶吧机水泵就行了,还能通过计算通电时间来算出水量。我小鱼缸 ...
茶吧水泵价格不高,直接用水泵也是不错的一个方案。
-
回复了主题帖:
自动浇花系统第二帖之硬件连接
蓝雨夜 发表于 2025-2-23 21:34
这电磁阀什么价格阿
十块钱一个,淘宝上很多。
-
回复了主题帖:
自动浇花系统第二帖之硬件连接
秦天qintian0303 发表于 2025-2-24 08:18
这个主控板是自己做的吗?居然还是彩色PCB的
是买的,嘉立创出的arduino开发板。
- 2025-02-23
-
发表了主题帖:
自动浇花系统第二帖之硬件连接
本帖最后由 serialworld 于 2025-2-23 19:24 编辑
经过物料采购后终于凑齐了所有物料,可以开始搭建硬件了。
主要工作是如何布局相应的模块,好在选的盒子足够大,布局也没有费太多的时间。
比较费事的是给安装底板打孔,孔的位置一定要准确。不过手工操作,加上动手能力有限,还是有几个孔打的有些歪。DIY吗,将就一下了。
组装后的结果见下图。之后烧录了一个简单的程序,测试了一下功能,没有什么问题。只是发现一个现象,电磁阀打开时,开一会儿就烫手,大概计算了一下功率大概4W,还是挺大了。
这个倒是有点出乎我的意料。之前也没有接触过电磁阀的应用,烫手也应该没有问题吧。另外测试了一下水流情况,当高度差大于50CM的时候,水流还是可以的,毕竟只是浇花,可以通过延长电磁阀打开时间来增加总的水量。下一步是软件方面的工作,需要花一些时间了。对了,硬件方面的工作也没有完全结束。后续应该会增加一个手动控制的按键及一个温度传感器。
- 2025-02-15
-
回复了主题帖:
自动浇花系统制作第一帖
Jacktang 发表于 2025-2-15 10:09
执行部分建议使用常闭型电磁阀。如12V/24V,响应时间≤0.5秒,可减少开关延迟对虹吸水流量的影响
目前选用的的确是12V的电磁阀,使用的是净水器2分的电磁阀。不知道是否选用的管子太细。
另外开关延迟如何对虹吸水流产生影响,不明白。
-
回复了主题帖:
【新年点灯】ghost
不错不错!!!
-
发表了主题帖:
自动浇花系统制作第一帖
本帖最后由 serialworld 于 2025-2-15 22:07 编辑
一直想做一个自动浇花的系统,但是迟迟没有开始。最近准备开始制作。
目标:仿照图书《爱上Arduino》的自动灌溉系统的使用国内可以购买的物料进行制作,完成度在80%左右,也会改动原有的系统。
初步的构想的功能目标:
1.室内使用,自动定时浇花,支持最大5盆花,不使用水泵,使用虹吸方式供水,交流供电
2.尽量成为有点实用的东西,不能成为又增加的没有的东西
初步计划使用的物料可能包括:
1.时钟模块
2.Arduino UN开发板或其他单片机开发板
3.继电器模块
4.电磁阀 12V 2分
5.水管 2分外径约6.5mm,内径4.1mm,水桶等
6.电源 12V 1.5A
7.外盒 160X160X90
8.固定模块用底板150x150x2
9.M2,M3 等螺丝
10.开关按键
11.Arduino原型开发板
12.导线排针
计划时间:1个月
目前已经准备的物料如下图,目前还
缺少时钟模块和模块固定底板。陆续采购中...
目前制作还未开始,还请大家多提意见!!!
- 2025-02-04
-
回复了主题帖:
ESP32 S2和DTH11制作的温湿度计
lugl4313820 发表于 2025-2-3 07:52
这个是非常好的设计呀,背板是万能板吗?如果配了电池,可以跑多长时间?
背板不是万用板,是打样的pcb板,本来是其他用途的,这次拿来用了。
估计配电池是不行的,电流测量了一下大概60mA,太大了。还不知道如何降低电流。
- 2025-02-03
-
发表了主题帖:
ESP32 S2和DTH11制作的温湿度计
本帖最后由 serialworld 于 2025-2-3 07:42 编辑
使用Arduino ESP32 S2和DTH11制作的温湿度计
#define LED_PIN 15
#include <U8x8lib.h>
#include <Ticker.h>
#include <Adafruit_NeoPixel.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>
#define DHTTYPE DHT11 // DHT 11
#define DHTPIN 33
DHT_Unified dht(DHTPIN, DHTTYPE);
#define PIN_WS2812B 18 // The ESP32 pin GPIO16 connected to WS2812B
#define NUM_PIXELS 8 // The number of LEDs (pixels) on WS2812B LED strip
#define PIN_DHT11 33
Adafruit_NeoPixel ws2812b(NUM_PIXELS, PIN_WS2812B, NEO_GRB + NEO_KHZ800);
U8X8_SH1106_128X64_NONAME_SW_I2C u8x8(11, 12, /* reset=*/U8X8_PIN_NONE);
Ticker ticker1;
Ticker ticker2;
char temp2[20];
char hum2[20];
void led_show() {
ws2812b.clear();
for (int pixel = 0; pixel < NUM_PIXELS; pixel++) { // for each pixel
ws2812b.setPixelColor(pixel, ws2812b.Color(random(1, 15), random(1, 15), random(1, 15))); // it only takes effect if pixels.show() is called
delay(50);
ws2812b.show();
}
// delay(10);
// ws2812b.clear(); // set all pixel colors to 'off'. It only takes effect if pixels.show() is called
// ws2812b.show(); // update to the WS2812B Led Strip
// delay(10); // 1 second off time
}
void led_show2() {
ws2812b.clear();
for (int pixel = 0; pixel < NUM_PIXELS; pixel++) { // for each pixel
ws2812b.setPixelColor(pixel, ws2812b.Color(random(1, 5), random(1, 5), random(1, 5))); // it only takes effect if pixels.show() is called
}
ws2812b.show(); // update to the WS2812B Led Strip
delay(100); // 1 second off time
}
void led_show3() {
ws2812b.clear();
static int count = 0;
int index;
int position;
for (position = 0; position < NUM_PIXELS; position++) {
ws2812b.clear();
for (int pixel = 0; pixel < NUM_PIXELS; pixel++) { // for each pixel
// if (position == pixel or (position+count)%NUM_PIXELS == pixel)
if (position == pixel or (position + count) % NUM_PIXELS == pixel)
ws2812b.setPixelColor(pixel, ws2812b.Color(random(1, 20), random(1, 20), random(1, 20)));
else
ws2812b.setPixelColor(pixel, ws2812b.Color(0, 0, 0));
}
ws2812b.show();
delay(100);
}
count++;
}
void callback1() {
digitalWrite(LED_PIN, HIGH);
led_show3();
}
void callback2() {
digitalWrite(LED_PIN, LOW);
led_show3();
}
void setup() {
// put your setup code here, to run once:
sensor_t sensor;
pinMode(LED_PIN, OUTPUT);
Serial.begin(9600);
u8x8.begin();
u8x8.setPowerSave(0);
ticker1.attach(5, callback1);
ticker2.attach(3, callback2);
dht.begin();
ws2812b.begin(); // initialize WS2812B strip object (REQUIRED)
}
void loop() {
// put your main code here, to run repeatedly:
// digitalWrite(LED_PIN, HIGH);
// delay(1000);
// digitalWrite(LED_PIN, LOW);
// delay(1000);
sensors_event_t event;
dht.temperature().getEvent(&event);
Serial.print(F("Temperature: "));
float temp1 = event.temperature;
Serial.print(temp1);
Serial.println(F("°C"));
dht.humidity().getEvent(&event);
Serial.print(F("Humidity: "));
float hum1 = event.relative_humidity;
Serial.print(hum1);
Serial.println(F("%"));
u8x8.refreshDisplay();
// delay(100);
// u8x8.clear();
// u8x8.setFont(u8x8_font_px437wyse700b_2x2_r);
u8x8.setFont(u8x8_font_courB18_2x3_r);
// u8x8.setFont(u8x8_font_chroma48medium8_r);
// u8x8.refreshDisplay(); // only required for SSD1606/7
dtostrf(temp1, 2, 1, temp2);
dtostrf(hum1, 2, 1, hum2);
// u8x8.setFont(u8x8_font_chroma48medium8_r);
u8x8.drawString(0, 1, "Tem:");
u8x8.drawString(8, 1, temp2);
u8x8.setInverseFont(0);
u8x8.drawString(0, 5, "Hum:");
u8x8.drawString(8, 5, hum2);
u8x8.setInverseFont(0);
//u8x8.drawString(0,8,"Line 8");
//u8x8.drawString(0,9,"Line 9");
u8x8.refreshDisplay(); // only required for SSD1606/7
// Serial.print("Hello world!\n");
// Serial.println(esp_random());
// Serial.println(random(1, 15));
Serial.print(touchRead(T1));
Serial.print("\t");
Serial.print(touchRead(T2));
Serial.print("\t");
Serial.print(touchRead(T3));
Serial.print("\t");
Serial.print(touchRead(T4));
Serial.print("\t");
Serial.println(touchRead(T5));
}
- 2025-02-01
-
回复了主题帖:
【新年花灯】STM32 F030 点亮WS2812流水灯
视频来了!!原来是操作的不对。[localvideo]bdeb9260de4d6ede6f9c7b642bc5d02f[/localvideo]
- 2025-01-28
-
回复了主题帖:
【新年花灯】STM32 F030 点亮WS2812流水灯
站内的视频实在是上传不了。来个连接吧。【STM32 F030 点亮WS2818 LED】 https://www.bilibili.com/video/BV1kgFxewEK2/?share_source=copy_web&vd_source=f8a5898a4f3328d68b9d500f3b20469c