- 12V Akku mit 280 Ah bauen         
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 12

Thema: C-Schönheiten (C18) und LC-Display

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    18.05.2006
    Alter
    36
    Beiträge
    150

    C-Schönheiten (C18) und LC-Display

    Anzeige

    LiFePo4 Akku selber bauen - Video
    Hallo!

    Ich versuche schon länger ein LC-Display anzusteuern, aber es funktioniert nicht. Ich hab da zwar einen Initialisierungscode programmiert, aber der funktioniert anscheinend nicht. Leider kann ich jetzt nicht den Code mitschicken, kommt erst später.

    Aber ich versuche auch ein wenig Ordnung da reinzubringen. Da hab ich was im Netz gefunden, womit man Bits Namen geben kann. Das sah so aus:

    z.B:

    Code:
    #pragma char LCD_CTRL		@ PORTB
    
    Bit LCD_RS			@ PORTB.1;
    Leider hat der Compiler (C1 nur den ersten Teil verstanden. Aber die direkte Bit-Zuweisung hat nicht funktioniert. Was hab ich falsch gemacht? Bzw. Wie kann ich das anders oder besser machen?

    Liebe Grüße,
    Norbert

  2. #2
    Benutzer Stammmitglied
    Registriert seit
    05.06.2007
    Ort
    Dortmund
    Alter
    33
    Beiträge
    42
    Hi,

    ich habe ebenfalls ein Problem ein LCD mit einem 18F4550 anzusteuern. Ich arbeite erst seit kurzem mit den 18ern. Compilieren tue ich ebenfalls mit C18. Hier mal der fürs LCD relevante Code:

    Code:
    //Überprüfe LCDStatus
    void waitForLCD(void)
    {
    	//Steuerleitungen einstellen
    	LATE |= 0b00000010; //RW
    	LATE &= 0b11111011; //RS
    
    	//RD4..7 Inputs
    	LATD &= 0b00001111;
    	TRISD = 0xFF;
    	
    	//Busyschleife
    	cBusy = 0x80;
    	do
    	{
    		LATE |= 0b00000001;
    		Delay1TCY();
    		cBusy = PORTD;
    		LATE &= 0b11111110;
    		Delay1TCY();
    		LATE |= 0b00000001;
    		Delay1TCY();
    		LATE &= 0b11111110;
    	}while((cBusy & 0b10000000) != 0x00);
    
    	//Leitungen zurücksetzen
    	LATE &= 0b11111001; //RW, RS
    	TRISD = 0x0F;
    	LATD &= 0b00001111;
    
    	return;	
    }
    
    //Übertrage Steuerdaten an LCD
    void sendCWToLCD(char cWord)
    {
    	//Busy-Check
    	waitForLCD();
    
    	//Steuerleitungen einstellen
    	LATE &= 0b11111000;
    	
    	//Übertragen der Bits 4..7
    	LATD &= 0b00001111;
    	LATD |= cWord & 0b11110000;
    	LATE |= 0b00000001;
    	Delay1TCY();
    	LATE &= 0b11111110;
    
    	//Übertragen der Bits 0..3
    	LATD &= 0b00001111;
    	LATD |= (cWord & 0b00001111) << 4;
    	LATE |= 0b00000001;
    	Delay1TCY();
    	LATE &= 0b11111110;
    }
    
    //Übertrage Daten an LCD
    void sendDWToLCD(char cWord)
    {
    	//Busy-Check
    	waitForLCD();
    
    	//Steuerleitungen einstellen
    	LATE &= 0b11111100; //RW
    	LATE |= 0b00000100; //RS
    	
    	//Übertragen der Bits 4..7
    	LATD &= 0b00001111;
    	LATD |= cWord & 0b11110000;
    	LATE |= 0b00000001;
    	Delay1TCY();
    	LATE &= 0b11111110;
    
    	//Übertragen der Bits 0..3
    	LATD &= 0b00001111;
    	LATD |= (cWord & 0b00001111) << 4;
    	LATE |= 0b00000001;
    	Delay1TCY();
    	LATE &= 0b11111110;
    
    	LATE &= 0b11111011; //RS
    }
    
    //Initialisierung des LCD
    void initLCD(void)
    {
    	//15ms Warten
    	Delay10KTCYx(10);
    
    	//Sende Init-Byte (1)
    	LATD &= 0b00001111;
    	LATD |= 0b00110000;
    	LATE |= 0b00000001;
    	Delay1TCY();
    	LATE &= 0b11111110;
    
    	//5ms Warten
    	Delay10KTCYx(5);
    
    	//Sende Init-Byte (2)
    	LATD &= 0b00001111;
    	LATD |= 0b00110000;
    	LATE |= 0b00000001;
    	Delay1TCY();
    	LATE &= 0b11111110;
    
    	//100us Warten
    	Delay100TCYx(10);
    
    	//Sende Init-Byte (3)
    	LATD &= 0b00001111;
    	LATD |= 0b00110000;
    	LATE |= 0b00000001;
    	Delay1TCY();
    	LATE &= 0b11111110;
    
    	Delay100TCYx(10);
    
    	//4-bit
    	LATD &= 0b00001111;
    	LATD |= 0b00100000;
    	LATE |= 0b00000001;
    	Delay1TCY();
    	LATE &= 0b11111110;
    	
    	Delay100TCYx(10);
    
    	//Display löschen
    	sendCWToLCD(0b00000001);
    	
    	//4-bit Interface und 5x8 Matrix
    	sendCWToLCD(0b00101000);
    
    	//Display aus
    	sendCWToLCD(0b00001000);
    
    	//Cursorrichtung rechts, Shift aus
    	sendCWToLCD(0b00000010);
    
    	//Display ein
    	sendCWToLCD(0b00001100);
    }
    Pinbelegung:

    D4..7 -> RD4..7
    E -> RE0
    RW -> RE1
    RS -> RE2

    Nur damit ihr euch nicht wundert: An RD0..3 sind Eingänge für ne Tastermatrix.

    Wenn ich das Programm laufen lasse passiert nix. Das Display zeigt nix bzw. bei runtergedrehter Kontrastspannung schwarze Kästen an, als wäre es nicht initialisiert.

    mfg The Scientist

  3. #3
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    18.05.2006
    Alter
    36
    Beiträge
    150
    Hallo!

    So Leute, ich hab jetzt den Code.

    Hier kommt er:

    Code:
    	wait_ms(50);
    			   
     
    	   TRISA = 0b00111111;     //PORT A wird als Eingang gesetzt, bis auf die RA6(OSC für Oszillator verwendet) (RA7 gibt es nicht)
    	   TRISB = 0b00000000;     //Port B wird als Ausgang gesetzt
    	   TRISC = 0b11000000;     //PORT C wird als Ausgang gesetzt nur die RC6 und RC7 werden als Eingang gesetzt, für meine beiden gelben Taster
    	   TRISD = 0b11110000;	   //PORT D: RD4-7 werden als Eingang gesetzt für meine 4 roten Taster; RD0-RD3 werden als Ausgang gesetzt für etwaige Verwendung (Ansteuerung der MOSFETs, Schrittmotor
    	   TRISE = 0b00001111;
    
    		LATD = 0b00000000;
    		wait_ms(50);
    		wait_ms(50);
    		LATB = 0x30;
    		wait_ms(50);
    		wait_ms(50);
    		LATD = 0b00000100;
    wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);
    		LATD = 0b00000000;
    
    		wait_ms(50);wait_ms(50);
    		LATD = 0b00000100;
    wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);
    		LATD = 0b00000000;
    
    		wait_ms(50);wait_ms(50);
    		LATD = 0b00000100;
    wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);
    		LATD = 0b00000000;
    
    		wait_ms(50);wait_ms(50);
    		LATD = 0b00000100;
    wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);
    		LATD = 0b00000000;
    
    			LATD = 0b00000100;
    wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);
    			LATD = 0b00000000;		
    
    
    		wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);
    		LATB = 0b00111000;
    	
    		LATD = 0b00000100;
    wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);
    		LATD = 0b00000000;
    		wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);
    
    		LATB = 0b00001111;
    	
    		LATD = 0b00000100;
    wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);
    		LATD = 0b00000000;
    		wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);
    
    		LATB = 0b00000001;
    	
    		LATD = 0b00000100;
    wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);
    		LATD = 0b00000000;
    		wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);
    
    		LATB = 0b00000110;
    	
    		LATD = 0b00000100;
    wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);
    		LATD = 0b00000000;
    		wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);wait_ms(50);
    Ist vielleicht ein wenig wirr war, aber ich hab da schon so viele Delay-Zeiten reingegegeben, dass es ja reicht. Aber es funktioniert trotzdem nicht.

    Noch zur Erklärung. Ich verwende den 8-Bit Modus, und mein Datenregister ist das Register B. RS ist RD0, R/W ist RD1, E ist RD2

    So ich hoffe ihr findets einen Feher. Und ich hoffe man kennt sich aus.

    lg,
    Norbert

  4. #4
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    08.10.2004
    Ort
    ferd. Waldmüllerg. 7/2
    Alter
    39
    Beiträge
    456
    @theodrin (1. post):
    Also das "Bit" hab ich erlich noch nie bei dem C18 gesehen, wobei ich aber sagen muss, dass ich mich bei dem eher an den standard synthax von C halte , so weit es geht . Bei dem geht den Bits namen zu geben am einfachsten mit einem #define (also bei deinem Beispiel zB "#define LCD_RS PortB.1").

    @TheScientist: mMn bist du zu schnell für das LCD. Schon bei der Abfrage der Busy-Flags musst du nach dem Enable mindestens 40µs warten, bevor das LCD bereit ist, die Daten herauszurücken. Aber das "Delay1TCY()" verzögert nur um 1 Befehlszyklus (also ein "nop" in ASM). Ich weiß jetzt nicht, wie hoch (oder eher hoffentlich, wie niedrig) du dein PIC getaktet hast, aber schon bei einem externen Takt von 4MHz ist das zu wenig. Bei Sprut stehen eigentlich recht gut die Timings für die einzelnen Schritte zum Ansprechen des Displays drin.

    @theodrin: Wie schaut deine wait-routine aus? C18 benutz ich auch nicht seit sehr langem, aber mir ist noch keine Funktion untergekommen die wait_ms() heißt. Hast du auch geschaut, ob die wirklich 1ms Verzögerung erstellt (also pin toggeln und mit osci oder Frequenzcounter nachmessen)?

    Ist das eure vollständige Initialisierung? Weil ihr müsst noch den ADC von den Pins des PICs abschalten.

    lg
    Mobius

  5. #5
    Benutzer Stammmitglied
    Registriert seit
    05.06.2007
    Ort
    Dortmund
    Alter
    33
    Beiträge
    42
    Moin,

    habs jetzt hinbekommen. Es lag kurioserweise am Flachbandstecker. Beim Zurammendrücken scheinen einige Messer nicht richtig in das Kabel gedrungen zu sein. Neues Kabel - läuft.

    @Mobius: Der PIC läuft mit Int. PLL+20MHz Quarz bei 48MHz. Laut den Timings im Datenblatt ist das viel zu schnell. Aber lustigerweise funktioniert es ja. Und zwar muss ich nach dem Enable immer min. 220ns warten. Wie lange das Display dann für einen Befehl braucht, ist ja im Prinzip egal, da es solange ja "Busy" ist. Und das abfragen des Busy-Flags dauert laut Datenblatt 0µs.
    Mit meinen 48MHz müsste ich ja intern bei 12Mips sein, oder? Also würde ich beim Enable nur etwa 83ns warten. Werde das zur Sicherheit mal verdreifachen.

    mfg The Scientist

  6. #6
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    18.05.2006
    Alter
    36
    Beiträge
    150
    Hallo!

    Danke für die Beschreibung mit dem #define. Ich hab die andere Variante nur wo gesehen und dachte halt, dass ich das auch so verwenden könnte. Aber egal, wenns so geht, dann freuts mich.

    Bei mir läuft das Display leider immer noch nicht. Ich verwende übrigens auch den PIC18F4550. Ich hab nen 20Mhz-Quarz. Das mit dem PLL versteh ich nicht ganz. Was heißst das noch mal? Weil da kann ich ja 4 verschiedene Konfigurationseinstellungen dazu setzen.
    Also das ein Befehlszyklus vier Takte braucht, weiß ich, also das man halt die Frequenz vom Quarz durch 4 teilen muss um die Frequenz zu erhalten.
    Genau wie das TheScientist gemacht hat mit seinen 12Mips. Aber wie bringt er mit einem 20Mhz-Quarz 48Mhz raus, also dann 12Mips und nicht 5Mips?

    lg
    Norbert

  7. #7
    Benutzer Stammmitglied
    Registriert seit
    05.06.2007
    Ort
    Dortmund
    Alter
    33
    Beiträge
    42
    Ich verwende folgende Konfiguration:

    Vorteiler für PLL: 5 d.h. der PLL wird mit 20MHz/5=4MHz gespeist. Daraus macht er 96MHz.

    Die Teile ich für die CPU nochmal durch 2, also 48MHz. Mehr geht auch nicht.

    In C18 sieht das dann so aus:

    Code:
    //Konfiguration
    #pragma config PLLDIV = 5, CPUDIV = OSC1_PLL2, USBDIV = 2, FOSC = HSPLL_HS // Int. 48MHz, Ext.-Src. 20MHz
    #pragma config PWRT = ON
    #pragma config BOR = OFF
    #pragma config VREGEN = OFF
    #pragma config WDT = OFF
    #pragma config MCLRE = ON
    #pragma config PBADEN = OFF
    #pragma config LVP = OFF
    mfg The Scientist

  8. #8
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    08.10.2004
    Ort
    ferd. Waldmüllerg. 7/2
    Alter
    39
    Beiträge
    456
    Also PLL ist ein Phase Lock Loop, d.h. ein interner Oscillator, dessen Flanken mit den Flanken eines externen (für den PLL gesehen) Quelle synchronisiert werden. Bei dem PIC ist es so, dass der PLL fest auf einer Frequenz von 96Mhz läuft und dass er mit einem 4MHz Takt "gespeist" werden muss. Die 96MHz werden dann zur Erzeugung der USB-Frequenzen und des CPU-Taktes verwendet (geteilt durch 2 ergibt diese 48MHz internen Takt, das nochmal durch 4 ergibt 12MHz also 12 Million Instructions per Second = Mips).
    Danach ist es nur noch ein Rechenspiel, da TheScientist einen 20MHz Quarz am Chip hängen hat ergibt sich, dass er den Takt durch 5 teilen muss um auf die 4MHz Speisefreuquenz für den PLL zu kommen.

    Der riesen Vorteil von dem PLL ist, dass man nur eine kleinen externen Takt braucht und man doch mit dem µC sau schnelle unterwegs ist. Und die Störungen die ein 4MHz Quarz erzeugt sind bei weitem nicht so groß, als wenn man einen 48MHz in der Schaltung hat, die seine hochfreuenten Störungen überall reinspeißt.

    Die Einstellung des PLLs wird sehr schön im Datenblatt erklärt (also wie man was setzten muss, damit es funktioniert ). Oder du übernimmst 1:1 den Code von TheScientist und dann musst du nur noch den Wert des Vorteiler für den PLL ändern (immer so wählen, dass du auf einen internen Takt von 4MHz kommt, setzt natürlichen einen Quarz mit einem vielfachen von 4MHz voraus ).

    lg
    Mobius

  9. #9
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    18.05.2006
    Alter
    36
    Beiträge
    150
    Hallo!

    Na das ist für mich ne Neuigkeit. Danke, das klingt ja echt gut.

    Aber noch ne Frage: Den PLL kann ich ein und ausschalten oder?
    Weil ich hab nämlich bei FOSC = HS stehen und damit verwende ich ja die PLL nicht oder? Das heißt für mich gilt das nicht, oder?
    Wenn ich schreibe FOSC = HSPLL_HS wie The Scientist, dann zählt das schon, aber so wie ich es im Moment habe nicht, oder?
    Also es reicht ein Ja wenn ich recht habe, oder ein Nein, wenn ich Unrecht habe.

    lg,
    Norbert

  10. #10
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    18.05.2006
    Alter
    36
    Beiträge
    150
    Hallo!

    Ich hab gerade versucht, meine wundervollen Namen wie LCD_RS zu verwenden aber der Compiler schreibt mir einen Fehler hin. Was hab ich falsch gemacht?

    Das ganze ist jetzt so definiert:

    Code:
    /** Portbezeichnungen ********************************************************/ 
    
    #define LCD_DATA  		PORTB
    #define LCD_DATA_TRIS 	TRISB
    #define LCD_CTRL		PORTD
    #define LCD_CTRL_TRIS 	TRISD
    
    #define LCD_RS 		 LCD_CTRL.0;
    #define LCD_RW		 LCD_CTRL.1;
    #define LCD_E		 LCD_CTRL.2;
    Und dann wollte ich halt z.B das LCD_RS Bit setzen und hab hingeschrieben: LCD_RS = 1;
    und daraufhin schreibt mir der Compiler einen Fehler hin. Was funktioniert da bitte nicht?

    lg
    Norbert

    Edit: Ich hab was vergessen. Also die Namen für die Register funktionieren. Also die Namen für ein ganzes Register. Da kann ich z.B schreiben LCD_DATA = 12; also das funktioniert, aber mit den Bits das geht nicht.

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

fchao-Sinus-Wechselrichter AliExpress