Wyświetlacz LCD 2x16. Obsługa w C.

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
ODPOWIEDZ
hagop
-
Posty: 16
Rejestracja: 15 maja 2009, 18:53
Lokalizacja: Słupsk

Wyświetlacz LCD 2x16. Obsługa w C.

Post autor: hagop » 15 maja 2009, 19:25

Witam!

Jestem w trakcie tworzenia softu dla mojego urządzonka (sterownik wentylatorow komputera bardziej zaawansowana wersja :P). Ponieważ BASCOMA mam dość dobrze opanowanego postanowiłem się przesiąść na C.

Próbowałem uruchomić wyświetlacz zgodnie z kursem z EDW 12/2005 lecz niestety nie działa. Wyświetlacz jest na pewno sprawny, ponieważ aby sprawdzić czy urządzenie działa napisałem program w BASCOMIE sprawdzający wszystkie moje założenia.


Oto program:

Plik główny:

Kod: Zaznacz cały

#include <avr\io.h>
#include <inttypes.h>
#include <avr\pgmspace.h>


#include "hardware.h"
#include "lcd_komendy.h"
#include "makra.h"
//--------------------------------------------------
// Generowanie opóźnień
#define delay250ns() {asm volatile("nop"::);}

#define delayus8(t)\
	{asm volatile( \
		"delayus8_loop%=: \n\t"\
			"nop \n\t"\
			"dec %[ticks] \n\t"\
			"brne delayus8_loop%= \n\t"\
	: :[ticks]"r"(t) );}
	// DEC - 1 cykl, BRNE 2 cykle, + 1xnop. Zegar 4MHz

void delay100us8(uint8_t t)
{
	while(t>0)
	{
		delayus8(100);
		--t;
	}
}
// Koniec opóźnień
//--------------------------------------------------

#define LCD_EPULSE() \
	{PORT(LCD_EPORT) |= 1<<LCD_E; \
	delay250ns(); \
	PORT(LCD_EPORT) &= ~(1<<LCD_E);}


void LCDsendHalf(uint8_t data)
{
	data = (data & 0x0F) << LCD_D4;
	//data |= 0xF0;
	//data &= 0x0F;
	//data <<= LCD_D4;
	PORT(LCD_DPORT) =
		(PORT(LCD_DPORT) & ~(0x0F<<LCD_D4)) | data;
	//PORT(LCD_DPORT) &= ~(0x0F<<LCD_D4);
	//PORT(LCD_DPORT) |= data;
	LCD_EPULSE();
}

void LCDsend(uint8_t data)
{
	// Starsza część
	LCDsendHalf(data>>4);
	// Młodsza część
	LCDsendHalf(data);
	delayus8(120);
}

// Funkcje interfejsu
void LCDcommand(uint8_t command)
{
	PORT(LCD_RSPORT) &= ~(1<<LCD_RS);
	LCDsend(command);
}

void LCDdata(uint8_t data)
{
	PORT(LCD_RSPORT) |= 1<<LCD_RS;
	LCDsend(data);
}

void LCDcls(void)
{
	LCDcommand(LCDC_CLS);
	delay100us8(48);
}

void LCDhome(void)
{
	LCDcommand(LCDC_HOME);
	delay100us8(48);
}

void LCDinit(void)
{
	delay100us8(150);
	PORT(LCD_RSPORT) &= ~(1<<LCD_RS);
	LCDsendHalf(LCDC_FUNC|LCDC_FUNC8b);
	delay100us8(41);
	LCDsendHalf(LCDC_FUNC|LCDC_FUNC8b);
	delay100us8(2);
	LCDsendHalf(LCDC_FUNC|LCDC_FUNC4b);
	delay100us8(2);
	// Teraz jest już 4b. Koniec korzystania z sendHalf
	LCDcommand(LCDC_FUNC|LCDC_FUNC4b|LCDC_FUNC2L|LCDC_FUNC5x7);
	LCDcommand(LCDC_ON);
	LCDcls();
	LCDcommand(LCDC_MODE|LCDC_MODER);
	LCDcommand(LCDC_ON|LCDC_ONDISPLAY|LCDC_ONCURSOR);
}

void LCDstr_P(prog_char* str)
{
	char znak;
	while( 0 != (znak = pgm_read_byte(str++)) )
		LCDdata(znak);
}

