Pages: [1] 2   Go Down
Author Topic: Wecker-Projekt - RTC, DCF, LED dimmen  (Read 1051 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,

wie in der Überschrift schon genannt, habe ich mir ein "kleines" Projekt für den Einstieg in die Welt der µC vorgenommen.
Mein Ziel ist ein Wecker, der eine gewisse Zeit vor der Weckzeit einen LED-Strip (o.ä.) einschaltet und in einem Zeitraum von einigen Minuten (geplant bis zu 30 Min.) langsam hochdimmt.

Mein derzeitiger Aufbau besteht aus dem UNO, einem 16x2 Display (HD477* kompatibel) und eben dem RTC. (DCF77 fehlt noch mangels Wissen wie das Signal am besten auszuwerten ist - das gibt glaub ich noch einige Probleme  smiley-sweat)
Derzeit bin ich noch recht am Anfang und kämpfe gerade mit der Adressierung des RTC-Moduls. Ich habe ein Tiny RTC V1.1 von Amazon (Marketplace). Die Dokumentation von DFRobot (hier klicken) finde ich aber etwas mager - ich komme damit nicht recht weiter - (kennt hier jemand eine bessere Dokumentation?)
Ich habe mir die DS1307 und OneWire Bibliotheken runtergeladen und habe mir hier den Beispiel-Sketch "DS1307.ino" genommen und den Großteil in meinen Sketch übertragen.
Was ich komisch finde: In diesem Sketch wird nirgens eine I²C Adresse des RTC angegeben... Das verwirrt mich etwas.
Das größte Problem habe ich aber zur Zeit mit den folgenden beiden Zeilen:
Code:
//DS1307.h

#include <Wire.h>
#include <DS1307.h>

int rtc[7];
byte rr[7];
int ledPin =  13;
void setup()
{
  DDRC|=_BV(2) |_BV(3);  // POWER:Vcc Gnd      //Um diese beiden Zeilen geht es <<<<<<<<<<
  PORTC |=_BV(3);  // VCC PINC3
...
Für mich ist das eine bitweise Oderverknüpfung in einer logischen Oder-Verknüpfung deren Ergebnis einfach wieder verworfen wird (zumindest wird es nicht zugewiesen). Ich habe schon die .h-Dateien durchsucht nach einer funktion namens BV oder _BV - konnte aber nichts finden... Was ist das??  smiley-razz

Später sollte dann noch ein DCF77 Modul und ein Temperatur-Sensor hinzukommen - beim DCF77 habe ich derzeit aber recht dunkle Aussichten  smiley-confuse
Wenn ich das Projekt fertigstellen kann, werde ich es aber auch mal richtig vorstellen um Anderen solche Probleme zu ersparen smiley

Der Vollständigkeit halber ist hier noch mein aktueller Code:
Code:
// include the library code:
#include <LiquidCrystal.h>
//#include <Time.h>
#include <Wire.h>
#include <DS1307.h>

int rtc[7];  //RTC-Ausgabe-Feld
byte rr[7];  //RTC-Eingabe-Feld (zum Zeiteinstellen über Serial)

short prev;  // Variable für die zeitlichen Aktualisierungsabstände

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);



void setup() {
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  
  Serial.begin(9600);
  
  // RTC-Einstellungen
  DDRC|=_BV(2) |_BV(3);  // POWER:Vcc Gnd
  PORTC |=_BV(3);  // VCC PINC3
  RTC.get(rtc,true);
  RTC.SetOutput(DS1307_SQW1HZ);  //Alternative: SQ4KHZ, SQ8KHZ, SQ32KHZ, LOW, HIGH  // 1 Hz Signal geplant für den Interrupt
  
  setPWM(9, 50);  // Dummy-Einstellung des ersten PWM-Kanals
  setPWM(10, 200);  // Dummy-Einstellung des zweiten PWM-Kanals
  lcdDrawPWM(50, 200);  // PWM-Werte auf dem Display anzeigen/aktualisieren
  lcdDrawTemp(22.4);    // Dummy-Wert Temperatursensor anzeigen
  
  attachInterrupt(0, lcdDrawTime, HIGH);  //Interrupt zur Uhr-Aktualisierung über SQ-Pin des RTC mit 1 Hz
}

void loop() {
  delay(100);
}

void lcdDrawTime() {
  byte timeH;  byte timeM;  byte timeS;
  RTC.get(rtc, true);
  
  lcd.setCursor(0, 0);
  timeH = BCD2DEC(rtc[2]);
  timeM = BCD2DEC(rtc[1]);
  timeS = BCD2DEC(rtc[0]);
  
  if (timeH < 10) lcd.print(" ");
  lcd.print(timeH);
  lcd.print(":");
  if (timeM < 10) lcd.print("0");
  lcd.print(timeM);
  lcd.print(":");
  if (timeS < 10) lcd.print("0");
  lcd.print(timeS);
}

void lcdDrawPWM(int pwm1, int pwm2) {
  lcd.setCursor(0,1);
  if (pwm1 < 100) lcd.print(" ");
  if (pwm1 < 10 ) lcd.print(" ");
  lcd.print((byte) (pwm1 / 2.55));
  lcd.print("%|");
  if (pwm2 < 100) lcd.print(" ");
  if (pwm2 < 10 ) lcd.print(" ");
  lcd.print((byte) (pwm2 / 2.55));
  lcd.print("%");
}

  
void lcdDrawTemp(float temp) {
  byte celsius[8] = {
    B01000,
    B10100,
    B01000,
    B00011,
    B00100,
    B00100,
    B00100,
    B00011 };
  lcd.createChar(0, celsius);
  lcd.setCursor(11, 1);
  lcd.print(temp);
  lcd.setCursor(15,1);
  lcd.write(byte(0));
}

void setPWM(int pin, byte tastgrad) {
  //Setzt den ausgewählten Pin auf einen PWM-Wert (0...255)
  if (pin == 3 || pin == 5 || pin == 6 || pin == 9 || pin == 10 || pin == 11) {
    analogWrite(pin, tastgrad);
  }
}

// BCD zu Dec Umwandlung, da der RTC die Werte im BCD-Code ausgibt
char BCD2DEC(char var){
  if (var>9){
     var=(var>>4)*10+(var&0x0f);
  }
  return var;
}
« Last Edit: December 25, 2013, 12:47:11 pm by Aurillium » Logged

Forum Moderator
BZ (I)
Online Online
Brattain Member
*****
Karma: 258
Posts: 21488
+39 349 2158303
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Für mich ist das eine bitweise Oderverknüpfung in einer logischen Oder-Verknüpfung deren Ergebnis einfach wieder verworfen wird (zumindest wird es nicht zugewiesen). Ich habe schon die .h-Dateien durchsucht nach einer funktion namens BV oder _BV - konnte aber nichts finden... Was ist das??
DDRC Da wird direkt auf das Richtungsregister (Eingang oder Ausgang) des Port C zugegriffen.
PORTC Das ist das Portregister von Port C um Ausgänge direkt zu setzen.
Wo hast Du diesen Code her?

Quote
Was ich komisch finde: In diesem Sketch wird nirgens eine I²C Adresse des RTC angegeben... Das verwirrt mich etwas.
Könnte die in der Bibliothek direkt hinterlegt sein?
Grüße Uwe
Logged

Germany S-H
Offline Offline
Faraday Member
**
Karma: 143
Posts: 3009
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ich habe schon die .h-Dateien durchsucht nach einer funktion namens BV oder _BV - konnte aber nichts finden... Was ist das?? 

_BV ist das "Bit Value" Macro von AVR.

Der Parameter gibt an, wie oft eine "1" nach links geschoben werden soll, um den Wert zu erreichen:

_BV(2) => 1 << 2 => 0x04
_BV(3) => 1 << 3 => 0x08

Und natürlich ist auch "|=" eine Zuweisung, nur eben als verkürzte Schreibweise.
Das funktioniert mit logischen Operatoren genau so wie es hier auf der Seite unter "9.3. Erweiterte Darstellung arithmetischer Operatoren" für arithmetische Operatoren erklärt wird:
http://pronix.linuxdelta.de/C/standard_C/c_programmierung_9.shtml
Logged

Offline Offline
Faraday Member
**
Karma: 118
Posts: 3918
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Überlege dir erst mal ob das wirklich nötig ist. Da wird anscheinend das RTC Modul über die Port-Pins mit Strom versorgt. Sowas ist eigentlich nur nötig wenn man Sleep-Modi benutzt um den Prozessor schlafen zu legen und dabei auch externe Peripherie abschaltet (solange diese weniger als 40mA zieht). Ansonsten reicht es das RTC Modul fest mit Strom zu versorgen.

_BV() steht für BitValue und setzt da entsprechende Bit. _BV(2) steht dann für b010 und _BV(3) steht für b1000

Da scheinst aber jemand Code von einer AVR Seite kopiert zu haben. Auf dem Arduino gibt es dafür digitalWrite(pinNummer, LOW/HIGH) zur besseren Lesbarkeit. Und pinMode() für das Richtungs-Register. Das ist zwar relativ langsam, aber für die meisten Anwendungen reicht es locker.
« Last Edit: November 09, 2013, 11:07:21 am by Serenifly » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Danke für deine schnelle Antwort smiley
@Uwe: Du hast recht, so viel ich bisher gelesen habe, haben die RTC meistens die Adresse 0x68 - so steht in der DS1307.h auch passenderweise die Zeile: #define DS1307_CTRL_ID B1101000  //DS1307
B1101000 = 0x68

Den Code habe ich aus einem Beispiel-Sketch, der mit der DS1307.h Library mitgeliefert wird. Downloadlink ist im Startposting verlinkt - auf der Seite von DFRobot.
Mit den Registern kenn ich mich leider gar nicht aus.
Ich denke ich sollte mir wohl eine andere RTC-Informationsquelle als DFRobot suchen? smiley-grin


EDIT:
Zum Thema |=  - da hab ich mich etwas in der Arduino Reference verhauen, stimmt das ist eine Zuweisung. smiley
Dann ist es also AVR-Code, der da hineingemischt wurde, das erklärt so einiges.
DDRC -> PinMode() von Pin 2 und 3 wird hier auf "1" gesetzt
PORTC |= _BV(3) -> DigitalWrite(3, High)

Das komische daran ist, dass der RTC gar nicht an diese Pins angeschlossen werden soll. Ich habe das ebenfalls mitgelieferte Wiring-Diagramm mal angehängt - auf Pin 2 wäre nur DS - die Stromversorgung funktioniert, wie schon gesagt wurde über die dafür vorgesehenen Pins.
DS ist wohl für das EEPROM, das brauche ich nicht, daher kommt auf Pin 2 der Pin SQ für den INT0 Interrupt, mit dem ich die Uhr-Anzeige aktualisieren möchte.

Edit2:
Fazit: Die beiden Zeilen sind nicht sinnvoll und fliegen raus - danke für eure Hilfe smiley


* Leonardo.png (120.48 KB, 685x600 - viewed 89 times.)
« Last Edit: November 09, 2013, 11:08:50 am by Aurillium » Logged

Dresden
Offline Offline
God Member
*****
Karma: 13
Posts: 771
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Zum 1307 gibts ein sehr gutes Datenblatt.
Da steht eigentlich alles wichtige drin...
Logged

------------
Grüssle, Sly

Offline Offline
Faraday Member
**
Karma: 118
Posts: 3918
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Dann lass das weg. Ist unnötig.

AVR Code ist manchmal nicht schlecht. Direkte Port-Manipulation braucht man wenn man Pins sehr schnell oder gleichzeitig setzen will, z.B. LED Matrizen oder parallele D/A-Wandler. Und wenn man z.B. Timer oder andere interne Funktionen direkt programmiert.

Es gibt übrigens einige RTC Libs. Kannst auch einfach eine andere nehmen.
Logged

Germany, Dresden
Offline Offline
Sr. Member
****
Karma: 15
Posts: 425
30 Jahre Elektronikbastelei, Programmieren null Ahnung!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Kannst auch die LIB von hier nehmen
http://playground.arduino.cc/Code/time
Mit der habe ich gute Erfahrungen gemacht, die funzt auch mit einem DS3231 RTC Modul, was wesentlich präziser bei gleichem Preis beim freundlichen Chinesen ist.
Diese Seite hier hilft dir beim Stellen des RTC Modules per Sketch.
http://www.epochconverter.com/
Das macht allerdings nur mit einer Batterie zum Puffern des RTC's Sinn  smiley
Bei mir sollen mal 6x 74HC595 mit ein paar Treibern dahinter 7 Segment LED Anzeigen treiben, wobei ich die Ziffernsegmente aus "LED's vom Meter" realisieren werde.

Gruß Gerald
Logged

rot ist blau und Plus ist Minus

Wien
Offline Offline
Edison Member
*
Karma: 28
Posts: 1882
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

hi,

mein tip: nimm die library DS1307new. mit der tut man sich leichter.

gruß stefan
Logged

Forum Moderator
BZ (I)
Online Online
Brattain Member
*****
Karma: 258
Posts: 21488
+39 349 2158303
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Danke für deine schnelle Antwort smiley
@Uwe: Du hast recht, so viel ich bisher gelesen habe, haben die RTC meistens die Adresse 0x68 - so steht in der DS1307.h auch passenderweise die Zeile: #define DS1307_CTRL_ID B1101000  //DS1307
B1101000 = 0x68

Den Code habe ich aus einem Beispiel-Sketch, der mit der DS1307.h Library mitgeliefert wird. Downloadlink ist im Startposting verlinkt - auf der Seite von DFRobot.
Mit den Registern kenn ich mich leider gar nicht aus.
Ich denke ich sollte mir wohl eine andere RTC-Informationsquelle als DFRobot suchen? smiley-grin

Dann habe die schlecht gearbeitet und die Maxime nicht beherzigt, daß Beispiele so einfach wie möglich sein solllen und aller unnötige Code, der für das erklären nicht nötig ist, wegzulassen.
Auch die Spannungsversorgung über Ausgangspins ist eine schlechte Angewohnheit die man nicht machen darf.

Grüße Uwe
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ja, Uwe, da geb ich dir recht.

Habe jetzt nach der Empfehlung von Eisebär auf die DS1307 umgestellt (https://code.google.com/p/ds1307new/wiki/Reference). Damit funktioniert jetzt alles wunderbar - zumindest solange ich nicht die Zeit einstellen möchte. Ich hab mich jetzt schon den ganzen Tag damit beschäftigt und die Zeit tot geschlagen, komme aber dennoch nicht weiter... und brauche noch mal eure Hilfe.
Das folgende ist jetzt mein Code zum Einstellen des RTC über die COM-Schnittstelle. Es wird alles schön ausgeführt und am Seriellen Monitor bekomme ich die Ausgabe, die Daten würden übernommen - die RTC-FillByXYZ werden also ausgeführt. Es passiert aber einfach nichts. Die Zeit läuft nach RTC.StartClock einfach wieder weiter...
In mitgelieferten Beispiel-Sketch "DS1307_Test" steht, die Adressen des RAMs wären umbelegt von 08h...3Fh auf 00h...38h.
Die Zeiteinstellung muss ja den Bereich 00h...07h Ansprechen - die Fill-Methoden sollten das doch eigentlich hergeben, sonst wäre die ganze Bibliothek etwas chaotisch.
Code:
void setRTC(){
  // Read received characters, build values and set RTC:
    
  uint16_t year;
  uint8_t month, day, dow;
  uint8_t hour, minute, second;

  RTC.stopClock();  
  delay(5);
  
  //COM-String muss das Format haben: DDMMYYYYhhmmss  
  day   =  comReadDigit() *10;
  delay(1);
  day   +=  comReadDigit();
  delay(1);
  month =  comReadDigit() *10;
  delay(1);
  month +=  comReadDigit();
  delay(1);
  year  =  comReadDigit() *1000;
  delay(1);
  year  +=  comReadDigit() *100;
  delay(1);
  year  +=  comReadDigit() *10;
  delay(1);
  year  +=  comReadDigit();  // mit DS1307new: Vollständige Jahreszahl
  delay(1);
  Serial.println();
  if((day <32 && day > 0) && (month > 0 && month < 13) && (year > 1999 && year < 2100)) {
    RTC.fillByYMD(year, month, day);
    Serial.println("Datum uebernommen.");
  }
  else {
    Serial.println("Fehler in der Vorgabe des Datums! Datum nicht eingestellt!");
  }
  
  hour  =  comReadDigit() *10;
  delay(1);
  hour  +=  comReadDigit();
  delay(1);
  minute =  comReadDigit() *10;
  delay(1);
  minute +=  comReadDigit();
  delay(1);
  second  =  comReadDigit() *10;
  delay(1);
  second  +=  comReadDigit();
  delay(1);
  if((hour >= 0 && hour < 25) && (minute >= 0 && minute < 60) && (second >= 0 && second < 60)) {
    RTC.fillByHMS(hour, minute, second);
    Serial.println("Uhrzeit uebernommen.");
  }
  else {
    Serial.println("Fehler in der Vorgabe der Uhrzeit! Uhrzeit nicht eingestellt!");
  }
  delay(10);
  RTC.startClock();
  
  Serial.print("Zeit empfangen:");
  Serial.print(hour);
  Serial.print(":");
  Serial.print(minute);
  Serial.print(":");
  Serial.print(second);
  Serial.print(" ");
//  Serial.print(dow);
//  Serial.print(",");
  Serial.print(day);
  Serial.print(".");
  Serial.print(month);
  Serial.print(".");
  Serial.println(year);

short comReadDigit() {
  // Liest Zahlen in einzelnen Ziffern von 0...9 ein - nicht für andere Zeichen verwendbar, da der ASCII Offset ("0" = 0d48) verwendet wird
  short digit = -1;
  digit = Serial.read() -48;
  return digit;
}
PS: Wie werde ich die Schlusszeichen des COM-Strings (Zeichen 10 und 13) am elegantesten los (sonst ist ja Serial.available() noch true). Ist es hier üblich einfach noch zwei mal read() zu verwenden? bzw. am Schluss:
while(true) {
  if(!Serial.available()) break;
}

Danke für Eure Hilfe, bin am verzweifeln  smiley-sweat
« Last Edit: November 10, 2013, 10:49:12 am by Aurillium » Logged

Offline Offline
Faraday Member
**
Karma: 118
Posts: 3918
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Die übliche Vorgehensweise um den Empfangspuffer zu leeren ist:

Code:
while(Serial.available())
{
     Serial.read();
}
Logged

Offline Offline
Edison Member
*
Karma: 38
Posts: 1164
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wenn mich nicht alles täuscht mußt du nach
    RTC.fillByYMD bzw     RTC.fillByHMS
noch jeweils ein
     RTC.setTime();  
folgen, um die Änderungen zu speichern, und anschliessend wieder eine
    RTC.startClock();

steht hier: https://code.google.com/p/ds1307new/wiki/Reference#setTime
Logged

Grüße
Gunther

Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Oh mann...  smiley-roll
Immer wieder lese ich die Reference rauf und runter, aber das hab ich übersehen... Ist wohl nicht so gut, zu lange mit Problemlösung zu verbringen, irgendwann steht man wie der Ochs vorm Berg und sieht die Lösung vor einem nicht mehr smiley
Logged

Forum Moderator
BZ (I)
Online Online
Brattain Member
*****
Karma: 258
Posts: 21488
+39 349 2158303
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ei guter Rat ist wenn Du mal bei einem Programm nicht weiterkommst nicht unbedingt den Fehler finden wollen. mach eine Pause, lenke Dich ab und dann später findest Du den Fehler sofort.
Grüße Uwe
« Last Edit: November 10, 2013, 12:31:40 pm by uwefed » Logged

Pages: [1] 2   Go Up
Jump to: