Go Down

Topic: DS 3231 Zeitschaltuhr mit LCD-Display (Read 9079 times) previous topic - next topic

agmue

Nicht erschöpfend, aber eine Language Reference und von da weiter nach Serial.
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

michael_x

Quote
nur über minimalste Grundkenntnisse im Programmieren
Schon klar. Gerade am Anfang ist die "Lernkurve" am steilsten, wenn man will. Da wollte ich nur einen kleinen Schubs geben.
Wie das genau werden soll zwischen Serial.read() und RTC stellen, wird noch eine kleine Herausforderung für dich, das hab ich erstmal weggelassen. Für die nächste Zeit ist deine supergenaue DS3231 ja erstmal richtig gestellt.

Für Arduino findet man so viele Sketche. Das ist toll, aber immer erst der Anfang.
Dass es läuft, zählt erst, wenn man weiss, warum  ;)

OK, manchmal behaupte ich auch das Gegenteil:
"Jeder Sketch der tut was er soll, ist ein guter Sketch"

jurs

Scheint nicht bei jeden durchgedrungen zu sein, das ich nur über minimalste Grundkenntnisse im Programmieren verfüge und mir nicht eigene Sketche ausdenken kann.
Da trifft es sich ja gut, dass ich es verstanden habe, wie gering Deine Programmierkeenntnisse sind, weil ich Dir ja ein Beispielprogramm für die Zeitschaltuhr machen und damit an diesem Wochenende anfangen wollte.

In Sachen RTC kann ich Entspannung vermelden: Ich konnte inzwischen bei mir zwar keine funktionierende DS3231 aus der Bastelkiste ziehen, sondern nur einen DS3231 "Chronodot v2.0" ohne eingelötete Header und ohne Lithium-Battereie als Backup. Die benötigte Lithiumbatterie scheint eine CR1620 zu sein und so eine habe ich hier nicht.

Anyway, ich habe eine DS1307 vom Typ "Tiny RTC" finden und in Betrieb nehmen können. Damit steht der Entwicklung eines Beispielprogramms mit folgenden Funktionen erstmal nichts im Wege:
- programmierbare Zweikanal-Schaltuhr mit zwei täglichen Schaltzeiten (eine Einschaltzeit/eine Ausschaltzeit)  pro Kanal also nichts mehr im Wege
- die Programmierung erfolgt über den seriellen Monitor
- Zeiteinstellung kompatibel für DS3231 und DS1307 RTC-Module
- Speicherung der Konfigurationsdaten für Einschalt-/Ausschaltzeiten im EEPROM
- (die gepseicherten Konfigurationsdaten werden bei jedem Power-on oder Reset automatisch wieder eingelesen

Ich setze mich mal dran und probiere was.

Wenn ich was habe, poste ich es hier in diesem Thread und Du kannst es ausprobieren und kommentieren.

G4rt3l

#33
Nov 26, 2016, 02:01 pm Last Edit: Nov 26, 2016, 02:11 pm by G4rt3l
Okay hab es hinbekommen. Vielen Dank für die Anregungen.
War nicht so schwer wie gedacht, aber in dem RCSwitch Beitrag konnte
man sich ganz gut rausdenken die man die RTC ausliest und dann war es
nur noch sinnig füllen:

(Habe den Code in zwei Teile teilen müssen da nicht mehr als 9000 Zeichen erlaubt sind)

P.S. Ich bin trotzdem noch auf deinen Lösungsansatz gespannt jurs! Falls du noch Lust hast das parallel zu erstellen :)

Code: [Select]

#include <Wire.h>
#include "ds3231.h"
#include "INTERVAL.h"
#include <LiquidCrystal.h>

LiquidCrystal lcd(2,3,4,5,6,7);


#define RTC_ADDRESS 0x68

#define BUFF_MAX 128

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

uint8_t time[8];
char recv[BUFF_MAX];
unsigned int recv_size = 0;
unsigned long prev, interval = 1000;

