Komisches Arduino-Phänomen mit PROGMEM und DCF77-Empfang

Gast #6783235
Lesenswert?

Ich brüte aktuell über einem LCD-Uhrenprojekt als Vorbereitung für eine 
Word-Clock.

Derzeit werte ich ein DCF77-Modul aus, stelle damit regelmäßig die 
DS3132 RTC und habe auch noch einen DHT22-Temperatur/Feuchtigkeitssensor 
angeschlossen. Daneben nutze ich auch 2 JQ6500 MP3-Soundmodule zum 
Abspielen von Glockenschlägen und Uhrenticken.

Jetzt wollte ich noch eine Kalenderfunktionalität einbauen. Dazu wird im 
Sketch am Anfang eine Struktur definiert und einmal am Tag geprüft, ob 
relevante Ereignisse vorliegen. Diese werden dann abwechselnd auf dem 
LCD-Display ausgegeben.

Die Kalenderdaten liegen im PROGMEM, um Variablenspeicher zu sparen.
Sobald ich die Einleseroutine mit kompiliere, fkt. der DCF-Emfang nicht 
mehr und bei der Soundausgabe gibt es auch Probleme. Gerade als ob im 
Speicher etwas durcheinander gekommen wäre.

Was mache ich hier falsch? Kann man den PROGMEM-Speicher so mit memcpy_P 
() einlesen? Irgendwo ein ', ", & etc. vergessen?

Hier die Struktur:
1
struct event_type
2
{
3
    // Struktur z.B. für Geburtstage
4
    byte Tag;
5
    byte Monat;
6
    int  Jahr;          // 9999 = Feiertag
7
    char Name[22];
8
    byte Typ;           // 1 = Geburtstag, 2 = Todestag, 3 = Jahrestag, 4 = Restmüll, 5 = Blaue Tonne, 6 = Gelbe Tonne, 7 = Biomüll
9
};
10

11
const event_type Ereignis[] PROGMEM =
12
{
13
    // hier die Datümer und die Namen auflisten
14
    {24, 12, 9999, "Heiligabend", 3},
15
    {25, 12, 9999, "1. Weihnachtstag", 3},
16
    {26, 12, 9999, "2. Weihnachtstag", 3},
17
    {7, 8, 9999, "Sylvester", 3},
18
    // ...
19
};
20

21
event_type Ereignis_SRAM;                   // wird für die Kopie in den Variablenspeicher benötigt


Tägliches Abfragen (hier kommen anscheinend die Probleme her):
1
        DateTime RTC_Zeit = rtc.now();
2
    
3
        if (RTC_Zeit.day() != Tag_alt)      // wenn neuer Tag, dann Termine einlesen
4
        {
5
            Tag_alt = RTC_Zeit.day();
6
            Flag_Tagesereignis = false;
7
    
8
            for (int i = 0; i < sizeof(Ereignis) / sizeof(event_type); i++)
9
            {
10
                // über die Tabelle loopen und Tag/Monat mit aktuellem Datum vergleichen
11
                // dann den Namen anzeigen etc.
12
    
13
                memcpy_P (&Ereignis_SRAM, &Ereignis[i], sizeof(event_type));       // zuerst einen Eintrag des PROGMEM-Arrays ins SRAM (Variablenspeicher) kopieren
14
    
15
                if (Ereignis_SRAM.Tag == RTC_Zeit.day() && Ereignis_SRAM.Monat == RTC_Zeit.month())
16
                {
17
                    switch (Ereignis_SRAM.Typ)                                // 1 = Geburtstag, 2 = Todestag, 3 = Jahrestag
18
                    {
19
                        case 1:
20
                            Ereignis_Typ = '*';
21
                            break;
22
                        case 2:
23
                            Ereignis_Typ = '+';
24
                            break;
25
                        case 3:
26
                            Ereignis_Typ = ' ';
27
                            break;
28
                    }
29
    
30
                    Flag_Tagesereignis = true;                                          // wir haben ein Ereignis an diesem Tag gefunden, das angezeigt werden soll
31
    
32
                    Serial.println (Ereignis_SRAM.Name);
33
                    Serial.println (Ereignis_SRAM.Tag);
34
                    Serial.println (Ereignis_SRAM.Monat);
35
                    Serial.println (Ereignis_SRAM.Jahr);
36
                    Serial.println (Ereignis_SRAM.Typ);
37
    
38
                    strcpy (Ereignis_Name, Ereignis_SRAM.Name);                         // String2 = String1 geht nicht, daher strcpy nutzen !
39
    
40
                }
41
            }
42
        }
1
    if (Flag_Tagesereignis == true)
2
    {
3
        // Infos abwechselnd darstellen
4

5
        Anzeige_s++;            // Anzeigedauer in Sekunden hochzählen, startet bei 0
6

7
        if (Display == 0)
8
        {
9
            if (Anzeige_s == 1)
10
            {
11
                lcd.setCursor(0, 2);
12
                lcd.print(F("                    "));
13

14
                lcd.setCursor(0, 2);
15
                lcd.print(Wochentag[RTC_Zeit.dayOfTheWeek()]);
16

17
                lcd.setCursor(10, 2);
18
                char buf3[] = "DD.MM.YYYY";
19
                lcd.print(RTC_Zeit.toString(buf3));
20
            }
21
            if (Anzeige_s == 5)
22
            {
23
                Anzeige_s = 0;
24
                Display   = 1;
25
            }
26
        }
27
        else
28
        {
29
            if (Anzeige_s == 1)
30
            {
31
                lcd.setCursor(0, 2);
32
                lcd.print(F("                    "));
33

34
                lcd.setCursor((10 - (strlen(Ereignis_Name) + 2) / 2), 2);       // mittig ausgeben
35
                lcd.print(Ereignis_Name);
36
                lcd.print(' ');
37
                lcd.print(Ereignis_Typ);
38
            }
39
            if (Anzeige_s == 5)
40
            {
41
                Anzeige_s = 0;
42
                Display   = 0;
43
            }
44
        }
45
    }
