Forum: Mikrocontroller und Digitale Elektronik Bit im Register setzten ohne andere Bits zuverändern.


von Anfänger (Gast)


Lesenswert?

Hey Forum

Ich hab am nächstes Schuljahr Programmierung in c auf den Stundenplan an 
ucs und wollte mich schonmal etwas ein arbeiten. Und muss jetzt mal eine 
ganz doofe Frage stelle. Wie ändere ich Bits in einem Register ohne 
andere zu ändern also aus ein bit von 1 auf 0 oder von 0 auf 1 aber die 
andern sollen unverändert bleiben.

von Teo D. (teoderix)


Lesenswert?


von Anfänger (Gast)


Lesenswert?

Also hab ich das Richrig verstanden =| zum 1 setzten und &= zum 0 
setzen?

von Sebastian S. (amateur)


Lesenswert?

Einen mikroskopisch kleinen Teil.
Beschäftige Dich doch mal mit binären Zahlen, dann wird das Ganze gleich 
viel klarer.
Muss aber nicht sein.

von Anfänger (Gast)


Lesenswert?

Hab mir den Beitrag mal durch Gelesen und hab mal 2 Verständnis fragen

Wenn ich ein Port habe nennen wir ihn mal A mit den Wert 0b0000

Jetzt schreibe ich

A|= (1<<1) | (1<<4);

Ist das, dass selbe wie

A|= (1<<1);
A|= (1<<4);

Dann hat A den Wert 0b1001?

Wenn ich jetzt


A&= (1<<1) & (1<<4);

Setzte ist A=0b0000 ?

von Sebastian S. (amateur)


Lesenswert?

Wie bereits gesagt: Beschäftige Dich mit binären Zahlen.

A ist nur zufällig gleich 0

(1<<1) & (1<<4);

ist 0

A &= 0 ist Null.

Du hattest aber den Sonderwunsch: "Wie ändere ich Bits in einem Register 
ohne andere zu ändern"

Das stimmt aber nicht.

Ist A vorher 1101, so ist A &= 0 ebenfalls 0.

von icke (Gast)


Lesenswert?

Anfänger schrieb:
> Ist das, dass selbe wie
>
> A|= (1<<1);
> A|= (1<<4);
Ja


Anfänger schrieb:
> Dann hat A den Wert 0b1001?
Nein

(1<<1) | (1<<4)
=> 10010
du wolltest

(1<<0) | (1<<3)
Die bits sind nicht 1 und 4 sondern 0 und 3

Anfänger schrieb:
> Wenn ich jetzt
>
> A&= (1<<1) & (1<<4);
>
> Setzte ist A=0b0000 ?

Nein
Du must noch negieren
also
!((1<<1) & (1<<4))

MfG

von Sebastian S. (amateur)


Lesenswert?

Vorsicht bissiger Hund:
(1<<1) & (1<<4) ist Null

0000.0010    0000.0010
    &            |
0001.0000    0001.0000
    =            =
0000.0000    0001.0010


0000.0000    0001.0010
    !            !
1111.1111    1110.1101


0001.0010    0001.0010
    &            &
1111.1111    1110.1101
    =            =
0001.0010    0000.0000

oder so

TO hier kannst Du auch "sehen" warum etwas binäre Zahlen nicht schaden 
können.

A guats Nächtlie

: Bearbeitet durch User
von Frickelfritze (Gast)


Lesenswert?

Anfänger schrieb:
> A|= (1<<1);
> A|= (1<<4);
>
> Dann hat A den Wert 0b1001?

Nein.

weil 1<<1 den Wert  2 ergibt  ( b0010)
weil 1<<4 den Wert 16 ergibt  (b10000)

im 8-Bit Zahlenraum schiebt man sinnvollerweise 0 bis 7 mal.

von avr (Gast)


Lesenswert?

icke schrieb:
> !((1<<1) & (1<<4))

Sebastian S. schrieb:
> 0000.0000    0001.0010
>     !            !
> 1111.1111    1110.1101

Auweia. Bitte nicht die logische mit der bitweisen Negation verwecheln. 
Richtig wäre hier '~' statt '!'.

