Neuanfang aber wie

Hallo ins Forum
nachdem ich bereits zweimal mit eurer Hilfe die Sketche hinbekommen habe dachte ich,jetzt aber vernünftig. Also erstmal einen Plan.


Ich möchte eine Uhr zum Leben erwecken und mit den Tasten einen "Wecker"
stellen.Da ich auch mit Kicad hadere ist der Plan noch nicht fertig.

Gruß Walter

Geht so.
Allerdings wirst Du mit der 1302 nicht glücklich werden.

Gegenfrage: Warum verwendest du die RTC DS1302 ?
Die ist nicht sehr genau, besser ist eine DS3231.

@HotSystems @my_xy_projekt
Dies sind die Teile die mir zur Verfügung stehen ( Starterkid ) und ich habe auch gelesen das die 1302 bis zu 10 sec/Woche falsch geht.
https://wolles-elektronikkiste.de/ds1302-und-ds1307-rtc-real-time-clock

Ok, verstehe ich, dennoch Hier ein Beispiel für den Preis einer deutlich besseren RTC.

Wegschmeißen und DS3231 – Echtzeituhr verwenden!

Hallo,
dann solltest Du noch überlegen wie Du die Uhr stellen willst. Du willst ja nicht alle paar Wochen den PC anschließen um die Zeit zu stellen. Das geht mit einem 3Tasten Menü . Für den Taster 1 bietet sich eine Doppelfunktion an (z.B doppelclick , click )
Taster 1 Modus (ändern / Zeit / Weckzeit / speichern ende )
Taster 2 plus
Taster 3 minus.

Aber die Variante mit der besseren RTC ist da viel besser.

Heinz

Man kann ja durchaus noch weitere Taster einsetzen. Pins sind noch genügend frei. Und bei Verwendung einer I2C-RTC werden noch weitere 3 Pins frei.
Und evtl. hilft dir dieses Menü dabei.

wie wäre das denn mit einem ESP32 C3 supermini oder ein beliebiger anderer ESP32. Die haben eine Echtzeituhr eingebaut und mit der WiFi-Funktion kann man die Uhr auch noch von einem NTC-server im Internet automatisch stellen. (Muss allerdings im Bereich eines WiFi-Routers sein). Ich baue viele DIY Uhren und mache das so.
... nur so eine Idee ...

wenn es von interesse ist, hier ist meine Routine zum Uhr stellen mit nur 2 Knöpfen und einem OLED Display.

// set digital clock with two buttons and OLED display

