Moin!
Ich versuche gerade das Signal einer Fernbedienung auszulesen.
Funktioniert auch bis jetzt ganz gut. Bis auf eine Sache.
Ich habe mir eine Variable (volatile int32_t data) angelegt, in der ich
die 27 eingelesenen bits spiechern will.
Das wollte ich nach folgendem Schema tun:
1
if(bit==1)
2
{
3
data|=(1<<(26-count_bits));
4
5
}
6
else
7
{
8
data&=~(1<<(26-count_bits));
9
10
}
11
count_bits++;
Nach langem rätseln, habe ich festgestellt, das alles über (1<<15) nicht
funktioniert, so als wären die zwei höheren Bytes wo anders im Speicher
abgelegt, oder so.
Hat von euch schon mal jemand so ein Problem gehabt?
Ich bin für jeden Tipp dankbar!!!
Grüße Jan
Jan S. schrieb:> Nach langem rätseln, habe ich festgestellt, das alles über (1<<15) nicht> funktioniert, so als wären die zwei höheren Bytes wo anders im Speicher> abgelegt, oder so.> Hat von euch schon mal jemand so ein Problem gehabt?> Ich bin für jeden Tipp dankbar!!!
weil der compiler alles mit INT (16bit) rechnet.
data |= ((uint32_t)1<<(26-count_bits));
sollte das Problem beheben.
Der Compiler nimmt nicht immer den grøsste Variablentyp, dass musst du
im durch einen cast mitteilen. Ist ein fieser Stolperstein, ich hoffe
damit ist dein Problem geløst.
Peter II schrieb:> data |= ((uint32_t)1<<(26-count_bits));
Alternativ geht auch:
1
data|=(1L<<(26-count_bits));
Bei der Gelegenheit:
Dein Codefragment scheint aus einer Schleife zu stammen. Bei jedem
Durchlauf muss die Bitmaske (1L << (26 -count_bits)) neu berechnet
werden.
Die Shiftoperation ist beim AVR eine sehr aufwendige Sache und kostet
Zeit und Codegröße. Schau mal:
1
#include<stdint.h>
2
#include<avr/io.h>
3
4
// Datenquelle, durch volatile wird in der Simulation der
5
// Lesezugriff erzwungen
6
volatileuint8_tbit;
7
8
// im Original auch als volatile deklariert
9
volatileint32_tdata;
10
11
// Orginaler Aufbau der Schleife
12
// Das zuerst übertragene Bit steht abschließend im LSB von data.
13
14
voidshift1(void)
15
{
16
uint8_tcount_bits;
17
18
count_bits=0;
19
while(count_bits<=26)
20
{
21
if(bit==1)
22
{
23
data|=(1L<<(26-count_bits));
24
}
25
else
26
{
27
data&=~(1L<<(26-count_bits));
28
}
29
count_bits++;
30
}
31
}
ergibt diesen Assemblercode:
1
void shift1(void)
2
{
3
ce: cf 92 push r12
4
d0: df 92 push r13
5
d2: ef 92 push r14
6
d4: ff 92 push r15
7
d6: 2a e1 ldi r18, 0x1A ; 26
8
d8: 30 e0 ldi r19, 0x00 ; 0
9
{
10
data |= (1L<<(26-count_bits));
11
}
12
else
13
{
14
data &= ~(1L<<(26-count_bits));
15
da: cc 24 eor r12, r12
16
dc: dd 24 eor r13, r13
17
de: 76 01 movw r14, r12
18
e0: c3 94 inc r12
19
uint8_t count_bits;
20
21
count_bits = 0;
22
while(count_bits <= 26)
23
{
24
if (bit == 1)
25
e2: 80 91 00 01 lds r24, 0x0100
26
e6: 81 30 cpi r24, 0x01 ; 1
27
e8: f9 f4 brne .+62 ; 0x128 <shift1+0x5a>
28
{
29
data |= (1L<<(26-count_bits));
30
ea: 80 91 01 01 lds r24, 0x0101
31
ee: 90 91 02 01 lds r25, 0x0102
32
f2: a0 91 03 01 lds r26, 0x0103
33
f6: b0 91 04 01 lds r27, 0x0104
34
fa: b7 01 movw r22, r14
35
fc: a6 01 movw r20, r12
36
fe: 02 2e mov r0, r18
37
100: 04 c0 rjmp .+8 ; 0x10a <shift1+0x3c>
38
102: 44 0f add r20, r20
39
104: 55 1f adc r21, r21
40
106: 66 1f adc r22, r22
41
108: 77 1f adc r23, r23
42
10a: 0a 94 dec r0
43
10c: d2 f7 brpl .-12 ; 0x102 <shift1+0x34>
44
10e: 84 2b or r24, r20
45
110: 95 2b or r25, r21
46
112: a6 2b or r26, r22
47
114: b7 2b or r27, r23
48
116: 80 93 01 01 sts 0x0101, r24
49
11a: 90 93 02 01 sts 0x0102, r25
50
11e: a0 93 03 01 sts 0x0103, r26
51
122: b0 93 04 01 sts 0x0104, r27
52
126: 22 c0 rjmp .+68 ; 0x16c <shift1+0x9e>
53
}
54
else
55
{
56
data &= ~(1L<<(26-count_bits));
57
128: 80 91 01 01 lds r24, 0x0101
58
12c: 90 91 02 01 lds r25, 0x0102
59
130: a0 91 03 01 lds r26, 0x0103
60
134: b0 91 04 01 lds r27, 0x0104
61
138: b7 01 movw r22, r14
62
13a: a6 01 movw r20, r12
63
13c: 02 2e mov r0, r18
64
13e: 04 c0 rjmp .+8 ; 0x148 <shift1+0x7a>
65
140: 44 0f add r20, r20
66
142: 55 1f adc r21, r21
67
144: 66 1f adc r22, r22
68
146: 77 1f adc r23, r23
69
148: 0a 94 dec r0
70
14a: d2 f7 brpl .-12 ; 0x140 <shift1+0x72>
71
14c: 40 95 com r20
72
14e: 50 95 com r21
73
150: 60 95 com r22
74
152: 70 95 com r23
75
154: 84 23 and r24, r20
76
156: 95 23 and r25, r21
77
158: a6 23 and r26, r22
78
15a: b7 23 and r27, r23
79
15c: 80 93 01 01 sts 0x0101, r24
80
160: 90 93 02 01 sts 0x0102, r25
81
164: a0 93 03 01 sts 0x0103, r26
82
168: b0 93 04 01 sts 0x0104, r27
83
16c: 21 50 subi r18, 0x01 ; 1
84
16e: 30 40 sbci r19, 0x00 ; 0
85
void shift1(void)
86
{
87
uint8_t count_bits;
88
89
count_bits = 0;
90
while(count_bits <= 26)
91
170: 8f ef ldi r24, 0xFF ; 255
92
172: 2f 3f cpi r18, 0xFF ; 255
93
174: 38 07 cpc r19, r24
94
176: 09 f0 breq .+2 ; 0x17a <shift1+0xac>
95
178: b4 cf rjmp .-152 ; 0xe2 <shift1+0x14>
96
{
97
data &= ~(1L<<(26-count_bits));
98
}
99
count_bits++;
100
}
101
}
102
17a: ff 90 pop r15
103
17c: ef 90 pop r14
104
17e: df 90 pop r13
105
180: cf 90 pop r12
106
182: 08 95 ret
Du kannst den variablen Shift aber ohne größere Probleme vermeiden. Der
nachfolgende Code sollte funktionsgleich sein. (Ist ungetestet, also
besser mal im Simulator durchspielen!)
Das jeweils "neue" Bit wird "links" (auf Bitposition 26) eingetragen und
ein einziger 32Bit-Shift (nach rechts) gemacht. Damit steht am Ende
das zuerst übertragene Bit auch im LSB von data.
1
// Optimierter Algorithmus
2
// Die variable Shift-Operation ist durch eine zur Übersetzungszeit
3
// feststehende Konstante ersetzt
4
// Das zuerst übertragene Bit steht weiterhin im LSB von data.
5
6
voidshift2(void)
7
{
8
uint8_tcount_bits;
9
10
count_bits=0;
11
while(count_bits<=26)
12
{
13
data=data>>1;
14
if(bit==1)
15
{
16
data|=(1L<<26);
17
}
18
else
19
{
20
data&=~(1L<<26);
21
}
22
count_bits++;
23
}
24
}
ergibt
1
00000184 <shift2>:
2
// Die variable Shift-Operation ist durch eine zur Übersetzungszeit feststehende Konstante ersetzt
3
// Das zuerst übertragene Bit steht weiterhin im LSB von data.
4
5
6
void shift2(void)
7
{
8
184: 2b e1 ldi r18, 0x1B ; 27
9
uint8_t count_bits;
10
11
count_bits = 0;
12
while(count_bits <= 26)
13
{
14
data = data >> 1;
15
186: 80 91 01 01 lds r24, 0x0101
16
18a: 90 91 02 01 lds r25, 0x0102
17
18e: a0 91 03 01 lds r26, 0x0103
18
192: b0 91 04 01 lds r27, 0x0104
19
196: b5 95 asr r27
20
198: a7 95 ror r26
21
19a: 97 95 ror r25
22
19c: 87 95 ror r24
23
19e: 80 93 01 01 sts 0x0101, r24
24
1a2: 90 93 02 01 sts 0x0102, r25
25
1a6: a0 93 03 01 sts 0x0103, r26
26
1aa: b0 93 04 01 sts 0x0104, r27
27
if (bit == 1)
28
1ae: 80 91 00 01 lds r24, 0x0100
29
1b2: 81 30 cpi r24, 0x01 ; 1
30
1b4: 91 f4 brne .+36 ; 0x1da <shift2+0x56>
31
{
32
data |= (1L << 26);
33
1b6: 80 91 01 01 lds r24, 0x0101
34
1ba: 90 91 02 01 lds r25, 0x0102
35
1be: a0 91 03 01 lds r26, 0x0103
36
1c2: b0 91 04 01 lds r27, 0x0104
37
1c6: b4 60 ori r27, 0x04 ; 4
38
1c8: 80 93 01 01 sts 0x0101, r24
39
1cc: 90 93 02 01 sts 0x0102, r25
40
1d0: a0 93 03 01 sts 0x0103, r26
41
1d4: b0 93 04 01 sts 0x0104, r27
42
1d8: 11 c0 rjmp .+34 ; 0x1fc <shift2+0x78>
43
}
44
else
45
{
46
data &= ~(1L<<26);
47
1da: 80 91 01 01 lds r24, 0x0101
48
1de: 90 91 02 01 lds r25, 0x0102
49
1e2: a0 91 03 01 lds r26, 0x0103
50
1e6: b0 91 04 01 lds r27, 0x0104
51
1ea: bb 7f andi r27, 0xFB ; 251
52
1ec: 80 93 01 01 sts 0x0101, r24
53
1f0: 90 93 02 01 sts 0x0102, r25
54
1f4: a0 93 03 01 sts 0x0103, r26
55
1f8: b0 93 04 01 sts 0x0104, r27
56
1fc: 21 50 subi r18, 0x01 ; 1
57
void shift2(void)
58
{
59
uint8_t count_bits;
60
61
count_bits = 0;
62
while(count_bits <= 26)
63
1fe: 19 f6 brne .-122 ; 0x186 <shift2+0x2>
64
{
65
data &= ~(1L<<26);
66
}
67
count_bits++;
68
}
69
}
70
200: 08 95 ret
In der Codegröße (126 Bytes im Vergleich zu 182 Bytes vorher) ist die
Funktion bereits kleiner.
Der Unterschied in der Ausführungszeit ist noch dramatischer: Dein
Original macht in jedem Durchlauf (26 - bit_count) 32Bit-Shifts, das
sind insgesamt 351. Der veränderte Algrithmus kommt mit einem
32Bit-Shift pro Durchlauf aus (also 27).
Grüße
Stefan
PS: Als Optimierung war -O1 eingestellt. Mit -Os würde es zwar noch
etwas kleiner, das geschilderte Problem bleibt aber.
Jan S. schrieb:> Mit casten klappts. Man. Sowas muss man sich merken!!!> Danke für die schnelle Hilfe und einen schönen Tag noch!
Du kannst auch Warnungen lesen und beachten. Der Compiler meckert
nämlich, wenn man die 1 aus dem Bereich eines int schiebt.
Es ist einfacher Warnungen zu beheben als Fehler zur Laufzeit. Aber
jeder hat eben sein Steckenpferd ;-)
Auf einem 32 bitter würde das übrigens mit den meisten Compilern so
gehen. Ohne Casting wird eben immer vom Standart Datentyp int
ausgegangen und der ist beim Avr nunnmal 16 Bit.
Ein Integer ist in der Regel so groß wie die Allzweckregister der CPU,
mindestens aber 16 Bit.
hmm... schrieb:> Ein Integer ist in der Regel so groß wie die Allzweckregister der CPU,> mindestens aber 16 Bit.
Aber auch auf 64-Bit-Plattformen selten 64 Bit.
Das war ja auch nur der Vollständigkeit halber, weil mein Vorredner über
die Größe von int auch auf anderen Plattformen als 8-Bitter gespriochen,
aber dieses Detail nicht erwähnt hat.
Abgesehen davon habe ich damit zum Thema mehr beigetragen als du!