Forum: Mikrocontroller und Digitale Elektronik Port Definitionen


von Anfänger (Gast)


Lesenswert?

Hallo Leute.

Ich bin neu auf dem Gebiet µC.
Es wäre schön wenn ihr mir bei einem einfachen Problem(...für mich 
nicht!)helfen könntet.

Ich habe Makros für bestimmte Pins festgelegt. Ich hoffe das ist richtig 
so.

Bsp.:
1
/**
2
    Portdefinition für ADC0
3
*/
4
#define PORT_ADC_0             PORTA
5
#define PIN_ADC_0              PINA
6
#define BIT_ADC_0              0

Nun mein Problem. Wie übergebe ich dies einer Funktion?
Wenn ich z.B. ein Funktion habe int GetADC(???), wie übergebe ich der 
Funtion jetzt den richtigen Kanal für die AD-Messung? Und wie kann ich 
in der Funktion damit arbeiten. Muss ich den Pin oder das Bit übergeben?
1
int GetADC(???)
2
{
3
// hier Code
4
5
return ADC;
6
}

von NurEinGast (Gast)


Lesenswert?


von Oliver (Gast)


Lesenswert?

1
#define PORT_ADC_0             PORTA
2
#define PIN_ADC_0              PINA
3
#define BIT_ADC_0              0

sind #defines, die bei der Nutzung von PORTC als Standard-IO sinnvoll 
sind. Nutzt du dagegen den ADC, helfen die dir nicht weiter.

Ist der ADC aktiviert, dann wird der ADC-Kanal in den unteren Bits des 
ADMUX-Registers eingestellt. Insofern wäre eine brauchbare Definition 
für deine Funktion:
1
int GetADC(uint8_t Kanal)

Für mehr Infos guggst du hier:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#ADC_.28Analog_Digital_Converter.29


Oliver

von Anfänger (Gast)


Lesenswert?

Danke, aber so habe ich das nicht gemeint. Vieleicht verstehe ich auch 
was falsch. Ich will z.B. in einem "switch case" abfragen, welches 
define übergeben wurde. Oder ist das nicht so einfach?

von Zulu (Gast)


Lesenswert?

Weisst Du, das ist eigentlich eine C-Frage und hat erstmal nichts mit 
Ports oder so zu tun. Das ist auch in Ordnung so. Aber ich schreibe das, 
damit Du mitbekommst, wie Du selbst Deine Fragen einordnen kannst, wenn 
später mal neue kommen.

>Ich will z.B. in einem "switch case" abfragen, welches
>define übergeben wurde.
Ein define wird nicht "übergeben". Mit defines wird einfach nur 
Textersatz definiert, der vom Preprozessor_ _vor dem kompilieren 
behandelt wird.
Schreibst Du also z.b.
1
#define NETT FREUNDLICH
2
3
Du bist NETT zu mir.

dann macht der Preprozessor (natürlich ist das obige kein C-Programm, 
aber der Preprozessor würde das machen. Probiere es.) daraus
1
#define NETT FREUNDLICH
2
3
Du bist FREUNDLICH zu mir.

Lies dazu mal in einem guten C-Buch das Kapitel über den Preprozessor.

D.h. also, wenn Du mit define letzlich an die Stelle, wo der definierte 
Name auftaucht, eine Zahl setzt, dann musst Du damit umgehen, als wenn 
da von Anfang an eine Zahl gestanden hätte.

In einem C-Programm kann man eine Zahl z.B. an eine Funktion übergeben. 
Und was muss eine Funktion an dieser Stelle in ihrer Deklaration haben? 
Richtig, einen Parameter. Und wenn der Parameter eine Zahl ist? Richtig, 
einen integralen Typ wie int, unsigned, char usw.

Das lies bitte auch mal in einem C-Buch nach.

OK?

von Anfänger (Gast)


Lesenswert?

OK verstanden! Danke.

Dann aber noch eine Frage.
Wie definiere ich dann zentral irgendwelche PORTs, PINs, um im Programm 
immer damit arbeiten zu können. Auch Funktionen übergeben und so?
Kann ich da vieleicht mit Enumeratoren arbeiten?

z.B. so?
1
/**
2
    Enumerator für analoge Eingänge
3
*/
4
5
typedef enum
6
{
7
    AIN_ADC_0,      // Analogeingang 0
8
    AIN_ADC_1,      // Analogeingang 1
9
    AIN_ADC_2,      // Analogeingang 2
10
    AIN_ADC_3,      // Analogeingang 3
11
12
    AIN_COUNT       // Anzahl der Digitalausgänge
13
}
14
TE_AIN;

Und dann abfragen?
1
int GetADC(TE_AIN channel)
2
{
3
4
   switch (channel)
5
   ...
6
   ...
7
8
}

von Zulu (Gast)


Lesenswert?

Mach es doch mit defines. Es ging nur darum, das Du defines nicht 
"übergeben" kannst. Das sind einfach Zahlen. Enums gehen natürlich auch. 
Aber Du musst halt aufpassen, wie die Nummerierung wird. Lies bitte 
erstmal ein C-Buch gründlich durch. Dann klären sich viele Fragen.

von gast (Gast)


Lesenswert?

die PORTs und PINs sind doch definiert als :
PORTB  und DDRB usw ..


wenn du einen pin setzen willst musst du ihn vorher als ausgang setzen
DDRB |= (1<<PB0)
setzt PB0 als ausgang

PORTB |= (1<<PB=0)
setzt den ausgang PB0 auf 1
PORTB &= ~(1<<PB0)
löscht den ausgang


wenn du den Analogeingang nutzt
muss du dem ADC MUX register sagen welchen eingan du gerne messen willst
das ergebniss steht dann im ADCH und ADCL register

für mehrer messungen musst du den MUX umschalten und messen
die ergebnisse kannst du in variablen speichern und verwenden


ansonst sind alle pins  des AVRs schon drin

also PORT für die ports eben DDR für datenrichtung
PIN für die eingangsabfrage

PB3  ist das 4te Bit von PORTB
weil PB0 .......PB7   sind 8 bit

von Anfänger (Gast)


Lesenswert?

So hab ich das nicht gemeint. Natürlich sind alle PINs/PORTs schon 
definiert. Wenn in meinem Programm aber zB. der PORTB 100mal auftaucht 
und mir fällt ein, dass ich doch den PORTC nehmen will, dann muss ich 
alles ändern und nicht nur ein "define"! verstehst du was ich meine?

Wie macht man sowas???
Bei einer Zahl ist das kein Problem.

#define PI 3,141

Aber wie mache ich das mit PORTs und PINs.

Kann aber auch sein, dass ich zu blöd bin!

Danke

von Karl H. (kbuchegg)


Lesenswert?

Anfänger schrieb:
> So hab ich das nicht gemeint. Natürlich sind alle PINs/PORTs schon
> definiert. Wenn in meinem Programm aber zB. der PORTB 100mal auftaucht
> und mir fällt ein, dass ich doch den PORTC nehmen will, dann muss ich
> alles ändern und nicht nur ein "define"! verstehst du was ich meine?
>
> Wie macht man sowas???

Du denkst zu komplizert
1
#define LED_PORT  PORTB
2
3
void foo()
4
{
5
  LED_PORT = 0x20;
6
}
7
8
void foo2()
9
{
10
  LED_PORT = 0x80;
11
}
12
13
void foo3()
14
{
15
  LED_PORT = 0x45;
16
}


Wenn deine LEDS jetzt vom PORTB auf den PORTC umziehen, änderst du 
einfach das #define und bist fertig.
Denk immer daran: #define macht nur Textersetzungen. Im nachfolgenden 
Text wird überall LED_PORT durch PORTB textuell ersetzt noch ehe der 
Compiler den Code zu Gesicht bekommt.

von Anfänger (Gast)


Lesenswert?

Und wenn ich jetzt eine einzelne LED am PIN 1 anschalten will. Muss ich 
das das Bit oder den Pin angeben.

von Anfänger (Gast)


Lesenswert?

Ach und noch was. Wie kann ich das einer Funktion übergeben. Ich kann ja 
kein define übergeben. Wie macht man das?

von Karl H. (kbuchegg)


Lesenswert?

Anfänger schrieb:
> Und wenn ich jetzt eine einzelne LED am PIN 1 anschalten will. Muss ich
> das das Bit oder den Pin angeben.

Stell dir vor, wie das tatsächliche Ergebnis aussehen soll

Du willst haben, dass der Compiler dieses zu Gesicht bekommt
1
void foo()
2
{
3
  PORTB |= ( 1 << PB1 );
4
}

weil an Pin 1 vom Port B momentan deine LED hängt.
Jetzt möchtest du das aber besser konfigurierbar haben, was ja 
grundsätzlich gut ist.
Also nennst du PORTB den LED_PORT und anstelle von PB1 möchtest du 
ERROR_LED schreiben, weil das die Funktion der Led ist
1
#define LED_PORT   PORTB
2
#define ERROR_LED  PB1
3
4
void foo()
5
{
6
  LED_PORT |= ( 1 << ERROR_LED );
7
}

Mach einfach mal gedanklich jetzt die Textersetzungen. Ersetze den Text 
LED_PORT durch PORTB und den Text ERROR_LED durch PB1
Es kommt genau das Gewünschte   PORTB = ( 1 << PB1 ); heraus. Und so 
wird es dann auch durch den Compiler gejagt.

Mittels #define kannst du jeden beliebigen Text durch irgendeinen 
anderen Text ersetzen lassen. Wichtig ist aber: Es ist nur eine 
Textersetzung, die abläuft ehe der Compiler den Code zu Gesicht bekommt. 
Wenn du in deinem Editor die Replace Funktion benutzt und LED_PORT durch 
PORTB ersetzt, dann machst du genau das was auch der Präprozessor macht.

von Zulu (Gast)


Lesenswert?

>Und wenn ich jetzt eine einzelne LED am PIN 1 anschalten will. Muss ich
>das das Bit oder den Pin angeben.

ACHTUNG: Was in diesem Zusammehang "PIN" heisst, also PINA, usw. bezieht 
sich auf den gesamten Port von 8 Bit nicht auf einen einzelnen Anschluss 
des IC, der im englischen "Pin", im deutschen "Stift" heisst. Es steht 
glaube ich für "Port INput" im Unterschied zur DDR (wie DDRA) oder PORT 
(wie PORTA) die für die Datenrichtung und den Ausgang zuständig sind.

Die Pins sind durchnummeriert und jeweils einem Bit des Port zugeordnet. 
Gewöhnlich ist PIN0 auch Bit 0 usw. (Möglicherweise fangen die Ports mit 
1 ein, dann ist PIN1 dem Bit 0 zugeordnet. Ich weiss gerade nicht wie es 
bei den AVR-Definitionen ist).

von Anfänger (Gast)


Lesenswert?

Ja danke, das habe ich auch verstanden.
Aber jetzt habe ich eine Funktion.
Dieser Funktion möchte ich übergeben, welcher PIN geschaltet werden 
soll.

Und ich hab geschrieben:

#define LED_PORT   PORTB
#define ERROR_LED  PB1

Die Funktion:

void SetLED(???)
{

}

Ich kann ja nicht schreiben:

SetLED(ERROR_LED);

von Zulu (Gast)


Lesenswert?

Da habe ich ein wenig schlecht geschrieben. Es muss heissen:

Ein einzelner Pin, also ein einzelner Anschluss oder Stift wird durch P 
gefolgt von dem Portnamen A, B usw. gefolgt von einer Ziffer 
gekennzeichnet.

Die Pins sind also durchnummeriert und jeweils einem Bit des Port 
zugeordnet.
Gewöhnlich ist PA0 auch Bit 0 usw. (Möglicherweise fangen die Ports mit
1 ein, dann wäre PA1 dem Bit 0 zugeordnet. Ich weiss gerade nicht wie es
bei den AVR-Definitionen ist).

von Karl H. (kbuchegg)


Lesenswert?

Anfänger schrieb:
> Ja danke, das habe ich auch verstanden.
> Aber jetzt habe ich eine Funktion.
> Dieser Funktion möchte ich übergeben, welcher PIN geschaltet werden
> soll.
>
> Und ich hab geschrieben:
>
> #define LED_PORT   PORTB
> #define ERROR_LED  PB1
>
> Die Funktion:
>
> void SetLED(???)
> {
>
> }
>
> Ich kann ja nicht schreiben:
>
> SetLED(ERROR_LED);