int Wasserpumpe = 11; 

#define PIN 12
Adafruit_NeoPixel strip = Adafruit_NeoPixel(33, PIN, NEO_GRB + NEO_KHZ800);
// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)

byte ss, mm,  hh = 0;   // Save Variables for time

/*
Schaltzeit Wasserpumpe 07:00-07:02
Schaltzeit Licht 06:00-19:00
*/

byte Wasserpumpe_ein_hh=7;
byte Wasserpumpe_ein_mm=0;
byte Wasserpumpe_aus_hh=7;
byte Wasserpumpe_aus_mm=02;

byte Licht_ein_hh=06;
byte Licht_ein_mm=00;
byte Licht_aus_hh=19;
byte Licht_aus_mm=00;

/*
RTC Funktionen zur Steuerung der RTC DS3231
*/

void TimeRead(){
  Wire.beginTransmission(RTC_ADDRESS);
  Wire.write(0x00);               // Pointer auf Sekunden
  Wire.endTransmission();
  Wire.requestFrom(RTC_ADDRESS, 3);
  ss= bcdToDec(Wire.read());
  mm= bcdToDec(Wire.read());
  hh= bcdToDec(Wire.read());
}

void RTC_Set(){
  Wire.beginTransmission(RTC_ADDRESS);
  Wire.write(0x00);
  Wire.write(decToBcd(ss));    // 0 to bit 7 starts the clock
  Wire.write(decToBcd(mm));
  Wire.write(decToBcd(hh));      // If you want 12 hour am/pm you need to set
  Wire.endTransmission();
}

void RTC_Start(){
  Wire.beginTransmission(RTC_ADDRESS);
  Wire.write(0x00);
  Wire.write(decToBcd(ss));    // 0 to bit 7 starts the clock
  Wire.endTransmission();
}

byte decToBcd(byte val)
{
  return ((val/10)<<4)+(val%10);
}

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ((val>>4)*10)+val%16;
}



G4rt3l

Code: [Select]
void setup()
{
    Serial.begin(9600);
    Wire.begin();
    DS3231_init(DS3231_INTCN);
    memset(recv, 0, BUFF_MAX);
    Serial.println("GET time");
    lcd.begin(16, 2);
    lcd.clear();
    
    //Serial.println("Setting time");       // Zum Zeiteinstellen!
    //parse_cmd("T304413626112016",16);     // T= Time; Sekunden: 45; Minuten: 25; Stunden: 18; Tag der Woche: 1=Montag, 2=Dienstag etc.;Datum: 23 11 2016;; 16 für 16 Bytes

strip.begin();
  strip.show(); // Initialize all pixels to 'off'
  pinMode(Wasserpumpe, OUTPUT);
 
 
  Wire.begin();                 // Start I2C Kommunikation
  Wire.beginTransmission(RTC_ADDRESS);      // Beginn Kommunikation auf  Adresse 0x68
  Wire.write(0x0E);                               // Pointer auf Control Register 0x07
  Wire.write(0x00);                               // Controlbyte for RTC to set the sqw Output to 1Hz
  Wire.endTransmission();             // Beenden der I2C Kommunitkation
  TimeRead();
  RTC_Start();
  Serial.begin(9600);
  Serial.print("start");
 
}

