Wie kann ich meinen Compiler anweisen, 8-Bit-Bytes anstelle von 16-Bit-Ganzzahlen zu verwenden?

Ich habe den folgenden Code in meinem Mikrocontroller-Programm:

int analogValue = ADCH;        // ADC Data Register

//
// Simple analog comparator. 
// If analogValue lower than threshold then toggle output high,
// Otherwise toggle it low.
//
if ( analogValue > 128 ) {
    PORTB = 0;                 // Port B Data Register
} else {
    PORTB = _BS( outputPin );  // Port B Data Register
}

Woher:

  • ADCH ist das Register, das den Wert vom ADC enthält
  • PORTB ist ein digitaler Ausgangsport, der eine LED umschaltet

Als ich mir den resultierenden Assembler-Code ansah, bemerkte ich, dass er einen 16-Bit-Vergleich durchführt (Zeile 40-44), wo genau genommen nur 8 Bit ausreichend gewesen wären:

40:   90 e0           ldi     r25, 0x00       ; 0
42:   81 38           cpi     r24, 0x81       ; 129
44:   91 05           cpc     r25, r1
46:   14 f0           brlt    .+4             ; 0x4c <__SREG__+0xd>
48:   18 ba           out     0x18, r1        ; PORTB
4a:   f5 cf           rjmp    .-22            ; 0x36 <__CCP__+0x2>
4c:   28 bb           out     0x18, r18       ; PORTB
4e:   f3 cf           rjmp    .-26            ; 0x36 <__CCP__+0x2>

Mir ist klar, dass ich analogValue als int deklariert habe , was auf AVR tatsächlich 16 Bit ist, aber ...

Wie kann ich den Compiler anweisen, den 8-Bit-Vergleich zu verwenden? Die Arduino IDE erlaubt mir die Verwendung von byte , avr-gcc jedoch standardmäßig nicht.

Auf dieser Seite finden Sie das vollständige Programm und den daraus resultierenden zerlegten Code.

EDIT1:

Ändern intin charändert den Assemblycode in:

14:   11 24           eor     r1, r1          ; r1 = 0
3e:   18 ba           out     0x18, r1        ; PORTB

Den Test grundsätzlich komplett überspringen.

EDIT2: (Thnx: Wouter van Ooijen)

Ändern intin unsigned charändert den Assemblycode in:

3c:   85 b1           in      r24, 0x05       ; ADCH
3e:   ...
40:   87 fd           sbrc    r24, 7          ; compare < 128 (well optimized)
42:   02 c0           rjmp    .+4             ; 0x48 <__SREG__+0x9>
44:   18 ba           out     0x18, r1        ; 24
46:   f7 cf           rjmp    .-18            ; 0x36 <__CCP__+0x2>
48:   98 bb           out     0x18, r25       ; 24
4a:   f5 cf           rjmp    .-22            ; 0x36 <__CCP__+0x2>

Antworten (2)

Ich denke tatsächlich, dass eine bessere Praxis, die diese architektonische Mehrdeutigkeit vermeidet, darin besteht, <stdint.h>deklarative Typen einzuschließen und dann zu verwenden, wie:

  • uint8_t für vorzeichenlose 8-Bit-Ganzzahlen
  • int8_t für vorzeichenbehaftete 8-Bit-Ganzzahlen
  • uint16_t für vorzeichenlose 16-Bit-Ganzzahlen
  • uint32_t für vorzeichenlose 32-Bit-Ganzzahlen

usw...

Dies scheint zu funktionieren (überprüfte den Assembler-Code erneut). Kannte diese Typen überhaupt nicht. Wo kommt die _ther?
_t gibt herkömmlicherweise an, dass es sich um einen Typ handelt
Dies sind Standard-Ganzzahltypen mit fester Breite, die in C99 eingeführt wurden. Möglicherweise müssen Sie <stdint.h> #einschließen. en.wikipedia.org/wiki/C_data_types#Fixed_width_integer_types
+1. Ich verwende dies, um Unklarheiten zu beseitigen und für ultimative Portabilität
Eine Gefahr bei der Verwendung solcher Typen besteht darin, dass Ausdruckstypen auf überraschende Weise oft nicht portierbar sind. Auf einem System mit int16 Bit beispielsweise verhalten sich uint32_t flag;die Anweisungen flag &= ~0x00004000;und flag &= ~0x00010000;wie erwartet, aber flag &= ~0x00008000;etwas anders.

Die mehr oder weniger Standarddefinition eines Bytes in C ist „unsigned char“.

Ah, das unsignedTeil hat den Job gemacht, charkompiliert von alleine ohne Warnungen.
Ein berühmter C-Fehler ist, dass der Compiler „char“ entweder als „signed char“ oder „unsiged char“ interpretieren kann, sodass der effektive Bereich von einfachem „char“, auf den Sie sich verlassen können, 0..127 beträgt. Verwenden Sie einfaches 'char' nur für 7-Bit-ASCII, niemals für etwas anderes.