Hallo allemaal,

Zal me eerst even voorstellen, ik ben Jeroen, kom uit Almere, en kwam eigelijk uit wanhoop op deze site terecht :P

Ik zit op de Hogeschool van Amsterdam als eerstejaars bij de opleiding Elektrotechniek en we kregen daar een project waarbij ik o.a. een menu kan maken op een LCD scherm(MC1602-syr) door middel van het programmeren in C voor de Microcontroller.(Atmega32) Alleen dat wilt niet helemaal werken :\

Wat ik nodig heb voor mijn menu is drie knoppen en een ADC.
Die knoppen en ADC houden de pinnen bij de poorten A en D in beslag en kan ik dus alleen 8 dataingangen aansluiten op de C poort.

Ik ben al twee weken bezig en ik heb verschillende methode's geprobeerd.

De dataingangen van het LCD waren aangesloten op poort PC7 t/m PC0. Toen kwam het probleem van de JTAG debugger. Deze was uitgezet. Alsnog geen beeld maar alleen blokjes. Als ik de tekst 'LCD' in een while loop zet werk het wel.

Toen heb ik, als test, de Dataingangen aangesloten op poort D van de microcontroller(ook in de code gewijzigd natuurlijk) en daar kwam LCD uit. Het werkt dus wel.

Daarna heb ik geprobeerd , op de D poort , met een while loop tekst, een knopje aan te sluiten(op Int0 / PD3) om de tekst te laten veranderen.(Zie code onderaan) Dit is nog niet gelukt.

Toen kwam ik erachter dat je het LCD scherm ook kan instellen op een 4-bits dataingang. Met de 4bits dataingang LCDscherm is het mogelijk die aan te sluiten op de D poort van de microcontroller en ook de knoppen te gebruiken die ook op de Cpoort aangesloten zitten. Dat klonk mooi in de oren. Alleen het werkt niet..
Ik heb geen idee wat ik fout doe en ik kom er níet uit. Kan iemand mij helpen?

Hieronder de datasheet van de Atmega32 en het LCD schema en de software code geprogrammeerd in C.

http://www.atmel.com/dyn/resources/prod_documents/doc2503.pdf


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

#define lcdcommand(d)  (lcdwrite((d),PORTB&0xFE));  // RS low
#define lcdputc(d)     (lcdwrite((d),PORTB|0x01));  // RS high



volatile int i=0;


void printMenu(void);
void lcdputstring(char *s);

ISR(INT0_vect){
	i++;

    if (i==3){
    i=0;
    }

}


void lcdwrite(char d, char type){
  PORTB = type;         // RS low or high
  PORTB = PORTB|0x02;   // make E high
  PORTD = d;            // assign data
  PORTB = PORTB&0xFD;   // make E low
  _delay_us(1520);      // wait 1,52 ms worst case delay
}

void initlcd(void)
{
  DDRD = 0xF0;          // pd7...pd4 output
  DDRB = DDRB|0x03;     // pin 0 and 1 port B: RS en E

_delay_ms(15);
  lcdcommand(0x38);
  lcdcommand(0x38);
  lcdcommand(0x38);
  lcdcommand(0x20);   // set 4-bit
  lcdcommand(0x28);  // 4-bit, 2 lines, 5x8
  lcdcommand(0x0C);  // display on, cursor off
  lcdcommand(0x06);  // write right
  lcdcommand(0x01);  // clear display
}


int main(void){
  
  initlcd();        // initialization LCD     
  printMenu();

  sei();

  while (1) {

PORTD &= 0x0F
PORTD >> 4
PORTD &= 0x0F

void printMenu(void);
{

	if (i==0){
	  lcdcommand(0x01);     // clear display     
	  lcdputc('T');         // write text
	  lcdputc('E');
	  lcdputc('S');
	  lcdputc('T');     
	}
	if (i==1){
	lcdcommand(0x01);       // clear display
	  lcdputc('T');         // write text
	  lcdputc('E');
	  lcdputc('S');
	  lcdputc('T');
	  lcdputc('1');
	  lcdcommand(0xC0);
	  lcdputc('*');        
	}
	if (i==2){
	lcdcommand(0x01);       // clear display
	  lcdputc('T');         // write text
	  lcdputc('E');
	  lcdputc('S');
	  lcdputc('T');
	  lcdputc('2');

	  lcdcommand(0xC0);

	  }

  
}

   asm volatile ("nop");
  }
}

