Forum: Mikrocontroller und Digitale Elektronik Reset verhalten MEGA8


von Anton (Gast)


Lesenswert?

Hallo,

ich hätte nochmal eine kurze frage.

Nach drücken der Reset Taste an meinem Mega 8 stellt sich 
unterschiedliches verhalten bezüglich eines LCD dar.
Es ist ein HD447 kompatibles display.

Nach Reset Funktioniert es meist. Leider tritt ab und zu ein Fehler auf, 
sodass das Display initialisiert, aber der Cursor nicht blinkt.
Teilweise bleiben zeichen stehen.


Woran könnte das liegen? Muss das Display ebenso, wie der uc 
ausgeschaltet werden, damit es richtig funktioniert?

Vielen dank

von Klaus D. (kolisson)


Lesenswert?

>> Muss das Display ebenso, wie der uc
>> ausgeschaltet werden, damit es richtig funktioniert?

Na dann sieht man wenigstens die Fehler nicht mehr.


Takt ? Software ? Beschaltung ?

Gruss K

von spess53 (Gast)


Lesenswert?

Hi

Sieht nach einer zu kurzen Wartezeit vor der Initialisierung aus.

MfG Spess

von Peter D. (peda)


Lesenswert?

Unvollständige Initialisierung, Du setzt zu Anfang nicht korrekt in den 
8Bit-Modus zurück. Die Sequenz im Datenblatt enthält nicht umsonst 
"überflüssige" Befehle.

8Bit-Kommandos im 4Bit-Modus oder sogar auf dem falschen Nibble, geht 
schief.


Peter

von Anton (Gast)


Lesenswert?

Okay,

also hier mal der Code für die initialisierung. An Port D habe ich eine 
LED hängen. Damit ich sehe, dass erst ein paar mal geblinkt wird, bevor 
das LCD initialisiert wird.

leider erscheint danach kein cursor.
Trotz beseitigung meines verdrahtungsfehlers.
R/W liegt auf GND.
Aktuell ist der interne 1mhz takt aktiviert (per fuses).

Code:

#include <avr/io.h>
  #define F_CPU 1000000UL
#include <util/delay.h>



int main(void){
int i=0;
DDRC=0xff;
PORTC=0x00;
DDRD=0xff;
PORTD=0b00100000;
for(i=0;i<5;i++){
PORTD^=(1<<5);
_delay_ms(200);
}


PORTC=0b00000011;
_delay_ms(1);
PORTC|=(1<<4);
_delay_ms(1);
PORTC&=~(1<<4);
_delay_ms(100);

PORTC=0b00000011;
_delay_ms(1);
PORTC|=(1<<4);
_delay_ms(1);
PORTC&=~(1<<4);
_delay_ms(50);

PORTC=0b00000011;
_delay_ms(1);
PORTC|=(1<<4);
_delay_ms(1);
PORTC&=~(1<<4);
_delay_ms(50);

/*4 bit*/
PORTC=0b00000010;
_delay_ms(1);
PORTC|=(1<<4);
_delay_ms(1);
PORTC&=~(1<<4);
_delay_ms(50);




/*2 Zeilen*/
PORTC=0b00000010;
_delay_ms(1);
PORTC|=(1<<4);
_delay_ms(1);
PORTC&=~(1<<4);
_delay_ms(50);

PORTC=0b00001000;
_delay_ms(1);
PORTC|=(1<<4);
_delay_ms(1);
PORTC&=~(1<<4);
_delay_ms(50);

/*display aus*/
PORTC=0b00000000;
_delay_ms(1);
PORTC|=(1<<4);
_delay_ms(1);
PORTC&=~(1<<4);
_delay_ms(50);

PORTC=0b00001000;
_delay_ms(1);
PORTC|=(1<<4);
_delay_ms(1);
PORTC&=~(1<<4);
_delay_ms(50);

/*löschen*/
PORTC=0b00000000;
_delay_ms(1);
PORTC|=(1<<4);
_delay_ms(1);
PORTC&=~(1<<4);
_delay_ms(50);
PORTC=0b00000001;
_delay_ms(1);
PORTC|=(1<<4);
_delay_ms(1);
PORTC&=~(1<<4);
_delay_ms(50);

/*cursor rechts shift*/
PORTC=0b00000000;
_delay_ms(1);
PORTC|=(1<<4);
_delay_ms(1);
PORTC&=~(1<<4);
_delay_ms(50);
PORTC=0b00000110;
_delay_ms(1);
PORTC|=(1<<4);
_delay_ms(1);
PORTC&=~(1<<4);
_delay_ms(50);




/*einschalten*/
PORTC=0b00000000;
_delay_ms(1);
PORTC|=(1<<4);
_delay_ms(1);
PORTC&=~(1<<4);
_delay_ms(50);
PORTC=0b00001100;
_delay_ms(1);
PORTC|=(1<<4);
_delay_ms(1);
PORTC&=~(1<<4);
_delay_ms(50);



while(1){
PORTD^=(1<<5);
_delay_ms(1000);

};
return 0;
}

