Forum: Mikrocontroller und Digitale Elektronik Makro für: PORTD |= (1<<PD1)


von Philipp L. (viech)


Lesenswert?

Hallo,

ist es möglich ein Makro zum setzen einzelner Ausgänge zu schreiben?

So funktioniert es leider noch nicht :-)

#define Servo1_ein (PORTD |= (1<<PD0));
#define Servo1_aus (PORTD |= (0<<PD0));


int main(void)
{
  DDRD |= (1<<PD0);
        while (1)
    {

    Servo1_ein;
    _delay_ms(500);
    Servo1_aus;
    _delay_ms(500);

    }
}

: Verschoben durch User
von MWS (Gast)


Lesenswert?

Zu viele Semikolons.

von Philipp L. (viech)


Lesenswert?

Geht auch so nicht..

#define Servo1_ein (PORTD |= (1<<PD0))

von Bimbo. (Gast)


Lesenswert?

C-Buch lesen:
1
#define Servo1_aus (PORTD &= ~(0<<PD0));

von Bimbo. (Gast)


Lesenswert?

Ich meine natürlich:
1
#define Servo1_aus (PORTD &= ~(1<<PD0));

von Philipp L. (viech)


Lesenswert?

Bimbo. schrieb:
> Ich meine natürlich:
>
1
> #define Servo1_aus (PORTD &= ~(1<<PD0));
2
>

ja, bin grad dabei ein C-Buch zu lesen.

ich verstehe jedoch nicht wirklich, warum ich das Bit negieren soll 
anstatt eine 0 hineinzuschreiben (~ steht aber auch so im Buch).
Das mit der 0 wirkt für mich übersichtlicher, gibt es einen Grund dafür?

Dies funktionier ja nun auch:

#define Ein (PORTD |= (1<<PD0))
#define Aus (PORTD &= (0<<PD0))   <- sollte ich dies unterlassen?

int main(void)
{
  DDRD |= (1<<PD0);
    while (1)
    {

    Ein;
    _delay_ms(500);
    Aus;
    _delay_ms(500);

    }
}

: Bearbeitet durch User
von MWS (Gast)


Lesenswert?

Philipp L. schrieb:
> Das mit der 0 wirkt für mich übersichtlicher, gibt es einen Grund dafür?

Du kannst eine 0 hundertmal schieben, es bleibt eine 0. Eine Variable 
oder ein Register mit 0 zu verodern ergibt keine Änderung des selben.

von Bimbo. (Gast)


Lesenswert?

C-Buch GRÜNDLICH durchlesen ;).

#define Aus (PORTD &= (0<<PD0))

ist das selbe wie

#define Aus (PORTD &= 0);

Und wenn du etwas mit 0 undest kommt 0 heraus.

Liesnochmal ganz ganz genau nach, was |=, &=, ~, ^= etc. so machen.

von Bimbo. (Gast)


Lesenswert?

PS: #define Aus (PORTD &= (0<<PD0))  macht alle Bits, nicht nur PD0 
sondern auch PD1-PD7 zu 0.

von HildeK (Gast)


Lesenswert?

Suche mal im Forum nach sbit.h von Peter Dannegger.

Dann würde dein Code in etwa so aussehen:

#include "sbit.h"
#include // anderes
1
#define SERVO         PORT_D0
2
#define SERVO_oe      DDR_D0
3
4
#define EIN    1
5
#define AUS    0
6
#define OUTPUT 1
7
8
int main()
9
{
10
  SERVO_oe = OUTPUT; 
11
12
  while(1)
13
  {
14
    SERVO = EIN; 
15
    _delay_ms(500);
16
    SERVO = AUS; 
17
    _delay_ms(500);
18
  }
19
}

Philipp L. schrieb:
> ich verstehe jedoch nicht wirklich, warum ich das Bit löschen soll,
> anstatt eine 0 hineinzuschreiben.
> Das mit der 0 wirkt für mich übersichtlicher, gibt es einen Grund dafür?
Es gibt einen Grund: es funktioniert nicht.

Nimm doch mal das Statement auseinander:
- Du schreibst ein ein (temporäres) Register eine Null und schiebst die 
nach links um PD0 Stellen (0<<PD0). (PDx enthält eine einfache 
Integerzahl von 0...7). Bleibt Null. Jetzt machst du ein OR mit '0' und 
dem bisherigen Inhalt von PORTD. Bewirkt rein gar nichts.

Im anderen Fall schiebst du eine '1' um x Stellen nach links (1<<PD0). 
Gibt bei PD0 eine temporäre '1' bzw. 0x01. Das wird invertiert zu 0xFE. 
Und das wiederum verUNDest du mit dem Inhalt von PORTD. Damit wird die 
rechte Stelle auf Null gesetzt, die andern bleiben unberührt.
Das wolltest du.

