Forum: Mikrocontroller und Digitale Elektronik Timer 1 (CTC) unregelmäßig


von Sven Z. (treito)


Angehängte Dateien:

Lesenswert?

Hallo,

ich bin noch Anfänger in Sachen Atmel. Ich habe ein Testprogramm 
geschrieben (Ampelschaltung nach einer Projektvorgabe).
Nun zum Problem: Es funktioniert auch soweit, bloß manchmal scheint der 
Timer zu hängen. In der "Nachtschaltung" sollten die LEDs mit 0,5Hz 
blinken doch manchmal scheinen diese zu hängen als wenn einmal vergessen 
wird , den Blinktakt umzuschalten.
Verwendet ist ein Atmega8, ich habe mich schaltungstechnisch an dem 
LCD2USB-Projekt orientiert (Grundschaltung ohne USB), die Dioden 
verwenden alle eine gemeinsame Anode. Externer Takt mit 12MHz-Quarz.
Was ist falsch?

Gruß,

Sven

von mizch (Gast)


Lesenswert?

volatile.

von Sven Z. (treito)


Lesenswert?

Okay, das habe ich aus dem Tutorial übernommen...
Daran soll es liegen? Was immer das auch heißen mag...

von mizch (Gast)


Lesenswert?

Daran muss nicht alles liegen, aber das ist zumindest ein Grund, warum 
es nicht sauber funktionieren dürfte.

Du möchtest Dich über den Qualifier „volatile“ im Zusammenhang mit 
Übergaben vom und zum Interrupt informieren.  Die Suchfunktion dürfte 
Dir weiterhelfen, denn es ist ein, wenn nicht der Standardfehler.

von Sven Z. (treito)


Lesenswert?

Danke erst einmal für die Hilfe.

Naja wie gesagt, das steht so im Tutorial und als ich gesucht habe, bin 
ich nicht drauf gestoßen.
Es sieht schon wesentlich besser aus, auch wenn ich nun das Gefühl habe, 
dass er ggf. zwischendurch 1-2x etwas zu schnell blinkt, aber das kann 
auch eine Täuschung sein.
Morgen ggf. mal ein Oszilloskop dranhängen, dann sehe ich ja, wie 
"sauber" das Signal ist.
So, während ich das geschrieben habe, hat die Schaltung 4x 
hintereinander schneller geblinkt. Okay, die "Hänger" sind weg, aber der 
Timer ist noch unregelmäßig.

von Anja (Gast)


Lesenswert?

mizch schrieb:
> volatile

mizch meinte damit daß du z.B. vergessen hast den Struct "x" als 
volatile zu deklarieren. (Gilt für alle Variable die sowohl im 
Hauptprogramm als auch im Interrupt verwendet werden).
Bei der Optimierung rechnet der Compiler sonst nicht damit daß sich die 
Variable ändern könnte. Er liest sie dann ggf. nur ein einziges Mal und 
dann nie wieder. Die volatile -Deklaration verhindert diese Optimierung.

Gruß Anja

von Sven Z. (treito)


Lesenswert?

Okay Danke,

ich hatte natürlich volatile komplett gelöscht, da ich das so verstanden 
habe. Aber: Mit volatile habe ich die Hänger, ohne volatile läufts ab 
und an schneller.

von Karl H. (kbuchegg)


Lesenswert?

Nein

gemeint ist, dass du zb x.ein sowohl in der ISR als auch im 
Hauptprogramm benutzt. Daher sollte das auch volatile sein

von Karl H. (kbuchegg)


Lesenswert?

Allerdings bin ich nicht wirklich davon überzeugt, das das hier konkret 
das Problem ist.

Deine Statemaschine ist so dermassen unübersichtlich und kompliziert, 
das Problem wird wohl dort irgendwo zu suchen sein.

Die struct die du hast: wirf sie raus. SIe erfüllt keinen sinnvollen 
Zweck. Mach da normale Variablen draus und die die es brauchen 
zusätzlich auch noch volatile.