// Koniec obsługi wyświetlacza
//--------------------------------------------------
//prog_char g_napispgm[] = "Lancuch z FLASHa"; // globalna


// START
int main(void)
{
	//----------------------------------------------
	// Inicjacja - uwaga: uproszczona, może wymagać
	// zmian przy zmianie przyporządkowania portów
	DDR(LCD_DPORT) = 1<<LCD_E | 1<<LCD_RS | 1<<LCD_D4 | 1<<LCD_D5 | 1<<LCD_D6 |1<<LCD_D7;

	LCDinit();
	// Koniec inicjacji
	//----------------------------------------------

	// \/ Bez tego, czasami zerowanie z poziomu programatora
	// \/ powoduje śmieci na wyświetlaczu.
	LCDcls();

	LCDstr_P(/*(prog_char*)*/PSTR("Witaj!"));
	LCDcommand(LCDC_DDA|64);
	LCDstr_P((prog_char*)PSTR("Lancuch z FLASHa"));
	//LCDstr_P(g_napispgm);

	return 0;
}
Plik hardware.h

Kod: Zaznacz cały

#ifndef HARDWARE_H_
#define HARDWARE_H_
//         USTAWIENIA PORTÓW

//			LCD
#define LCD_RS 1
#define LCD_RSPORT D
#define LCD_E 0
#define LCD_EPORT D
#define LCD_DPORT D
#define LCD_D4 5
#define LCD_D5 3
#define LCD_D6 4
#define LCD_D7 2
//			SW
#define SW1_SW1 0
#define SW1_SW1PORT B
#define SW_SW2 7
#define SW_SW3 6
#define SW_SWPORT D
//			PWM OUT
#define PWM_PWMPORT C
#define PWM_PWM1 5
#define PWM_PWM2 4
#define PWM_PWM3 3
#define PWM_PWM4 2

//			RPM
#define RPM_RPMPORT C
#define RPM_RMP1 1
#define RPM_RMP2 0

//			1WIRE
#define DS18B20_1WIREPORT B
#define DS18B20_1WIRE 2

#endif /* HARDWARE_H_ */
Plika makra.h

Kod: Zaznacz cały

#ifndef MAKRA_H_
#define MAKRA_H_
// Makra upraszczające dostęp do portów
// *** Port
#define PORT(x) XPORT(x)
#define XPORT(x) (PORT##x)
// *** Pin
#define PIN(x) XPIN(x)
#define XPIN(x) (PIN##x)
// *** DDR
#define DDR(x) XDDR(x)
#define XDDR(x) (DDR##x)

#endif /* MAKRA_H_ */
plik lcd_komendy.h

Kod: Zaznacz cały


#ifndef LCD_KOMENDY_H_
#define LCD_KOMENDY_H_

// Komendy sterujące wyświetlaczem
#define LCDC_CLS		0x01
#define LCDC_HOME		0x02
#define LCDC_MODE		0x04
	#define LCDC_MODER		0x02
	#define LCDC_MODEL		0
	#define LCDC_MODEMOVE	0x01
#define LCDC_ON 		0x08
	#define LCDC_ONDISPLAY	0x04
	#define LCDC_ONCURSOR	0x02
	#define LCDC_ONBLINK	0x01
#define LCDC_SHIFT		0x10
	#define LCDC_SHIFTDISP	0x08
	#define LCDC_SHIFTR		0x04
	#define LCDC_SHIFTL		0
#define LCDC_FUNC		0x20
	#define LCDC_FUNC8b		0x10
	#define LCDC_FUNC4b		0
	#define LCDC_FUNC2L		0x08
	#define LCDC_FUNC1L		0
	#define LCDC_FUNC5x10	0x4
	#define LCDC_FUNC5x7	0
#define LCDC_CGA		0x40
#define LCDC_DDA		0x80



#endif
Plik hardware.h i oraz inicjalizacja wyświetlacza została przeze mnie zmodyfikowana względem oryginału.

Na wyświetlaczu pojawiają mi się krzaczki tylko w pierwszej linii.
Na początku popełniłem błąd bo atmega8 pracowała na 12MHz wiec zmieniłem jej zegar na wewnętrzny 4Mhz aby opóźnienia się zgadzały lecz to nie pomogło.

Próbowałem uruchomić też inne dostępne biblioteki do obsługi lcd. Albo nie działało, albo się nie kompilowało albo były krzaczki.

