Atmega32 + LCD zeigt nichts an

Ich versuche, ein Programm in C zu schreiben, um Text auf diesem LCD anzuzeigen, aus irgendeinem Grund zeigt es überhaupt nichts an. Ich habe dieses Tutorial auf YouTube befolgt und mein Schulbuch verwendet (ich habe vor kurzem angefangen, Elektrotechnik zu studieren), aber selbst nachdem ich genau kopiert hatte, was da war (außer den Anschlüssen und dem Zeug), funktionierte es immer noch nicht.

Ich hatte gehofft, jemand hier könnte einen kurzen Blick darauf werfen und erkennen, was los ist. Ich weiß nicht mehr, was ich tun soll.

#include <avr/io.h>
#include <util/delay.h>

//These are the DDR and PORT associated with the 8 bits data send/received
#define LCD_DDR             DDRC
#define LCD_PORT            PORTC

//LCD_COMMAND_DDR if you will, so with the three pins Enable/RegisterSelect/ReadWrite
#define LCD_CMD_DDR         DDRD
#define LCD_CMD_PORT        PORTD
#define LCD_CMD_RS          PIND0
#define LCD_CMD_RW          PIND1
#define LCD_CMD_E           PIND2

#define LED_PIN             PIND7

//Just some defenitions to make it easier for me
#define LCD_CLEAR_DISPLAY   0b00000001
#define LCD_CURSOR_HOME     0b00000010
//Enable display/cursor/blink
#define LCD_DISP_ALL        0b00001111
//Set it to 8 bits mode
#define LCD_SET_MODE        0b00111000
// Set Auto-increment noshift
#define LCD_SET_AI_NOSHIFT  0b00000110

void initializeLCD();
void commandLCD(unsigned char d);
void putcLCD(unsigned char c);
void checkIfBusy();
void switchEnable();

int main(void)
{
initializeLCD();

putcLCD(0x41);
putcLCD('A');
putcLCD('L');
putcLCD('L');
putcLCD('O');
}

void initializeLCD()
{
LCD_DDR = 0xFF;
LCD_PORT = 0x00;

LCD_CMD_DDR = 0xFF;
LCD_CMD_PORT = 0x00;

_delay_ms(200);

commandLCD(LCD_SET_MODE);
commandLCD(LCD_DISP_ALL);
commandLCD(LCD_CLEAR_DISPLAY);
commandLCD(LCD_SET_AI_NOSHIFT);
}

void checkIfBusy()
{
    //Set LCD DDR to input
LCD_DDR = 0x00;
    //Set RegisterSelect low so the 'inner registry' is selected (not the characters on the screen)
LCD_CMD_PORT &= ~(1 << LCD_CMD_RS);
    //Set ReadWrite high so I can read data
LCD_CMD_PORT |= 1 << LCD_CMD_RW;

while(LCD_PORT >= 0x80)
{
    switchEnable();
}

    //ReadWrite back to low so I can write to it again
LCD_CMD_PORT &= ~(1 << LCD_CMD_RW);
    //DDR back to output
LCD_DDR = 0xFF;
}

void switchEnable()
{
    //Enable high
LCD_CMD_PORT |= (1 << LCD_CMD_E);
asm volatile ("nop"); //delay a bit (tried it also with _delay_ms(200);
asm volatile ("nop");
    //Enable low
LCD_CMD_PORT &= ~(1 << LCD_CMD_E);
}

void commandLCD(unsigned char d)
{
    //delay untill busyflag is off
checkIfBusy();
    //put command to the port
LCD_PORT = d;
    //set both RegisterSelect and ReadWrite low
LCD_CMD_PORT &= ~((1 << LCD_CMD_RS)|(1 << LCD_CMD_RW));
switchEnable();
    // Clear the port
LCD_PORT = 0x00;
_delay_ms(2);
}

void putcLCD(unsigned char c)
{
    //see if we're done
checkIfBusy();
    // put character to port
LCD_PORT = c;
    //Set ReadWrite low
LCD_CMD_PORT &= ~(1 << LCD_CMD_RW);
    //Set RegisterSelect high
LCD_CMD_PORT |= (1 << LCD_CMD_RS);
switchEnable();
LCD_PORT = 0x00;
_delay_ms(2);
}

