Hallo,
ich möchte den Status von verschiedenen Relais in einet Struktur
speichern
1
typedefenum
2
{
3
RELAIS_1,
4
RELAIS_2,
5
RELAIS_3,
6
RELAIS_4,
7
RELAIS_5,
8
NOF_RELAIS
9
}Relais_te;
10
11
typedefstruct
12
{
13
constuint8_tpin;
14
boolstate_b;
15
}Relais_ts;
16
17
18
staticRelais_tsrelais_as[NOF_RELAIS]={
19
[RELAIS_1]={.pin=(1<<PINB1),.state_b=false},
20
[RELAIS_2]={.pin=(1<<PINB2),.state_b=false},
21
[RELAIS_3]={.pin=(1<<PINB3),.state_b=false},
22
[RELAIS_4]={.pin=(1<<PINB4),.state_b=false},
23
[RELAIS_5]={.pin=(1<<PINB5),.state_b=false}
24
};
jedoch bekomme ich bei der Initialisierung für jeden Pin den Wert 0
heraus.
Ich verstehe es aber nicht, woran es noch liegen könnte.
Was mache ich bei der initialisierung falsch?
Liegt vermutlich daran, dass du in Zeile 8 immer das gleiche Element
ansprichst.
relais_ps = &relais_as[RELAIS_5];
Da solte vermutlich der index relais_e rein?
Klaus H. schrieb:> Liegt vermutlich daran, dass du in Zeile 8 immer das gleiche> Element> ansprichst.>> relais_ps = &relais_as[RELAIS_5];>> Da solte vermutlich der index relais_e rein?
Ja, da sollte relais_e rein.
Trotzdem sollte keine 0 rauskommen.
Auch wenn ich relais_e eintrage, bekomme ich immer 0 zurück.
Da 1 << PINB5 auch nicht mehr in einem character reinpasst das auch noch
ein wenig angepasst.
Das riecht ziemlich nach einem Overflow.
Sind die PIN Nummern >= 8 ?
Speichere mal direkt PINBx ohne Shift und schau dir die Ausgabe aus.
Hast Du die Warnings des Compilers ausgeschaltet?
Was nutzt Du denn für einen Compiler/Plattform?
Möglicherweise wird relais_as beim Anlaufen von der runtime nicht sauber
initialisiert? Man könnte mal in den de-assemblierten Code schauen um
das zu prüfen.
Chandler B. schrieb:> Hallo,> ich möchte den Status von verschiedenen Relais in einet Struktur> speichern
Du postest in der Rubrik "PC-Programmierung", der Code lässt aber auf
einen AVR schliessen.
Welcher Compiler in welcher Version für welche Zielhardware ist es denn?
Oliver
Oliver S. schrieb:> Du postest in der Rubrik "PC-Programmierung", der Code lässt aber auf> einen AVR schliessen.>> Welcher Compiler in welcher Version für welche Zielhardware ist es denn?
oh ?, tatsache :/
Ja, es geht auch um einem AVR auf einem Arduino Board (atmega328p)
als compiler benutze ich den avr-gcc compiler und flashe das ganze mit
avrdude über isp auf dem atmega.
Klaus H. schrieb:> Sind die PIN Nummern >= 8 ?> Speichere mal direkt PINBx ohne Shift und schau dir die Ausgabe aus.
Die Pins sind PINB0=0, PINB1=1, PINB2=2, ..., PINB7=7 also sowieso
kleiner als 8 und ich benutze auch nur bis PINB5
Ich muss das morgen noch einmal testen, wenn ich wieder zu hause bin.
Nur mal Interesse halber, welcher tiefere Sinn steckt dahinter, die
Pinzugriffe derartig zu verschwurbeln.
D.h. wie soll die praktische Anwendung aussehen?
Vermutlich wird der Compiler dadurch gezwungen, die Zugriffe memory
mapped zu machen, also nicht einfach über direkte Bitbefehle und auch
nicht atomar (mögliche Konflikte beim Setzen in Interrupts).
Peter D. schrieb:> Vermutlich wird der Compiler dadurch gezwungen, die Zugriffe memory> mapped zu machen, also nicht einfach über direkte Bitbefehle und auch> nicht atomar (mögliche Konflikte beim Setzen in Interrupts).
Vermutlich. Wobei gcc durchaus einige Varianten erkennt und entsprechend
sbi oder cbi einsetzt.
Würde hier aber auch empfehlen statt der Maske eher die Pin-Nummer zu
speichern und im Code "PORTB |= (1<< x.pin)"... zu nutzen.
Klaus H. schrieb:> Würde hier aber auch empfehlen statt der Maske eher die Pin-Nummer zu> speichern und im Code "PORTB |= (1<< x.pin)"... zu nutzen.
Ineffizient. Worst case hast du dann zur Laufzeit eine Schleife nur
dafür, dass du die Bitmaske ausrechnest.
Jörg W. schrieb:> Ineffizient. Worst case hast du dann zur Laufzeit eine Schleife nur> dafür, dass du die Bitmaske ausrechnest.
Warum?
Ineeffizient bedeutet unwirtschaftlich oder nicht leistungsfähig.
Aber das gilt im Sinne der Ressourcen nur wenn es von der
Geschwindigkeit darauf ankommt. Wenn ich beim Programmieren schnell zum
Ziel komme ist das durchaus "effizient"....
Wenn die Pinnummer statt der Maske gespeichert wird, kann man auch
direkt die asm Befehle (sbi, cbi ) nutzen. Schneller geht's nicht. Aber
das würde ich nur machen wenn es aus Performance Gründen Sinn macht.
Goldene Regel der Softwareprogrammierung:
Nie im Voraus manuell optimieren. Nur wenn eine messbare Verbesserung
daraus entsteht. Aktuelle Compiler können es normalerweise besser.
Jörg W. schrieb:> Bitte poste mal ein compilierbares Minimalbeispiel, sowohl den> Sourcecode als auch das bei dir compilierte ELF-File.
siehe anhang
Oliver S. schrieb:> Schön, und welche Version genau? Windows oder Linux?
Windows
avr-gcc (GCC) 5.3.0
Klaus H. schrieb:> Wenn die Pinnummer statt der Maske gespeichert wird, kann man auch> direkt die asm Befehle (sbi, cbi ) nutzen. Schneller geht's nicht.
Du denkst viel zu sehr in Assembler.
In C gibt es keine Notation für eine Bit-Nummer. Es gibt nur Bitmasken,
mit denen man logische Verknüpfungen machen kann. Wenn du die Bitmaske
gleich in der Initialisierung erzeugst, dann ist sie zumindest
garantiert für den Compiler sichtbar eine Konstante. Erzeugst du sie
erst später, weil du nur eine Bit-Nummer hast, dann hängt es vom Kontext
ab, ob der Compiler erkennen kann, dass sie konstant ist. Kann er es
nicht, läufst du Gefahr, dass dort eine Schleife aus Schiebebefehlen
produziert wird.
Die Umwandlung einer konstanten Bitmaske in CBI/SBI (oder SBIS/SBIC) ist
ohnehin Aufgabe des Compilers, die kannst du ihm nicht abnehmen, indem
du irgendwo nur Bit-Nummern abspeicherst.
Chandler B. schrieb:> siehe anhang
Der Code sieht korrekt aus. Deine struct steht als Einziges in .data:
1
Contents of section .data:
2
800100 02000400 08001000 2000 ........ .
.data wird auch ordnungsgemäß in den RAM geladen beim Start:
1
00000074 <__do_copy_data>:
2
74: 11 e0 ldi r17, 0x01 ; 1
3
76: a0 e0 ldi r26, 0x00 ; 0
4
78: b1 e0 ldi r27, 0x01 ; 1
5
7a: e6 ed ldi r30, 0xD6 ; 214
6
7c: f2 e0 ldi r31, 0x02 ; 2
7
7e: 02 c0 rjmp .+4 ; 0x84 <__do_copy_data+0x10>
8
80: 05 90 lpm r0, Z+
9
82: 0d 92 st X+, r0
10
84: aa 30 cpi r26, 0x0A ; 10
11
86: b1 07 cpc r27, r17
12
88: d9 f7 brne .-10 ; 0x80 <__do_copy_data+0xc>
Falls du nicht direkt das ELF programmierst sondern das Hex-File, auch
das sieht korrekt aus:
1
:0A02D60002000400080010002000E0
Die Abfrage der einzelnen Pin-Masken ist etwas umständlich, aber
korrekt:
In r30:r31 steht (anfangs) die Adresse 0x100 (aus r16:r17 übernommen).
Der entsprechende Wert wird zuerst gelesen und auf 0 / !0 verglichen, in
Abhhängig davon wird '0' oder '1' in r24 geladen und uart_characterPut()
gerufen. Danach wird PORTB eingelesen, der Wert erneut von 0x100
gelesen, mit dem Wert aus PORTB verODERt und auf PORTB geschrieben.
Jörg W. schrieb:> Du denkst viel zu sehr in Assembler.
Ups das wollte ich eigentlich nicht. Ich wollte ausdrücken dass man
nicht zu schnell optimieren sollte.
Ist schon eine Weile her, dass ich avr programmiert habe. Das meiste
wurde mit Bitmasken gemacht. Nur in speziellen Optimierungsfällen
(Geschwindigkeit einer Pin Ausgabe) hab ich darauf geachtet, dass
sbi/cbi genutzt wurde.
Hatte nicht mehr daran gedacht dass die Pin-Nummer im Opcode des Befehls
gespeichert ist. Der Compiler kann es dann nicht in allen Fällen
auflösen.
Asche auf mein Haupt.
Oliver S. schrieb:> Jörg W. schrieb:>> Der Code sieht korrekt aus.>> Ja, aber das hier dürfte dann der Quell allen Übels sein:
Uff, ja. :-}
2 KiB allein an Puffern für einen Controller, der insgesamt 2 KiB SRAM
hat.
Klaus H. schrieb:> Nur in speziellen Optimierungsfällen (Geschwindigkeit einer Pin> Ausgabe) hab ich darauf geachtet, dass sbi/cbi genutzt wurde.
Ist ja durchaus sinnvoll.
> Hatte nicht mehr daran gedacht dass die Pin-Nummer im Opcode des Befehls> gespeichert ist.
Ja, leider. Das ist wohl der Preis dafür, dass man diese Befehle in
einem Taktzyklus abarbeiten kann.