von Carl D. (jcw2)


Lesenswert?

Philipp L. schrieb:
> Bimbo. schrieb:
>> Ich meine natürlich:
>>
1
>> #define Servo1_aus (PORTD &= ~(1<<PD0));
2
>>
>
> ja, bin grad dabei ein C-Buch zu lesen.
>
> ich verstehe jedoch nicht wirklich, warum ich das Bit negieren soll
> anstatt eine 0 hineinzuschreiben (~ steht aber auch so im Buch).
> Das mit der 0 wirkt für mich übersichtlicher, gibt es einen Grund dafür?

Weil AND keine Zuweisung ist!
Die Negation des Bits erzeugt eine Maske, bei der alle Bits, außer dem 
einen, gesetzt sind, bei AND also nicht gelöscht werden.

> Dies funktionier ja nun auch:
>
> #define Ein (PORTD |= (1<<PD0))
> #define Aus (PORTD &= (0<<PD0))   <- sollte ich dies unterlassen?
Ja, denn so werden ALLE PORTD Bits gelöscht.

von HildeK (Gast)


Lesenswert?

Philipp L. schrieb:
> Dies funktionier ja nun auch:
>
> #define Ein (PORTD |= (1<<PD0))
> #define Aus (PORTD &= (0<<PD0))   <- sollte ich dies unterlassen?

Ja, das funktioniert - in deinem Fall. Aber es löscht nicht nur PD0 
sondern den ganzen PORTD. Und wenn da was anderes stand? Dann ist es 
auch gelöscht!

von Philipp L. (viech)


Lesenswert?

HildeK schrieb:

> Nimm doch mal das Statement auseinander:
> - Du schreibst ein ein (temporäres) Register eine Null und schiebst die
> nach links um PD0 Stellen (0<<PD0). (PDx enthält eine einfache
> Integerzahl von 0...7). Bleibt Null. Jetzt machst du ein OR mit '0' und
> dem bisherigen Inhalt von PORTD. Bewirkt rein gar nichts.
>
> Im anderen Fall schiebst du eine '1' um x Stellen nach links (1<<PD0).
> Gibt bei PD0 eine temporäre '1' bzw. 0x01. Das wird invertiert zu 0xFE.
> Und das wiederum verUNDest du mit dem Inhalt von PORTD. Damit wird die
> rechte Stelle auf Null gesetzt, die andern bleiben unberührt.
> Das wolltest du.

Vielen Dank! das hatte ich etwas falsch verstanden...

Noch eine Frage, welche aus deiner Antwort kommt:
Der Befehl "Port_D0 = x" aus der Lib ist gut, aber wie setze ich ohne 
zusatz Lib einen einzelnen Ausgang in Abhängigkeit einer Variable?
Ich habe hier im Forum unter 
Beitrag "Variable an Ausgang zuweisen" auch nur einen Thread 
gefunden, bei dem dies durch eine If-abfrage gelöst ist.
Das kommt mir recht umständlich vor, konnte ich in Basic doch auch immer 
schreiben: PORTB.0 = x

Das Thema habe ich auch schon "verzweifelt" im Buch gesucht..

: Bearbeitet durch User
von HildeK (Gast)


Lesenswert?

Philipp L. schrieb:
> Der Befehl "Port_D0 = x" aus der Lib ist gut, aber wie setze ich ohne
> zusatz Lib einen einzelnen Ausgang in Abhängigkeit einer Variable?

Dafür sind die Makros ins sbit.h eher nicht geeignet.
Da aber die Portnummerierung PD0...PD7 soweit mir bekannt ist immer 
letztlich mit den Zahlen 0..7 belegt sit, kannst du auch direkt 
schreiben (i sei die Variable):
PORTD |= (1<<i) zum setzen bzw. PORTD &= ~(1<<i) zum löschen.
Das gilt natürlich auch für andere Ports.
Also einfach die herkömmliche Variante verwenden. Das geht natürlich 
auch, wenn man sonst im Programm sbit.h verwendet.

von Philipp L. (viech)


Lesenswert?

HildeK schrieb:
> Philipp L. schrieb:
>> Der Befehl "Port_D0 = x" aus der Lib ist gut, aber wie setze ich ohne
>> zusatz Lib einen einzelnen Ausgang in Abhängigkeit einer Variable?
>
> Dafür sind die Makros ins sbit.h eher nicht geeignet.
> Da aber die Portnummerierung PD0...PD7 soweit mir bekannt ist immer
> letztlich mit den Zahlen 0..7 belegt sit, kannst du auch direkt
> schreiben (i sei die Variable):
> PORTD |= (1<<i) zum setzen bzw. PORTD &= ~(1<<i) zum löschen.
> Das gilt natürlich auch für andere Ports.
> Also einfach die herkömmliche Variante verwenden. Das geht natürlich
> auch, wenn man sonst im Programm sbit.h verwendet.