Nach der Antwort unten:

int main(void)
{
LCD_DDR = 0xFF;
LCD_PORT = 0x00;

LCD_CMD_DDR = 0xFF;
LCD_CMD_PORT = 0x00;
initializeLCD();

putcLCD(0x41);
}


void initializeLCD()
{
_delay_ms(15);

initCommandLCD(0b00110000);
_delay_ms(5);
initCommandLCD(0b00110000);
_delay_ms(100);
initCommandLCD(0b00110000);
_delay_ms(100);
initCommandLCD(0b00111000);
_delay_ms(100);
initCommandLCD(0b00001000);
_delay_ms(100);
initCommandLCD(0b00000001);
_delay_ms(100);
initCommandLCD(0b00000111);
_delay_ms(100);
}

void checkIfBusy()
{
LCD_DDR = 0;
LCD_CMD_PORT |= 1 << LCD_CMD_RW;
LCD_CMD_PORT &= ~(1 << LCD_CMD_RS);

while(LCD_PORT >= 0x80)
{
    switchEnable();
}

LCD_DDR = 0xFF;
}

void switchEnable()
{
LCD_CMD_PORT |= (1 << LCD_CMD_E);
_delay_ms(2);
LCD_CMD_PORT &= ~(1 << LCD_CMD_E);
}

void initCommandLCD(unsigned char d)
{
LCD_PORT = d;
    LCD_CMD_PORT &= ~((1 << LCD_CMD_RW)|(1 << LCD_CMD_RS));
    switchEnable();
    LCD_PORT = 0;
}

void commandLCD(unsigned char d)
{
checkIfBusy();
    initCommandLCD(d);
}

void putcLCD(unsigned char c)
{
checkIfBusy();
LCD_PORT = c;
LCD_CMD_PORT &= ~(1 << LCD_CMD_RW);
LCD_CMD_PORT |= (1 << LCD_CMD_RS);
switchEnable();
LCD_PORT = 0;
}
Hast du einen Debugger oder ein Oszi? Mein Verdacht fällt auf "LCD_CMD_PORT &= ~(1 << LCD_CMD_RS); LCD_CMD_PORT |= 1 << LCD_CMD_RW;" aber ohne Kommentare ist es schwer zu sagen, was das tun soll.
Es wäre nützlich, Ihren Init-Code zu sehen. Ziehen Sie die Freigabe hoch?
Ich kommentiere den Code, ich habe einen MKRISPII-Programmierer, kein Oszilloskop.
@Samuel mein Init-Code? Es ist da, richtig?
Oh, tut mir leid, ich weiß nicht, wie ich es verpasst habe. Warum aktivieren Sie es und deaktivieren es dann in switchEnable()? Sollte es nicht aktiviert bleiben?
Nun, sowohl im Tutorial als auch in meinem Buch wurde angegeben, dass dies getan werden sollte, nicht wirklich ein Grund. Ich werde versuchen, es zu tun, ohne die Aktivierung zu deaktivieren.
Das Auskommentieren LCD_CMD_PORT &= ~(1 << LCD_CMD_E);in switchEnable hat nicht funktioniert.
@ pjc50 was wäre an diesen Aussagen falsch? Ich habe sie jetzt kommentiert.
Ah, ok, ich kann kein Zeitdiagramm für das LCD finden, aber ich verstehe, was Sie versuchen zu tun. Enable wird die parallelen Daten eintakten. Ich sehe nichts anderes falsch. Ich weiß, dass es nicht viel hilft, aber ich würde einfach die Verkabelung noch einmal überprüfen.
Hmm ich schau nochmal nach, habe es schon 3 mal wieder zusammengesetzt. Trotzdem danke.
EDIT: Meine einzige Schlussfolgerung ist, dass alles richtig verdrahtet ist.
Offensichtliche Überprüfung, die Sie mit einem Multimeter durchführen können: Läuft es überhaupt? Sind die logischen Signale so, wie Sie es erwarten?
@ pjc50 Spannungen sind definitiv wie erwartet. Es kann auch sein, dass das LCD defekt ist, ich habe kein LCD zur Verfügung, um dies zu überprüfen. Morgen habe ich noch eine übrig.
Gibt es einen Grund, warum Sie nicht standardmäßige Binärnotation und nicht Standard-C mit Hex-Notation verwenden?
@Lundin Nein, nur damit ich "sehen" konnte, was es tun würde, war ich mir sicher, dass die Ports, die ich aktiv sein wollte, aktiv waren, da es nicht funktionierte.