Sinnvoll wäre eine struct, die einen Zustand deiner Statemachine 
beschreibt.
Ein derartiger Zustand ist gekennzeichnet durch
  auszugebende Bitmuster an Port B
  auszugebende Bitmuster an Port C
  auszugebende Bitmuster an Port D
  Zeitdauer des Zustands
  Nummer des nächsten Zustands
  was du sonst noch brauchst

Da könntest du eien struct sinnvoll einsetzen. Deine Statemachine ist 
dann einfach nur ein Array aus derartigen Strukturen.

Und dein Hauptprogramm wird sehr einfach werden. Die ganze Logik der 
Zustandsmaschine steckt einzig in den Daten im Array. Dort ist der 
Ablauf kodiert.

von Sven Z. (treito)


Lesenswert?

Also falls mit Statemaschine die Zählerstandsabfrage gemeint sein 
sollte: Diese wird ja im sog. Nachtbetrieb nicht verwendet. Ursprünglich 
wollte ich auch nur die Ausgänge ändern, die sich bei einer 
Zählerstandsänderung ändern, aber da das Blinken gestört ist, hatte ich 
die Befürchtung, dass er sich ggf. verzählt und das wäre fatal, wenn 
nachher alle gleichzeitig grün hätten oder so.

von Sven Z. (treito)


Lesenswert?

Hey danke,

das Problem war echt das struct.
Aber wie könnte ich das denn mit dem struct lösen bezüglich 
Übersichtlichkeit? Kann ich dann z.B. sagen: "PORTB=x"?

von Karl H. (kbuchegg)


Lesenswert?

1
struct state
2
{
3
  uint8_t BitsB;
4
  uint8_t BitsC;
5
  uint8_t BitsD;
6
  uint8_t nextState;
7
};
8
9
struct state Ampel[] =
10
  {
11
    // Bits an B (BitsB)
12
    //      Bits an C (BitsC)
13
    //            Bits an D (BitsD)
14
    //                       nächster Zustand (nextState)
15
    { 0x00, 0x00, 0x00,      1 },
16
    { 0xFF, 0x00, 0x00,      2 },
17
    { 0x00, 0xFF, 0x00,      3 },
18
    { 0x00, 0x00, 0xFF,      0 },
19
  };
20
21
int main()
22
{
23
   ...
24
25
  zustand = 0;
26
  while( 1 ) {
27
28
   
29
    PORTB = Ampel[ zustand ].BitsB;
30
    PORTC = Ampel[ zustand ].BitsC;
31
    PORTD = Ampel[ zustand ].BitsD;
32
33
    zustand = Ampel[ zustand ].nextState;
34
35
    _delay_ms( 500 );
36
  }
37
}


> Kann ich dann z.B. sagen: "PORTB=x"?
Schön langsam werde ich es müde, immer und immer wieder denselben Satz 
stereotyp vorzubeten:

Kauft euch Literatur!
Ihr laboriert an 'Problemen' rum, die in jedem noch so grindigen 
C-Lehrbuch ausführlich und erschöpfend erklärt werden.

Manchmal hasse ich die "Ich such mir im Internet mein Halbwissen 
zusammen weil Buch lesen so uncool ist"-Generation.

von Sven Z. (treito)


Lesenswert?

Sorry,

