Forum: Mikrocontroller und Digitale Elektronik DCF-Uhr Übungsprojekt


von kobold254 (Gast)


Lesenswert?

Hi,
ich bin kürzlich in das Thema AVR Programmierung eingestiegen.
Ich verwende den ATTINY2313a und wollte zur Übung auf einem alphanum. 
Display mir mittels DCF Empfänger die Uhrzeit anzeigen lassen. Ich weiß, 
dass es dazu zahlreiche Foreneinträge gibt, allerdings wollte ich zum 
Üben die Funktionalität selbst implementieren.
Das Display läuft soweit, allerdings schlägt die Abfrage des Busyflags 
aus irgendeinem Grund fehl (wenn ich nach der Displayinitialisierung das 
BF mit busycheck() aufrufe funktionierts nicht...). Das Display ist 
korrekt angeschlossen und wird mit 8 Datenleitungen verwendet.
1
void busycheck(void)
2
{
3
  PORTD |= (1 << RW); //Daten lesen
4
  PORTD &= ~(1 << RS); //Befehl
5
  
6
  PORTD |= (1 << E);
7
  DDRB &= ~(1 << DATA7);//Datenbit7 als Eingang --> Busyflag
8
  
9
  while(PINB & (1 << DATA7))
10
  {
11
    PORTD &= ~(1 << E);
12
    _delay_us(1);
13
    PORTD |= (1 << E);
14
  }
15
  DDRB |= (1 << DATA7); //Datenbit 7 wieder als Ausgang definieren
16
}

Das Problem habe ich durch eine Wartezeit umgangen... über eine 
Problemlösung wäre ich aber sehr dankbar :)

Das wesentlich schlimmere Problem ist die DCF Decodierung... ich weiß 
echt nichtmehr weiter...
ich habe folgenden Quelltext:
1
ISR(INT0_vect)   
2
{
3
  static char syncevent=0;
4
  
5
  uint8_t counter = 0;
6
  uint8_t i;
7
  short rawdata[59];
8
  char buffer [sizeof(uint32_t)*8+1];
9
  char minbuffer [20];
10
  int minute;
11
  
12
  if (syncevent==0)
13
  {
14
    while ((PIND & (1 << PINDCF)) == 0)
15
    {
16
      _delay_ms(10);
17
      counter++;
18
      if (counter > 172)
19
      {
20
        syncevent = 1;
21
        PORTD |= ( 1 << PIND6);
22
        break;
23
      }
24
    }
25
  }
26
  else
27
  {
28
    for(i=0;i<60;i++)
29
    {
30
      counter = 0;
31
      while ((PIND & (1 << PINDCF)) == 0); //Warten auf High
32
      
33
      while(PIND & (1 << PINDCF)) //High Länge ermitteln
34
      {
35
        _delay_ms(1);
36
        counter++;
37
        
38
      }
39
      if (counter>170) //Signallaenge groesser 170 ms, dann logisch 1, sonst 0
40
      {
41
        PORTD |= ( 1 << PIND6);
42
        rawdata[i]=1;
43
        string2display(itoa(rawdata[i],buffer,2),ZEILE1+i);
44
      }
45
      else
46
      {
47
        PORTD &= ~( 1 << PIND6);
48
        rawdata[i]=0;
49
        string2display(itoa(rawdata[i],buffer,2),ZEILE1+i);
50
      }
51
    }
52
    syncevent = 0;
53
    
54
    minute = rawdata[20];
55
    minute +=rawdata[21]*2;
56
    minute +=rawdata[22]*4;
57
    minute +=rawdata[23]*8;
58
    minute +=rawdata[24]*10;
59
    minute +=rawdata[25]*20;
60
    minute +=rawdata[26]*40;
61
    //string2display(itoa(minute,minbuffer,2),ZEILE4); //<<<<<<Problemzeile<<<<  
62
  }

Ich kann mir die einzelnen Bits wunderbar auf dem Display anzeigen (Oszi 
hängt dran die Daten passen auch :) ):
string2display(itoa(rawdata[i],buffer,2),ZEILE1+i);

Wenn ich die Problemzeile allerdings mit drin habe, funktioniert das 
nichtmehr, das Minutenergebnis kommt auch nicht...(das Display bleibt 
leer)
Auch wenn ich anderweitig die Variable minute verwende (z.B. if-Abfrage) 
tritt der Fehler auf...