Und entweder
~((1<<1) | (1<<4))
oder
~(1<<1) & ~(1<<4)

von icke (Gast)


Lesenswert?

avr schrieb:
> Auweia. Bitte nicht die logische mit der bitweisen Negation verwecheln.
> Richtig wäre hier '~' statt '!'.

Autsch! Sorry und danke!
Meine Muttersprache ist Pascal.
Da Schreibt man einfach Not
und der Compiler ist schlau genug zu erkennen ob binär oder logisch.
Bei C habe ich immer wieder Probleme.

MfG

von Tanja (Gast)


Lesenswert?

wieder ein sehr schönes beispiel für die C hater Seite :-)
Die ich übrigens super finde, auch wenn man C lernen will!! da man 
versucht die Beispiele zu verstehen auch wenn manche Flach sind, so sind 
die für Anfänger supe, da man sieht ob man darauf reingefallen wäre..
Zeigt aber auch wieder die Vorteile von Pascal...!

von Lothar (Gast)


Lesenswert?

Anfänger schrieb:
> Wie ändere ich Bits in einem Register

Wieder nur für AVR gültige Antworten hier. Auf einem ARM mit 
Bit-adressierbaren Registern oder einem 8051 geht das auch in C direkt 
(und atomar) so:

#define LED P0_0
LED ^= 1;

bzw.

sbit LED = P0^0;
LED ^= 1;

von Anfänger (Gast)


Lesenswert?

Ok mit der 0 war ein Flüchtigkeitsfehler. Natürlich meinte ich 1<<0 und 
1<<3.

Zu der atomaren Sache mal ne frage. Wenn ich im Register A die Bits 0-7 
mit den Buchstaben a-h versehe mit #define

Muss ich beim zuweisen der Bits dann immer das Register mit angeben, 
oder weiß der Compiler automatisch das es sich bei b immer um das 1. bit 
aus Register A handelt?

Dann könnte man doch, wenn man zur ausgangsfrage zurückkehrt einfach 
schreiben

b=1 und A hat den Wert 0b00000010 = dez 2

Und dann bei b=0 hat A den Wert 0

von Anfänger (Gast)


Lesenswert?

also probier gerade mit den bit Operationen etwas rum jetzt steh ich 
gerade vor einem Problem und find nicht die richtige Operation.

ich hab in A= entwerder 0b001 oder 0b011 stehen

jetzt will ich sicher gehen das dort egal welcher zustand von den beiden 
gegeben ist in A= 0b011 steht aber ich find nicht die richtige 
Operation.

von Carl D. (jcw2)


Lesenswert?

Anfänger schrieb:
> Zu der atomaren Sache mal ne frage. Wenn ich im Register A die Bits 0-7
> mit den Buchstaben a-h versehe mit #define
>
> Muss ich beim zuweisen der Bits dann immer das Register mit angeben,
> oder weiß der Compiler automatisch das es sich bei b immer um das 1. bit
> aus Register A handelt?

Nein, sowas geht (in C) nur, wenn die Hardware es kann und der Compiler 
entsprechende Erweiterungen hat.
8051 z.B. hat P0 als einen 8-Bit-Port und P0_0..P0_7 als mit speziellen 
Befehlen direkt addressierbare Bits, die HW-seitig die Bits des P0 sind. 
Typische 8051-C-Compiler kennen den Datentyp __bit und erlauben mit "at 
0x80" die Adresse einer Variable festzulegen. Damit kann man dann deine 
Vorstellung verwirklichen.
 ARM hat dafür "Bitbanding", aber das ist für die Zeit nach den 
Grundlagen ;-)

Allgemein ist ein Port eine 8..32-Bit-Variable und die einzelnen Bits 
müssen durch AND und OR manipuliert werden.
HW-Ports sind übrigens (fast immer) "volatile" deklariert, was bedeutet, 
der Compiler muß jederzeit mit einer Änderung rechnen, die er nicht 
selbst verursacht hat. Wenn man dann 2 Statements benutzt um 2 Bits zu 
manipulieren,
1
 // ASM in handübersetzt AVR-like 
