Tijd instellen dmv drukknoppen arduino uno klok

Hey Allen,

Ik zit met volgende... Ik heb nog zeer weinig ervaring met de arduino-taal, ik beheers slechts de simpele zaakjes. Door van het net voorbeelden te plukken en te combineren ben ik er toch in geslaagd een werkende klok met RTC module te maken.

Nu zou ik dit graag uitbreiden zodat ik ze met behulp van druktoetsjes kan instellen.

Het geheel is aangesloten als volgt:

LCD op pinnen 12, 11, 5, 4, 3, 2 zoals in het voorbeeld op de site
RTC I2C op A4 en A5

volgende sketch:

#include "Wire.h"
#include <LiquidCrystal.h>
#define DS1307_I2C_ADDRESS 0x68
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
 
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}
 
void getDateDs1307(byte *second,byte *minute,byte *hour,byte *dayOfWeek,byte *dayOfMonth,byte *month,byte *year)
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();
 
  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
 
  *second     = bcdToDec(Wire.read() & 0x7f);
  *minute     = bcdToDec(Wire.read());
  *hour       = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek  = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month      = bcdToDec(Wire.read());
  *year       = bcdToDec(Wire.read());
}
 
 
void setup()
{
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  Wire.begin();
 
  lcd.begin(16, 2);
}
 
void loop()
{
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  String s, m, d, mth, h;
   
  getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
 
  if (second < 10) { s = "0" + String(second); } else { s = String(second); }
  if (minute < 10) { m = "0" + String(minute); } else { m = String(minute); }
  h = String(hour);
  if (dayOfMonth < 10) { d = "0" + String(dayOfMonth); } else { d = String(dayOfMonth); }
  if (month < 10) { mth = "0" + String(month); } else { mth = String(month); }
   
  char* days[] = { "NA", "Ma", "Di", "Wo", "Do", "Vry", "Zat", "Zon" };
   
  lcd.clear();
  
  lcd.setCursor(4,0);
  
  lcd.print(h + ":" + m + ":" + s);
  
  lcd.setCursor(1,1);
  
  lcd.print(String(days[dayOfWeek]) + " " + d + "/" + mth + "/20" + year);
  delay(1000); 
}

Ik heb geen flauw idee hoe er aan te beginnen, want de gewijzigde tijd moet ook weer naar de RTC geschreven worden denk ik dan zo.....

Iemand die me op weg kan helpen?

ik ben ook met een klok bezig.

dit is de code die ik gebruik voor het instellen van de tijd.

misschien heb je er wat aan.

mvg

Mark

#include "Arduino.h"
#include <Wire.h>
#include "RTClib.h"
				// *** Nico: Ik gebruik D3 voor mijn ledstrip
#define BUTTON_AAN	LOW			// *** Nico: door dit te doen kun je gemakkelijk switchen tussen pullup/down switches
#define DEBOUNCE_TIME 25

const int hourButtonPin = 3;
const int minButtonPin = 4;

int buttonPushCounter = 1;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button
int hourButtonState;
int minButtonState;

int seconds; //00-59;
int minutes; //00-59;
int hours;//1-12 - 00-23;
int day;//1-7
int date;//01-31
int month;//01-12
int year;//0-99;


RTC_DS1307 rtc;

void setup() {
   Serial.begin(57600);
  
   pinMode(hourButtonPin,INPUT);
   pinMode(minButtonPin,INPUT);
   hourButtonState = 0;
   minButtonState = 0;
   
   #ifdef AVR
   Wire.begin();
   #else
   Wire1.begin(); // Shield I2C pins connect to alt I2C bus on Arduino Due
   #endif
   rtc.begin();
   if (! rtc.isrunning()) {
   Serial.println("RTC is NOT running!");
   }
   


}
void loop() {
 
  check_buttons();
}


void set_time()
{
   Wire.beginTransmission(104);
   Wire.write(0);
   Wire.write(decToBcd(seconds));
   Wire.write(decToBcd(minutes));
   Wire.write(decToBcd(hours));
   Wire.endTransmission();
}


void setHour()
{
  hours++;
  if(hours > 23)
  {
   hours = 0;
  // seconds = 0;
  // minutes = 0;
  }
  set_time();
 
}
void setMinutes()
{
  minutes++;  
  if(minutes > 59)
  {
   minutes = 0;
  }
 // seconds=0;
   set_time();
 }

void check_buttons()
{
  hourButtonState = digitalRead(hourButtonPin);
  minButtonState = digitalRead(minButtonPin);
 
  if(hourButtonState == HIGH){
    setHour();
    delay(200);
  }
 
  if(minButtonState == HIGH){
    setMinutes();
    delay(200);
  }
}

byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}

Ik doe het makkelijk en laat de RTC klok gelijk zetten door de PC.
Na het uploaden staat de RTC op de PC-tijd minus ongeveer 10 seconden, dat is de tijd die het duurt om het programma in de arduino te laden. De seconden kun je daarna "handmatig" gelijk zetten.

