Forum: Mikrocontroller und Digitale Elektronik bitfeld dekrementieren => Überraschung.


von AVR-Bastler (Gast)


Lesenswert?

Hallo,

ich benutze auf den AVRs gerne Bitfelder um Flags zu speichern. Die 
Bitfelder lege ich dann auf ein Register unterhalb 0x1F, z.B. so:
1
typedef volatile union { //
2
  uint8_t flags;
3
  struct {
4
  uint8_t counter:4;
5
  uint8_t t2_tick:1;
6
  uint8_t alarm_state:1;
7
  uint8_t messung:1;
8
  uint8_t reserve:1;
9
  } __attribute__ ((packed));
10
} SYS_STATUS_REG;
11
12
#if defined (__AVR_ATmega8A__)
13
#define S_status (* (volatile SYS_STATUS_REG *) &TWCR)
Hier habe ich mal aus Spaß und Langeweile statt nur Flags einen 4bit 
Counter platziert. Mit gcc auf dem PC funktioniert das: Beim 
Dekrementieren zählt er von 15 auf 0 und fängt dann wieder bei 15 an.
Auf dem AVR zählt er ein bisschen anders....
1
S_status.counter=15;
2
  for (uint8_t i=20; i<21; --i) {
3
    itoa( S_status.counter, buffer, 10);
4
    uart_puts(buffer);
5
    uart_puts_P("\n\r");
6
    --S_status.counter;
7
  }
ergibt:
5
4
1
0
5
...
Hat der Compiler hier etwas tot optimiert?
Flags: -Wall -Os -fpack-struct -fshort-enums -ffunction-sections 
-fdata-sections -std=gnu99 -funsigned-char -funsigned-bitfields 
-mmcu=atmega8a -DF_CPU=4000000UL

von asdfasd (Gast)


Lesenswert?

Controlregister eignen sich nur selten als Counter ...

von jz23 (Gast)


Lesenswert?

AVR-Bastler schrieb im Beitrag #5151726:
> ich benutze auf den AVRs gerne Bitfelder um Flags zu speichern. Die
> Bitfelder lege ich dann auf ein Register unterhalb 0x1F

Und warum legst du die nicht ins RAM?

von Carl D. (jcw2)


Lesenswert?

Falls du den Fehler im Compiler vermutest, wo ist dias Disassembly? -> 
.lss
Sonst: MemoryMapped-IO-Register, die jederzeit ihren Wert ändern kann, 
ist mit "volatile" zu deklarieren, weil?
Eventuell genau deshalb.

: Bearbeitet durch User
von A. S. (Gast)


Lesenswert?

Was macht denn TWOR?

von Peter D. (peda)


Lesenswert?

AVR-Bastler schrieb im Beitrag #5151726:
> #define S_status (* (volatile SYS_STATUS_REG *) &TWCR)

Gehts noch, was soll der Unfug?

TWCR ist ein Konfigurationsregister, d.h. man darf nur die erlaubten 
Bits setzen oder löschen (siehe Datenblatt).
Und das hat in der Regel Folgen für die damit verbundenen IO-Pins.
Und viel Spaß, wenn Du Interruptenablebits setzt, aber keinen Handler 
dafür hast.

Bitfelder erzeugen oft deutlich umständlicheren Code als Bytevariablen. 
Daher sieht man oft, daß erfahrene Programmierer ein ganzes Byte als 
Flag "verschwenden".
Und Zählervariablen <8Bit wirst Du bei denen auch nicht finden können.

: Bearbeitet durch User
von AVR-Bastler (Gast)


Lesenswert?

jz23 schrieb:
> Und warum legst du die nicht ins RAM?
Wie ich oben schon sagte: aus Neugierde, nicht aus Notwendigkeit.

Peter D. schrieb:
> man darf nur die erlaubten
> Bits setzen oder löschen
Peter, Du bist wenigstens etwas näher dran als die Anderen:
Das Problem ist nicht, dass es ein Konfigurationsregister ist (denn wenn 
die Peripherie ausgeschaltet wäre, könnte ich konfigurieren so viel ich 
will).
Das Problem ist, dass es genau dieses Register ist:

1. Es ist gar nicht unterhalb 0x1F, entspricht also gar nicht dem 
gewünschten Zweck.
2. Genau hier ist neben dem TWINT auch das TWEN drin - hier wird also 
entgegen jedem Sinn und Verstand das unbenutzte TWI aktiviert.
3. Bit 1 gibt's hier gar nicht - deshalb zählt er auch so komisch.

Fazit: Tippfehler, es sollte TWBR sein, nicht TWCR. Es war halt schon 
spät...
Mannomann - hätte ich nicht spaßeshalber den Counter da reingepackt 
sondern ein Flag an Position 1, hätte ich lange gesucht.

