Forum: Mikrocontroller und Digitale Elektronik ATMEGA 32 Port als Eingang und als Ausgang


von Patrick N. (gnr1993)


Lesenswert?

Hallo Liebes Forum,

ich sitze momentan an einem kleinen Projekt. Dieses soll unter anderm 
ein LCD Display erhalten 
(http://www.reichelt.de/LCD-Module-DIP-Anschluss/LCD-162-DIP/index.html?;ACTION=3;LA=2;ARTICLE=44903;GROUPID=3009;SID=11Th2Htn8AAAIAAGC37UA583d34fa1d7eea237f05d23b8e140395). 
In diesem Tutorial 
(http://www.mikrocontroller.net/articles/AVR-Tutorial:_LCD) habe ich 
gelesen, dass man durch Setzen oder nicht setzen von RW unter anderem 
das Busy Flag auslesen kann. Das kommt ja, wenn man das LCD im 8bit 
betrieb laufen lässt auf Port7 des LCD. Ich würde das LCD auch gerne im 
8bit Modus laufen lassen, da ich nicht so viele Ports brauche, und es 
somit auch schneller sein sollte (oder irre ich mich da ? ) auf 
jedenfall angenehmer anzusteuern :D. Das ganze soll in GCC programmiert 
werden. Meine frage nun: wie kann ich einen Port in GCC als Ausgang und 
als Eingang (gleichzeitig benutzen) ??. Durch DDRC = 0xFF setze ich ja 
alle ports als ausgang (oder verwechsel ich das gerade ?? ).

Habe einen kleinen Code ausschnitt (ich denke aber er ist falsch ^^ aber 
keine Ahnung, wie er richtig sein sollte ...)

LCD DDR wird vorher auf 0xFF gesetzt.
static void lcd_enable( void )
{
    LCD_PORT |= (1<<LCD_EN);     // Enable auf 1 setzen
    while(LCD_PORT != 0x80)  // Auf Busy flag Warten
    LCD_PORT &= ~(1<<LCD_EN);    // Enable auf 0 setzen
}

MfG GnR1993

wenn meine Fragestellung unklar ist, dann schreibt das bitte ;) .. und 
auch bitte was ihr nicht versteht, damit ich euch die fehlenden 
Informationen geben kann.

Danke schonmal im vorraus ;)

von Thomas (kosmos)


Lesenswert?

LCD ist beui mir schon etwas her. Weiß also deswegen gerade nicht ob es 
eine extra Busy-Leitung hatte, wenn nicht musst du halt nach absenden 
deiner Befehle den Portpin als Eingang umschalten.

Ich programmiere ja in Assembler und habe mir für solche Zwecke die 
binäre Schreibweise angewöhnt. Da man da gleich sieht wie die Pins 
geschalten sind, bei hex ist halt nur FF und 00 und bei dez 255 und 0 
auf den ersten Blick eindeutig.

ldi temp, 0b11111111
out DDRC, temp        ;Alle PortC Pins als Ausgang

Befehle und Daten verschicken

ldi temp, 0b01111111  ;PinC7 als Eingang Rest Ausgang
out DDRC, temp

Auf busy prüfen

danach Port wieder als Ausgang umschalten

von ... (Gast)


Lesenswert?

Für den GCC wäre das Tutorial passender:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung

Wegen dem RW, schau Dir mal die LCD-Lib von Peter Fleury an:
http://homepage.hispeed.ch/peterfleury/avr-software.html#libs
Bei der wird auch vom LCD gelesen.

von Klaus W. (mfgkw)


Lesenswert?

Erstens kannst du nicht gleichzeitig Ports als Eingang und Ausgang 
setzen. Zweitens brauchst du das auch gar nicht: nur solange du etwas 
ausgibst, muß man mit DDR... auf Ausgang setzen, solange du etwas 
einliest als Eingang.

