Forum: Mikrocontroller und Digitale Elektronik Komisches Arduino-Phänomen mit PROGMEM und DCF77-Empfang


von Martin (Gast)


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
    }

von jo mei (Gast)


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.

von EAF (Gast)


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.

von Martin (Gast)


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 ...

von EAF (Gast)


Lesenswert?

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

Warum willst du das?

Beitrag #6783424 wurde von einem Moderator gelöscht.
von jo mei (Gast)


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 --- */

von EAF (Gast)


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.
von Sebastian (Gast)


Lesenswert?

Welcher uC? Atmega1284P?

LG, Sebastian

Beitrag #6783928 wurde von einem Moderator gelöscht.
Beitrag #6783946 wurde von einem Moderator gelöscht.
Beitrag #6783976 wurde von einem Moderator gelöscht.
von Dietrich L. (dietrichl)


Lesenswert?

Martin schrieb:
> Nun funktioniert´s, aber warum, kann ich nicht sagen ...
>
> Komisch war vorher nur: Compiler nölt nicht, Prg. macht trotzdem
> seltsame Dinge ;-)

Spekulation: Das Timing für den DCF77-Empfang reicht nicht, da das 
sonstige Programm zuviel Verarbeitungszeit verbraucht. Das merkt der 
Compiler natürlich nicht...

von Lok-Doc (Gast)


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.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.