void loop() {

    INTERVAL(1000UL){                 //Jede  Minute nach Zeit schauen
    TimeRead();
    Serial.print(hh);
    Serial.print(":");
    Serial.println(mm);
    
  }
  if (hh==Wasserpumpe_ein_hh && mm==Wasserpumpe_ein_mm){   // Einschalten
    INTERVAL (200UL){
      digitalWrite(Wasserpumpe, HIGH);
    }
  }
  if (hh==Wasserpumpe_aus_hh && mm>=Wasserpumpe_aus_mm){   // Ausschalten
    INTERVAL(200UL){
      digitalWrite(Wasserpumpe, LOW);
    }
  }
    if (hh==Licht_ein_hh && mm==Licht_ein_mm){   // Einschalten
    INTERVAL (200UL){
      colorWipe(strip.Color(62, 6, 148), 50); // Ultra Violet
    }
  }
  if (hh==Licht_aus_hh && mm>=Licht_aus_mm){   // Ausschalten
    INTERVAL(200UL){
      colorWipe(strip.Color(0,0,0), 50); // LED Strip aus
    }
  }
    char in;
    char tempF[6];
    float temperature;
    char buff[BUFF_MAX];
    unsigned long now = millis();
    struct ts t;

    // show time once in a while
    if ((now - prev > interval) && (Serial.available() <= 0)) {
        DS3231_get(&t); //Get time
        parse_cmd("C",1);
        temperature = DS3231_get_treg(); //Get temperature
        dtostrf(temperature, 5, 1, tempF);

        lcd.clear();
        lcd.setCursor(0,0);
        
        lcd.print(t.mday);
        
        printMonth(t.mon);
        
        lcd.print(t.year);
        
        lcd.setCursor(0,1); //Go to second line of the LCD Screen
        lcd.print(t.hour);
        lcd.print(":");
        if(t.min<10)
        {
          lcd.print("0");
        }
        lcd.print(t.min);
        lcd.print(":");
        if(t.sec<10)
        {
          lcd.print("0");
        }
        lcd.print(t.sec);
        
        lcd.print(' ');
        lcd.print(tempF);
        lcd.print((char)223);
        lcd.print("C ");
        prev = now;
    }

    
    if (Serial.available() > 0) {
        in = Serial.read();

        if ((in == 10 || in == 13) && (recv_size > 0)) {
            parse_cmd(recv, recv_size);
            recv_size = 0;
            recv[0] = 0;
        } else if (in < 48 || in > 122) {;       // ignore ~[0-9A-Za-z]
        } else if (recv_size > BUFF_MAX - 2) {   // drop lines that are too long
            // drop
            recv_size = 0;
            recv[0] = 0;
        } else if (recv_size < BUFF_MAX - 2) {
            recv[recv_size] = in;
            recv[recv_size + 1] = 0;
            recv_size += 1;
        }

    }
}

