serialworld

  • 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

最近访客

< 1/4 >

统计信息

已有77人来访过

  • 芯积分:460
  • 好友:--
  • 主题:27
  • 回复:106

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言