Hallo, Suche schon seit langem ein sbit-Makro für AVR und bin jetzt auf dieser Seite fündig geworden. Besser gesagt hab ich zwei sbit.h gefunden. Meine Frage welche von denen kann ich für meinen AVR ATmega2560 verwenden? Wie benutze ich dieses Makro jetzt? Bsp.(1 ausgeben an PortB Pin4): #include <avr/io.h> #include <C:pfad zur .h-datei\sbit.h> int main(void) { SBIT(DDRB,4) = 1; while(1) { SBIT(PORTB,4) = 1; } }
Christian Gruber schrieb: > Meine Frage welche von denen kann ich für meinen AVR ATmega2560 > verwenden? > Wie benutze ich dieses Makro jetzt? Ich würde das kurze makro verwenden. Es sieht für mich universell Nutzbar aus. Einziges Manko: Das Makro verwendet immer 8 PINs. Wenn Du noch einen Port im Controller hast der nur 4,6 oder 7 Pins hat, darfst Du die darauf folgenden halt nie ansprechen. Christian Gruber schrieb: > Wie benutze ich dieses Makro jetzt? Die Frage hast Du dir selbst beantwortet. :-)
1 | SBIT(PORTB,4) = 1; |
Das SBIT-Makro aus sbit_kurz.txt ist für sich imo witzlos. Stattdessen würde ich lieber nehmen:
1 | #define set_bit(var, bit) ((var) |= (1ULL << (bit)))
|
2 | #define clear_bit(var, bit) ((var) &= ~(1ULL << (bit)))
|
Verwendung:
1 | set_bit(DDRB, 4); |
2 | clear_bit(PORTB, 4); |
Die Variante mit dem Bitfeld ist erst zusammen mit den zusätzlichen Defines aus sbit_lang.txt interessant. Dann kannst Du nämlich schreiben:
1 | DDR_B4 = 1; |
2 | PORT_B4 = 0; |
Allerdings musst Du für jedes Bit in jedem Register ein entsprechendes Define haben. In sbit_lang.txt ist es ja nur für die I/O-Ports und nicht für die ganzen anderen Register definiert. Imo lohnt es sich nicht, das selber alles einzupflegen. Das wäre eher Aufgabe des Toolchain-Anbieters gewesen.
Hallo, auch wenn der letzte Beitrag zu diesem Thread schon 4 Monate alt ist, grabe ich ihn hier nochmals aus. Auch ich verwende schon seit Jahren (besser Jahrzehnten) die Peter'sche sbit.h include Datei, um gezielt auf IO Ports zuzugreifen. Also speziell mit:
1 | struct BitsOfByte |
2 | {
|
3 | uint8_t b0:1; |
4 | uint8_t b1:1; |
5 | uint8_t b2:1; |
6 | uint8_t b3:1; |
7 | uint8_t b4:1; |
8 | uint8_t b5:1; |
9 | uint8_t b6:1; |
10 | uint8_t b7:1; |
11 | } __attribute__((__packed__)); |
12 | #define SBIT(port,pin) ((*(volatile struct BitsOfByte*)&port).b##pin)
|
Ich habe dann aber mal in den daraus resultierenden assembler code geschaut, der doch sehr kryptisch und lang ist, und dann auch noch mit movw instructions arbeitet, als zwei Bytes. Hier ein Beispiel: --> Hier der C Code: ##############################################
1 | #define MY_PORT SBIT (PORTC, 6)
|
2 | uint8_t i; |
3 | i=1; |
4 | MY_PORT = i; |
############################################## --> Hier der resultierende Assembler Code: ##############################################
1 | i=1; |
2 | 242c: 81 e0 ldi r24, 0x01 ; 1 |
3 | 242e: 8a 83 std Y+2, r24 ; 0x02 |
4 | MY_PORT = i; |
5 | 2430: 85 e3 ldi r24, 0x35 ; 53 |
6 | 2432: 90 e0 ldi r25, 0x00 ; 0 |
7 | 2434: 2a 81 ldd r18, Y+2 ; 0x02 |
8 | 2436: 21 70 andi r18, 0x01 ; 1 |
9 | 2438: 21 70 andi r18, 0x01 ; 1 |
10 | 243a: 22 95 swap r18 |
11 | 243c: 22 0f add r18, r18 |
12 | 243e: 22 0f add r18, r18 |
13 | 2440: 20 7c andi r18, 0xC0 ; 192 |
14 | 2442: fc 01 movw r30, r24 |
15 | 2444: 30 81 ld r19, Z |
16 | 2446: 3f 7b andi r19, 0xBF ; 191 |
17 | 2448: 23 2b or r18, r19 |
18 | 244a: fc 01 movw r30, r24 |
19 | 244c: 20 83 st Z, r18 |
############################################## Bei sehr zeitkritischen Anwendungen sieht das nicht sehr optimiert aus, denn es gibt doch die beiden AVR instructions: SBI P,b Set Bit in I/O Register CBI P,b Clear Bit in I/O Register Gibt es keine elegantere, bzw. einfacherer Methode in C, diesen beiden instructions in den assembler code einzubauen ? Vielleicht kann Peter hierzu ein paar Kommentare beisteuern. Gruß Manni
Manfred L. schrieb: > SBI P,b Set Bit in I/O Register > CBI P,b Clear Bit in I/O Register Hallo was du referierst bezieht sich auf und nur auf Konstanten. Dein Code zeigt aber einen Variablenzugriff, das da passiert ist dann klar. Du könntest auch auf inline C Code zurückgreifen. inline void portc6(uint8_t value) { if (value) { // != 0 PORTC &= (1<<6); } else { // == 0 PORTC |= ~(1<<6); } }
Manfred L. schrieb: > auch wenn der letzte Beitrag zu diesem Thread schon 4 Monate alt ist, > grabe ich ihn hier nochmals aus. 4 Monate? Fast 7 Jahre! Manfred L. schrieb: > Bei sehr zeitkritischen Anwendungen sieht das nicht sehr optimiert aus Das kann es auch nicht, wenn du dem Compiler nicht sagst, dass du optimierten Code wünschst. Mit -Os wird
1 | MY_PORT = i; |
von GCC 9.2.0 übersetzt in
1 | sbrc r24,0 |
2 | sbi 0x15,6 |
3 | sbrs r24,0 |
4 | cbi 0x15,6 |
Das sind gerade mal 5 Taktzyklen. Besser geht es nicht, wenn der Wert von i zur Compilezeit nicht bekannt ist.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.