#include <SPI.h>
#include <Wire.h>
#include <DS3231.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
Adafruit_SSD1306 oled = Adafruit_SSD1306(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

DS3231 Clock;


int GetPin = 18;
int SetPin = 19;

bool Century = false;
bool h12;
bool PM;

int DoW;
const char *WeekDay[] = {"Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado", "Domingo"};
bool END;

int Block[7]; //Data Block for Clock setting values
int i=0;
int y=0;


void setup() 
{
  Serial.begin(9600);
  Clock.setClockMode(false);    
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Address 0x3C default
  oled.display();
  delay(2000);
  oled.clearDisplay();
  oled.setTextSize(1);
  oled.setTextColor(SSD1306_WHITE);
  oled.setCursor(10, 10);
  oled.println("RTC actual time is ");
  oled.println("---------------------");

   
    Block[0] = Clock.getYear(), DEC;
    Block[1] = Clock.getMonth(Century), DEC;
    Block[2] = Clock.getDate(), DEC;
    Block[3] = Clock.getDoW(), DEC;
    Block[4] = Clock.getHour(h12,PM), DEC;
    Block[5] = Clock.getMinute(),DEC;
    Block[6] = Clock.getSecond(),DEC;

   oled.print(Block[0]);
   oled.print("-");
   oled.print(Block[1]);
   oled.print("-");
   oled.print(Block[2]);
   oled.print(" ");

   oled.print(Block[3]);
   oled.print(":");
   oled.print(Block[4]);
   oled.print(":");
   oled.println(Block[5]);
   oled.display();
    
  pinMode(GetPin, INPUT);
  pinMode(SetPin, INPUT);

  while (!digitalRead(SetPin)) {;}
  
  delay(1000); 

// **************** NOW INPUT DATA *******************

   InputData();
   
} //end procedure

void loop()
{
  //END = true;
    oled.clearDisplay();
    oled.setTextSize(1);
    oled.setTextColor(SSD1306_WHITE);
    oled.setCursor(0,0);
   oled.print(Clock.getYear(), DEC);
   oled.print("-");
   oled.print(Clock.getMonth(Century), DEC);
   oled.print("-");
   oled.print(Clock.getDate(), DEC);
   oled.print(" ");
   oled.println(WeekDay[Clock.getDoW()-1]);

   oled.setTextSize(2);
   oled.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
   oled.setCursor(15,30);
   Clock.setClockMode(false);
   oled.print(Clock.getHour(h12, PM), DEC); //24-hr
   oled.print(":");
   oled.print(Clock.getMinute(), DEC);
   oled.print(":");
   oled.println(Clock.getSecond(), DEC);
  
   oled.display();
}


void InputData()
  {
       while (i<7) // input date/time values
        {
        if (digitalRead(GetPin)) // ajust actual value
         {
          Block[i]++ ;
          if (Block[0] > 32) {Block[0] = 22;}
          if (Block[1] > 12) {Block[1] = 1;}
          if (Block[2] > 31) {Block[2] = 1;}
          if (Block[3] > 7 ) {Block[3] = 1;}
          if (Block[4] > 23) {Block[4] = 0;}
          if (Block[5] > 59) {Block[5] = 0;}
          if (Block[6] > 59) {Block[6] = 0;}      
          
          delay(300);      
         }
         
         showInput();
         
         if (digitalRead(SetPin)) // set value and goto next 
         {
          i++;
          delay(500);
         }      
        } // ready input date/time values 0 to 5
     
    delay(100);
    while(!digitalRead(SetPin)) 
    {
    oled.clearDisplay();
    oled.setTextSize(1);
    oled.setTextColor(SSD1306_WHITE);
    oled.setCursor(0,12);
    oled.print("Ready for adjust time");
    oled.display();
    }
    SetClock();
  }

void showInput()
 {
  oled.clearDisplay();
  oled.setTextSize(1);
  oled.setTextColor(SSD1306_WHITE);
  oled.setCursor(0, 0);
  oled.println("Now input Date/time");
  oled.println("---------------------");

  oled.setCursor(0,15);
  oled.print("Year Month Day DoW");
  for (y=0; y<4; y++)
  {
    oled.setCursor((y*30+10),25);
    if (y==i) {oled.setTextColor(SSD1306_BLACK, SSD1306_WHITE);} else {oled.setTextColor(SSD1306_WHITE);}
    oled.print(Block[y]);
  }
  oled.setTextColor(SSD1306_WHITE);
  oled.setCursor(0,35);
  oled.print("Hour Minute Second");
    for (y=4; y<7; y++)
  {
  oled.setCursor(((y-4)*30+10),45);
  if (y==i) {oled.setTextColor(SSD1306_BLACK, SSD1306_WHITE);} else {oled.setTextColor(SSD1306_WHITE);}
  oled.print(Block[y]);
  }
  oled.display();
 } 

 void SetClock()
  {
   Clock.setClockMode(false);  // set to 12h
   Clock.setSecond(Block[6]);
   Clock.setMinute(Block[5]);
   Clock.setHour(Block[4]);
   Clock.setDoW(Block[3]);
   Clock.setDate(Block[2]);
   Clock.setMonth(Block[1]);
   Clock.setYear(Block[0]);

   oled.setTextSize(2);
   oled.setTextColor(SSD1306_WHITE);
   oled.setCursor(10, 40);
   oled.println("* READY *");
   oled.display();
   delay(1000);   
  }

Da bin ich wieder habe jetzt ein RTC_mini Modul und [Erstes Projekt: Wecker :)] gefunden darauf aufbauend https://wolles-elektronikkiste.de/ds3231-basierter-wecker versucht.
wenn ich jetzt diesen Code ändere geht es nicht.

Ich ändere lediglich in den Zeilen
19 die const 3 auf 4
20 die const 4 auf 7