Bücher habe ich hier auch schon zwei und ich brauche das Teil bis 
übermorgen also habe ich nicht die Zeit diese 1000-Seiten durchzulesen.
Mein Hauptproblem war halt, wie ich ein struct den Ports zuweisen kann. 
Auf dieses Doppelstructungetüm bin ich nun mal nicht gekommen.
2. Problem: An Port B+C hängen Taster und ich war mir nicht sicher, ob 
ich dann einfach zuweisen darf ansonsten hätte ich Bitmuster zugewiesen 
(0b00011111 oder dergleichen).
Okay, das Codebeispiel würde so nicht klappen, aber ich wüsste nun, wie 
ich das umsetzen müsste. Danke.
Auflage ist das exakte Timingdiagramm so wie verwendet (Zähler von 
0-30). Mit delay möchte ich auch ungerne arbeiten, damit ich Blinktakt 
(Nachtschaltung) und Zähltakt trennen kann. Außerdem müsste der Zähltakt 
erniedrigt werden, wenn die Schaltung unter "realen" Bedingungen laufen 
soll und da wäre ein delay von 10s hinderlich bzgl. Tastendruck.

von Sven Z. (treito)


Lesenswert?

Also mit dem struct geht es nicht - es passiert das, was ich befürchtet 
hatte: Die Taster (Eingänge) versagen den Dienst!

von Sascha W. (sascha-w)


Lesenswert?

das hat doch mit dem struct nichts zu tun, du musst bei der Zuweisung 
zum Port nur dafür sorgen, das nur die Ausgangsbits geändert werden.

mal angenommen PB0 und PB1 sind Tastereingänge

alt:
>  PORTB = Ampel[ zustand ].BitsB;

neu:
>  uint8_t temp;
>  ....
>  ....
>  temp = PORTB & 3;
                * nur Bits die nicht verändert werden dürfen (taster)
>  PORTB = temp | (Ampel[ zustand ].BitsB & 252);
                * und die neuen Ausgangsbits dazu

>  ....
>  ....

deine Wartezeit packst du einfach noc in den struct mit rein, und die 
Tag/Nacht-schaltung realisierst du in dem du in dem struct 2 Bereich 
verwendest, die mit dem nextState in sich geschlossen sind aber über 
deinen taster oder wie auch immer umschaltbar sind.
z.B.
0 bis 25 Tag (bei 25 Rücksprung zu 0)
Nacht -> Umschaltung auf 26
26 bis 35 Nacht (bei 36 Rücksprung auf 26)

Sascha

von Sven Z. (treito)


Angehängte Dateien:

Lesenswert?

Hmm okay, werde es mal testen, danke

Nein, die Auflage war, ein festes Taktdiagramm zu verwirklichen 
eigentlich per SPS. Das Atmel-Board dient dazu zu zeigen, dass es auch 
anderweitig geht, wir uns aber dagegen entschieden haben.
Naja und der C++-Kurs beginnt erst in ein paar Monaten, leider.
Ich habe die Schaltung aber soweit hinbekommen mit Ablauf, indem ich 
gesagt habe, wann die nächste Änderung stattfindet und wenn der Zähler 
dahinspringt, hüpft er nun eine Zeile weiter.
Das mit der Bit-Einschränkung werde ich mal antesten. Ich kann zwar 
etwas Java und auch C, aber dieses struct-Gerippe ist für mich doch 
recht komplex gewesen, auch wenn ich es nun verstehe, aber hey, das ist 
mein erstes Projekt mit dem Atmel, also das erste Programm, welches ich 
selber schreibe. Ich hatte zuvor nur ein paar Schaltungen aus dem Netz 
nachgebaut. Eigentlich wollte ich mit was simplen anfangen wie: Ich 
drücke einen Taster und ein Licht geht an und aus...
Naja ich packe den Code mal in den Anhang, allerdings ist das 
struct-Gerippe auskommentiert, da es ja (noch) nicht läuft...

Gruß,

Sven

von Sven Z. (treito)


Angehängte Dateien:

Lesenswert?

Ich bekomme langsam eine Krise...

Der Trick funktioniert zwar, allerdings nur für einen Durchlauf. Wenn 
die Position zurückgesetzt wird, dann gehen alle Ausgänge auf null (und 
somit alle LEDs an), aber wieso?!

von Sven Z. (treito)


Lesenswert?

Fehler gefunden! Nun gehts! :-D

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.