Ja, ich meinte aber eher folgendes Beispiel:

#int x=0;

int main(void)
{
  DDRD |= (1<<PD0);

while (1)
    {
    PORT_D0 = x;  <-- Ist dies auch ohne sbit.h übersichtlich 
darstellbar?
        }
}

interruptroutine:
if_xxx X=1
if_xxx X=0

: Bearbeitet durch User
von HildeK (Gast)


Lesenswert?

Philipp L. schrieb:
> PORT_D0 = x;  <-- Ist dies auch ohne sbit.h übersichtlich
> darstellbar?

Wenn du PORT_D0 verwendest, dann brauchst du sbit.h. Und x kann in dem 
Zusammenhang nur 0 oder 1 sein: den Pin D0 setzen oder rücksetzen.
Was willst du mit dem x erreichen?

von Cyblord -. (cyblord)


Lesenswert?

Philipp L. schrieb:
> ich verstehe jedoch nicht wirklich, warum ich das Bit negieren soll
> anstatt eine 0 hineinzuschreiben

Naja Lesen ist das eine. Versuchen zu verstehen was da passiert ist halt 
das Andere.
Vollziehe die Bitoperation mal von Hand. Dann sollte es klar werden.
Einfach Copy&Paste von Dingen die man nicht versteht hilft nicht weiter.

von Brummbär (Gast)


Lesenswert?

Btw:
Wenn Du "x" in einer ISR verändern möchtest muss es "volatile" sein.

von Peter D. (peda)


Lesenswert?

HildeK schrieb:
> Dafür sind die Makros ins sbit.h eher nicht geeignet.

Natürlich geht das, probiers aus.
x sollte aber von Typ bool sein, d.h. 0 oder 1.
Sollen auch andere Werte als true zugelassen sein, kann man schreiben:
1
  PORT_D0 = !!x;

von HildeK (Gast)


Lesenswert?

Peter D. schrieb:
> HildeK schrieb:
>> Dafür sind die Makros ins sbit.h eher nicht geeignet.
>
> Natürlich geht das, probiers aus.
> x sollte aber von Typ bool sein, d.h. 0 oder 1.
> Sollen auch andere Werte als true zugelassen sein, kann man schreiben:
> PORT_D0 = !!x;

Das schon, ich hatte verstanden, dass er die Portnummer als Variable 
wollte.

von Philipp L. (viech)


Angehängte Dateien:

Lesenswert?

Ich habe jetzt die sbit.h eingebunden und bin sehr überrascht über die 
Größe.

Bei dem Testprogramm (siehe Anhang) ist der Code ohne die sbit.h 106 
Bytes und mit der Sbit.h nur 104 Bytes groß.
Das sagt zumindest "myAVR ProgTool" beim brennen.

eigentlich müsste der Code doch größer werden ?

von A. S. (Gast)


Lesenswert?

Philipp L. schrieb:
> eigentlich müsste der Code doch größer werden ?

Nein.

Es wird ja deutlich, dass nur dieses Bit gesetzt/gelöscht werden soll, 
das ist weniger Aufwand als es vorher noch zu lesen

von MWS (Gast)


Lesenswert?

Peter D. schrieb:
> PORT_D0 = !!x;

Du schreibst an der Frage vorbei, welche lautete: wie geht's ohne 
(D)eine Lib?

Philipp L. schrieb:
> wie setze ich ohne
> zusatz Lib einen einzelnen Ausgang in Abhängigkeit einer Variable?

> konnte ich in Basic doch auch immer
> schreiben: PORTB.0 = x

Das geht in C nicht über einen einzelnen Befehl, das muss man 
zusammenbasteln und dürfte in etwa so entsprechen:

> uint8_t x = 1;
> PORTB = ((PORTB & ~(1 << PB0)) | ((x & 0x01) << PB0));
> x = 0;
> PORTB = ((PORTB & ~(1 << PB0)) | ((x & 0x01) << PB0));

Ist x ein Bool oder wird nie größer 1, kann (x & 0x01) durch x ersetzt 
werden.

von Philipp L. (viech)


Lesenswert?

Was man alles bei einem Blinkprogramm lernen kann :-)
Naja, aller Anfang ist schwer..

> das ist weniger Aufwand als es vorher noch zu lesen
PORTD = 0xff;
Ich dachte dies ist eine reine Zuweisung, warum lesen..

> Es wird ja deutlich, dass nur dieses Bit gesetzt/gelöscht werden soll
Schon, aber mittels unterroutine durch sbit.h
Ich dachte, hier muss mehr abgearbeitet werden..

von MWS (Gast)


Lesenswert?

A. S. schrieb:
> Es wird ja deutlich, dass nur dieses Bit gesetzt/gelöscht werden soll,
> das ist weniger Aufwand als es vorher noch zu lesen