Weiß villeicht irgendwer wo es hängt?

Achja PIND6 schaltet einfach ein LED als Feedback...die geht mit der 
Problemzeile auch nicht mehr...

von Carsten W. (eagle38106)


Lesenswert?

Hi!

Also, bei einem 8-Bit Datenbus am Port schaltet man immer alle Bits auf 
Eingang, wenn man etwas lesen will. Auch, wenn man hinterher nur ein Bit 
davon auswertet. Andernfalls treiben im Worst-Case sieben Leitungen 
gegeneinander.

Carsten

von Gregor O. (zappes)


Lesenswert?

Ich bin nicht der Spezialist für die Feinheiten vopn C/C++, aber 
irgendwie finde ich die Puffergröße 20 für minbuffer etwas schräg. Ich 
würde den Puffer einfach mal Sicherheitshalber 33 Bytes groß machen, um 
sicher zu gehen, dass es da keinen Überlauf gibt. Oder als Basis bei der 
Konvertierung "10" statt "2" nehmen.

von Peter D. (peda)


Lesenswert?

kobold254 schrieb:
> short rawdata[59];
>   char buffer [sizeof(uint32_t)*8+1];
>   char minbuffer [20];
>   int minute;

Wie willst Du 173 Byte auf nem MC mit 128 Byte RAM unterbringen?
Und etwas Stack sollte auch noch sein.

von kobold254 (Gast)


Lesenswert?

Schonmal danke für die vielen Tips werden das ganze heute Abend mal 
ausprobieren ;):)

@Carsten Wille: Ich werds versuchen aber generell sollte es doch möglich 
sein jedes Bit eines Ports anders zu verwenden oder?

@Gregor Ottmann: Werde die Basis auf 10 ändern, war mein Fehler beim 
Posten, habe schon so viel probiert, habe die falsche Basis drin gehabt

@Peter Dannegger: Guter Einwand :):D ich frag mich nur wieso des AVR 
Studio nicht meckert?:(

Melde mich später wieder, wenn die Veränderungen eingeflossen sind ;)

von Karl H. (kbuchegg)


Lesenswert?

kobold254 schrieb:
> Schonmal danke für die vielen Tips werden das ganze heute Abend mal
> ausprobieren ;):)
>
> @Carsten Wille: Ich werds versuchen aber generell sollte es doch möglich
> sein jedes Bit eines Ports anders zu verwenden oder?

Natürlich.
Aber du bist ja mit dem µC nicht alleine.

Was macht denn das LCD, wenn du mittels RW es beauftragst, seine 
Informationen rauszugeben? Es schaltet seinerseits seine 8 
Datenleitungen auf Ausgang. Damit steht es
1
   µC                      LCD
2
  +--------+             +---------+
3
  |    DB7 | <---------< | DB7     |
4
  |    DB6 | >---------< | DB6     |
5
  |    DB5 | >---------< | DB5     |
6
  |    DB4 | >---------< | DB4     |
7
  |    DB3 | >---------< | DB3     |
8
  |    DB2 | >---------< | DB2     |
9
  |    DB1 | >---------< | DB1     |
10
  |    DB0 | >---------< | DB0     |
11
  +--------+             +---------+

DB7 hast du korrekt am µC auf Eingang umgeschaltet. Aber was ist mit dem 
Rest? Das dich die anderen Bits nicht interessieren, interessiert ja das 
LCD nicht. Das schaltet seine restlichen Bit-Leitungen ebenfalls auf 
Ausgang und gibt dort seine Daten drauf. Nur das eben der µC seine 
restlichen Portpins ebenfalls auf Ausgang geschaltet hat. Sagen wir mal 
das LCD möchte DB2 auf 1 ziehen, der µC möchte die Leitung aber auf 0 
ziehen (weil da zufällig vom letzten mal nach ein 0 Bit am Portpin 
liegt). Nicht gut. 2 Ausgänge lässt man nie gegeneinander arbeiten!

: Bearbeitet durch User
von Yvonne J. (laserlight)


Lesenswert?

...ich bin kürzlich in das Thema AVR Programmierung eingestiegen.

Falsches Projekt für einen Einstieg:

- alphanum.Display mir mittels
- DCF Empfänger die
- Uhrzeit anzeigen lassen

Gleich 3 Wünsche auf einmal. Viel zu viel, ertsmal eine LED blinken 
lassen.

