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
intmain(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
intmain(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
>> 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
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.
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.
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?
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.
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
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.
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.
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?
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.
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?
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!
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"?
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.
> 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.