Proszę o pomoc :)

[ Dodano: 2009-05-16, 22:00 ]
nikt nie jest w stanie mi pomoc rozwiązać ten problem?

Awatar użytkownika
Wesker
-
Posty: 27
Rejestracja: 01 lut 2006, 10:33
Lokalizacja: Leżajsk

Post autor: Wesker » 17 maja 2009, 21:46

Kod: Zaznacz cały

LCDsendHalf(LCDC_FUNC|LCDC_FUNC8b);
Wywołanie funkcji z takim parametrem powinno wystąpić trzykrotnie podczas inicjalizacji. Dodaj tą linię i opóźnienie 200us zaraz po tej drugiej.

hagop
-
Posty: 16
Rejestracja: 15 maja 2009, 18:53
Lokalizacja: Słupsk

Post autor: hagop » 18 maja 2009, 23:19

Niestety nie pomaga :( Próbowałem z większymi opóźnieniami 300us i też nic. Teraz już nie wyświetlają się krzaczki ale 1 linia jest wypełniona prostokątami (pole znaku podświetlone całe).

Awatar użytkownika
Wesker
-
Posty: 27
Rejestracja: 01 lut 2006, 10:33
Lokalizacja: Leżajsk

Post autor: Wesker » 19 maja 2009, 17:59

W pliku hardware.h widzę, że definiujesz wszystkie wyprowadzenia(jak w Bascomie), ale autor w tym akurat przypadku napisał funkcje LCDsendHalf, która wymaga by linie wyświetlacza D4 do D7 były dołączone do kolejnych wyprowadzeń portu począwszy od zdefiniowanego LCD_D4 reszta nie była definiowana. Np. jeśli #define LCD_D4 2 to kolejne muszą być dołączone do kolejnych wyprowadzeń portu czyli 3, 4 i 5. Jak widać LCD_D4 może mieć maksymalnie 4. Możesz albo zmienić połączenia albo musisz napisać fragment kodu, który odpowiednie bity zmiennej data wystawi na właściwe wyprowadzenia portu.

Jeszcze jedno: lcd_sendHalf() wykorzystuje dane z dolnego półbajtu. Więc tam, gdzie ją wykorzystujesz(4 razy) argument musi być przesunięty np.

Kod: Zaznacz cały

lcd_sendHalf( (LCDC_FUNC|LCDC_FUNC8b) >> 4 );
o czym było pisane w EdW 08/2007.

hagop
-
Posty: 16
Rejestracja: 15 maja 2009, 18:53
Lokalizacja: Słupsk

Post autor: hagop » 26 maja 2009, 20:41

próbowałem zmodyfikować ta funkcje sendHalf ale niestety nie udało mi się ;/ wertują neta znalazłem gotową bibliotekę lecz dalej nie chce nic wyświetlić;/ oto kod:

Kod: Zaznacz cały

#include <avr\io.h>
#include <inttypes.h>
#include <avr\pgmspace.h>
#include <util/delay.h>

#include "HD44780.h"
//#include "HD44780.c"
//#include "hardware.h"
//#include "lcd_komendy.h"
//#include "makra.h"

void _LCD_OutNibble(unsigned char nibbleToWrite)
{
if(nibbleToWrite & 0x01)
	LCD_DB4_PORT |= LCD_DB4;
else
	LCD_DB4_PORT  &= ~LCD_DB4;

if(nibbleToWrite & 0x02)
	LCD_DB5_PORT |= LCD_DB5;
else
	LCD_DB5_PORT  &= ~LCD_DB5;

if(nibbleToWrite & 0x04)
	LCD_DB6_PORT |= LCD_DB6;
else
	LCD_DB6_PORT  &= ~LCD_DB6;

if(nibbleToWrite & 0x08)
	LCD_DB7_PORT |= LCD_DB7;
else
	LCD_DB7_PORT  &= ~LCD_DB7;
}

void _LCD_Write(unsigned char dataToWrite)
{
LCD_E_PORT |= LCD_E;
_LCD_OutNibble(dataToWrite >> 4);
LCD_E_PORT &= ~LCD_E;
LCD_E_PORT |= LCD_E;
_LCD_OutNibble(dataToWrite);
LCD_E_PORT &= ~LCD_E;
_delay_us(50);
}
//-------------------------------------------------------------------------------------------------
//
// Funkcja zapisu rozkazu do wyświetlacza
//
//-------------------------------------------------------------------------------------------------
void LCD_WriteCommand(unsigned char commandToWrite)
{
LCD_RS_PORT &= ~LCD_RS;
_LCD_Write(commandToWrite);
}
//-------------------------------------------------------------------------------------------------
//
// Funkcja zapisu danych do pamięci wyświetlacza
//
//-------------------------------------------------------------------------------------------------
void LCD_WriteData(unsigned char dataToWrite)
{
LCD_RS_PORT |= LCD_RS;
_LCD_Write(dataToWrite);
}
//-------------------------------------------------------------------------------------------------
//
// Funkcja wyświetlenia napisu na wyswietlaczu.
//
//-------------------------------------------------------------------------------------------------
void LCD_WriteText(char * text)
{
while(*text)
  LCD_WriteData(*text++);
}
//-------------------------------------------------------------------------------------------------
//
// Funkcja ustawienia współrzędnych ekranowych
//
//-------------------------------------------------------------------------------------------------
void LCD_GoTo(unsigned char x, unsigned char y)
{
LCD_WriteCommand(HD44780_DDRAM_SET | (x + (0x40 * y)));
}
//-------------------------------------------------------------------------------------------------
//
// Funkcja czyszczenia ekranu wyświetlacza.
//
//-------------------------------------------------------------------------------------------------
void LCD_Clear(void)
{
LCD_WriteCommand(HD44780_CLEAR);
_delay_ms(2);
}
//-------------------------------------------------------------------------------------------------
//
// Funkcja przywrócenia początkowych współrzędnych wyświetlacza.
//
//-------------------------------------------------------------------------------------------------
void LCD_Home(void)
{
LCD_WriteCommand(HD44780_HOME);
_delay_ms(2);
}
//-------------------------------------------------------------------------------------------------
//
// Procedura inicjalizacji kontrolera HD44780.
//
//-------------------------------------------------------------------------------------------------
void LCD_Initalize(void)
{
unsigned char i;
LCD_DB4_DIR |= LCD_DB4; // Konfiguracja kierunku pracy wyprowadzeń
LCD_DB5_DIR |= LCD_DB5; //
LCD_DB6_DIR |= LCD_DB6; //
LCD_DB7_DIR |= LCD_DB7; //
LCD_E_DIR 	|= LCD_E;   //
LCD_RS_DIR 	|= LCD_RS;  //
_delay_ms(15); // oczekiwanie na ustalibizowanie się napiecia zasilajacego
LCD_RS_PORT &= ~LCD_RS; // wyzerowanie linii RS
LCD_E_PORT &= ~LCD_E;  // wyzerowanie linii E

for(i = 0; i < 3; i++) // trzykrotne powtórzenie bloku instrukcji
  {
  LCD_E_PORT |= LCD_E; //  E = 1
  _LCD_OutNibble(0x03); // tryb 8-bitowy
  LCD_E_PORT &= ~LCD_E; // E = 0
  _delay_ms(5); // czekaj 5ms
  }

LCD_E_PORT |= LCD_E; // E = 1
_LCD_OutNibble(0x02); // tryb 4-bitowy
LCD_E_PORT &= ~LCD_E; // E = 0

_delay_ms(1); // czekaj 1ms
LCD_WriteCommand(HD44780_FUNCTION_SET | HD44780_FONT5x7 | HD44780_TWO_LINE | HD44780_4_BIT); // interfejs 4-bity, 2-linie, znak 5x7
LCD_WriteCommand(HD44780_DISPLAY_ONOFF | HD44780_DISPLAY_OFF); // wyłączenie wyswietlacza
LCD_WriteCommand(HD44780_CLEAR); // czyszczenie zawartosći pamieci DDRAM
_delay_ms(2);
LCD_WriteCommand(HD44780_ENTRY_MODE | HD44780_EM_SHIFT_CURSOR | HD44780_EM_INCREMENT);// inkrementaja adresu i przesuwanie kursora
LCD_WriteCommand(HD44780_DISPLAY_ONOFF | HD44780_DISPLAY_ON | HD44780_CURSOR_OFF | HD44780_CURSOR_NOBLINK); // włącz LCD, bez kursora i mrugania
}



int main(void)
{
	_delay_ms(1000);

	for(;;)
	{
	LCD_Initalize();
	_LCD_Write('b');
	_delay_ms(1000);
	LCD_Clear();
	_LCD_Write('e');
	_delay_ms(1000);
	LCD_Clear();
	}
	return 0;
}

-------------------------------------------------------------------

plik nagłówka:
//-------------------------------------------------------------------------------------------------
// Wyświetlacz alfanumeryczny ze sterownikiem HD44780
// Sterowanie w trybie 4-bitowym bez odczytu flagi zajętości
// z dowolnym przypisaniem sygnałów sterujących
// Plik : HD44780.h
// Mikrokontroler : Atmel AVR
// Kompilator : avr-gcc
// Autor : Radosław Kwiecień
// Źródło : http://radzio.dxp.pl/hd44780/
// Data : 24.03.2007
//-------------------------------------------------------------------------------------------------

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

//-------------------------------------------------------------------------------------------------
//
// Konfiguracja sygnałów sterujących wyświetlaczem.
// Można zmienić stosownie do potrzeb.
//
//-------------------------------------------------------------------------------------------------
#define LCD_RS_DIR		DDRD
#define LCD_RS_PORT 	PORTD
#define LCD_RS			(1 << PD1)

#define LCD_E_DIR		DDRD
#define LCD_E_PORT		PORTD
#define LCD_E			(1 << PD0)

#define LCD_DB4_DIR		DDRD
#define LCD_DB4_PORT	PORTD
#define LCD_DB4			(1 << PD5)

#define LCD_DB5_DIR		DDRD
#define LCD_DB5_PORT	PORTD
#define LCD_DB5			(1 << PD3)

#define LCD_DB6_DIR		DDRD
#define LCD_DB6_PORT	PORTD
#define LCD_DB6			(1 << PD4)

#define LCD_DB7_DIR		DDRD
#define LCD_DB7_PORT	PORTD
#define LCD_DB7			(1 << PD2)

//-------------------------------------------------------------------------------------------------
//
// Instrukcje kontrolera Hitachi HD44780
//
//-------------------------------------------------------------------------------------------------

#define HD44780_CLEAR					0x01

#define HD44780_HOME					0x02

#define HD44780_ENTRY_MODE				0x04
	#define HD44780_EM_SHIFT_CURSOR		0
	#define HD44780_EM_SHIFT_DISPLAY	1
	#define HD44780_EM_DECREMENT		0
	#define HD44780_EM_INCREMENT		2

#define HD44780_DISPLAY_ONOFF			0x08
	#define HD44780_DISPLAY_OFF			0
	#define HD44780_DISPLAY_ON			4
	#define HD44780_CURSOR_OFF			0
	#define HD44780_CURSOR_ON			2
	#define HD44780_CURSOR_NOBLINK		0
	#define HD44780_CURSOR_BLINK		1

#define HD44780_DISPLAY_CURSOR_SHIFT	0x10
	#define HD44780_SHIFT_CURSOR		0
	#define HD44780_SHIFT_DISPLAY		8
	#define HD44780_SHIFT_LEFT			0
	#define HD44780_SHIFT_RIGHT			4

#define HD44780_FUNCTION_SET			0x20
	#define HD44780_FONT5x7				0
	#define HD44780_FONT5x10			4
	#define HD44780_ONE_LINE			0
	#define HD44780_TWO_LINE			8
	#define HD44780_4_BIT				0
	#define HD44780_8_BIT				16

#define HD44780_CGRAM_SET				0x40

#define HD44780_DDRAM_SET				0x80

//-------------------------------------------------------------------------------------------------
//
// Deklaracje funkcji
//
//-------------------------------------------------------------------------------------------------

void LCD_WriteCommand(unsigned char);
void LCD_WriteData(unsigned char);
void LCD_WriteText(char *);
void LCD_GoTo(unsigned char, unsigned char);
void LCD_Clear(void);
void LCD_Home(void);
void LCD_Initalize(void);

//-------------------------------------------------------------------------------------------------
//
// Koniec pliku HD44780.h
//
//-------------------------------------------------------------------------------------------------

tym razem na wyświetlaczu nie pojawiają się żadne krzaczki. ekran jest posty.
opóźnienie 1 sek w funkcji main służy do ustabilizowania się napięcia na wyświetlaczu.

ODPOWIEDZ