Forum: Mikrocontroller und Digitale Elektronik sbit bei AVR


von Hannes K. (chgruber)


Angehängte Dateien:

Lesenswert?

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;
  }
}

von Florian T. (florian_t)


Lesenswert?

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;

von Fabian O. (xfr)


Lesenswert?

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.

von Manfred L. (manni)


Lesenswert?

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

von Karl M. (Gast)


Lesenswert?

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);
  }
}

von Yalu X. (yalu) (Moderator)


Lesenswert?

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
Noch kein Account? Hier anmelden.