Drittens kannst du nicht nur alleine das BUSY abfragen; du musst 
vielmehr per DDR... alle Datenbits als Eingang setzen, RS auf 0, RW auf 
1, EN auf 1 und damit liest du alle 8 Datenbit.
Davon interessiert dich nur BUSY, damit kannst du machen was du willst 
und vor dem nächsten Schreiben musst du wieder DDR... auf Ausgang 
aetzen.

von Patrick N. (gnr1993)


Lesenswert?

Danke für die ganzen schnellen Antworten (echt gute Community :P )
@ ...: Ja, das Tutorial habe ich gelesen, aber es benutzt 4Bit und warte 
Zeiten ;) ich will mir aber die Warte Zeiten sparen und das ganze über 
Busy machen :P

@Klaus: klar,  will ja nicht den anderen ports nen High Pegel geben und 
dann nur von einem lesen ;), will ja nicht mein LCD zerstören :D ...

also muss ich das ganze dann wahrscheinlich so machen:

(LCD an Port C , RW, RS und E auf Port A)

C-Code:
1
#define LCD_PORT      PORTC
2
#define LCD_DDR       DDRC
3
#define LCD_ADD_PORT  PORTA
4
5
6
static void lcd_enable( void )
7
{
8
    
9
    LCD_ADD_PORT |= (1<<LCD_EN) | (1<<LCD_RW)   ;     // Enable auf 1 setzen
10
    LCD_DDR = 0b00000000;
11
    while(LCD_PORT != 0b10000000);  // Auf Busy flag Warten
12
    LCD_ADD_PORT &= ~(1<<LCD_EN);    // Enable auf 0 setzen
13
14
}
15
16
//Dann wäre ja hier alle meine LCD datenbytes auf READ, oder?
17
//Und wenn ich dann schreiben will, würde ja folgendes kommen:
18
19
void lcd_command( uint8_t data )
20
{
21
    LCD_ADD_PORT &= ~(1<<LCD_RS);    // RS auf 0 setzen
22
    LCD_ADD_PORT &= ~(1<<LCD_RW);    // RW auf 0 setzen
23
    LCD_DDR = 0b11111111;
24
    lcd_out( data );             // Bits Senden
25
    LCD_DDR = 0b00000000;
26
    LCD_ADD_PORT |= (1<<LCD_RW);
27
    while(LCD_PORT != 0b10000000);  // Auf Busy flag Warten
28
29
}

So müsste das ganze doch aussehen, oder?

@Thomas ;) ich persönlich komm mit der Umrechnung absolut klar :D is ja 
auch eigentlich simpel :D .. maximal F und 0001 is ja ne eins 0010 ne 2 
und sow weiter ;) und wenn man die dann addiert, hat man das gesamte :D
PS: ich weiß auch, dass du das wahrscheinlich wusstest :P

MfG
GnR1993

von Thomas (kosmos)


Lesenswert?

und eine hex53? Hand aufs Herz auf den ersten Blick erkennt man das nur 
in Binär welcher Portpin was macht.

von Karl H. (kbuchegg)


Lesenswert?

Patrick Nies schrieb:
> Danke für die ganzen schnellen Antworten (echt gute Community :P )
> @ ...: Ja, das Tutorial habe ich gelesen, aber es benutzt 4Bit und warte
> Zeiten ;) ich will mir aber die Warte Zeiten sparen und das ganze über
> Busy machen :P

Macht aber im Endeffekt keinen bis kaum einen Unterschied. Denn das 
lesen des Busy Bits gibts nun mal nicht gratis (= kostet auch Zeit).

Und Hand aufs Herz. Auch mit Warten kannst du immer noch schneller aufs 
LCD schreiben, als irgendein Mensch lesen kann.

von Andreas W. (geier99)


Lesenswert?

Thomas O. schrieb:
> und eine hex53? Hand aufs Herz auf den ersten Blick erkennt man das nur
> in Binär welcher Portpin was macht.

na ja, nicht wirklich Hex ist bei mir ins Blut gegangen und die Bits 
habe ich sofort vor den Augen ohne nachzudenken.
Bei den vielen Einsen und Nullen würde ich mich bloss verzählen:-)