Alvast bedankt allemaal !

Ik heb je code niet heel goed bekeken, maar de volgende 2 dingen vielen mij meteen op:
- je hebt interrupts niet aan gezet met sei();
- De functie printmenu moet in de while loop.

Owja die sei();
Overheen gekeken ..
Bedankt Atom, heb je tips uitgevoerd, geeft geen foutmeldingen in AVR Studio. Kan het alleen op het moment nog niet uittesten op de microcontroller, zit zonder programmer op het moment.

Ziet iemand anders nog fouten waardoor het niet werkt?
Tips gewaardeerd :D

Code gewijzigd in openingspost

Verander je [ quote ] tag in [ code ] (zonder de spaties), dan wordt je code beter leesbaar. Dan krijg je zoiets:


void lcdwrite(char d, char type)
{
    PORTB = type;			// RS low or high
    PORTB = PORTB | 0x02;		// make E high
    PORTD = d;				// assign data
    PORTB = PORTB & 0xFD;		// make E low
    _delay_us(1520);			// wait 1,52 ms worst case delay
}

void initlcd(void)
{
    DDRD = 0xF0;			// pd7...pd4 output
    DDRB = DDRB | 0x03;			// pin 0 and 1 port B: RS en E

    _delay_ms(15);
    lcdcommand(0x38);
    lcdcommand(0x38);
    lcdcommand(0x38);
    lcdcommand(0x20);			// set 4-bit
    // enz...
}

Dat kan nooit goed gaan. Ofwel gebruik je 8-bit mode, en dan schakel je PD0 ... PD7 als uitgang. Ofwel doe je aan 4-bit mode, maar dan moet je voor elke byte eerst de high-nibble versturen, gevolgd door de low-nibble.
Hou daar rekening mee bij het initialiseren. Na de laatste instructie hierboven, moet je alle volgende instructies in 4-bit mode uitvoeren!

Die code is toch goed?
Ik maak van DDRD de poorten
PD7 PD6 PD5 en PD4 m'n uitgangspoorten
en bij lcdcommand(0x20) laat ik weten dat het een 4-bit is.
Hoe werkt dat dan met die nibble? Dat snap ik niet.

Heb nu juist voor de mogelijkheid gekozen voor 4-bit data omdat ik bij een 8bit data te weinig knoppen heb, ik heb er namelijk 3 nodig.

Hoe en waar regel je dat steeds een byte in tweeen wordt gesplitst en verstuurd naar PortD4 t/m 7 ?

Hmm byte splitsen? Daar had ik nog niets over gelezen.
Nu ik erover nadenk is dat best logisch aangezien je geen 8 bits meer heb waardoor ik alle bits in 1 keer kan versturen..
Dus als ik het goed heb, als ik een U wil plaatsen op m'n LCD

U = 0101 0101

Moet ik eerst 0101 moet versturen (van rechts)
en dan 0101 moet versturen (van links)?

Dan ga ik daar even mee spelen ^^

Zo is het, ja. Eerst de high-nibble, gevolgd door de low-nibble.

Op 14 april 2009 14:58:07 schreef pros:
Zo is het, ja. Eerst de high-nibble, gevolgd door de low-nibble.

Ik kreeg eerst gewoon zwarte blokjes op m'n scherm, dus dat ie gewoon aan is.

N.a.v. de high nibble low libble theorie had ik het volgende gedaan in de While(1){ } :

PORTD &= 0x0F
PORTD >> 4
PORTD &= 0x0F