Gast #6783284
Lesenswert?

Martin schrieb:
> Was mache ich hier falsch?

Erstelle ein Minimal-Programm welches den Fehler repoduziert bzw.
repoduzierbar macht und poste es hier.

Dann kann man weiter sehen.

--> Längeren Sourcecode nicht im Text einfügen,
--> sondern als Dateianhang.

Du siehst schon an der Re-Formatierung deiner Source-Fragmente
dass es so wie es jetzt ist, eine Qual ist, abgesehen vom
fehlenden Gesamt-Programm.
Gast #6783340
Lesenswert?

1
struct Event_type
2
{
3
    // Struktur z.B. für Geburtstage
4
    byte Tag;
5
    byte Monat;
6
    int  Jahr;          // 9999 = Feiertag
7
    char Name[22];
8
    byte Typ;           // 1 = Geburtstag, 2 = Todestag, 3 = Jahrestag, 4 = Restmüll, 5 = Blaue Tonne, 6 = Gelbe Tonne, 7 = Biomüll
9
};
10
const Event_type ereignis[] PROGMEM =
11
{
12
    // hier die Datümer und die Namen auflisten
13
    {24, 12, 9999, "Heiligabend", 3},
14
    {25, 12, 9999, "1. Weihnachtstag", 3},
15
    {26, 12, 9999, "2. Weihnachtstag", 3},
16
    {7, 8, 9999, "Sylvester", 3},
17
    // ...
18
};
19

20
void setup() 
21
{
22
  Serial.begin(9600);
23
  for(const Event_type &e:ereignis)
24
  { 
25
    Serial.println((const __FlashStringHelper*)e.Name);
26
  } 
27
}
28

29
void loop() 
30
{
31

32
}


Ausgabe:
1
Heiligabend
2
1. Weihnachtstag
3
2. Weihnachtstag
4
Sylvester

Für die anderen Felder könntest du pgm_read_byte() und seine Freunde 
nutzen.
Gast #6783393
Lesenswert?

Beim Erstellen der Minimalversion ist mit aufgefallen, dass der 
Kalenderabfrageteil viel zu oft aufgerufen wird und vorher immer wieder
1
DateTime RTC_Zeit = rtc.now();

zur Übernahme der Real-Time-Clock-Zeit aufgerufen wurde.

Habe nun den Block verschoben, dass er nur jede Sekunde aufgerufen wird.
Dort konnte ich mir das DateTime sparen, da RTC_Zeit schon gesetzt war.

Nun funktioniert´s, aber warum, kann ich nicht sagen ...

Komisch war vorher nur: Compiler nölt nicht, Prg. macht trotzdem 
seltsame Dinge ;-)

@EAF: Mit pgm_read und Konsorten ist es mir nicht gelungen, den Text 
einzulesen. Da sitzt das Problem ws. wieder 80 cm vor dem Bildschirm ...
Beitrag #6783424 wurde von einem Moderator gelöscht.
Gast #6783469
Lesenswert?

Martin schrieb:
> Mit pgm_read und Konsorten ist es mir nicht gelungen, den Text
> einzulesen.

Oft vergisst man dabei dass pgm_read_byte(..) (als Beispiel)
ein Argument vom Datentyp PGM_P verlangt, also einen Pointer
auf Daten im Flash. Mit normalen Pointer auf einen String im
RAM funktioniert das nicht.
1
void uart_putstring_progmem (PGM_P ss)
2
{
3
    uint8_t val;
4
    while ( (val=pgm_read_byte(ss++)) != 0 )
5
      uart_putchar(val);
6
} /* --- uart_putstring_progmem --- */
Gast #6783572
Lesenswert?

jo mei schrieb:
> Oft vergisst man dabei dass pgm_read_byte(..) (als Beispiel)
> ein Argument vom Datentyp PGM_P verlangt, also einen Pointer
> auf Daten im Flash. Mit normalen Pointer auf einen String im
> RAM funktioniert das nicht.

Gerne wird vergessen/unterschlagen, dass das Arduino Print, welches 
seine Eigenschaften an Serial, Wire, LCD und viele weitere vererbt, 
schon von hause aus Progmem Strings lesen und ausgeben kann.

Es macht also Null Komma gar keinen Sinn, Strings aus dem Progmem zu 
lesen, wenn man sie unverändert ausgeben(printen) möchte.
Beitrag #6783593 wurde von einem Moderator gelöscht.
Beitrag #6783598 wurde von einem Moderator gelöscht.
Beitrag #6783710 wurde von einem Moderator gelöscht.
Beitrag #6783928 wurde von einem Moderator gelöscht.
Beitrag #6783946 wurde von einem Moderator gelöscht.
Beitrag #6783976 wurde von einem Moderator gelöscht.
Gast #6784023
Lesenswert?

Da das DCF77-Signal ja recht langsam ist (1 Bit pro Sekunde) und im 
Sketch selbst nicht so wahnsinnig viel passiert, sollte das Timing schon 
passen. Ich verwende auch keine delays(); alles wird brav über millis() 
abgefackelt.

Evtl. werden Timer oder Interrupts von den libraries parallel genutzt, 
das muss ich gelegentlich noch prüfen. Wenn dem so wäre, müßte es jedoch 
öfter Fehler geben.

Werde berichten.
Beitrag #6784044 wurde von einem Moderator gelöscht.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren