PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Verständnisproblem #define



Arkon
23.01.2012, 14:02
Moin,

ich spiele grade mit einem Mega8 und einem L298N rum um zwei Motoren anzusteuern.

Ich versuche dabei das Prinzip (in Hard- wie Software) vom einem vorhandenen Board / Programm nachzuvollziehen.

Verdrahtet ist der L298N wie folgt mit dem Mega8 (nur Logik):

L298N -> Mega8

IN1 -> PB5
IN2 -> PB4
ENA -> PB2 (OC1B)

IN3 -> PD4
IN4 -> PD5
ENB -> PB1 (OC1A)

Die Drehrichtung wird ja über H(igh) und L(ow) an den Input(IN)-Pins vorgegeben. Über die PWM-Pins an ENA und ENB wird die Geschwindigkeit geregelt. Die Geschwindigkeit funktioniert auch und wurde auch von mir verstanden. Aber bei der Richtungswahl komme ich grade nicht weiter:

Die Funktion dafür sieht wie folgt aus (wurde scheinbar vom Asuro adoptiert)



void MotorDir(unsigned char left_dir, unsigned char right_dir)
{
PORTD = (PORTD &~ ((1 << PD4) | (1 << PD5))) | left_dir;

PORTB = (PORTB &~ ((1 << PB4) | (1 << PB5))) | right_dir;
}

Beim Funktionsaufruf werden “Schlüsselwörter” übergeben (FWD,RWD,BREAK,FREE) welche wie folgt definiert werden:



#define FWD (1 << PB5) /* (1 << PD5) */
#define RWD (1 << PB4) /* (1 << PD4) */
#define BREAK 0x00
#define FREE (1 << PB4) | (1 << PB5) /* (1 << PD4) | (1 << PD5)*/

So viel zur Theorie und den Grundlagen. Mein Problem ist jetzt folgendes:

Um die Drehrichtung zu bestimmen wird einer der beiden IN-Pins pro Motor auf H der andere auf L gezogen (BREAK und FREE mal außen vor). Da aber die Pins PD4 und PD5 in der Definition auskommentiert sind, werden diese doch bei einem Funktionsaufruf gar nicht geändert, bzw. ein



MotorDir(FWD,FWD);


würde doch ein



PORTD = (PORTD &~ ((1 << PD4) | (1 << PD5))) | (1<<PB5);


erzeugen.


Wie ist es jetzt also Möglich, dass mit dem Aufruf der Funktion die Pegel von PD4 und PD5 beeinflusst werden?
Haben die /* */ hinter einem #define vielleicht eine andere Wirkung als das auskommentieren des dazwischen befindlichen Codes?

markusj
23.01.2012, 14:11
Auskommentiert ist der zweite Teil, weil PD5 gleich PB5 gilt (ist beides Mal die Zahl 5). Damit kann das gleiche Makro sowohl für die Richtung links als auch rechts verwendet werden.

Was der Code macht ist relativ einfach: Er löscht erst beide Richtungsbits auf einer Seite und setzt dann die von dir übergebenen, im Falle von FWD also Pin 5 am jeweiligen Port.

mfG
Markus

Arkon
23.01.2012, 14:15
Also wird unterschieden, ob PORTD oder PORTB beschrieben werden soll und dazu passend aus dem #define das PD5 bzw PB5 ausgewählt?

sternst
23.01.2012, 14:19
Also wird unterschieden, ob PORTD oder PORTB beschrieben werden soll und dazu passend aus dem #define das PD5 bzw PB5 ausgewählt?Nein, im Define ist es immer PB5. Aber PD5 und PB5 sind einfach beide das Gleiche, nämlich einfach 5.

PORTD = 1<<PD5;
PORTD = 1<<PB5;
PORTD = 1<<5;Alle drei Zeilen sind völlig identisch.


PS: Ist aber schlechter Programmierstil, weil verwirrend (wie man sieht).
Ich hätte es eher so geschrieben:
#define FWD (1 << 5) /* PD5,PB5 */

markusj
23.01.2012, 14:24
Also wird unterschieden, ob PORTD oder PORTB beschrieben werden soll und dazu passend aus dem #define das PD5 bzw PB5 ausgewählt?
Nein, sieh dir Mal den Code hier genauer an:



#define FWD (1 << PB5) /* (1 << PD5) */
#define RWD (1 << PB4) /* (1 << PD4) */
#define BREAK 0x00
#define FREE (1 << PB4) | (1 << PB5) /* (1 << PD4) | (1 << PD5)*/

void MotorDir(unsigned char left_dir, unsigned char right_dir) {

PORTD = (PORTD &~ ((1 << PD4) | (1 << PD5))) | left_dir;

PORTB = (PORTB &~ ((1 << PB4) | (1 << PB5))) | right_dir;
}

MotorDir(FWD,FWD);

PB5 wird irgendwo in den Untiefen der avr-libc als 5 definiert, ebenso PD5. Warum? Weil es eben das Bit 5 im entsprechenden Register ist. Der Trick besteht einfach darin, dass die Pinbelegung für Links/Rechts symmetrisch gemacht wurde, damit sind alle Konstanten übertragbar. Aus FWD wird also (1 << 5)

MotorDir setzt jetzt auf beiden Seiten beide Richtungspins auf 0 und "verodert" da dann dein FWD rein. Die Funktion überschreibt also IMMER den Status beider Seiten, MotorDir(FWD, FWD) tut nichts anderes als in den Register PORTD und PORTB jeweils Bit 5 zu setzen. Der Konstanten ist es vollkommen egal, wo sie eingesetzt wird, niemand wählt da irgendwas aus ...

mfG
Markus

Arkon
23.01.2012, 14:28
Ah jetzt ja.....

Danke an euch. Hab den Code wie sternst gepostet hat geändert. So macht das auch wieder Sinn :)

radbruch
23.01.2012, 14:28
Hallo

Wenn dein Programm io.h includet, dann sucht der Kompiler nach der zum Kontroller passenden io-Datei:

C:\WinAVR\avr\include\avr\iom8.h

Und in dieser Datei findest du die Defines für PB5 und PD5.
(Da findet man auch die schwer zu merkenden ISR-Namen)

Gruß

mic

"wurde scheinbar vom Asuro adoptiert" Quelle des Programms?

Arkon
23.01.2012, 14:49
wurde scheinbar vom Asuro adoptiert" Quelle des Programms?

Jemand an unserer Hochschule hat das Board und das Programm dazu geschrieben. War vor 2 oder 3 Jahren bei einem Wettkampf an der FH im Einsatz. Wurde dann durch ein neues, komplexeres Board ersetzt (dass ich auch für meinen Low-Cost-Bot verwende). Ich konnte halt ein paar "Restbestände" abgreifen.

Arkon
24.01.2012, 09:38
Nachtrag:

Kann mir noch jemand erklären, warum bei MotorDir(FREE,FREE); die Motoren frei drehen?

Um dies zu erreichen muss der Enable-Pin des jeweiligen Motors auf LOW gezogen werden. Das wären ja die beiden PWM-Pins OC1A und OC1B bzw. PB2 und PB3.

Nach meinem, scheinbar fehlerhaften, Verständnis wird ja so der PORTD bzw. PORTB komplett auf LOW gezogen. Davon unbeeindruckt dürfte doch aber die PWM-Einstellung sein wordurch die Enable-Pins nicht (dauerhaft) auf LOW gezogen werden.

markusj
24.01.2012, 12:39
Negativ, FREE setzt jeweils die Pins 4 und 5 auf HIGH. Die beiden High-Side Transistoren werden also ausgeschaltet, die beiden Low-Side Transistoren werden durch das PWM beeinflusst. Der Stromfluss setzt sich aber unabhängig von den Low-Side Transistoren durch die Freilaufdioden fort, der Motor wird relativ wenig abgebremst. Bei BREAK wird dagegen der Stromfluss abgebremst, da VCC bei den High-Side Transistoren durchgeschaltet wird, der Stromfluss durch die beiden unteren Freilaufdioden aber eigentlich in die entgegengesetzt Richtung läuft.

mfG
Markus