Hallo zusammen,
in einer Funktion bräuchte ich die Möglichkeit, Pin-Nummern dynamisch zu
adressieren. Also anstatt z.B.: "PORTB |= (1<<PB1)" -> "PORTB |=
(1<<PB{variable})". Ich habe versucht dieses "Problem" zu googlen aber
leider findet sich einfach nichts...
Vielen Dank jetzt schon für eure Hilfe!
Der Vorgang ist dann vermutlich auch nicht atomar, da der Compiler
daraus wohl kein sbi bzw. cbi machen kann.
Also aufpassen wenn du in Interrupts Operationen auf dem selben PORT
durchführst.
Das könnte man jedoch durch eine Funktion lösen:
chris schrieb:> Der Vorgang ist dann vermutlich auch nicht atomar, da der Compiler> daraus wohl kein sbi bzw. cbi machen kann.> Also aufpassen wenn du in Interrupts Operationen auf dem selben PORT> durchführst.>> Das könnte man jedoch durch eine Funktion lösen:
Ach, durch die Funktion wird die Operation atomar?
Frank M. schrieb:> Ach, durch die Funktion wird die Operation atomar?
Der eigentliche Zugriff auf das PORT-Register sollte m.M. nach dadurch
atomar sein, da in der Funktion dann lauter sbi-Befehle stehen.
Benutzt man aber
1
PORTB|=(1<<x);
dann wird das wohl ein read-modify-write.
Und zwischen modify und write kann dann ein Interrupt zuschlagen und den
PORT modifizieren, so dass es Probleme gibt. (Das write macht die vom
Interrupt vorgenommene Veränderung sofort wieder rückgängig, indem es
den gesamten PORT beschreibt.)
Allerdings gebe ich zu, dass ich gerade keine Zeit habe, meine Theorie
anhand des asm-Codes zu überprüfen. Möglicherweise irre ich mich also.
Vielleicht schafft der Compiler es ja auch, aus einer variablen
Pinnummer einen sbi-Befehl zu machen.
So, ich habe es mal ausprobiert (gcc 4.7.2, Optimierung -Os)
Quellcode siehe Anhang.
Mit der oben von mir geposteten Funktion wird wie erwartet für jeden Pin
ein sbi erzeugt:
1
void portb_set_pin(uint8_t pin)
2
{
3
switch (pin)
4
66: e8 2f mov r30, r24
5
68: f0 e0 ldi r31, 0x00 ; 0
6
6a: e8 30 cpi r30, 0x08 ; 8
7
6c: f1 05 cpc r31, r1
8
6e: 90 f4 brcc .+36 ; 0x94 <portb_set_pin+0x2e>
9
70: e6 5e subi r30, 0xE6 ; 230
10
72: ff 4f sbci r31, 0xFF ; 255
11
74: 09 94 ijmp
12
{
13
case 0:
14
PORTB |= (1<<0);
15
76: 28 9a sbi 0x05, 0 ; 5
16
break;
17
78: 08 95 ret
18
case 1:
19
PORTB |= (1<<1);
20
7a: 29 9a sbi 0x05, 1 ; 5
21
break;
22
7c: 08 95 ret
23
case 2:
24
PORTB |= (1<<2);
25
7e: 2a 9a sbi 0x05, 2 ; 5
26
break;
27
80: 08 95 ret
28
case 3:
29
PORTB |= (1<<3);
30
82: 2b 9a sbi 0x05, 3 ; 5
31
break;
32
84: 08 95 ret
33
case 4:
34
PORTB |= (1<<4);
35
86: 2c 9a sbi 0x05, 4 ; 5
36
break;
37
88: 08 95 ret
38
case 5:
39
PORTB |= (1<<5);
40
8a: 2d 9a sbi 0x05, 5 ; 5
41
break;
42
8c: 08 95 ret
43
case 6:
44
PORTB |= (1<<6);
45
8e: 2e 9a sbi 0x05, 6 ; 5
46
break;
47
90: 08 95 ret
48
case 7:
49
PORTB |= (1<<7);
50
92: 2f 9a sbi 0x05, 7 ; 5
51
94: 08 95 ret
Mit dem variablen Shift wird dagegen wild durch die Gegend gerechnet:
1
PORTB |= (1<<pin_nr);
2
6c: 45 b1 in r20, 0x05 ; 5
3
6e: 9c 01 movw r18, r24
4
70: 00 90 00 01 lds r0, 0x0100
5
74: 02 c0 rjmp .+4 ; 0x7a <main+0x24>
6
76: 22 0f add r18, r18
7
78: 33 1f adc r19, r19
8
7a: 0a 94 dec r0
9
7c: e2 f7 brpl .-8 ; 0x76 <main+0x20>
10
7e: 24 2b or r18, r20
11
80: 25 b9 out 0x05, r18 ; 5
12
82: eb cf rjmp .-42 ; 0x5a <main+0x4>
Flashverbrauch ist 202 byte (Funktion) vs. 174 byte (variabler Shift)
Ohne mich mit Assembler genauer auszukennen, vermute ich dass die
Funktionsvariante wohl schneller ist als der variable Shift.
Und eben zusätzlich atomar.
lg
Chris
Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.
Wichtige Regeln - erst lesen, dann posten!
Groß- und Kleinschreibung verwenden
Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang