Strukt initialisieren probleme

OP #7595679
Lesenswert?

Hallo, ich möchte den Status von verschiedenen Relais in einet Struktur speichern

1
typedef enum
2
{
3
    RELAIS_1,
4
    RELAIS_2,
5
    RELAIS_3,
6
    RELAIS_4,
7
    RELAIS_5,
8
    NOF_RELAIS
9
} Relais_te;
10

11
typedef struct
12
{
13
    const uint8_t pin;
14
    bool state_b;
15
} Relais_ts;
16

17

18
static Relais_ts relais_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?

1
static void relaisInit_v(void);
2
static void relaisInit_v(void)
3
{
4
    char c;
5
    for (uint8_t relais_e=0; relais_e<NOF_RELAIS; relais_e++)
6
    {
7
        Relais_ts* relais_ps;
8
        relais_ps = &relais_as[RELAIS_5];
9
        c = relais_e + '0';
10
        uart_characterPut(c);
11
        c = relais_ps->pin + '0';
12
        uart_characterPut(c);
13

14
        UNSETPIN(PORTB, relais_ps->pin);
15
        relais_ps->state_b = false;
16
    }
17
}

hier bekomme dann als ausgabe 0010203040

OP #7595762
Lesenswert?

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.

1
... ...
2
        if (relais_ps->pin == 0)
3
        {
4
            c = 0 + '0';
5
        }
6
        else
7
        {
8
            c = 1 + '0';
9
        }
10
        //c = relais_ps->pin + '0';
11
        uart_characterPut(c);
OP #7597210
Lesenswert?

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.

#7598466
Lesenswert?

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

#7598708
Lesenswert?

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.

#7598990
Lesenswert?

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.

Beitrag #7599031 wurde von einem Moderator gelöscht.
OP #7599032
Lesenswert?

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

Angehängte Dateien:
Moderator Persönliche Seite #7599086
Lesenswert?

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:

1
 1b0:   00 e0           ldi     r16, 0x00       ; 0
2
 1b2:   11 e0           ldi     r17, 0x01       ; 1
3
 1b4:   80 e3           ldi     r24, 0x30       ; 48
4
 1b6:   f8 2e           mov     r15, r24
5
 1b8:   8f 2d           mov     r24, r15
6
 1ba:   0e 94 53 00     call    0xa6    ; 0xa6 <uart_characterPut>
7
 1be:   f8 01           movw    r30, r16
8
 1c0:   80 81           ld      r24, Z
9
 1c2:   88 23           and     r24, r24
10
 1c4:   11 f0           breq    .+4             ; 0x1ca <main+0x4e>
11
 1c6:   81 e3           ldi     r24, 0x31       ; 49
12
 1c8:   01 c0           rjmp    .+2             ; 0x1cc <main+0x50>
13
 1ca:   80 e3           ldi     r24, 0x30       ; 48
14
 1cc:   0e 94 53 00     call    0xa6    ; 0xa6 <uart_characterPut>
15
 1d0:   95 b1           in      r25, 0x05       ; 5
16
 1d2:   f8 01           movw    r30, r16
17
 1d4:   80 81           ld      r24, Z
18
 1d6:   89 2b           or      r24, r25
19
 1d8:   85 b9           out     0x05, r24       ; 5
20

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.

#7600408
Lesenswert?

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.

Moderator Persönliche Seite #7600464
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren