Forum: Mikrocontroller und Digitale Elektronik Kommunikation zwischen zwei STK500


von Bernd H. (berndy)


Lesenswert?

Hallo Forum,


ich habe zwei STK500 und möchte, dass diese miteinander kommunizieren.

STK_1 und STK_2 sind über PORTB miteinander verbunden.

STK_1 wurde so programmiert, dass es stetig eine bestimmte Zeichenfolge 
auf PORTB und PORTD ausgibt:
1
int main (void){
2
DDRB=0xff;  //PortB auf Ausgang
3
DDRD=0xff;  //PortD auf Ausgang
4
while(1){
5
PORTB=0b01010101;  //Zeichenfolge
6
PORTD=0b01010101;  //Zeichenfolge
7
}
8
}

STK_2 erhält die Zeichenfolge (PORTB) und soll diese anzeigen (PORTD).
Wie müsste ein einfaches/kurzes Programm dazu aussehen?
1
int main(void){
2
DDRB=0x00;  //PortB auf Eingang
3
DDRD=0xff;  //PortD auf Ausgang
4
PORTD=0xff;  //damit LEDs aus
5
while(1){
6
//Programm?
7
}
8
}

Gibt es eine einfache Möglichkeit um PB0 auf PD0 zu setzen?
PB0 -> PD0
PB1 -> PD1
...
PB7 -> PD7


Mit elektronischen Grüßen
Bernd

von Troll (Gast)


Lesenswert?

PORTD=PINB; ??!!

von Bernd H. (berndy)


Lesenswert?

Vielen Dank Troll!

Hat super geklappt!
1
PORTD=PINB;

Kann man das auch mit einzelnen Pins machen?

von Karl H. (kbuchegg)


Lesenswert?

Bernd Hauegg schrieb:
> Vielen Dank Troll!
>
> Hat super geklappt!
>
1
PORTD=PINB;
>
> Kann man das auch mit einzelnen Pins machen?

Kommt drauf an.
Wenn man C gut kann, dann kann man sich syntaktisch das Leben leichter 
machen.

Aber im Grunde läuft es selbst dann auf

   if( Pin_Eingang ist high )
     Setze Pin_Ausgang auf high
   else
     Setze Pin Ausgang auf low


hinaus, nur mit dem Unterschied, dass einem der Compiler da etwas 
abnehmen kann. Aber solange du nicht soweit bist, vergiss die Anmerkung 
einfach wieder und schreibs in der gezeigten ausführlichen Langvariante.

Ich schreib das jetzt absichtlich nicht in korrekter Syntax :-)
Denn das ist das kleine EinmalEins. Wenn du Kommunikation zwischen µC 
betreiben willst, solltest du diesen Bit-Teil problemlos Nachts um halb 
vier, 10 Sekunden nach dem Wecken fehlerfrei in deinem Programm stehen 
haben. Darüber darfst du noch nicht mal nachdenken müssen, wie das geht.

Wenn doch: dann ist µC-Kommunikation noch zu schwer für dich.
AVR-GCC-Tutorial

von Drillmaster (Gast)


Lesenswert?

Bernd Hauegg schrieb:
> Kann man das auch mit einzelnen Pins machen?

Da kann man auch selbst draufkommen, wenn man PORTD=PINB; kapiert hat.
Wie wär's mit ein wenig selbständigem Lernen? Macht Spass mit den guten 
Tutorials, die es hier im Forum gibt.

Links dazu? Nee, nee! Auch das kann man leicht selber finden.

von Karl H. (kbuchegg)


Lesenswert?

Drillmaster schrieb:

> Links dazu? Nee, nee! Auch das kann man leicht selber finden.

Sei nicht so streng :-)
Links zum Tutorial oder zum Artikel Bitmanipulation geben wir 
eigentlich immer 'kostenlos' raus.

von Bernd H. (berndy)


Lesenswert?

Vielen Dank euch, für das kleine Ein-Mal-Eins ;-)

von Doppler (Gast)


Lesenswert?

Und noch ein Tip:

Man kann auch mit zwei µC auf einem STK500 experimentieren, natürlich 
in unterschiedlichen Sockeln und unterschiedlichen SPROGx.

von Bernd H. (berndy)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Aber im Grunde läuft es selbst dann auf
>
>    if( Pin_Eingang ist high )
>      Setze Pin_Ausgang auf high
>    else
>      Setze Pin Ausgang auf low
>
>
> hinaus


Ich habe jetzt folgende Abfrage verwendet:
1
PORTD = 0b10101010;  //Ausgangszustand
2
3
while(1){
4
5
if( PINB & (1<<PINB1) == 1){
6
PORTD = 0b11110000;
7
}
8
if( PINB & (1<<PINB1) == 0){
9
PORTD = 0b00001111;
10
}
11
12
}

Interessanterweise komme ich aber in keine der beiden Abfragen in der 
while-Schleife, obwohl über PortB nur "1" gesendet wird.
Was ist an der Abfrage falsch?

von Karl H. (kbuchegg)


Lesenswert?

Das hier

  if( PINB & (1<<PINB1) == 1){

ergibt NICHT 1, wenn der Pin gesetzt ist.

In C ist weniger oft mehr. So auch hier.

  if( PINB & (1<<PINB1) ) {
    ....

  }
  else {
    ....
  }


Das Ergebnis des & muss nicht 1 sein. Es reicht, wenn es nicht 0 ist.
Und genau das macht das if sowieso: Wenn der if Ausdruck einen Wert 
ungleich 0 ergibt, dann wird der then-Zweig genommen, ansonsten der 
else-Zweig


In C gilt

  0            bedeutet logisch "falsch"
  ungleich 0   bedeutet logisch "wahr"

Beachte: ungleich 0!
ungleich 0 ist aber nicht dasselbe wie 1.
Denn 2 ist ungleich 0. Aber 2 ist nicht gleich 1.


Mit deinem Vorsatz, so explizit wie möglich zu sein, hast du dir selbst 
ins Knie geschossen. Denn wenn der Pin B1 auf 1 ist, dann ist das 
Ergebnis von PINB & (1<<PINB1) eine glatte 2 (weil 1<<PINB1 ausgewertet 
den Wert 2 ergibt). Wenn schon explizit, dann müsste man das so 
schreiben

  if( (PINB & (1<<PINB1)) == (1<<PINB1) ) {

Aber: Das wird dann schon wieder aufgrund der Länge unübersichtlich und 
öffnet neue Fehlermöglichkeiten. Die beste Variante ist es daher, auf 
die Variante

  if( (PINB & (1<<PINB1)) != 0 ){

zu setzen und dabei dann auch noch auszunutzen, dass das != 0 sowieso im 
if schon drinnensteckt

  if( PINB & (1<<PINB1) ) {

Hier hat man am wenigsten Möglichkeiten für Fehler ohne dass die 
Klarheit darunter leidet.

von Karl H. (kbuchegg)


Lesenswert?

Nachtrag.

Den Pin hast du auf Eingang belassen?
Denn Pullup hast du eingeschaltet?

von Karl H. (kbuchegg)


Lesenswert?

Ach herrlich.
Deine Anweisung hat noch ein weiteres Problem. Sorry, dass ich das nicht 
gleich bemerkt habe.

Die Operator Precedence ist falsch.

Der COmpiler hat dein

  if( PINB & (1<<PINB1) == 1){

so aufgefasst (ich mach da mal Leerezeichen und zusätzliche Klammern 
rein, damit man besser sieht, worauf ich hinaus will

  if( PINB  &    (  (1<<PINB1) == 1 ) ){

                 ^                  ^
                 |                  |
                 +------------------+

Er hat also den Vergleich falsch rum gruppiert.
Zur Übung kannst du ja mal feststellen, welches Ergebnis das nach sich 
zieht und was das für deine Abfrage bedeutet.
http://www.difranco.net/compsci/C_Operator_Precedence_Table.htm

von Bernd H. (berndy)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Den Pin hast du auf Eingang belassen?
> Denn Pullup hast du eingeschaltet?

Der Pin ist weiterhin auf Eingang.

Wenn der PullUp nicht automatisch über das DDR eingeschaltet wird, dann 
NEIN. Ich wusste gar nicht, dass der PullUp extra eingeschaltet werden 
muss.

Das muss ich dann - wie ich gerade eben gelesen habe - über
1
PORTx = 0xff;  //PullUp an allen PortPins aktivieren
einschalten, richtig?

Die internen (?) PullUps müssten aber ausschließlich auf den Ports 
aktiviert werden, auf denen etwas ausgegeben wird, nicht aber auf dem 
einlesenden Port.

Die Frage ist also, wozu ich die PullUps einschalten muss.

von Karl H. (kbuchegg)


Lesenswert?

Bernd Hauegg schrieb:
> Karl Heinz Buchegger schrieb:
>> Den Pin hast du auf Eingang belassen?
>> Denn Pullup hast du eingeschaltet?
>
> Der Pin ist weiterhin auf Eingang.
>
> Wenn der PullUp nicht automatisch über das DDR eingeschaltet wird, dann
> NEIN. Ich wusste gar nicht, dass der PullUp extra eingeschaltet werden
> muss.

Vergiss es.
Ich war in Gedanken bei Tastern. Du hast ja einen anderen AVR am Pin 
hängen. Passt schon.

von Bernd H. (berndy)


Lesenswert?

Ich habe die if-Abfrage jetzt auf die richtig Antwort geändert.
1
while(1){
2
3
if( PINB & (1<<PINB1) ){  // entspricht != 0
4
 PORTD = 0b11110000;
5
}
6
else{
7
 PORTD = 0b00001111;
8
}
9
10
}


Die Abfrage scheint allerdings invers zu sein, was Ihrer Erklärung 
entgegen spräche.
Karl Heinz Buchegger schrieb:
> if( (PINB & (1<<PINB1)) != 0 ){
>
> zu setzen und dabei dann auch noch auszunutzen, dass das != 0 sowieso im
> if schon drinnensteckt

Nach obigem Code sind wir im "else" sobald der Port auf "high" ist. Wo 
könnte der Fehler sein?

von Karl H. (kbuchegg)


Lesenswert?

Bernd Hauegg schrieb:
> Ich habe die if-Abfrage jetzt auf die richtig Antwort geändert.
>
>
1
> while(1){
2
> 
3
> if( PINB & (1<<PINB1) ){  // entspricht != 0
4
>  PORTD = 0b11110000;
5
> }
6
> else{
7
>  PORTD = 0b00001111;
8
> }
9
> 
10
> }
11
>
>
>
> Die Abfrage scheint allerdings invers zu sein, was Ihrer Erklärung
> entgegen spräche.


Es gibt auch noch eine 2-te Möglichkeit :-)
Ein 1 Bit am PORTD schaltet die LED aus und nicht ein.

Und da die beiden Ausgaben am Port symetrisch sind, kann man diese 
beiden Fälle optisch nicht unterscheiden, wenn man nicht weiß welche 
Portausgabe was macht.

von Bernd H. (berndy)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Und da die beiden Ausgaben am Port symetrisch sind, kann man diese
> beiden Fälle optisch nicht unterscheiden, wenn man nicht weiß welche
> Portausgabe was macht.

d.h. ich kann das "Ergebnis" nur mit einem Oszi überprüfen?

von Karl H. (kbuchegg)


Lesenswert?

Ich schlage mal vor
1
  if( PINB & (1<<PINB1) ){  // entspricht != 0
2
    PORTD = 0b10000000;
3
  }
4
  else{
5
    PORTD = 0b00000010;
6
  }

so. jetzt kann man die beiden Fälle gut unterscheiden. Jeweils 7 LED
sind gleich, nur eine ist anders. je nachdem welche anders ist (damit 
ist
nicht gesagt, dass sie leuchtet oder nicht leuchtet. Sie ist einfach nur
anders), weiß man, ob eine 0 oder eine 1 am PB1 vorliegt. Und die beiden 
Indikator-Led sind so gewählt, dass es keine Verwechslungen geben kann.

> d.h. ich kann das "Ergebnis" nur mit einem Oszi überprüfen?

Bischen mehr Kreativität, wie man mit vorhandenen Mitteln Dinge 
eindeutig machen kann!

von Bernd H. (berndy)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Ich schlage mal vor  if( PINB & (1<<PINB1) ){  // entspricht != 0
>     PORTD = 0b10000000;
>   }
>   else{
>     PORTD = 0b00000010;
>   }

Und wenn ich "PinB1 entspricht 0" abfragen will, kann ich ja nicht
1
if( PINB & (0<<PINB1)
verwenden.

Müsste ich dafür den Ausdruck einfach "negieren"?
1
if( PINB  & ~(1<<PINB1)

Theoretisch müsste das ja funktionieren.

von Karl H. (kbuchegg)


Lesenswert?

Bernd Hauegg schrieb:
> Karl Heinz Buchegger schrieb:
>> Ich schlage mal vor  if( PINB & (1<<PINB1) ){  // entspricht != 0
>>     PORTD = 0b10000000;
>>   }
>>   else{
>>     PORTD = 0b00000010;
>>   }
>
> Und wenn ich "PinB1 entspricht 0" abfragen will, kann ich ja nicht
>
1
if( PINB & (0<<PINB1)
> verwenden.

Nein, kannst du nicht.
eine 0 kann man links und rechts schieben, sooft man will. Das Ergebnid 
ist trotzdem immer wieder einfach nur 0.  0 mal irgendeine Zahl ist 0. 
Egal welche Zahl. Zwischen 0<<PINB1 und 0<<PINB5 gibt es also keinen 
Unterschied. Beides ist nur eine komplizierte Schreibweise für 0.

> Müsste ich dafür den Ausdruck einfach "negieren"?
>
1
if( PINB  & ~(1<<PINB1)

fast

   if( ! (PINB & (1<<PINB1)) )

einfach das Ergebnis der Ausmaskierung umdrehen.

Langform:   if( (PINB & (1<<PINB1)) == 0 )

und da
   if( PINB & (1<<PINB1)
eine Kurzform für
   if( (PINB & (1<<PINB1)) != 0 )
war.

kann man daher die UMkehrung
   if( (PINB & (1<<PINB1)) == 0)
auch so schreiben, dass man den impliziten Vergleich mit 0 als ! 
ausdrückt

   if( !(PINB & (1<<PINB1)) )

man könnte es auch so schreiben

   if( (~PINB) & (1<<PINB1) )
also: Alle Bits vom PINB umdrehen, und dann eine normale Auswertung auf 
nicht 0 machen. Da die Bits in PINB umgedreht wurden, ist das dann 
effektiv keine Auswertung auf ein 1 Bit mehr, sondern auf ein 0 Bit am 
Portpin, welches ja durch das ~ zu einer 1 wurde.


Viele Wege führen nach Rom!
Aber 0<<irgendwas tut es nicht. 0<<irgendwas ist keine sinnvolle 
Operation. Denn egal was 'irgendwas ist' ... das Ergebnis steht fest. Es 
ist wieder 0.

von Karl H. (kbuchegg)


Lesenswert?

> if( PINB  & ~(1<<PINB1)
>
> Theoretisch müsste das ja funktionieren.


Es wird Zeit, dass du dir mal einfach eine Bitbelegung für PINB 
ausdenkst und dann die Operationen am Papier durchspielst.
Im Ernst. Das ist wichtig, dass du dir im klaren darüber bist, was die 
einzelnen OPerationen auf Bitebene machen. Und am Besten ist es immer 
noch: Learning by doing. Aber nicht der µC macht 'doing', sondern >DU< 
machst 'doing' - auf dem Papier mit ganz konkreten Bitwerten.
Es geht nicht darum, dass du weißt, das & eine UND-Operation ist. Das 
ist auswendig gelernt. Es geht darum zu ergründen welchen Effekt (und 
warum) eine bestimmte Operation bzw. eine Kombination von Operationen 
hat! Denn darauf sind wir in der Programmierung aus. Wir wollen einen 
bestimmten Effekt mit einzelnen Bits (und oft: NUR mit ganz bestimmten 
Bits) erreichen. Und dazu muss man seine Operationen in und auswendig 
kennen und wissen, welcher Effekt wie erreicht werden kann.

Wenn du die Fläche eines Rechtecks berechnen musst, dann weißt du ja 
auch, dass du Länge mal Breite rechnen musst. Und nicht Breite plus 
AUssentemperatur. Hast du die Aufgabe zu berechnen, wieviel Dünger du 
für dein Grundstück brauchst, dann ist da eine Kette von Wissen 
involviert, die du anwendest und nicht: Ich muss Multiplizieren um den 
Düngerverbrauch zu berechnen. Das ist zwar nicht falsch, aber das ist 
NICHT das Erstrebenswerte. Erstrebenswert ist, dass du weißt, dass du 
für den Verbrauch die Grundstücksfläche brauchst und das du weißt wie 
man die berechnet. Weiters ist wichtig, dass du den Dreisatz kennst: 
Wenn ich für 1 Quadratmeter soviel Dünger brauche, dann brauche ich für 
x Quadratmeter das x-fache davon. Lach nicht. Für so manchen hier im 
Forum stellt so etwas ein für ihn unlösbares Problem dar. Warum? Weil er 
seine Einzeloperationen nicht kennt und nicht die Phantasie hat, sich 
aus den Einzeloperationen das Komplette zusammenzustellen - und sei das 
eigentlich auch noch so einfach. Das sind dann die Anfragen nach dem 
Muster: Huch, ich muss rechnen! Huch, ich muss mir eine Formel 
ausdenken! Huch, gibts denn da keine fertige Formel dafür?
Und der springende Punkt ist: Wozu brauch ich da eine fertige Formel, 
wenn jeder mit 10 Sekunden nachdenken, sich herleiten kann (weil er die 
Einzeloperationen kennt und weiß, welchen Effekt, welches 
Zwischenergebnis) wie die komplette Operation läuft. Laufen muss.

Und hier ist es nicht anders. Deine Operationen heißen halt nicht Mal, 
Dividiert, Plus, Subtrahieren und Minus. Sondern sie heißen Und, Oder, 
Nicht, jeweils als logische Operation und als Bitoperation und du hast 
Linksschieben und Rechtsschieben (die eigentlich als die Bitoperation 
hinter einer Multiplikation mit 2 bzw. Potenzen davon, aufgefasst werden 
kann). That's it. Aber abgesehen davon, dass das andere Operationen 
sind, besteht da kein Unterschied zu den Grundrechenarten, die du in der 
Grundschaule gelernt hast. Und genauso wie du dort gelernt hast, sie 
anzuwenden und typische Anwendungsfälle zu erkennen, genauso muss man 
das mit diesen Operationen auch machen.

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.