Warum nicht?
Klar kannst du. ERROR_LED ist eine andere Schreibweise für PB1. Und das 
wiederrum ist nur eine andere Schreibweise für 1

Wenn der Präprozessor kommt, ersetzt er ERROR_LED durch PB1

Aus
  SetLED(ERROR_LED);

wird so
  SetLED(PB1);

Nun ist aber PB1 seinerseits wieder ein Makro, welches in io.h definiert 
ist
#define PB1 1

Also erfolgt konsequenterweise die nächste Ersetzung und da steht

  SetLED(1);

Also muss deine Funktion so aussehen
1
void SetLED( int i )
2
{
3
  ...
4
}

von Karl H. (kbuchegg)


Lesenswert?

Karl heinz Buchegger schrieb:

> Also muss deine Funktion so aussehen
>
>
1
> void SetLED( int i )
2
> {
3
>   ...
4
> }
5
>

Aber aus mehreren Gründen ist das keine so wahnsinnig gute Idee.
Zum einen ist der int überkandidelt. Ein unsigned char tut es an dieser 
Stelle auch.
Zum zweiten, und das ist schwerwiegender, ... geht es denn in der 
Funktion weiter:
1
void SetLED( unsigned char ledNr )
2
{
3
  LED_PORT |= ( 1 << ledNr );
4
}

Dieses 1 << ledNr ist aber eine teure Operation, weil der AVR keine 
Operation hat um eine 1 in einem Rutsch um eine variable Bitanzahl nach 
links zu schieben.

von Zulu (Gast)


Lesenswert?

>Ich kann ja nicht schreiben:
>SetLED(ERROR_LED);

Doch! Genau so schreibst Du das.

Aber Du musst natürlich die Funktion SetLED irgendwie füllen.

Du übergibst eine Zahl. Also
1
setLED (char LedNr) {
2
   LED_PORT |= ( 1 << LedNr );
3
}

Hinweis:
Da steht "char", was für einen Anfänger etwas verwirrend sein kann. Das 
spielt hier keine Rolle, das das nach "character" aussieht. Denn man 
kann die Werte auch als ganze Zahlen (die von 0 bis 255 gehen können) 
interpretieren. Gleichzeitig steht die Zahl dezimal 49 auch für das 
Zeichen '1', also die Ziffer Eins.

von Anfänger (Gast)


Lesenswert?

Also kann ich doch "defines" an Funtionen übergeben ?!?

von Zulu (Gast)


Lesenswert?

Und jetzt, Karl-Heinz erklär mal warum das unsigned char und nicht char 
heissen muss. Nicht das die LED quiekt anstatt zu leuchten. ;-)

von Karl H. (kbuchegg)


Lesenswert?

Anfänger schrieb:
> Also kann ich doch "defines" an Funtionen übergeben ?!?

Nein!!!!!!

#defines werden abgearbeitet, noch bevor der Compiler irgendetwas mit 
deinem Code macht.
Wenn sich der Compiler die Frage stellt, wie Funktionen aufgerufen 
werden und welche Argumente übergeben werden, existieren #define ganz 
einfach nicht mehr!

Stell es dir so vor:

Du schreibst deinen Code.

Und bevor du den Code compilierst, gehst du in deinem Editor her und 
benutzt die Replace-Funktion deines Editors um den Text LED_PORT durch 
den Text PORTB zu ersetzen.
Mehr passiert da nicht! Der Quelltext, der durch den Compiler geht, wird 
verändert noch bevor ihn der Compiler zu Gesicht bekommt.

Da wird nichts übergeben, da werden keine Datentypen ausgewertet.
Da wird einfach nur ein Text durch einen anderen Text ersetzt!

von Zulu (Gast)


Lesenswert?

>Also kann ich doch "defines" an Funtionen übergeben ?!?

Ein "define" kann  nicht "übergeben" werden. Das ist ein bischen so, als 
wenn Du fragst ob man das Wort "Kirsche" essen kann.