Ansonsten möge mancher, der hier geantwortet hat, mal seine Antwort mit 
den Fakten vergleichen. Es ist doch immer witzig hier. Und so 
freundlich...

von Peter D. (peda)


Lesenswert?

AVR-Bastler schrieb im Beitrag #5151930:
> Fazit: Tippfehler, es sollte TWBR sein, nicht TWCR.

Trotzdem wirst Du sowas bei einem erfahrenen Programmierer nicht finden. 
Da steht Lesbarkeit und Fehlervermeidung an erster Stelle.
Wie Du ja selber gemerkt hast, ist das aber Fehler provozierend.
Es besteht auch keinerlei Grund, mit RAM zu geizen, Du kannst ja bis zum 
ATmega328 upgraden.

So ein Code ist auch unfair gegenüber demjenigen, der Deinen Code weiter 
warten muß. Der wird erstmal das Grübeln kriegen, was zum Teufel diese 
Funktion mit dem TWI zu tun hat. Er wird ins Datenblatt schauen müssen, 
was das Register bedeutet. Er wird also lange brauchen, um den dirty 
hack als solchen zu erkennen, nur damit ein paar Byte und CPU-Zyklen 
gespart werden. Und dann darüber den Kopf schütteln und es nochmal 
sauber hinschreiben.

Und wenn Du selber den Code später um TWI erweitern willst, wirst Du den 
Hack längst vergessen haben und Dir dann aber so richtig die Karten 
legen.

: Bearbeitet durch User
von AVR-Bastler (Gast)


Lesenswert?

Peter D. schrieb:
> Es besteht auch keinerlei Grund, mit RAM zu geizen, Du kannst ja bis zum
> ATmega328 upgraden.
Für diese Anwendung reichte auch ein Atmega48. Den müsste ich aber 
bestellen. Von den Atmega8A liegen dagegen noch zu viele hier herum.

Wenn mal irgendjemand durch dieses Gerät in solche Begeisterung versetzt 
wird, dass ich ein Millionengeschäft wittere, dann werde ich bei den 
dann zu erwartenden Stückzahlen sicher neu über den "besten" µC für 
diesen Zweck nachdenken.

Peter D. schrieb:
> So ein Code ist auch unfair gegenüber demjenigen, der Deinen Code weiter
> warten muß.
Life is not fair. It never was.
In diesem speziellen Fall ist aber alles eine Frage der Dokumentation.
Ich für meinen Teil habe die Angewohnheit, nicht nur wichtige Stellen im 
Code zu markieren und zu kommentieren, sondern auch ein "Vorwort" im 
Kopf der main.c des Projektes zu schreiben, aus dem hervorgeht, welche 
Pins (für den Fall, dass die Doku der Schaltung mal abhanden kommt), 
welche Peripherie und welche GPIORs benutzt werden sowie welche Todos 
und Limitations noch offen sind.

Das alles mache ich nur für mich selbst, denn es können Jahre vergehen, 
bis ich mal wieder in den Code schaue.

Vor allem aber:
Alles, was Du schreibst, ist richtig und wichtig für den jugendlichen 
Programmier-Schüler, der von einer Zukunft als Software-Entwickler 
träumt.

In meinem Fall ist aber die einzige Kontrollinstanz der µC. Wenn der 
sagt: "Das geht so nicht.", dann muss ich ihm glauben.
Allen anderen höre ich zu.

von Kaj G. (Firma: RUB) (bloody)


Lesenswert?

AVR-Bastler schrieb im Beitrag #5152228:
> In diesem speziellen Fall ist aber alles eine Frage der Dokumentation.
> Ich für meinen Teil habe die Angewohnheit, nicht nur wichtige Stellen im
> Code zu markieren und zu kommentieren, sondern auch ein "Vorwort" im
> Kopf der main.c des Projektes zu schreiben, aus dem hervorgeht, welche
> Pins (für den Fall, dass die Doku der Schaltung mal abhanden kommt),
> welche Peripherie und welche GPIORs benutzt werden sowie welche Todos
> und Limitations noch offen sind.
Du solltest mal ganz dringend Buecher wie "Clean Code" lesen

von Feldstecher (Gast)


Lesenswert?

@Bastler
Du hast gefragt warum dein Code nicht funktioniert, Peter hat deine 
Frage beantwortet. Was gibts da noch rumzueiern?

von AVR-Bastler (Gast)


Lesenswert?

Kaj G. schrieb:
> Du solltest mal ganz dringend Buecher wie "Clean Code" lesen

Nein, sollte ich nicht. Warum nicht? Lies noch einmal, was  ich 
geschrieben habe.

@Feldstecher
Ja, ich habe meine Frage ausführlich beantwortet.
Ich weiß auch nicht, was a da noch zu "eiern" gibt.

Beitrag #5152401 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.