void parse_cmd(char *cmd, int cmdsize)
{
    uint8_t i;
    uint8_t reg_val;
    char buff[BUFF_MAX];
    struct ts t;

    //snprintf(buff, BUFF_MAX, "cmd was '%s' %d\n", cmd, cmdsize);
    //Serial.print(buff);

    // TssmmhhWDDMMYYYY aka set time
    if (cmd[0] == 84 && cmdsize == 16) {
        //T355720619112011
        t.sec = inp2toi(cmd, 1);
        t.min = inp2toi(cmd, 3);
        t.hour = inp2toi(cmd, 5);
        t.wday = inp2toi(cmd, 7);
        t.mday = inp2toi(cmd, 8);
        t.mon = inp2toi(cmd, 10);
        t.year = inp2toi(cmd, 12) * 100 + inp2toi(cmd, 14);
        DS3231_set(t);
        Serial.println("OK");
    } else if (cmd[0] == 49 && cmdsize == 1) {  // "1" get alarm 1
        DS3231_get_a1(&buff[0], 59);
        Serial.println(buff);
    } else if (cmd[0] == 50 && cmdsize == 1) {  // "2" get alarm 1
        DS3231_get_a2(&buff[0], 59);
        Serial.println(buff);
    } else if (cmd[0] == 51 && cmdsize == 1) {  // "3" get aging register
        Serial.print("aging reg is ");
        Serial.println(DS3231_get_aging(), DEC);
    } else if (cmd[0] == 65 && cmdsize == 9) {  // "A" set alarm 1
        DS3231_set_creg(DS3231_INTCN | DS3231_A1IE);
        //ASSMMHHDD
        for (i = 0; i < 4; i++) {
            time[i] = (cmd[2 * i + 1] - 48) * 10 + cmd[2 * i + 2] - 48; // ss, mm, hh, dd
        }
        byte flags[5] = { 0, 0, 0, 0, 0 };
        DS3231_set_a1(time[0], time[1], time[2], time[3], flags);
        DS3231_get_a1(&buff[0], 59);
        Serial.println(buff);
    } else if (cmd[0] == 66 && cmdsize == 7) {  // "B" Set Alarm 2
        DS3231_set_creg(DS3231_INTCN | DS3231_A2IE);
        //BMMHHDD
        for (i = 0; i < 4; i++) {
            time[i] = (cmd[2 * i + 1] - 48) * 10 + cmd[2 * i + 2] - 48; // mm, hh, dd
        }
        byte flags[5] = { 0, 0, 0, 0 };
        DS3231_set_a2(time[0], time[1], time[2], flags);
        DS3231_get_a2(&buff[0], 59);
        Serial.println(buff);
    } else if (cmd[0] == 67 && cmdsize == 1) {  // "C" - get temperature register
        Serial.print("temperature reg is ");
        Serial.println(DS3231_get_treg(), DEC);
    } else if (cmd[0] == 68 && cmdsize == 1) {  // "D" - reset status register alarm flags
        reg_val = DS3231_get_sreg();
        reg_val &= B11111100;
        DS3231_set_sreg(reg_val);
    } else if (cmd[0] == 70 && cmdsize == 1) {  // "F" - custom fct
        reg_val = DS3231_get_addr(0x5);
        Serial.print("orig ");
        Serial.print(reg_val,DEC);
        Serial.print("month is ");
        Serial.println(bcdtodec(reg_val & 0x1F),DEC);
    } else if (cmd[0] == 71 && cmdsize == 1) {  // "G" - set aging status register
        DS3231_set_aging(0);
    } else if (cmd[0] == 83 && cmdsize == 1) {  // "S" - get status register
        Serial.print("status reg is ");
        Serial.println(DS3231_get_sreg(), DEC);
    } else {
        Serial.print("unknown command prefix ");
        Serial.println(cmd[0]);
        Serial.println(cmd[0], DEC);
    }
}

void printMonth(int month)
{
  switch(month)
  {
    case 1: lcd.print(" Januar ");break;
    case 2: lcd.print(" Februar ");break;
    case 3: lcd.print(" Maerz ");break;
    case 4: lcd.print(" April ");break;
    case 5: lcd.print(" Mai ");break;
    case 6: lcd.print(" Juni ");break;
    case 7: lcd.print(" Juli ");break;
    case 8: lcd.print(" August ");break;
    case 9: lcd.print(" September ");break;
    case 10: lcd.print(" Oktober ");break;
    case 11: lcd.print(" November ");break;
    case 12: lcd.print(" Dezember ");break;
    default: lcd.print(" Error ");break;
  }
}

void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  }
}

jurs

Okay hab es hinbekommen.
OK, wenn Dir DAS so reicht, dann stelle ich meine eigenen Bemühungen für ein über den seriellen Monitor programmierbares und konfigurierbares Zweikanal-Zeitschaltuhrprogramm für den Rest des Wochenendes ein.

In Deinem Code kann ich nirgends erkennen, dass die Uhrzeit oder irgendeine Schaltzeit über den seriellen Monitor eingestellt werden kann, sondern ich sehe nur:
- Wenn die Uhrzeit beim Programmstart neu gestellt werden soll ==> Programmcode ändern, Programm neu hochladen
- Wenn die Uhrzeit danach beim Programmstart NICHT neu gestellt werden soll ==> Programmcode ändern, Programm neu hochladen
-Wenn Einschaltzeit oder Ausschaltzeit neu gestellt werden soll ==> Programmcode ändern, Programm neu hochladen
-am Termin der Sommerzeitumschaltung ==> RTC-Zeit läuft entweder eine Stunde falsch, oder Neuprogrammierung
-am Termin der Winterzeitumschaltung ==> RTC-Zeit läuft entweder eine Stunde falsch, oder Neuprogrammierung.