2
PORT |= (1<<2);   // in r24,PORT; ori r24,0x04; out PORT,r24
3
PORT |= (1<<4);   // in r24,PORT; ori r24,0x10; out PORT,r24
dann werden da garantiert 2 (Schreib)Zugriffe auf den Port draus.
Bei nur einen Statement
1
PORT |= ((1<<2) | (1<<4)); // in r24,PORT; ori r24,0x14; out PORT,r24
passieren dagegen beide Änderungen aus Port-Sicht gleichzeitig.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Carl D. schrieb:
> HW-Ports sind übrigens (fast immer) "volatile" deklariert, was bedeutet,
> der Compiler muß jederzeit mit einer Änderung rechnen, die er nicht
> selbst verursacht hat.

 Seit wann verursachen Compiler RT-Änderungen ?  ;-)

von Peter II (Gast)


Lesenswert?

Anfänger schrieb:
> ich hab in A= entwerder 0b001 oder 0b011 stehen
>
> jetzt will ich sicher gehen das dort egal welcher zustand von den beiden
> gegeben ist in A= 0b011 steht aber ich find nicht die richtige
> Operation.

einfach zuweisen, da muss man ja gar nicht rechnen

a = 0b011;

von Nop (Gast)


Lesenswert?

Anfänger schrieb:
> A|= (1<<1) | (1<<4);
>
> Ist das, dass selbe wie
>
> A|= (1<<1);
> A|= (1<<4);

Nein, das ist nicht immer dasselbe. Typischerweise wird sowas nämlich 
gebraucht, wenn A ein Register ist. Das wird dann als volatile 
deklariert. Variante 1 setzt beide Bits auf einmal, bei Variante 2 sind 
es zwei Schreibzugriffe, zwischen denen auch noch ein Interrupt 
passieren kann.

Ist A hingegen nicht das eigentliche Register, sondern eine normale, 
lokale Variable (Schattenregister), also nicht volatile, dann wid der 
Compiler den Code aus Variante 2 zu dem aus Variante 1 zusammenfassen.

Daß die Bitzählung bei 0 losgeht und nicht bei 1, wurde ja schon 
erwähnt.

von Lothar (Gast)


Lesenswert?

Carl D. schrieb:
> ARM hat dafür "Bitbanding", aber das ist für die Zeit nach den Grundlagen

Bitbanding ist nicht vollständig atomar, da ja intern doch wieder ein 
READ-MODIFY-WRITE ausgeführt wird. Aktuelle ARM haben tatsächlich wie 
ein 8051 Bit-adressierbare Peripherie-Register d.h. z.B. jedes Pin eines 
Ports wird in ein Byte im Speicher gemappt. Im C Include sieht das dann 
z.B. für LPC810 so aus:

#define PIN0BASE 0xA0000000
__IO_REG8(P0_0, PIN0BASE    , __READ_WRITE);
__IO_REG8(P0_1, PIN0BASE + 1, __READ_WRITE);
...

Somit geht dann in C:

#define LED P0_1
LED = 1;

Und daraus wird dann in ASM:

STRB TRUE, [PIN0BASE, #1]

Zudem haben aktuelle ARM auch noch eine AND-NOT-Logik zum atomaren 
Toggeln, das ist aber eher was für Inline ASM:

MOVS R0, #10B
STR  R0, [NOT0]

von vn nn (Gast)


Lesenswert?

icke schrieb:
> Da Schreibt man einfach Not
> und der Compiler ist schlau genug zu erkennen ob binär oder logisch.
> Bei C habe ich immer wieder Probleme.

Tanja schrieb:
> wieder ein sehr schönes beispiel für die C hater Seite :-)
> Die ich übrigens super finde, auch wenn man C lernen will!! da man
> versucht die Beispiele zu verstehen auch wenn manche Flach sind, so sind
> die für Anfänger supe, da man sieht ob man darauf reingefallen wäre..
> Zeigt aber auch wieder die Vorteile von Pascal...!
1
c = not(a and b)