// https://wolles-elektronikkiste.de/ds3231-basierter-wecker
// 22.04.2025 kopiert und erweitert Tempanzeige
// ds3231_alarm_clock_with_switch.ino

#include <Wire.h>
#include <RTClib.h>                        // library for the DS3231
#include <LiquidCrystal_I2C.h>             // library for the LCD display
#define SNOOZE_TIME 60                     // set snooze time
#define SET_INCREMENT_DELAY 260            // incrementation time for settings
#define MAX_ALARM_DURATION 20000           // maximum duration of an alarm
volatile bool setItemKeyPressed = false;   // flag for item key
volatile bool setValueKeyPressed = false;  // flag for value key
volatile unsigned long lastLow;            // needed to handle bouncing
bool alarmOn = false;                      // alarm activated
// mit anderen Eingängen keine Funktion 
// müssen Interrupteingänge fortlaufend genutzt werden ?

const int setItemPin = 2;                  // choose item to set / time setting mode
const int setValuePin = 3;//4;                 // set (increment) value / alarm setting mode
const int alarmPin = 4;//7;                    // Pin for the alarm switch

typedef enum TIME_UNIT {  // needed for struct "timeElement"
  YEAR,
  MONTH,
  DAY,
  HOUR,
  MINUTE,
  SECOND
} timeUnit;

typedef enum SET_MODE {  // setting modes
  DATE_TIME,
  ALARM
} setMode;

struct timeElement {  // for date/time/alarm setting
  timeUnit tUnit;
  uint16_t tMin;  // minimum value
  uint16_t tMax;  // maximum value
  char tname[7];  // name to display
};

timeElement tElementYear = { YEAR, 2025, 2050, "Year" };
timeElement tElementMonth = { MONTH, 1, 12, "Month" };
timeElement tElementDay = { DAY, 1, 31, "Day" };
timeElement tElementHour = { HOUR, 0, 23, "Hour" };
timeElement tElementMinute = { MINUTE, 0, 59, "Minute" };

RTC_DS3231 rtc;  // create RTC_DS3231 object
DateTime alarmTime = DateTime(2014, 1, 1, 7, 0, 0);
LiquidCrystal_I2C lcd(0x27, 20, 2);  // create display object (address, columns, rows)

void setup() {
  Serial.begin(115200);

  lcd.init();
  lcd.backlight();
  lcd.clear();

  if (!rtc.begin()) {
    Serial.println(F("Couldn't find RTC"));
    while (1) {}
  }
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));  // // set rtc to date/time of compilation
  rtc.disable32K();                                // stop signal at the 32K pin
  rtc.clearAlarm(1);
  rtc.clearAlarm(2);
  rtc.disableAlarm(1);
  rtc.disableAlarm(2);
  rtc.writeSqwPinMode(DS3231_OFF);  // stop signal at the SQW pin

  /* pressing the item or value button will cause a low signal at the corresponding pin
       and trigger an interrupt */
  pinMode(setItemPin, INPUT_PULLUP);
  pinMode(setValuePin, INPUT_PULLUP);
  pinMode(alarmPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(setItemPin), setItemKeyISR, FALLING);
  attachInterrupt(digitalPinToInterrupt(setValuePin), setValueKeyISR, FALLING);
  setItemKeyPressed = false;
  setValueKeyPressed = false;
}

void loop() {
  if (millis() % 1000 == 0) {  // update date/time every second
    printDateTime();
    delay(1);
  }

  if (setItemKeyPressed) {  // item key = date/time setting key
    goIntoSetMode(DATE_TIME);
  }

  if (setValueKeyPressed) {  // value key = alarm key
    goIntoSetMode(ALARM);
  }

  if (rtc.alarmFired(1) && alarmOn) {
    alarmAction();  // act on alarm
  }

  checkAlarmSetting();  // check whether alarm was (de-)activated
}

void checkAlarmSetting() {
  if (!digitalRead(alarmPin) && !alarmOn) {
    alarmOn = true;
    lcd.setCursor(15, 1);
    lcd.print("A");  // display alarm flag
    rtc.setAlarm1(alarmTime, DS3231_A1_Hour);
  } else if (digitalRead(alarmPin) && alarmOn) {
    alarmOn = false;
    lcd.setCursor(15, 1);
    lcd.print(" ");  // delete alam flag
    rtc.disableAlarm(1);
  }
}