von Karl H. (kbuchegg)


Lesenswert?

Zulu schrieb:
> Und jetzt, Karl-Heinz erklär mal warum das unsigned char und nicht char
> heissen muss. Nicht das die LED quiekt anstatt zu leuchten. ;-)

Gewöhn dir an auf Byteebene mit unsigned char zu arbeiten und du hast 
weniger Probleme. Selbst dann, wenn in einem speziellen Fall es keinen 
Unterschied macht ob char nun signed ist oder nicht.

von Zulu (Gast)


Lesenswert?

Du musst den Text, mit dem Du ein Programm/Algorithmus beschreibst 
streng von dem Programm selbst trennen.
Hier kommt nun noch dazu, das zwei "Programmiersprachen" übereinander 
gestapelt sind. Erst der Preprozessor. Er kann nur Textersatz 
beschreiben. Mehr nicht. Keine Verarbeitung, keine Formeln, keine 
Berechnungen. (Naja. Man kann mit Textersatz auch rechnen, aber das ist 
was für die Informatik-Vorlesungen). Dann erst kommt der C-Compiler. Und 
der rechnet auch nur teilweise mit konstanten Werten. Erst dann kommt 
das Programm selbst, das dann wirklich was berechnet.

von Zulu (Gast)


Lesenswert?

@ Karl-Heinz
>> Und jetzt, Karl-Heinz erklär mal warum das unsigned char und nicht char
>> heissen muss. Nicht das die LED quiekt anstatt zu leuchten. ;-)

>Gewöhn dir an auf Byteebene mit unsigned char zu arbeiten und du hast
>weniger Probleme. Selbst dann, wenn in einem speziellen Fall es keinen
>Unterschied macht ob char nun signed ist oder nicht.

Da hast Du recht. Aber im Moment arbeite ich gerade mit guint8 und wälze 
mich durch die gtk-docu. Da war mir das erstmal egal.

von Anfänger (Gast)


Lesenswert?

OK, jetzt bin ich vom Schlauch runter gestiegen. Ich habs kapiert!
Ich hab wirklich zu kompliziert gedacht.

Danke nochmal an alle, jetzt hats geklappt.

Dieses Forum und seine Gemeinde sind echt hilfsbereit, auch wenn ein 
dummer Anfänger Fragen stellt.

Bis dann ...

von Klaus W. (mfgkw)


Lesenswert?

Vielleicht meintest du sowas:
1
void bitset( volatile uint8_t *p_port, uint8_t bitnummer, uint8_t value )
2
{
3
  if( value )
4
  {
5
    *p_port |= (1<<bitnummer);
6
  }
7
  else
8
  {
9
    *p_port &= ~(1<<bitnummer);
10
  }
11
}

Dieser Funktion kannst du einen Port übergeben (als Adresse),
sowie eine Bitnummer und einen Wert (0 oder 1).
Der entsprechende Ausgangspin wird dann gesetzt oder gelöscht.

Z.B. könnte man mit:
1
  while( 1 )
2
  {
3
4
    bitset( &PORTD, 7, 1 );
5
    _delay_ms( 500 );
6
    bitset( &PORTD, 7, 0 );
7
    _delay_ms( 500 );
8
  }
eine LED blinken lassen.

Nachtrag:
Das funktioniert nicht mit allem, was man mit #define so
definieren kann.
Glücklicherweise sind bei einem AVR die Ports in den Adreßspeicher
eingeblendet (also wie jede Variable auch über die Adresse erreichbar)
und die PORT... sind etwa in der Art definiert:
1
#define PORTA  (*(uint8_t*)42)
(falls jetzt beispielsweise PORTA an der Stelle 42 eingeblendet ist,
was wahrscheinlich nicht ganz stimmen wird).
Bei bitset( &PORTA, 7, 1 ) würde also der erste Parameter zum
Wert &*(uint8_t*)42 werden, mithin 42 als uint8_t-Wert.
In der Funktion wird dann mit *(uint8_t*)42 wieder auf das Register
zugegriffen.

von Anfänger (Gast)


Lesenswert?

Auch nicht schlecht, Danke.

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.