zodat:

U = 0101 0101
0000 1111
----------
0000 0101

word verstuurd

dan 0101 0101 vier naar rechts verschoven

U = 0000 0101
0000 1111
----------
0000 0101

Wat een U zou moeten geven op het LCD scherm.
Alleen wat ik nu heb is 1 knipperend blokje.

Code geupdate in openingspost [/code]

PORTD &= 0x0F
PORTD >> 4
PORTD &= 0x0F

Dat gaat niet werken: de &= operatie is een assignment, dus na "PORTD &= 0xf" ben je de hoogste 4 bits kwijt; daarna shiften zonder op slaan is ook niet zo zinnig (waar blijft het resultaat?)
en daarna opnieuw een &= waarbij er dus effectief niks veranderd (omdat de shift geen assignment doet; als de shift wel wat deed, was PORTD nu 0000)

Je moet in twee stappen iets aan PORTD assignen:

Eest het hoge nibble: PORTD = (d & 0xF0)>>4;
En dan het lage nibble: PORTD = (d & 0x0F);

met de juiste delays en enable-flag-toggling...

je code wordt dan dus iets als:


void lcdwrite4bit(char d, char type){
  PORTB = type;         // RS low or high

  PORTB |= 0x02;        // make E high
  PORTD = (d & 0xF0)>>4;   // send high nibble
  PORTB &= (~0x02);     // make E low

  _delay_us(10); // ofzo?

  PORTB |= 0x02;        // make E high
  PORTD = (d & 0x0F);   // send low nibble
  PORTB &= (~0x02);     // make E low

  _delay_us(1520);      // wait 1,52 ms worst case delay
}

Edit: Oh ja, en je hebt de "De functie printmenu moet in de while loop" iets te letterlijk genomen... De implementatie van de functie mag natuurlijk gewoon buiten de main() functie, dat houdt de boel wel zo geordend. Er werd bedoeld om de functie-aanroep binnen de while lus te zetten, de "printMenu();" in de main() dus een paar regels naar beneden...

[Bericht gewijzigd door KaRaMBa op (14%)]

Bedankt voor je hulp en uitleg! Het is zo een stuk duidelijker. Ik ga het morgen even uittesten, dan heb ik een programmer tot m'n beschikking. Zal zo snel mogelijk laten horen of het is gelukt!


void lcdwrite4bit(char d, char type){
  PORTB = type;         // RS low or high

  PORTB |= 0x02;        // make E high
  PORTD = (d & 0xF0)>>4;   // send high nibble
  PORTB &= (~0x02);     // make E low

  _delay_us(10); // ofzo?

  PORTB |= 0x02;        // make E high
  PORTD = (d & 0x0F);   // send low nibble
  PORTB &= (~0x02);     // make E low

  _delay_us(1520);      // wait 1,52 ms worst case delay
}

Deze code gebruikt , beetje gespeelt met de delay, is nu 50. Maar krijg nog steeds geen tekst op m'n scherm, alleen blokjes..
Geen idee waarom xD Waar kan ik nog naar kijken?

Dat er nog zwarte blokjes op je display staan, betekent dat hij nog niet goed geinitialiseerd is. Als ik de datasheet erop nakijk is de timing niet helemaal goed bij het initialiseren. Dit heb ik uit de datasheet. http://www.uploadarchief.net/files/download/timingopstarten.jpg
Misschien dat dit helpt.

@J-r0en: Verwijder alles uit je broncode, dat niets met de LCD-sturing te maken heeft, en post die even (of plaats die elders, en post een link). Nu kunnen we enkel wat rondtasten in het duister...

Kleine update, we hebben uiteindelijk maar gewoon gekozen voor een 8bit op de D poort vanwege achterstand op het project. 1 interrupt gebruikt van Int2.
Dit werkt overigens, en we zijn van plan een tweede knop aan te sluiten op een poort die eigelijk geen interrupt is.