Woher weiß man da jetzt, ob gemeint ist
1
c = !(a && b);
oder
1
c = ~(a && b);
oder
1
c = !(a & b);
oder
1
c = ~(a & b);

von Felix H. (felixhu)


Lesenswert?

Anfänger schrieb:
> Wie ändere ich Bits in einem Register ohne
> andere zu ändern also aus ein bit von 1 auf 0 oder von 0 auf 1 aber die
> andern sollen unverändert bleiben.

Bei log. Verknüpfungen gilt:
Mit UND schaltet man bits aus.
Mit ODER schaltet man bits ein.
MIT Exklusiv-ODER invertiert man bits.

von avr (Gast)


Lesenswert?

Felix H. schrieb:
> Bei log. Verknüpfungen gilt:

Nein, du meinst bitweise Verknüpfungen.
Bei logischen geht es um boolsche Logik. Bei bitweisen um Bits.

von HildeK (Gast)


Angehängte Dateien:

Lesenswert?

Für mich besonders elegant zur Bitmanipulation erschien mir die Variante 
mit sbit.h - ich glaube, sie war von Peter Dannegger und ist sicher mit 
der Suchfunktion zu finden.
Dann sieht der entsprechende Teil im Programm z.B. so aus:
1
#include "sbit.h"
2
3
#define EIN     1
4
#define AUS     0
5
#define HIGH    1
6
#define LOW     0
7
8
#define OUTPUT  1
9
#define INPUT   0
10
11
#define KEY      PORT_C6  
12
#define KEY_DIR  DDR_C6
13
#define KEY_IN   PIN_C6
14
15
#define FET      PORT_B2
16
#define FET_DIR  DDR_B2
17
18
int main ()
19
{
20
  KEY = HIGH;      // Pullup on
21
  KEY_DIR = INPUT;
22
  FET_DIR = OUTPUT;
23
  FET = AUS;
24
25
  if (KEY_IN==HIGH)
26
    {
27
      FET = EIN;
28
    }
29
  else
30
    {
31
      FET = AUS; 
32
    }
33
.
34
.
35
.
36
}
Das soll nur ein anschauliches Beispiel sein - hier ohne 
Tastaturentprellung und Endlosschleife ...
Man hat am Kopf eben etwas mehr 'defines', erhält dafür aber auch einen 
deutlich besser lesbaren Code.

Ich hoffe, ich trete ihm nicht zu nahe, wenn ich die 'sbit.h' hier mit 
anhänge.

von Nop (Gast)


Lesenswert?

icke schrieb:
> Meine Muttersprache ist Pascal.
> Da Schreibt man einfach Not
> und der Compiler ist schlau genug zu erkennen ob binär oder logisch.

Dürfte daran liegen, daß Boolean in Pascal immer schon ein ganz eigener 
Datentyp war und somit And, Not usw. angewandt auf Datentyp Bool, immer 
eine logische Operation sein muß. Hingegen dieselben Operationen, 
angewandt auf Integer, werden dann wohl binäre Operationen sein.

In C gab es bis C99 keinen Datentyp Boolean. Man konnte sich das mit 
Makros nachahmen, aber das ergab dann wieder eigene Fallstricke. Es gilt 
in C, daß jede ganzzahlige Variable logisch TRUE ist, die ungleich 0 
ist. 0 ist dann FALSE.

von Nop (Gast)


Lesenswert?

P.S.: Ich hab auch anno dunnemals mit Pascal angefangen und bin dann 
nach C-Land ausgewandert. Dort habe ich mich so gut eingelebt, daß ich 
Pascal verlernt habe.

von Felix H. (felixhu)


Lesenswert?

avr schrieb:
> Nein, du meinst bitweise Verknüpfungen.

Falsch.

von avr (Gast)


Lesenswert?

Felix H. schrieb:
> avr schrieb:
>> Nein, du meinst bitweise Verknüpfungen.
>
> Falsch.

Noch schlimmer. Es bleibt aber dabei, dass logische Verknüpfungen zur 
boolschen Algebra gehören und damit nichts mit Bits zu tun haben.

von Felix H. (felixhu)


Lesenswert?

inner noch falsch.

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.