Es wird auch im anderen Fall nicht gelesen.

Der eigentliche Grund dürfte sein, dass beim Prozessor der PORTD im per 
SBI zu erreichenden IO-Adressbereich bis 0x1F liegen dürfte und ein SBI 
PORTD, 0 nur ein Opcode ist, während ein PORTD = 0xff zu LDI Rxx, 0xff 
und STS PORTD, Rxx wird, das sind zwei Opcodes.

von HildeK (Gast)


Lesenswert?

Philipp L. schrieb:
> Ich habe jetzt die sbit.h eingebunden und bin sehr überrascht über die
> Größe.
>
> Bei dem Testprogramm (siehe Anhang) ist der Code ohne die sbit.h 106
> Bytes und mit der Sbit.h nur 104 Bytes groß.

Die beiden Codeschnipsel machen auch nicht dasselbe. Links setzt du alle 
PORTD-Pins auf HIGH bzw. LOW, rechts nur D0!

von Philipp L. (viech)


Lesenswert?

> Die beiden Codeschnipsel machen auch nicht dasselbe. Links setzt du alle
> PORTD-Pins auf HIGH bzw. LOW, rechts nur D0!

Schon, aber mittels unterroutine durch sbit.h
Ich dachte, hier muss mehr abgearbeitet werden..

: Bearbeitet durch User
von HildeK (Gast)


Lesenswert?

Philipp L. schrieb:
> Schon, aber mittels unterroutine durch sbit.h

Da sind meiner Erinnerung nach nur oder fast nur #defines drin. Es 
werden nur Texte ersetzt.

von Philipp L. (viech)


Lesenswert?

Ist es möglich, einen Eingang ohne IF-Abfrage als 1 (0x01) oder 0 (0x00) 
in eine Variable zu schreiben?

in meinem Buch "AVR-Mikrocontroller - Programmierung in C" (evtl. kein 
gutes) ist dies nur mittels IF-Abfragen gelöst:

z.B.
If (PINB & (1<<PB2));
X = 1;

ich würde mir so etwas wünschen:

#define Taster (PINB2)
X = Taster

Es soll nicht das ganze Eingangsregister von PINB in x geschrieben 
werden, sondern der Eingang (z.b.PB2) in das unterse Bit von X.
also wenn das Register PINB=xxxxx1xx -> X = 0x01

: Bearbeitet durch User
von HildeK (Gast)


Lesenswert?

Schau dir das mal an:
Beitrag "Re: Attiny85 Pin als Eingang"
Basic und C sjnd nunmal unterschiedliche Sprachen mit unterschiedlicher 
Syntax.

von Einer K. (Gast)


Lesenswert?

Philipp L. schrieb:
> z.B.
> If (PINB & (1<<PB2));
> X = 1;

// C++
bool X = (PINB & (1<<PB2));

// C
uint8_t X =  (PINB & (1<<PB2)) > 0;

von A. S. (Gast)


Lesenswert?

Philipp L. schrieb:
> PORTD = 0xff;
> Ich dachte dies ist eine reine Zuweisung, warum lesen..

Sorry, hatte gedacht bezogen auf die verodern. Schaue mir Quelltext als 
Bild ungern an, hier ging's aber.

Kenne auch deinen Prozessor nicht, ob er bitbefehle hat.

Das sind aber dankbare Aufgaben, um Listings mit Assembler Mal zu 
erforschen.

von Philipp L. (viech)


Lesenswert?

>// C
> uint8_t X =  (PINB & (1<<PB2)) > 0;

Aus andrem Thread
>x = (PORTA & (1 << BIT)) == (1 << BIT)

Wo ist denn der Unterschied, ob ich PINx oder PORTx schreibe ?

von Peter D. (peda)


Lesenswert?

Philipp L. schrieb:
> ich würde mir so etwas wünschen:
>
> #define Taster (PINB2)
> X = Taster

Geht auch mit der sbit.h
x = PIN_B2;

von Einer K. (Gast)


Lesenswert?

Philipp L. schrieb:
> Wo ist denn der Unterschied, ob ich PINx oder PORTx schreibe ?
PORTx wird dauerhaft High sein, wenn der Pullup aktiviert ist.
Aber dennoch ist PINx dann u.U. Low, z.B. wenn der daran angeschlossene 
Taster betätigt wird.

von Wolfgang (Gast)


Lesenswert?

Philipp L. schrieb:
> Wo ist denn der Unterschied, ob ich PINx oder PORTx schreibe ?

Da könntest du einen Blick in das Datenblatt deines (unbekannten) 
Prozessors werfen. Meist gibt es dort ein ganzes Kapitel, dass sich mit 
dem Zusammenwirken der Register bei einem GPIO beschäftigt (inkl. 
Blockschaltbild)

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.