void goIntoSetMode(setMode settingMode) {
  alarmOn = false;
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(F("Press 1 sec"));
  delay(1000);  // press 1 second to go into setting mode
  if (digitalRead(setItemPin) == LOW || digitalRead(setValuePin) == LOW) {
    lcd.setCursor(0, 0);
    lcd.print(F("Setting Mode"));
    lcd.setCursor(0, 1);
    if (settingMode == DATE_TIME) {
      lcd.print(F("Date/Time"));
    } else {
      lcd.print(F("Alarm"));
    }
    /* wait until button is released */
    while (digitalRead(setItemPin) == LOW) {}
    while (digitalRead(setValuePin) == LOW) {}
    delay(50);  // debouncing
    if (settingMode == DATE_TIME) {
      setDateTime();
    } else {
      setAlarmTime();
    }
  }
  setItemKeyPressed = false;
  setValueKeyPressed = false;
}

void setDateTime() {         // date/time setting procedure
  DateTime now = rtc.now();  // get current time
  uint16_t tItem = 0;
  tItem = setDateTimeElement(&tElementYear, now.year());
  adjustRTC(YEAR, tItem);
  now = rtc.now();
  tItem = setDateTimeElement(&tElementMonth, now.month());
  adjustRTC(MONTH, tItem);
  now = rtc.now();
  tItem = setDateTimeElement(&tElementDay, now.day());
  adjustRTC(DAY, tItem);
  now = rtc.now();
  tItem = setDateTimeElement(&tElementHour, now.hour());
  adjustRTC(HOUR, tItem);
  now = rtc.now();
  tItem = setDateTimeElement(&tElementMinute, now.minute());
  adjustRTC(MINUTE, tItem);
  adjustRTC(SECOND, 0);
  lcd.clear();
  if (alarmOn) {
    lcd.setCursor(15, 1);
    lcd.print("A");  // display "alarm is on" flag
  }
  printDateTime();
}

void setAlarmTime() {  // procedure to set an alarm
  uint16_t value = 0;
  value = setDateTimeElement(&tElementHour, alarmTime.hour());
  alarmTime = DateTime(alarmTime.year(), alarmTime.month(), alarmTime.day(), value, alarmTime.minute(), 0);
  value = setDateTimeElement(&tElementMinute, alarmTime.minute());
  alarmTime = DateTime(alarmTime.year(), alarmTime.month(), alarmTime.day(), alarmTime.hour(), value, 0);
  lcd.clear();
  char alarmTimeBuf[] = "hh:mm";
  alarmTime.toString(alarmTimeBuf);
  lcd.setCursor(0, 0);
  lcd.print("Alarm: ");
  lcd.print(alarmTimeBuf);
  delay(1000);  // Show Alarm Time for one second
  lcd.clear();
  printDateTime();
}

void alarmAction() {
  lcd.clear();
  unsigned long alarmStart = millis();
  /* alarm was fired, not key pressed, and alarm did not exceed max. duration */
  while (!setItemKeyPressed && !setValueKeyPressed && (millis() - alarmStart < MAX_ALARM_DURATION)) {
    lcd.setCursor(5, 0);
    lcd.print(F("Alarm!"));
    delay(500);
    lcd.clear();
    delay(500);
    if (millis() < alarmStart) {  // if millis() overflow occured
      alarmStart = 0;
    }
  }
  /* wait till buttons are released: */
  while (digitalRead(setItemPin) == LOW || digitalRead(setValuePin) == LOW) {}
  rtc.clearAlarm(1);
  delay(50);  // debouncing
  DateTime now = rtc.now();
  if (millis() - alarmStart < MAX_ALARM_DURATION) {
    alarmTime = now + TimeSpan(SNOOZE_TIME);  // set new alarm (snooze)
    rtc.setAlarm1(alarmTime, DS3231_A1_Hour);
    lcd.setCursor(15, 1);
    lcd.print("S");  // display snooze flag
  } else {
    alarmOn = false;
  }
  setItemKeyPressed = false;
  setValueKeyPressed = false;
}