Nachdem Du hier mitteilst "Okay hab es hinbekommen.", teile ich dann nur noch abschließend mit
"Das ist ja schön für Dich, wenn Dir das so ausreicht"!
Und ich verabschiede mich dann hiermit aus diesem Thread-Thema.


BYE und schönes Wochenende noch!




Doc_Arduino

Hallo,

@ jurs, du darfst ruhig dein Schaltzeitenprogramm fertig stellen. Bin gespannt was du dir wieder ausgedacht hast.

Wegen der Lib und den tausend Warnungen. Was mir ja nicht gefällt bis jetzt.
Habe mal alten Code rausgesucht. Ganz ohne RTC Lib. Nur paar Funktionen.
Damit kannst fehlerfrei auf Sekunde, Minute, Stunde, Wochentag, Tag, Monat und Jahr zugreifen.
Was noch fehlt ist die Winter-Sommerzeitkorrektur.

Code: [Select]
/*
Arduino Mega2560
I2C RTC DS3231
*/

#include <Wire.h>
#define ds3231_adress  0x68   // Adresse

int Sekunde, Minute, Stunde, Wochentag, Tag, Monat, Jahr;
char RtcDateTimeBuf[26];  // Buffer zum Zwischenspeichern der formatierten DS3231 Werte

void setup()
{
  Wire.begin();
  Serial.begin(9600);
 
}

void loop()
{
  RtcRequestEverySecond();
}


void RtcRequestEverySecond()
{
 static unsigned long last_millis = 0;
 
 if (millis()-last_millis < 10000) return;  // Zeit noch nicht erreicht, Funktion abbrechen
 last_millis+=10000;                        // addiere 10sec
 
 if (read_RTC_DS3231 (ds3231_adress) == true) {    // RTC auslesen, wenn Fehlerstatus "wahr", dann
   Serial.println("DS3231 I2C Busfehler");
 }
 else {
   // Datum und Zeit für Ausgabe formatieren und in globalen String 'RtcDateTimeBuf' speichern
   snprintf(RtcDateTimeBuf,26,"%02d.%02d.%04d ; %02d:%02d:%02d",Tag,Monat,Jahr,Stunde,Minute,Sekunde);   
   Serial.println(RtcDateTimeBuf);
 } 
 
} // Ende "RtcRequestEverySecond"
 
 
 
boolean read_RTC_DS3231 (int i2c_adresse)
{
  boolean error = false;                   // Fehlerstatus setzen
  Wire.beginTransmission(i2c_adresse);     // Connect
  Wire.write(0);                           // Anfrage ab/der Register Nummer
  if (Wire.endTransmission() > 0 )         // war Connect fehlerfrei?
   {
    error = true;                          // I2C Busfehler
    return error;                          // Abruch
   }
   
  Wire.requestFrom(i2c_adresse, 7);        // 7 Bytes in Folge anfordern/lesen

  if (Wire.available() > 0 )               // sind Daten vorhanden?
    {
     Sekunde   = bcdToDec(Wire.read() & 0x7F);  // Maske für die ersten 7 Bits alleine
     Minute    = bcdToDec(Wire.read() );
     Stunde    = bcdToDec(Wire.read() & 0x3F);  // Umschaltung auf 24h statt 12h (AM/PM)
                          Wire.read();          // wäre der Wochentag
     Tag       = bcdToDec(Wire.read() );             
     Monat     = bcdToDec(Wire.read() );
     Jahr      = bcdToDec(Wire.read() ) + 2000;
    }   
  return error; 
}

byte bcdToDec(byte val)  // Hilfsfunktion zum Lesen/Schreiben der RTC
// Convert binary coded decimal to decimal number
// Hilfsfunktion für die Echtzeituhr
{
  return ( (val/16*10) + (val%16) );
}




Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Go Up