Antworten (2)

Ok, ich habe mir das Tutorial-Video angesehen. Ich kann das Datenblatt für den LCD-Treiber nicht finden, also gehe ich nur von dem Beispiel aus, das Sie verlinkt haben. Sie haben ein paar wichtige Unterschiede:

  1. Ihre Befehlssequenz ist nicht in der Reihenfolge des Beispiels. Es ist wichtig, die gleiche Reihenfolge zu haben, da einige Befehle manchmal zwei oder mehr Bytes umfassen.

  2. Sie warten nur 2 µs nach jedem Befehl, im Gegensatz zu nur nach dem LCD_CLEAR_DISPLAY. Der Code aus dem Video und der Webseite zeigt eine Verzögerung von 50 µs nach dem, was Sie den LCD_SET_MODEBefehl und den folgenden Befehl genannt haben.

  3. Sie senden dann einen anderen Befehl LCD_SET_AI_NOSHIFTals 0b00000110, auf der Webseite sendet er einen ähnlichen unbenannten Befehl von 0b00001110.

Versuchen Sie, Ihre Verzögerungszeiten zu erhöhen und dieselbe Befehlssequenz wie im Beispiel zu senden.

Ich hoffe, das löst Ihr Problem.

EDIT: Ah, habe das Datenblatt gefunden . Außerdem stelle ich fest, dass Sie zwischen den Befehlen nach beschäftigt suchen. Der Set-Mode-Befehl 0b00000110dauert 37 µs, aber das sollte wegen der Überprüfung in Ordnung sein. Das Datenblatt sagt jedoch, dass das Busy-Flag nicht überprüft werden kann, bevor der Set-Mode-Befehl gesendet wird und einige ms danach. Überprüfen Sie Seite 45 des verlinkten Datenblatts für die Initialisierungsroutine. Versuchen Sie, die Verzögerungen fest zu codieren, während sie geschrieben sind, und sehen Sie, ob es immer noch nicht funktioniert.

1. Ich habe alles noch einmal überprüft und einige Fälle gefunden, in denen dies passiert ist (ich habe das BipolarMood-Zeug satt: P), keine Lösung. Ich habe meinen Code praktisch gleich gemacht. (auch die Verzögerungszeiten) 2. Eigentlich warte ich nach jedem Befehl 2 ms. 3. Ich habe versucht, genau die gleichen Dinge zu senden wie er, aber es ist nichts passiert. Danke :)
Vielen Dank! Ich habe das Datenblatt ausgecheckt und alles aufgeschrieben, was sie als Initialisierung angegeben haben. Ich werde meinen Beitrag mit dem neuen Code aktualisieren, es funktioniert jedoch immer noch nicht.
Ich möchte hinzufügen, dass das Datenblatt auch besagt, dass die interne Reset-Schaltung das LCD für Sie initialisiert, wenn die Stromversorgungsbedingungen erfüllt sind. (S.59) Da meine Vcc gleich 5V ist, kann ich davon ausgehen, dass die interne Initialisierung funktioniert?
Dies scheint der Fall zu sein, es wird auf S.23 näher beschrieben. Versuchen Sie vielleicht, einfach den Befehl zu schreiben, um das LCD einzuschalten, gefolgt von einigen Zeichen? Stellen Sie die Uhr für den Atmega32 irgendwo ein oder ist sie standardmäßig auf 1 MHz eingestellt?
Der Takt ist standardmäßig auf 1 MHz eingestellt. Und Sie meinen so etwas?: _delay_ms(15); putcLCD('A');Soweit ich weiß, gibt es keinen Befehl zum Einschalten des LCD
Ja, Sie verwenden den Befehl bereits. Es ist 0x0Ffür LCD an, Cursor an und Blinken an (S.24).