z.B finde ich:   0xAFFE
viel besser zu lesen als:
                 0b1010111111111110

von Karl H. (kbuchegg)


Lesenswert?

>
1
> static void lcd_enable( void )
2
> {
3
>    
4
>    LCD_ADD_PORT |= (1<<LCD_EN) | (1<<LCD_RW)   ;     // Enable auf 1 setzen
5
>    LCD_DDR = 0b00000000;
6
>    while(LCD_PORT != 0b10000000);  // Auf Busy flag Warten
7
>    LCD_ADD_PORT &= ~(1<<LCD_EN);    // Enable auf 0 setzen
8
>
9
>}

nochmal drüber nachdenken.
Wie liest du denn vom LCD, wenn du gerade mitten drinn bist, den Enable 
Puls an das LCD zu geben, mit dem du eine Datenkommunikation auf den Weg 
bringst? Ausserdem steht dein Port immer noch auf Eingang, da wird dann 
das löschen des LCD_EN Flags nicht so toll kommen.

Wenn du schon auf das Busy Bits warten willst, dann so:
Abfrage ob das LCD Busy ist, BEVOR du eine neue Aktion am LCD machst 
(clear screen, zeichen ausgeben, etc...) nicht danach. Dein Programm 
macht ja in der Zwischenzeit weiter und kann dan andere Dinge tun, als 
auf das Busy Bit zu warten. Erst wenn du das nächste mal etwas vom LCD 
willst, muss das LCD mit seiner vorhergehenden Aktion fertig sein.

von Klaus W. (mfgkw)


Lesenswert?

Davon abgesehen prüft LCD_PORT != 0b10000000 nicht, ob das Busy gesetzt 
ist, sondern ob (Busy gesetzt && alle anderen gleich Null sind).

Wenn man nur das Busy testen will, müsste man etwa mit 
0!=(LCD_PORT&0b10000000) prüfen, oder 
((LCD_PORT&0b10000000)==0b10000000).

von Andreas (Gast)


Lesenswert?

Hallo Patrick,

ich kann zwar nur Assembler, aber was mir auffällt

1) Beim Lesen muss man nicht PORTx abfragen sondern PINx (eventuell ist 
das in C aber anders)

2) Das Lesen des Ports(PINx) muss in der Zeit zwischen Enable(High) und 
Enable(Low) erfolgen, d.h. die Enable-Umschaltung muss Teil deiner 
While-Schleife werden. In Assembler fügt man vorsichtshalber noch zwei 
Wartetakte ein (hängt vom Systemtakt ab)
Etwa so...
> DDRC auf Eingang
> RW-Bit setzen
> RS-Bit löschen
(Schleifenbeginn)
> Enable auf High schalten
> nop
> nop
> PINC lesen (nur MSB interessiert)
> Enable auf Low schalten
> Wiederhole, bis MSB=0
(Schleifenende)
(Jetzt kann DDRC wieder auf Ausgang gesetzt werden)

Ich hoffe der programmiersprachenfreie Algorithmus ist verständlich :)

Gruß Andreas

von Thomas (kosmos)


Lesenswert?

1
busy:
2
in temp, pina
3
sbic pina, 7
4
rjmp busy

so sieht bei mir die Busy Schleife aus, da ich bei dem Programm nicht 
viel zu tun habe wird läufts ohne Interrupts. Muss man halt auf den Port 
und den entsprechenden Pin ändern

von Andreas (Gast)


Lesenswert?

Hallo Patrick!

Konntest Du dein Projekt erfolgreich abschließen oder bist Du noch in 
der Umsetzung?

Es wäre schön hier noch einmal den erfolgreichen Lösungsansatz 
nachvollziehen zu können.

Es wird sicher auch in Zukunft Ratsuchende geben, die dankbar sind, wenn 
sie beim Suchen eine funktionierende Problemlösung finden ;-)

Gruß Andreas

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.