Projekt in die 3 Teilaufgaben aufteilen und einzeln ausbauen.

Yve

von kobold254 (Gast)


Angehängte Dateien:

Lesenswert?

Durch die Änderung am Port funktioniert der Busy-Check --> erledigt 
vielen Dank :)

Habe den Code umgeschrieben und verwende nun statt des Arrays eine 
uint_64 in die ich die Daten shifte... leider ohne Erfolg :(

@Yvonne J.: Blinkende LED habe ich davor gemacht ;) darüber hinaus habe 
ich schon einiges auf dem RPi programmiert ;) (u.a. auch das Display, 
allerdings ohne Busyflag und im 4-Bit Betrieb)

Habe den gesamten, aktuellen Quellcode mal in den Anhang ;)

BTW: die Shiftvariante braucht einiges mehr an Speicher, als die 
Variante mit dem short-array

von Joachim B. (jar)


Lesenswert?

kobold254 schrieb:
> Habe den Code umgeschrieben und verwende nun statt des Arrays eine
> uint_64 in die ich die Daten shifte... leider ohne Erfolg :(

schau dir das mal an:

Beitrag "DCF77 Uhr in C mit ATtiny26"

http://www.mikrocontroller.net/attachment/80829/dcf77.zip

kann man ne Menge von lernen


Peter Dannegger schrieb:
> Wie willst Du 173 Byte auf nem MC mit 128 Byte RAM unterbringen?
> Und etwas Stack sollte auch noch sein.
danke Peter, ewig nix von dir gelesen :-) wir hatten auch mal 
telefoniert)

ich habe auch am PC angefangen das auszuwerten einfach das Bit in einen 
Joystikport gegeben und alle 60ms per IRQ die Bits gelesen

PC Speicher satt und man kann locker reservieren und schieben, mit 60ms 
Interrupt ist es zwar etwas grob geht aber

am AVR kann man zum spielen ja auch größere nehmen wo der Speiche nicht 
so knapp ist.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

kobold254 schrieb:

> uint_64 in die ich die Daten shifte... leider ohne Erfolg :(

Was heisst 'ohne Erfolg'?

Tja.
Du gehst die Sache ein wenig naiv an, indem du annimmst du könntest das 
aus dem Stegreif fehlerfrei schreiben.
Wenn du schon ein wenig auf dem Pi programmiert hast, solltest du 
eigentlich wissen, dass man Programme schrittweise programmiert.
Erster Schritt: kriegst du eine Synchronisation auf die fehlende 
Sekundenmarke am Anfang einer Minute? Wenn nein, warum nicht?


Das die ganze ISR genau so gemacht ist, wie man das nicht macht, brauch 
ich wohl nicht extra dazu sagen. So kannst du dir den Interrupt auch 
gleich sparen und alles in der Hauptschleife machen. Wäre einfacher.

: Bearbeitet durch User
von kobold254 (Gast)


Lesenswert?

Synchronisation funktioniert ja ;) und die Bedingungen werden auch 
richtig aufgerufen ;) (Die LED am PIND6 zeigt mir das an, ich vergleiche 
mitm Oszi)

Ich weiß, dass das nicht aus dem Stegreif zu schreiben ist, deshalb 
sitze ich ja auch schon einige Zeit daran und habe hier um Hilfe gefragt 
:)

Ich gebe zu die ISR ist echt nicht schön :(... aber ist ja auch erstmal 
zum üben gedacht ;)

Ich werde mir mal den anderen Quelltext anschauen, über weitere Hilfe 
würde ich mich dennoch sehr freuen :)

von der alte Hanns (Gast)


Lesenswert?

>Erster Schritt: kriegst du eine Synchronisation auf die fehlende
>Sekundenmarke am Anfang einer Minute?

>Synchronisation funktioniert ja ;)

Dieses nun wundert mich, denn die Tastlücke sitzt am Ende der Minute.

von kobold254 (Gast)


Lesenswert?

Villeicht reden wir aneinander vorbei... ich meine die Synchronisation 
auf Bit 59, sodass längere Zeit 0 anliegt (siehe 
http://www.obonic.de/wp-content/uploads/time-sync/dcf77-signal.jpg), 
mein Signal ist invertiert ;)

von kobold254 (Gast)


Lesenswert?

Danke nochmals an alle habe das Problem mit einer switch-case-Struktur 
gelöst :)

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.