Ich musste JTAG oben in meinem Main deaktivieren:

MCUCSR = (1<<JTD);
MCUCSR = (1<<JTD);

Es funktioniert jetzt, mein Code ist gut, ich muss mein LCD nicht manuell initialisieren. Löschen Sie einfach den Bildschirm und optionale Befehle.

Endgültiger Code:

#include <avr/io.h>
#include <util/delay.h>
#include <math.h>

#define LCD_DDR             DDRC
#define LCD_PORT            PORTC

#define LCD_CMD_DDR         DDRD
#define LCD_CMD_PORT        PORTD
#define LCD_CMD_RS          PIND0
#define LCD_CMD_RW          PIND1
#define LCD_CMD_E           PIND2

#define LED_PIN             PIND7

void initializeLCD();
void commandLCD(unsigned char d);
void putcLCD(unsigned char c, unsigned char c1);
void checkIfBusy();
void switchEnable();
void putsLCD();
void lcdNewLine();
void resetLCD();

int currentLine = 0;
int currentChar = 0;

int main(void)
{
MCUCSR = (1 << JTD);
MCUCSR = (1 << JTD);

LCD_DDR = 0xFF;
LCD_PORT = 0x00;

LCD_CMD_DDR = 0xFF;
LCD_CMD_PORT = 0x00;

initializeLCD();

while(1)
{
    putsLCD("Printstuff");
    _delay_ms(3000);
}
}

void initializeLCD()
{
_delay_ms(15);

commandLCD(0x01);
commandLCD(0b00111100);
}

void checkIfBusy()
{
LCD_DDR = 0x00;
LCD_CMD_PORT |= 1 << LCD_CMD_RW;
LCD_CMD_PORT &= ~(1 << LCD_CMD_RS);

while(LCD_PORT >= 0x80)
{
    switchEnable();
}

LCD_DDR = 0xFF;
}

void switchEnable()
{
LCD_CMD_PORT |= (1 << LCD_CMD_E);
_delay_ms(2);
LCD_CMD_PORT &= ~(1 << LCD_CMD_E);
}

void commandLCD(unsigned char d)
{
checkIfBusy();
LCD_PORT = d;
LCD_CMD_PORT &= ~((1 << LCD_CMD_RW)|(1 << LCD_CMD_RS));
switchEnable();
LCD_PORT = 0;
}

void putcLCD(unsigned char c, unsigned char c1)
{
if(c == '\n')
{
    lcdNewLine();
    return;
}

if (currentChar >= 20 && c != ' ' && c1 != ' ' && c1 != '\0')
{
    currentChar = 0;
    putcLCD('-', ' ');
    lcdNewLine();
}

if (c == ' ' && currentChar == 1)
return;

checkIfBusy();
LCD_PORT = c;
LCD_CMD_PORT &= ~(1 << LCD_CMD_RW);
LCD_CMD_PORT |= (1 << LCD_CMD_RS);
switchEnable();
LCD_PORT = 0x00;
currentChar++;
}

void resetLCD()
{
checkIfBusy();
commandLCD(0x01);
currentChar = 1;
currentLine = 1;
}

void lcdNewLine()
{
char line = 20;
switch(currentLine)
{
    case 1:
    line *= 2;
    break;
    case 2:
    line *= 1;
    break;
    case 3:
    line *= 4.2;
    break;
}

line += 0b10000000;
checkIfBusy();
commandLCD(line);
currentLine += 1;
currentChar = 1;
}

void putsLCD(unsigned char *s)
{
checkIfBusy();
resetLCD();
int maxCount = strlen(s);

int i;
for(i = 0; i < maxCount; i++)
{
    if(s[i] == '\0')
    break;

    char arg2 = ' ';
    if(i + 1 < maxCount)
    arg2 = s[i + 1];

    putcLCD(s[i], arg2);
}
}
Ah, gut zu hören. Ich nehme an, dass es hilfreich wäre, den gesamten Code in die Zukunft aufzunehmen. Vielen Dank für das Nachfassen.
Ich werde in einer Stunde oder so, gerade nach Hause gekommen, schnell gepostet, während ich in der Schule war.