De regel RTC.adjust(DateTime(DATE, TIME)); doet dit kunstje.
En al het 'moeilijke werk wordt door de RTClib.h library gedaan.

/*
 * Toont tijd en zet RTC gelijk aan PC-tijd tijdens compileren
 * Om de RTC op de juiste tijd te zetten moet deze lijn aktief worden gemaakt:
 * RTC.adjust(DateTime(__DATE__, __TIME__));
 * Na het uploaden MOET deze regel weer gecomment worden d.m.v. //
 * // RTC.adjust(DateTime(__DATE__, __TIME__));
 * en eventueel opnieuw uploaden om de tijd weer te geven.
 * Doe je dat niet dan zal na een nieuwe start v/h programma de tijd van het
 * moment van compileren opnieuw in de registers gezet worden. 
 * Werkt ook voor DS3231 RTC module omdat de tijd/datum registers hetzelfde adres hebben.
 */

#include <Wire.h>                // Wordt gebruikt door RTC en I2C LCD
#include "RTClib.h"              // Handelt alle tijd en datum zaken af
#include <LiquidCrystal_I2C.h>   // library voor I2C LED display
// #include <LiquidCrystal.h>    // library voor parrallel aansturing LCD
LiquidCrystal_I2C lcd(0x26, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // defenieert LCD I2C aansturing
//LiquidCrystal lcd(12, 11, 5, 4, 3, 2);                       // parrallel aansturing

RTC_DS1307 RTC;  // Defenieert een RTC clock voor RTClib library
DateTime now;    // Bevat de huidige tijd en datum zoals in RTC module bijgehouden.

void setup()
{
  Wire.begin();     // initialiseert I2C databus, nodig voor RTC module
  lcd.begin(16, 2); // initaliseert LCD display als 2 regelig 16 karakter.
  lcd.clear();      // wist alle gegevens in en op de LCD display
  RTC.begin();      // initialiseert de RTC module

    // Haal de comment // weg om de RTC module te synchroniseren met de PC-tijd.
   //  RTC.adjust(DateTime(__DATE__, __TIME__));
}

void loop()
{
   showTime();
   delay(970);
}

void showTime()
{
    now = RTC.now();
    const char* dayName[] = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
    const char* monthName[] = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
    lcd.clear();
    lcd.print(String(dayName[now.dayOfWeek()]) + " " +
              (now.day() < 10 ? "0" : "") + now.day() + " " +
              monthName[now.month()-1] + " " + now.year());
    lcd.setCursor(0,1);
    lcd.print((now.hour() < 10 ? "0" : "") + String(now.hour()) + ":" +
              (now.minute() < 10 ? "0" : "") + now.minute() + ":" +
              (now.second() < 10 ? "0" : "") + now.second() );
}

Het werk zowel met een DS1307 als met een DS3231. Hebben beide hetzelfde I2C adres en hebben allebij tijd en datum in dezelfde registers zitten.

Ik ben een grote liefhebber van het RTC DS3231 geworden na teleurstellende resultaten met de naukeurigheid van een DS1307 RTC klok.
Die 1307 heeft een extern 32.768 Hz Xtal en de sommige chinese fabrikanten solderen een Xtal op de print zonder naar de specificaties van de DS1307 te kijken. het resultaat is een afwijking in de tijd.
Deze naukeurigheid wordt meestal uitgedrukt in ppm (parts per million). Ik heb al eens een DS1307 module gehad die 170ppm afweek. D.w.z. 170 seconde per miljoen seconden. Oftewel 3 minuten in 11 dagen. Waardeloos dus.

De DS3231 heeft een veel betere naukeurigheid omdat het Xtal in de chip zelf geintegreerd is. Een naukeurigheid van enige ppm is zonder afstellen vanzelfsprekend (een paar seconden per week afwijking maximaal).
In de DS3231 zit een speciaal register, het zgn. "aging register". Hier kan een waarde ingezet worden tussen -128 en +127.
elke waarde betekent ca. 0,1 ppm correctie.

Ik heb mijn DS3231 gedurende enige weken vergeleken met een DCF 77.5 kHz klokje. Ik registreerde een afwijking van 30 seconden (te snel) over 47 dagen. Omgerekend is 47 dagen ca. 4 miljoen seconden. Een afwijking van 30 seconden betekent dan dat mijn klok +7,4 ppm afweek.
Dus heb ik de waarde 74 in het aging register gezet (adres 0x10) en nu heeft mijn klok minder dan 0,1 seconde per week afwijking van de DCF77 tijd.

Hey Heren,

Hartelijk dank voor de replies,

@Disrupter: dat ga ik morgen eens goed bekijken, en eens wat testen. Wat voor klok ben je aan het maken?
Ik hoop mettertijd genoeg kennis op te steken om een mooie Nixie klok op arduino te laten draaien. Ik heb tot nu toe alleen nog maar klokken gemaakt met discrete TTL en CMOS IC's, maar ben het een beetje beu. Het neemt veel plek in en de printen worden complexer als er meer mogelijkheden worden ingebouwd, dus ook meer kans op fouten...

@Cartoonist: ik heb inderdaad ook gemerkt dat de module kwalitatief ondermaats is. Ik heb er 2 voor enkele euro's ( echt goedkoop) op de kop getikt op een beurs, de eerste is al in de recyclagebak beland, die bleek een defecte (of fake) chip te hebben. Deze doet het, maar wijkt inderdaad snel af.

Het uur van de PC overnemen had ik ook al ontdekt, maar dit wordt lastig op een stand-alone klok....

Maar voorlopig om wat te testen is het voldoende :smiley:

Koen_P_Belgium:
Ik hoop mettertijd genoeg kennis op te steken om een mooie Nixie klok op arduino te laten draaien. Ik heb tot nu toe alleen nog maar klokken gemaakt met discrete TTL en CMOS IC's, maar ben het een beetje beu. Het neemt veel plek in en de printen worden complexer als er meer mogelijkheden worden ingebouwd, dus ook meer kans op fouten...

Leuk project lijkt me, een nixie klok die door een arduino bestuurd wordt.

Dat kan heel goed met een Arduino UNO maar je moet wel bedenken dat de UNO maar 19 I/O pinnen heeft waarvan 2 (RX en TX) beter niet gebruikt kunnen worden.

Ik stel het me zo voor:

  1. een arduino UNO
  2. 6 nixie buizen die gemultiplexed worden, (heeft wel een hoop aansluitingen nodig 13 ofzo)
  3. een DS1307 of DS3231 RealTimeClock module. (gebruikt A4 en A5)
  4. een LCD die tijdens de ontwikkeling (eventueel ook voor de instellingen) wordt gebruikt (heeft 6 digitale I/O pinnen nodeg tenzij je de I2C uitvoering van de LCD-LED gebruikt, dan gaat de besturing over dezelfde A4 en A5 als de RTC)
  5. een stel drukknoppen om de klok te bedienen en gelijk te zetten.( minstens 5 drukknoppen UP, DOWN, LEFT, RIGHT en ENTER voor een soort menu. 5 I/O poorten of een enkele analoge poort d.m.v. de LCDKeypad.h library)

In je programma zag ik een delay(1000) om iedere seconde de RTC uit te lezen.
Een betere methode is om de RTC via een interrupt uit te lezen.
De RTC modules hebben een zogenaamde SQ uitgang, daaruit kan een blokgolf komen, de frequentie van die blokgolf kan bepaald worden d.m.v. registers, het 'control' register (en het status register voor de DS3231)
Als je een 1Hz blokgolf op SQ hebt kun je die aan een van de 2 interrupt pinnen van de arduino hangen. Deze blokgolf/Interrupt noem ik de 'heartBeat' (hartslag) van je schakeling.

Neem als declaratie op:
volatile byte secondsInterrupt = 0; // Pin 3 = interrupt 1

In de setup() initialiseer je de interrupt met de regel:

attachInterrupt(1, secondsRTC, FALLING);// interrupt vanaf RTC SQ-uitgang 1 Hz.

Maak een kleine subroutine waarnaar het programma springt als het een interrupt ontvangt:

void secondsRTC(void) {                 // *** ISR iedere seconde ***
  secondsInterrupt = 1;                 // ISR vlag = 1 : er was een 'seconds' interrupt.
}                                       // ***einde ISR ***

Dan neem je in je loop() de volgende regels op:

   if (secondsInterrupt == 1){          // **** doe als ISR vlag = 1  ****
       readTime();                      // de subroutine die iedere seconde de tijd registers leest.
       secondsInterrupt = 0;            // zet ISR vlag terug naar '0'
   }

Nu kun je in de loop() alle tijd van de processor besteden aan de andere routine's, zoals

void readButtons()
{
//deze routine leest de knoppen uit UP, DOWN, LEFT, RIGHT en ENTER
//hoe dit precies gebeurt is niet belangrijk voor de rest van het programma.
//het kan met 5 I/O pinnen maar ook over 1 pin, wordt alles lokaal in deze subroutine afgehandeld.
}

void(readTime()
{
// op de bekende manier met Wire.beginTransmission etc
}

void(setTime() // de kloktijd instellen.

void multiplexNixies() // aansturing nixies

Nog even hoe je de registers van de RTC instelt, voor de 1Hz op SQ, wat in de setup() kan gebeuren.
naar keuze de comments// weglaten voor DS1307 of DS3231

Wire.begin();                           // begin I2C routine
  Wire.beginTransmission(0x68);         // adress RTC DS1307 of DS3231
  Wire.write(byte(0x07));               // address control register [0x07 for DS1307]
  //Wire.write(byte(0x0E));             // address control register [0x0E for DS3231]
  Wire.write(byte(0x90));               // output SQ =1 Hz [0x90 for DS1307]
  //Wire.write(byte(0x00));             // output SQ =1 Hz [0x00 for DS3231]
  Wire.endTransmission();               // einde I2C routine

Hopelijk is een en ander begrijpelijk, anders vraag je maar meer uitleg.
Ik realiseer me dat je eigenlijk info vroeg om d.m.v. drukknoppen de tijd in te stellen.
Dat wil ik misschien later nog wel toelichten. (ben nu aan koffie toe)

(p.s. code tags toegevoegd op verzoek van MAS3)

Koffie al op ?

Als je code plaatst, doe dat dan in code tags

Wat je nu geplaatst hebt is heel moeilijk te volgen omdat er dingen door mekaar staan.
Dat heb je wel geprobeerd op te lossen met die stippellijntjes maar maakt het nog niet echt duidelijk.

MAS3:
Koffie al op ?

Als je code plaatst, doe dat dan in code tags

Wat je nu geplaatst hebt is heel moeilijk te volgen omdat er dingen door mekaar staan.
Dat heb je wel geprobeerd op te lossen met die stippellijntjes maar maakt het nog niet echt duidelijk.

Ik heb dat overwogen.

Maar het zijn maar 'code snippers'

als iets tussen code tags staat dan geef je de indruk dat het een stukje werkende code is die je zo kunt copieren en uploaden in je arduino.

Maar inderdaad, de langere stukken hadden beter tussen code kunnen staan, ik ga dat nu wijzigen.

Dit is een programma om d.m.v. 5 drukknoppen de tijd van een RTCklok, onafhankelijk van de PC in te kunnen stellen.
Bedoeld voor stand alone klokjes.

Ik heb de 'heartbeat' toegepast zoals eerder omschreven.

Ik realiseer me dat dit niet het allermooiste programma is, het kan eenvoudiger en mooier geschrejven worden.
Ik heb een aantal delen uit eigen programma's gepakt en gebruikt. Zoals de module readTime()
Ook de datum uitlezing is niet verder uitgewerkt.

Het is door alle comments nogal groot geworden daarom moet ik het in 2 delen posten.

eerst deel 1

#include <Wire.h>                                           // I2C library
#include <LiquidCrystal_I2C.h>                              // I2C LCD library
LiquidCrystal_I2C lcd1602(0x26, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Initialise the LCD I2C 
byte DS3231 = 0x68;                                         // geldt ook voor DS1307
char time[9] = {"00:00:00"};                                // formaat uur:minuut:seconde
char date[11] = {2014-01-01};                               // formaat jaar-maand-dag
byte knop = 0;
byte second, minute, hour;                                  // variables read from RTC
// declaratie pinnummers voor knoppen
const byte KEY_UP = 10;
const byte KEY_DOWN = 11;
const byte KEY_LEFT = 12;
const byte KEY_RIGHT = A0;
const byte KEY_SELECT = A1;
// einde declaratie drukknoppen
volatile byte secondsInterrupt = 0;     // Pin 3 = interrupt 1

void setup()
{
  Serial.begin(9600);                     // voor debugging print naar monitor
  Wire.begin();                           // initialiseer I2C routine
  Wire.beginTransmission(DS3231);       // adress RTC DS1307 of DS3231
  Wire.write(byte(0x07));               // address control register [0x07 for DS1307]
  //Wire.write(byte(0x0E));               // address control register [0x0E for DS3231]
  Wire.write(byte(0x90));               // output SQ =1 Hz [0x90 for DS1307]
  //Wire.write(byte(0x00));               // output SQ =1 Hz [0x00 for DS3231]
  Wire.endTransmission();               // einde setregister routine 
  lcd1602.begin(16,2);
  // initialiseer pinMode drukknoppen als input met internal PULLUP
  pinMode (KEY_UP    , INPUT_PULLUP);
  pinMode (KEY_DOWN  , INPUT_PULLUP);
  pinMode (KEY_LEFT  , INPUT_PULLUP);
  pinMode (KEY_RIGHT , INPUT_PULLUP);
  pinMode (KEY_SELECT, INPUT_PULLUP);
  // einde initialisatie drukknoppen
  attachInterrupt(1, secondsRTC, FALLING);// interrupt vanaf RTC SQ-uitgang 1 Hz.
}

void secondsRTC(void) {                   // *** ISR iedere seconde ***
  secondsInterrupt = 1;                   // ISR vlag = 1 : er was een 'seconds' interrupt.
}  

void loop()
{
   if (secondsInterrupt == 1){            // **** doe als ISR vlag = 1  ****
       readTime();                        // de subroutine die iedere seconde de tijd registers leest.
       secondsInterrupt = 0;              // zet ISR vlag terug naar '0'
   }                                      // einde ISR
  readButtons();
  if (knop == 5){                         // 
     knop=0;
     setTime(); 
  }
}

void readTime()
{                                                           // eens per seconde
  Wire.beginTransmission(DS3231);                           // begin transmission with RTC over I2C
  Wire.write(byte(0));                                      // set start address to '0'
  Wire.endTransmission();                                   // end of I2C communication with RTC
  Wire.requestFrom(DS3231, 3);                              // reads 3 bytes data from RTC-registers 
  second = bcdToDec(Wire.read());                           // first is seconds
  minute = bcdToDec(Wire.read());                           // second is minute
  hour = bcdToDec(Wire.read());                             // third is hour
  // tijd wordt in een string geplaatst daarom moet er 48 bij opgeteld worden asci 48 t/m 57  = cijfer 0/9
  time[0] = char((hour/10)+48);                             // fill time$ Hour tens
  time[1] = char((hour%10)+48);                             // fill time$ Hours
  time[2] = ':';                                            // fill time$ separator
  time[3] = char((minute/10)+48);                           // fill time$ minute tens
  time[4] = char((minute%10)+48);                           // fill time$ minutes
  time[5] = ':';                                            // fill time$ separator
  time[6] = char((second/10)+48);                           // fill time$ second tens
  time[7] = char((second%10)+48);                           // fill time$ seconds
  lcd1602.setCursor(0,0);                                   // LCD position 0 ,0
  //Serial.print(" time = ");Serial.println(time);
  lcd1602.print(time);                                      // Refresh Time display every second
}

byte bcdToDec(byte val) {                                   // *** function to calculate from HEX RTC data ***
  return ((val/16*10) + (val%16));                          // 
}  

byte decToBcd(byte val) {
  return ((val/10*16) + (val%10));
}

en deel 2, gewoon eraan vast plakken

void setTime()
{
  static byte timeSetter;   // 0 hour wordt gezet , 1 minute wordt gezet
  do{ 
     lcd1602.setCursor(6,0);                    // positie seconden
     lcd1602.print("00");                       // maskeert seconden met '00'
     if (timeSetter==0){                        // uren aanwijzer
       lcd1602.setCursor(0,1);                  // positie 0 op regel 1
       lcd1602.print("^^    xx");               // ^^ onder uren , xx onder seconden
     }
     if (timeSetter==1){                        // minuten aanwijzer
       lcd1602.setCursor(0,1);                  // positie 0 op regel 1
       lcd1602.print("   ^^ xx");               // ^^ onder minuten , xx onder seconden
     }
     readButtons();                             // lees druktoetsen
     switch (knop){                             // switch case voor de 5 druktoetsen
     case 1: // "UP":
       if (timeSetter==0){                      // 0 = uren
         hour=hour+1;hour=hour%24;              // uren altijd kleiner dan 24
         if (hour<10){                          // single digit uren
           lcd1602.setCursor(0,0);              // rechts uitlijnen
           lcd1602.print(' ');                  // maskeert tientallen
           lcd1602.print(hour);                 //
         }
         if (hour>=10){                         // uren in 2 digits
           lcd1602.setCursor(0,0);              //
           lcd1602.print(hour);                 //
         }
       }
       if (timeSetter==1){                      // 1 == minuten
         minute=minute+1;minute=minute%60;      // minuut altijd kleiner dan 60  
         if (minute<10){
           lcd1602.setCursor(3,0);              // rechts uitgelijnd
           lcd1602.print(' ');                  // maskeert tiental
           lcd1602.print(minute);               //
         }
         if (minute>=10){                       // minuten in 2 digits
           lcd1602.setCursor(3,0);              // 
           lcd1602.print(minute);               //
         }
       }
       knop=0;                                  // klaar voor opnieuw toetsaanslag te lezen   
       break;
     case 2: // "DOWN"
       if (timeSetter==0){                      // 0 voor uren
         if (hour==0) hour=hour+24;             // zodat uren niet negatief worden
         hour=hour-1;hour=hour%24;              // uren altijd kleiner dan 24
         if (hour<10){                          // zorgt dat uren rechts uitgekijnd zijn 
           lcd1602.setCursor(0,0);              // positie tientallen
           lcd1602.print(' ');                  // maskeert tientallen
           lcd1602.print(hour);                 // print uren
         }
         if (hour>=10){lcd1602.setCursor(0,0);  // uren in 2 digits
         lcd1602.print(hour);}                  // 
       }
       if (timeSetter==1){                      // '1' voor minuten
         if (minute==0) minute=minute+60;       // zodat minuten niet negatief worden
         minute=minute-1;minute=minute%60;      // zodat minuten altijd kleiner dan 60
         if (minute<10){                        // single digit minutem
           lcd1602.setCursor(3,0);              // uitgelijnd
           lcd1602.print(' ');
           lcd1602.print(minute);
         }
         if (minute>=10){                       // dubbel digit minuten
           lcd1602.setCursor(3,0);
           lcd1602.print(minute);
         }
       }
       knop=0;                                  // klaar voor volgende toetsaanslag
       break;                         
     case 3: //"LEFT":    
       timeSetter=0;                            // insteller voor uren
       knop=0;
       break;  
     case 4: //"RIGHT":     
       timeSetter=1;                            // insteller voor minuten
       knop=0;
       break;
     case 5: //"SELECT":                        // Schrijft de nieuwe tijd naar RTC
       Wire.beginTransmission(DS3231);          // begin transmission with RTC over I2C
       Wire.write(byte(0));                     // set start address to '0'
       Wire.write(0x00);                        // schrijft seconden in register 0x00
       Wire.write(decToBcd(minute));            // schrijft minuten in register 0x01
       Wire.write(decToBcd(hour));              // schrijft uren in register 0x02
       Wire.endTransmission();                  // klaar met nieuwe tijd wegschrijven
       break;                                   // N.B. seconden worden op 0 gezet.
     }
  } while (knop!=5);                            // Do While Loop totdat de tijd weggeschreven is 
  lcd1602.setCursor(0,1);                       // positie 0 op regel 1
  lcd1602.print("        ");                    // wist ^^ en xx van LCD
  knop=0;                                       // klaar voor volgende toetsaanslag
}

void readButtons()
{
  // als geen knop ingedrukt is pin status 'HIGH'
   if (digitalRead(KEY_UP)    == LOW) knop = 1; //"UP";
   if (digitalRead(KEY_DOWN)  == LOW) knop = 2; //"DOWN";
   if (digitalRead(KEY_LEFT)  == LOW) knop = 3; //"LEFT";
   if (digitalRead(KEY_RIGHT) == LOW) knop = 4; //"RIGHT";
   if (digitalRead(KEY_SELECT)== LOW) knop = 5; //"SELECT"
   delay(150); // eenvoudige 'debounce' 
}

N.B.

Je moet met bovenstaand voorbeeld van de tijd instellen wel een extra draadje aansluiten.
SQ uitgang van klokmoduul moet naar pin3 van arduino.

Anders heeft je klok geen hartslag en blijft stilstaan.

De 5 drukknoppen zitten aan de gedeclareerde pinnen 10,11,12,A0,A1 en de andere zijde zit aan massa. geen pull_up of pull_down weerstanden.

wooooow :slight_smile: ;D

@Cartoonist; Dat is een hele boterham! Superbedankt dat je je kennis met me wil delen, maar dit moet ik even laten bezinken, en een paar keer overlezen. Ik heb van mijn lieve kindjes ook nog niet echt de tijd gekregen je voorstel van de allereerste post even te testen, doe ik zo snel mogelijk.

De Square Wave zit standaard mee naar een header gebracht op het RTC bordje dus dat is ook geen probleem.
Een I2C lcd heb ik helaas niet ter beschikking....

Over het multiplexen van de nixie buizen, dat had ik heeeel ver in het achterhoofd; ik heb hier wel een hoopje Russische K155 ic's dat is de USSR variant van de 74141, de originele BCD naar DEC decoder waar je rechtstreeks de nixies kan aan hangen. Dus als ik er zo eentje gebruik, 4 IO pinnen om de bcd waarde naar de 74141 te sturen en 6 IO pinnen om de anodes te sturen..... maar nou ben ik al heel ver op de zaken aan het vooruit lopen......

Ik ga eerst proberen een goede klok, instelbaar te maken...

Maar alvast bedankt :wink:

Koen_P_Belgium:
Een I2C lcd heb ik helaas niet ter beschikking....

Haast onmisbaar, maakt 4 tot 6 pinnen vrij op je arduino, want gaat op dezelfde pinnen als je klok.
Is niet echt duur, nederlandse leverancier dus binnen een week in huis denk ik. (indien op voorraad),
(n.b. ik heb geen enkele relatie met deze firma)

Als je goed zoekt koop je zoiets in China voor ongeveer 1 euro incl. porto, maar dan mag je blij zijn als het voor de kerst ontvangen hebt.

(edit: link aangepast)

Hartelijk bedankt voor de link, heb er gelijk eentje besteld.

Ik heb ondertussen je post al enkele tientallen keren gelezen :o .... Dat van de interrupt heb ik helemaal begrepen, ga dit dadelijk eens in praktijk omzetten.

De code die is gebruikt om de tijd juist te zetten, zal ik nog eens een paar keer moeten overlezen...

Wat ik er nu uit opmaak:

void setup

serieel openen om te debuggen
initialiseer I2C
begin te praten met de rtc
vertel de rtc dat ie een 1Hz puls moet geven op de output SQ
stop praten met rtc
initialiseer LCD over I2C

die pinmodes begrijp ik iets niet goed, nl. de input_pullup (zoek ik dadelijk even op op de arduino website)

Dit heb ik inmiddels gedaan en begrepen :slight_smile:
attach interrupt,

hierna sluit je de accolade, dus veronderstel ik dat hiermee de void setup afgelopen is....

Void seconds rtc; hier denk ik dat ie gaat zeggen off hij de interrupt moet doen..

dan de loop:

als de vlag van de interrupt 1 is (vanaf hierboven denk ik dan) moet ie de subroutine readTime uitvoeren, als ie daarmee klaar is zet hij de vlag weer naar 0

readButtons knop ==5 als de centertoets gedrukt is en weer losgelaten?? voert hij subroutine setTime uit??

maar die subroutine setTime is chinees voor mij..... :blush: als je daar nog even een kleine toelichting over kan geven.....

Koen_P_Belgium:
readButtons knop ==5 als de centertoets gedrukt is en weer losgelaten?? voert hij subroutine setTime uit??

maar die subroutine setTime is chinees voor mij..... :blush: als je daar nog even een kleine toelichting over kan geven.....

Inderdaad, loslaten want als je ze vast blijft houden dan heb je iedere 150 milliseconden een nieuwe toetsslag, readButton() heeft een vertraging van 150 millis, kun je gerust iets groter maken. Niet te lang vasthouden anders interpreteert het programma dit als meerdere keren de toets indrukken.

Het aantal drukknoppen kun je ook kleiner maken, "DOWN" zou je bijvoorbeeld weg kunnen laten, maar dan kun je alleen omhoog instellen, niet terug omlaag. Zelfde geldt voor LEFT en RIGHT.
De grootste deel van de routine zorgt er enkel voor dat je op de LCD ziet wat er gebeurt.
Daar kun je naar wens grote stukken uit weglaten.
Als de routine klaar is met uren en minuten gelijkzetten dan druk je weer op SELECT, knop 5 , en dan wordt de nieuwe tijd naar de RTC geschreven en seconden op 0 gezet.

Als je te lang op knop 5 drukt (dat is niet de bedoeling) ga je eerst naar de setTime routine maar gelijk daarna ga je er dan weer uit. Dan wordt de bestaande tijd opnieuw weggeschreven maar de seconden wel op 0 gezet. Dus kun je de vertraging in readButtons() best iets groter maken. Een echte debounce routine is hier niet op zijn plaats want bij UP en DOWN moet je steeds dezelfde knop indrukken.
Een oplossing voor dit probleem (als je het zo wil noemen) zou zijn om enkel toets 5 een 'debounce' te geven zodat je eerst een andere toets moet indrukken voor je weer toets 5 kunt gebruiken.
Voor de rest is die routine minder mooi geschreven, is voor verbetering vatbaar.

Voor de duidelijkheid: Je moet wel even door lcd1602 heenkijken, meestal wordt in voorbeelden alleen lcd gebruikt als naam.
dus wat meestal lcd.print en lcd.setCursor wordt genoemd heet in mijn programma lcd1602.print en lcd1602.setCursor enz enz.

Soms heb ik 2 LCD displays, eentje noem ik dan lcd1602 en de andere lcd2004 omdat die 4 regels van 20 karakters heeft.
Ik hoef alleen te zorgen dat beide een verschillend I2C adres hebben.

Dat is het grote voordeel van I2C, je kunt meerdere displays en b.v. ook een toetsenbord, een klok, EEPROM geheugen, een kompas, barometer en nog zo vele andere soorten sensors aansluiten, die zijn allemaal te koop in een I2C uitvoering.
En dat allemaal aangesloten over dezelfde 2 arduino pinnen A4 en A5 .

Ik had hier gisteravond een hele tijd over zitten typen, maar na het klikken op de post knop kreeg ik een leeg edit venster met de mededeling dat ik een nieuw onderwerp wilde starten, alle noeste werk weg...

cartoonist:
Inderdaad, loslaten want als je ze vast blijft houden dan heb je iedere 150 milliseconden een nieuwe toetsslag, readButton() heeft een vertraging van 150 millis, kun je gerust iets groter maken. Niet te lang vasthouden anders interpreteert het programma dit als meerdere keren de toets indrukken.

Ik realiseer me dat het hier over de originele code gaat en dat ik het eens ben met je opmerkingen er over, maar...
De delay(150) hier is weer tenenkrommend, en dan het gewoon foute commentaar er nog bij.
Het heeft hele grote gevolgen voor deze code.

Inderdaad word hier gewoon de foute conclusie getrokken dat elke keer als je een toetsdruk ziet, dat een nieuwe is.
Als dat een of ander stoorpulsje, precies op het juiste moment zou zijn, dan word het ook als toetsdruk gezien.
Zou je eens een keer ff lekker op een toets drukken, zeg een halve seconde, dan worden er dus 3 toetsdrukken geregistreerd, die er echt niet waren.
En zie maar eens dat je altijd minder dan een zesde van een seconde op de toets drukt, veel succes daarmee.

Ik ben het er ook niet mee eens dat je een debounce niet zou kunnen gebruiken, omdat je de teller wil laten op- of aflopen.
Natuurlijk kun je zowel een debounce gebruiken, als zien dat de toets al een tijdje ingedrukt werd.
Dan moet je wel alle vormen van blokkerende code overboord gooien.
Dat is dus als eerste de delay().
Door die delay, heb je nu ook ineens een interrupt nodig om de hartslag niet te missen.
Want de interrupts werken wel gewoon door tijdens een delay(), zo'n beetje als enige.
Hoe lang duurt die hartslag puls, en kun je de lengte instellen ?

Verder is een while loop ook blokkerend, daar is vast een betere oplossing voor te bedenken.
Ik zie een while op regel 177 in de code die cartoonist in 2 delen heeft geplaatst, waar geen {curly braces} bij staan.
Ik vraag me af of het daar wel goed gaat.
Geen idee of het ook van cartoonist komt, maar degene die het bedacht heeft zou eens moeten kijken of het wel klopt.

Ik heb het donkerbruine (bijna zwarte) vermoeden dat je de code ook zo kunt maken dat je een meer intuïtieve interface krijgt, doordat je secondes, minuten, uren, dagen en maanden ook steeds sneller laat lopen, al naar gelang hoe lang je de toets ingedrukt houdt.
Dat word op veel apparaten zo ook gedaan mijn magnetron oven en mijn telefoon doen dat zo bijvoorbeeld.

Dit hele verhaal, alleen omdat ik een bijna allergische reactie krijg als ik hier zie dat er met delay() word gewerkt.
En wel op zo'n manier dat het behoorlijke consequenties heeft voor de rest van de code, waar met allerlei trucs omheen gewerkt moet worden.
Door slimmer programmeren, zonder delays, met meer bijhouden en alleen te doen wat er gedaan moet worden, kun je een heel eind komen.
Ik weet niet of de interrupt noodzakelijk is, daarom neem ik aan van wel.
Maar desnoods controleer je je hartslag eens wat vaker dan eens per keer dat je code doorlopen word, zodat de kans dat je m mist kleiner word.

Mijn verhaal was gisteravond nog een stukkie langer met meer argumenten er in.
Maar denk dat dit ook wel volstaat.

Just my 2 cents.

@Mas: Denk je wel om je hart :grin:

MAS3:
Ik weet niet of de interrupt noodzakelijk is, daarom neem ik aan van wel.
Maar desnoods controleer je je hartslag eens wat vaker dan eens per keer dat je code doorlopen word, zodat de kans dat je m mist kleiner word.

Die interrupt is in dit geval van een simpel stand-alone klokje natuurlijk niet noodzakelijk, maar kwaad kan het hier zeker niet.
Ik gebruik deze constructie standaard in mijn programma's als er een RTC klokmoduul in zit. Zo ook in mijn huisautomatiserings systeem met webserver. Dan heb ik geen delay nodig en ik hoef ook niet veelvuldig de klok te pollen. Voor mijn doeleinden werkt het perfect.

Ik had nooit eerder de moeite genomen na te denken over hoe je een klokje gelijk kunt zetten zonder PC. Daarom heb ik dat programmaatje gewoon gemaakt als hersen oefening voor mezelf en het zonder meer toen het eenmaal werkte gepost. Ik ga het programma verder niet verdedigen, alle kritiek erop is terecht.

MAS3:
Hoe lang duurt die hartslag puls, en kun je de lengte instellen ?

Ik gebruik:

volatile byte secondsInterrupt = 0;      // declaratie vlag

//in de setup()   
attachInterrupt(1, secondsRTC, FALLING); //  edge controlled interrupt. 

// ISR routine
void secondsRTC(void) {                // *** ISR zet vlag een maal per seconde***
  secondsInterrupt = 1;                  //  Er was een 'seconds' interrupt
}

De seconde blokgolf van de RTC heeft ongeveer een 50-50 duty cycle. De falling edge duurt een fractie van een microseconde maar speelt geen rol.
De ISR routine zelf duurt minder dan 1 milliseconde. Waarna dus 999 milliseconde vrij is voor willekeurig welke zaken.
In de loop() wordt iedere keer gekeken of de 'vlag' 1 is, indien zo dan wordt eenmalig de tijd gelezen, duurt ongeveer 10 millisecode.
Stel dat zonder secondsInterrupt de loop() van een willekeurig programma bijvoorbeeld 20 keer per seconde wordt doorlopen, en dus 20 keer de tijd worden gelezen. Dit duurt dan ongeveer 20*10 millis = 200 millis/seconde. Oftewel 20% van de tijd besteedt een programma dan aan het opvragen van de tijd. Dat is in een webserver of ander veel processortijd vragend programma best wel zonde van de tijd.

N.B. Dit is algemeen beschreven voor een willekeurig programma.
Niet zo ingewikkeld toch ?

edit: typfout hersteld

Nou nee hoor, je kunt dit dus prima doen zonder een interrupt en zonder de overdreven belasting.
Ik zou zelf niet zo snel een interrupt gebruiken als het ook zonder kan.
Het gebruik van de heartbeat is zonder meer een goed idee, daar heb ik ook nooit over getwijfeld.

Eerder zei ik al dat je geen dingen moet doen die niet nodig zijn (of eigenlijk alleen dingen die nodig zijn).
Dus kun je gaan kijken of de staat van de heartbeat inmiddels veranderd is, en je kunt dan gelijk kijken of dat een vallende of stijgende flank was.
In dat geval ga je de tijd lezen.
Je doet dan niet veel anders dan wat je met de interrupt doet, zonder dat speciale stukje gereedschap te moeten gebruiken.
Wanneer je snapt hoe een interrupt (ongeveer) werkt, dan kun je 'm ook correct toepassen.
Maar persoonlijk vind ik dat je daar niet een beginner mee "om de oren moet slaan".

Een interrupt is eigenlijk bedoeld om een zeer tijdkritische gebeurtenis te kunnen registreren.
Volgens mij heeft het verwerken van een gewone klok wel alles met tijd te maken, maar heel weinig met tijdkritische gebeurtenissen.