/* This functions sets a time element. Pressing the value key increments the value until
   the maximum value is reached. Pressing the item key will return. */
uint16_t setDateTimeElement(timeElement *tE, uint16_t currentSet) {
  char buf[13];
  clearLineLCD(0);
  lcd.setCursor(0, 0);
  sprintf(buf, "Set %s: ", tE->tname);
  lcd.print(buf);
  lcd.setCursor(12, 0);
  sprintf(buf, "%02d", currentSet);
  lcd.print(buf);
  setItemKeyPressed = false;
  while (!setItemKeyPressed) {
    if (setValueKeyPressed) {
      while (digitalRead(setValuePin) == LOW) {
        currentSet++;
        if (currentSet > tE->tMax) {
          currentSet = tE->tMin;
        }
        lcd.setCursor(12, 0);
        sprintf(buf, "%02d", currentSet);
        lcd.print(buf);
        delay(SET_INCREMENT_DELAY);
      }
    }
  }
  setItemKeyPressed = false;
  return currentSet;
}

void printDateTime() {  // display date/time
  DateTime now = rtc.now();

  char datBuf[] = "DDD, DD.MM.YYYY";      // define the date format
  char timeBuf[] = "hh:mm:ss";            // define the time format
  Serial.println(now.toString(datBuf));   // print date
  Serial.println(now.toString(timeBuf));  // print time
  lcd.setCursor(0, 0);
  lcd.print(datBuf);  // display date
  lcd.setCursor(0, 1);
  lcd.print(timeBuf);  // display time
  // eingefügt
  lcd.setCursor(10, 1);
  lcd.print(rtc.getTemperature());
}

void adjustRTC(timeUnit tU, uint16_t value) {  // adjust year, month, day etc.
  DateTime now = rtc.now();
  switch (tU) {
    case (YEAR):
      rtc.adjust(DateTime(value, now.month(), now.day(), now.hour(), now.minute(), now.second()));
      break;
    case (MONTH):
      rtc.adjust(DateTime(now.year(), value, now.day(), now.hour(), now.minute(), now.second()));
      break;
    case (DAY):
      rtc.adjust(DateTime(now.year(), now.month(), value, now.hour(), now.minute(), now.second()));
      break;
    case (HOUR):
      rtc.adjust(DateTime(now.year(), now.month(), now.day(), value, now.minute(), now.second()));
      break;
    case (MINUTE):
      rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), value, now.second()));
      break;
    case (SECOND):
      rtc.adjust(DateTime(now.year(), now.month(), now.day(), now.hour(), now.minute(), value));
      break;
  }
  delay(10);
}

void clearLineLCD(int line) {  // clears on line on the display
  char buf[17];
  sprintf(buf, "%16s", " ");
  lcd.setCursor(0, line);
  lcd.print(buf);
}

void setItemKeyISR() {              // ISR for pressed item key
  if (millis() - lastLow >= 300) {  // ignore bouncing when button is released
    setItemKeyPressed = true;
  }
  lastLow = millis();
}

void setValueKeyISR() {            // ISR for pressed value key
  if (millis() - lastLow >= 50) {  // ignore bouncing when button is released
    setValueKeyPressed = true;
  }
  lastLow = millis();
}

liege ich falsch mit meiner Vermutung das Interrupteingänge fortlaufend benutzt werden müssen wie im Beispiel also 2 3 4 und ich mir den Fehler mit der Zuweisung
2 4 7 geschaffen habe?
Gruß
Walter

Bei einem AVR328 Controller können nur die Pins 2 und 3 einen externen Interrupt basierend auf Flankenwechsel (Falling, Raising) verarbeiten. Andere Pins „verstehen“ lediglich Interrupts beim Erreichen vom High oder Low.

Ich habe den Code nicht weiter bearbeitet sollte aber dazuschreiben das ich mit einem UNO R3 versuche.

Dann war meine Vermutung richtig wie ich dann nachgelesen habe.
Danke für den Verweis .

Ein Uno R3 „besteht“ aus einem AVR328 Microcontroller