von Karl H. (kbuchegg)


Lesenswert?

Mit dem Code macht es echt keinen Spass, da Fehlersuche zu betreiben.

Das ist ein Spaghetticode erster Güte.
Schau doch mal ins Tutorial, wie man das richtig macht.

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung#Datei_lcd-routines.c:


PS: Nachdem du das LCD auf 4-Bit Modus umgestellt hast, musst du jedes 
Byte (auch die nachfolgenden Konfigurationsbytes) als 2 Nibbles 
übertragen. Ich kann das in deinem Code nicht erkennen, muss aber 
zugeben auch nicht so genau analysiert zu haben.

von Anton (Gast)


Lesenswert?

Hallo, entschuldige bitte,

ich hatte mir erlaubt, das ganze zusammenzufassen.
Hier die Version, die ich zu Anfang hatte.

Darin ist erstmal das Initialisieren enthalten.


#include <avr/io.h>
  #define F_CPU 16000000UL
#include <util/delay.h>
/*PORT B für Display*/
/*R/W auf GND*/

#define EN 4
#define RS 5
#define D4 0
#define D5 1
#define D6 2
#define D7 3

void wartefunktion(void){
_delay_ms(500);


void einschalt_verzoegerung(void){

wartefunktion();

}

void display_loeschen(void){
PORTB=(0<<EN)| (0<<RS)|(0<<D4)|(0<<D5)|(0<<D6)|(0<<D7);
//PORTB=0b00000000;
_delay_us(10);
PORTB|=(1<<EN);
_delay_us(10);
PORTB&=~(1<<EN);
_delay_us(10);

PORTB=(0<<EN)| (0<<RS)|(1<<D4)|(0<<D5)|(0<<D6)|(0<<D7);
//PORTB=0b00000001;
_delay_us(10);
PORTB|=(1<<EN);
_delay_us(10);
PORTB&=~(1<<EN);
_delay_ms(20);
}
void cursor_rechts(){
PORTB=(0<<EN)| (0<<RS)|(0<<D4)|(0<<D5)|(0<<D6)|(0<<D7);
//PORTB=0b00000000;
_delay_us(20);
PORTB|=(1<<EN);
_delay_us(20);
PORTB&=~(1<<EN);

_delay_us(20);
PORTB=(0<<EN)| (0<<RS)|(0<<D4)|(1<<D5)|(1<<D6)|(0<<D7);
//PORTB=0b0000011;
_delay_us(20);
PORTB|=(1<<EN);
_delay_us(20);
PORTB&=~(1<<EN);
_delay_ms(20);
}

void display_ein(void){
PORTB=(0<<EN)| (0<<RS)|(0<<D4)|(0<<D5)|(0<<D6)|(0<<D7);
//PORTB=0b00000000;
_delay_us(20);
PORTB|=(1<<EN);
_delay_us(20);
PORTB&=~(1<<EN);
_delay_us(20);

PORTB=(0<<EN)| (0<<RS)|(1<<D4)|(1<<D5)|(1<<D6)|(1<<D7);
//PORTB=0b00001111;
_delay_us(20);
PORTB|=(1<<EN);
_delay_us(20);
PORTB&=~(1<<EN);
_delay_us(20);
}
void display_aus(void){ //wartezeiten hier wichtig!
PORTB=(0<<EN)| (0<<RS)|(0<<D4)|(0<<D5)|(0<<D6)|(0<<D7);
//PORTB=0b00000000;
_delay_us(20);
PORTB|=(1<<EN);
_delay_us(20);
PORTB&=~(1<<EN);
_delay_us(20);
PORTB=(0<<EN)| (0<<RS)|(0<<D4)|(0<<D5)|(0<<D6)|(1<<D7);
//PORTB=0b00001000;
_delay_us(20);
PORTB|=(1<<EN);
_delay_us(20);
PORTB&=~(1<<EN);
_delay_ms(20);
}

void zwei_zeilig(void){
PORTB=(0<<EN)| (0<<RS)|(0<<D4)|(1<<D5)|(0<<D6)|(0<<D7);
//PORTB=0b00000010;
_delay_us(10);
PORTB|=(1<<EN);
_delay_us(10);
PORTB&=~(1<<EN);
_delay_us(10);
PORTB=(0<<EN)| (0<<RS)|(0<<D4)|(0<<D5)|(0<<D6)|(1<<D7);
//PORTB=0b00001000;
_delay_us(10);
PORTB|=(1<<EN);
_delay_us(10);
PORTB&=~(1<<EN);
_delay_ms(20);
}

void cursor_home(void){
PORTB=(0<<EN)| (0<<RS)|(0<<D4)|(1<<D5)|(0<<D6)|(0<<D7);
_delay_ms(1);
PORTB|=(1<<EN);
_delay_us(1);
PORTB&=~(1<<EN);
_delay_ms(20);

PORTB=(0<<EN)| (0<<RS)|(0<<D4)|(1<<D5)|(0<<D6)|(0<<D7);
_delay_ms(1);
PORTB|=(1<<EN);
_delay_us(5);
PORTB&=~(1<<EN);
_delay_ms(20);
}
void display_init(void){
//DDRB|=(1<<EN) | (1<<RS) | (1<<D4) | (1<<D5) | (1<<D6) | (1<<D7);


/*first*/
PORTB =(0<<EN) | (0<<RS) | (1<< D4)| (1<<D5) | (0<<D6)| (0<<D7);
//PORTB=0b00000011;
_delay_us(10);
PORTB|=(1<<EN);
_delay_us(10);
PORTB&=~(1<<EN);
_delay_ms(40);

/*second*/
PORTB =(0<<EN) | (0<<RS) | (1<< D4)| (1<<D5) | (0<<D6)| (0<<D7);
//PORTB=0b00000011;
_delay_us(10);
PORTB|=(1<<EN);
_delay_us(10);
PORTB&=~(1<<EN);
_delay_ms(20);


/*drei*/
PORTB =(0<<EN) | (0<<RS) | (1<< D4)| (1<<D5) | (0<<D6)| (0<<D7);
//PORTB=0b00000011;
_delay_us(10);
PORTB|=(1<<EN);
_delay_us(10);
PORTB&=~(1<<EN);
_delay_us(10);

PORTB =(0<<EN) | (0<<RS) | (0<< D4)| (1<<D5) | (0<<D6)| (0<<D7);
//PORTB=0b00000010;
_delay_us(10);
PORTB|=(1<<EN);
_delay_us(10);
PORTB&=~(1<<EN);
_delay_us(10);





/*vier*/
zwei_zeilig();
_delay_ms(50);
/*fünf*/
display_aus();
_delay_ms(50);
/*sechs*/
display_loeschen();
/*sieben*/
_delay_ms(50);
cursor_rechts();
/*acht*/
_delay_ms(50);
display_ein();
_delay_ms(50);
}

int main(void){
DDRB=0b00111111;
DDRD=0xff;
PORTB=0x00;

einschalt_verzoegerung();
display_init();

while(1){
};


return 0;
}

von Karl H. (kbuchegg)


Lesenswert?

Anton schrieb:

> ich hatte mir erlaubt, das ganze zusammenzufassen.
> Hier die Version, die ich zu Anfang hatte.


Die ist auch nicht besser, bzw. noch schlimmer.

Schreib das doch erst mal einfacher hin. Kein Mensch hat hier Lust deine 
Bitkonstanten aufzudröseln und sich zusammenzusuchen, was du da 
eigentlich ans LCD schickst, ob du dich vielleicht irgendwo ein Bit 
vergessen hast.

Funktionen einführen, die Bitkonstanten durch was Lesbares ersetzen.
Das Tutorium-Beispiel zeigt dir
  wie man eine lesbare Struktur hinkriegt
  welche Aufteilung in Funktionen bzw. Subfunktionen sinnvoll ist.

von Karl H. (kbuchegg)


Lesenswert?

Du kannst auch mal probieren die Tutorial-Funktionen einfach zu 
übernehmen. Im Header File die Konfiguration anpassen und dann nachsehen 
ob die zuverlässiger laufen. Wenn ja, dann ist es irgendwas in deiner 
Software. Wenn nein, dann wird es wohl deine Hardware sein.

von Karl H. (kbuchegg)


Lesenswert?

PS:
Es muss jetzt natürlich nicht sein, dass dein Code nach der 
Aufräumarbeit stabiler läuft. Aber zumindest ist es einfacher sich davon 
zu überzeugen, dass du da keinen Bock geschossen hast.

von Anton (Gast)


Lesenswert?

Hmm, also ich finde das eigentlich garnicht so schlecht lesbar.

Prinzipiell,

ins port schreiben, enable an/aus, nächster befehl...

von Karl H. (kbuchegg)


Lesenswert?

Anton schrieb:
> Hmm, also ich finde das eigentlich garnicht so schlecht lesbar.

Dann bist du nicht sehr anspruchsvoll

>
> Prinzipiell,
>
> ins port schreiben, enable an/aus, nächster befehl...

Mach dir wenigstens für enable an/aus eine eigene Funktion
1
void enablePuls()
2
{
3
  _delay_us(20);
4
  PORTB|=(1<<EN);
5
  _delay_us(20);
6
  PORTB&=~(1<<EN);
7
}

und schon verkürzt sich der Rest. Zb.:
1
void display_loeschen(void)
2
{
3
  PORTB=(0<<EN)| (0<<RS)|(0<<D4)|(0<<D5)|(0<<D6)|(0<<D7);
4
  //PORTB=0b00000000;
5
  enablePuls();
6
  _delay_us(10);
7
8
  PORTB=(0<<EN)| (0<<RS)|(1<<D4)|(0<<D5)|(0<<D6)|(0<<D7);
9
  //PORTB=0b00000001;
10
  enablePuls();
11
  _delay_ms(20);
12
}
13
14
void cursor_rechts()
15
{
16
  PORTB=(0<<EN)| (0<<RS)|(0<<D4)|(0<<D5)|(0<<D6)|(0<<D7);
17
  //PORTB=0b00000000;
18
  enablePuls();
19
  _delay_us(20);
20
21
  PORTB=(0<<EN)| (0<<RS)|(0<<D4)|(1<<D5)|(1<<D6)|(0<<D7);
22
  //PORTB=0b0000011;
23
  enablePuls();
24
  _delay_ms(20);
25
}
26
27
...

Jetzt bedenken wir noch, dass ein Kommando übertragen IMMER nach dem 
gleichen Muster abläuft: Zuerst das höherwertige Nibble, dann das 
niederwertige Nibble und schreiben dafür auch noch eine Funktion
1
void display_command( uint8_t command )
2
{
3
  PORTB = ( command & 0xF0 );
4
  enablePuls();
5
  _delay_us(20);
6
7
  PORTB = ( command & 0x0F ) << 4;
8
  enablePuls();
9
  _delay_us(20);
10
}

und schon können die Einzelfunktionen schon wieder kürzer und 
übersichtlicher geschrieben werden
1
void display_loeschen(void)
2
{
3
  display_command( 0b00000001 );
4
  _delay_ms(20);
5
}
6
7
void cursor_rechts()
8
{
9
  display_command( 0b00000110 );
10
  _delay_ms(20);
11
}

Für die magischen Konstanten noch ein paar #define
1
#define LCD_COMMAND_CLEAR          0b00000001
2
#define LCD_COMMAND_CURSOR_RIGHT   0b00000110
3
4
void display_loeschen(void)
5
{
6
  display_command( LCD_COMMAND_CLEAR );
7
  _delay_ms(20);
8
}
9
10
void cursor_rechts()
11
{
12
  display_command( LCD_COMMAND_CURSOR_RIGHT );
13
  _delay_ms(20);
14
}

und jetzt vergleich mal deine Funktionen mit dieser letzten Version. 
Welche ist leichter zu lesen und zu verstehen?

Aus 15 Zeilen Code für display_löschen ist ein schicker 2-Zeiler 
geworden, den jeder mit einmal Hinsehen verifizieren kann, solange

   die Konstanten richtig sind
   display_command richtig geschrieben ist.


Und das beste am ganzen: display_löschen ist nicht mehr abhängig davon, 
wie und wo du dein LCD angeschlossen hast. Ändert sich da was, dann ist 
die einzige Stelle die Anpassung benötigt, die Funktion display_command 
bzw. enablePuls. Und die gilt dann automatisch auch für alle anderen 
Kommando-Funktionen.

von Anton (Gast)


Lesenswert?

Okay, da bin ich jetzt überzeugt :)

Ich werde meinen code nochmal überarbeiten.

Nebenher:
Auf meinem Board gibt es zwei steckplätze. Ich habe das Programm jetzt 
mal auf einen Mega 8538 geladen.
es funktioniert.
Das "aufhängen" und stehenlassen von zeichen ist verschwunden.

Anscheindn ist etwas mit der Verdrahtung des Sockels nicht in Ordnung? 
Vielleicht ist auch der Mega8 defekt.

Ich werde morgen einen neuen kaufen. Bis dann programmier ich auf dem 
anderen.

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.