XC8 HD44780

Başlatan a.zorba, 06 Temmuz 2012, 09:16:35

a.zorba

acemi C ci için  .  mplabx  xc8 derleyici ile yapılmış  18f2550  uyumlu tercihen  OpenXLCD  ile yapılmış karekter ve rakam göstermeyi içeren örnek bir program paylaşabilirimisiniz.
Bilenler bilir . Biz maraşlilar için şehir olarak şubat ay' i bayram ,kurtuluş ,yaz in gelmesiydi. Şimdi karalar in yas in ayı oldu.

Tagli

Daha önceden C18 ile biraz uğraşarak çalıştırdığım Microchip XLCD kütüphanesini geçenlerde baya bir boğuşmama rağmen nedense XC8'de çalıştıramadım. Sonunda pes edip kendi kütüphanemi yazdım. Şimdilik sadece 4 bit modunu destekliyor ve tanımlı portun büyük nibble'ı için test ettim. Küçük nibble için de kod var ama onu denemedim. Eminim pek çok eksiği vardır, işime yarayan özelliklerini çalıştıracak kadar uğraştım sadece.

lcd.h
#ifndef LCD_H
#define LCD_H

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include "globals.h"  ****** BU KISMI ÇIKARMAN GEREKECEK, ASAGIDA ACIKLADIM

#define LCD_DELAY 5

#define ON 1
#define OFF 0

//Control Pins
#define LCD_RS LATCbits.LATC0
#define LCD_RW LATCbits.LATC1
#define LCD_E LATCbits.LATC2

//Data Port
#define UPPER //Lower nibble support is NOT tested!
#define INTERNAL_WAIT //Wait for BF included in functions.
#define LCD_LAT LATD
#define LCD_PORT PORTD
#define LCD_TRIS TRISD

//LCD Shift Commands for lcdCommand()
#define CURSOR_LEFT B'00010000'
#define CURSOR_RIGHT B'00010100'
#define SCREEN_LEFT B'00011000'
#define SCREEN_RIGHT B'00011100'

//Function Prototypes
void lcdInit();
void lcdPutChar(char c);
char lcdBusy(void);
void lcdPutStr(char *str);
void lcdSetAddr(char addr);
void lcdCommand(char cmd);
void lcdDisplay(char onOff);
void lcdCursor(char onOff);
void lcdBlink(char onOff);
void lcdNewChar(char pos, const char *ptr);

//LCD Macros
#define lcdClear() lcdCommand(0x01)
#define lcdHome() lcdCommand(0x02)

#endif


lcd.c
#include "lcd.h"

//Local Function Prototypes
void clockE(void);
void write(char c);
char read(void);

//Local variables
char displayMode;


void lcdInit(){
	displayMode = 0x08;

#ifdef UPPER
	LCD_LAT &= 0x0F;
	LCD_TRIS &= 0x0F;
#else
	LCD_LAT &= 0xF0;
	LCD_TRIS &= 0xF0;
#endif
	LCD_E = 0;
	LCD_RS = 0;
	LCD_RW = 0;

	//----Software Reset Sequence----
	delayMS(30); // > 15 ms
#ifdef UPPER
	LCD_LAT &= 0x0F;
	LCD_LAT |= 0b00110000; //LCD_PORT = 0b00110000
#else
	LCD_LAT &= 0xF0;
	LCD_LAT |= 0b00000011;
#endif
	clockE();
	delayMS(10); // > 4.1 ms
	clockE();
	delayMS(1); // > 100 us
	clockE();

#ifdef UPPER
	LCD_LAT &= 0x0F;
	LCD_LAT |= 0b00100000; //LCD_LAT = 0b00100000
#else
	LCD_LAT &= 0xF0;
	LCD_LAT |= 0b00000010;
#endif
	clockE();

	lcdCommand(0b00101000);
	lcdCommand(0b00001000); //Shutdown everything
	lcdCommand(0b00000001); //Clear Display
	lcdCommand(0b00001100); //Display On
}

//Common write routine
void write(char c){
	LCD_RW = 0;
	char low = 0, high = 0;
	char temp = 0;

	low = c & 0x0F;
	high = (c & 0xF0) >> 4;
#ifdef UPPER
	LCD_TRIS &= 0x0F;
	LCD_LAT &= 0x0F;
#else
	LCD_TRIS &= 0xF0;
	LCD_LAT &= 0xF0;
#endif

	//Sending high nibble
#ifdef UPPER
	temp = (high << 4) & 0xF0;
#else
	temp = high & 0x0F;
#endif
	LCD_LAT |= temp;
	clockE();

	//Sending low nibble
#ifdef UPPER
	LCD_LAT &= 0x0F;
	temp = (low << 4) & 0xF0;
#else
	LCD_LAT &= 0xF0;
	temp = low & 0x0F;
#endif
	LCD_LAT |= temp;
	clockE();

#ifdef UPPER
	LCD_LAT &= 0x0F;
#else
	LCD_LAT &= 0xF0;
#endif
}

//Common read routine
char read(void){
	char temp = 0;
	LCD_RW = 1;
#ifdef UPPER
	LCD_LAT &= 0x0F;
	LCD_TRIS |= 0xF0;
#else
	LCD_LAT &= 0xF0;
	LCD_TRIS |= 0x0F;
#endif
	__delay_us(LCD_DELAY);

	LCD_E = 1;
	__delay_us(LCD_DELAY);
#ifdef UPPER
	temp |= LCD_PORT & 0xF0;
#else
	temp |= (LCD_PORT & 0x0F) << 4;
#endif
	LCD_E = 0;
	__delay_us(LCD_DELAY);

	LCD_E = 1;
	__delay_us(LCD_DELAY);
#ifdef UPPER
	temp |= (LCD_PORT & 0xF0) >> 4;
#else
	temp |= LCD_PORT & 0x0F;
#endif
	LCD_E = 0;
	__delay_us(LCD_DELAY);

	return temp;
}

void lcdCommand(char cmd){
#ifdef INTERNAL_WAIT
	while(lcdBusy() == 1);
#endif

	//Checking for display option change
	if ((cmd & 0b11111000) == 0b00001000){
		displayMode = cmd;
	}

	LCD_RS = 0;
	write(cmd);
}

void lcdPutChar(char c){
#ifdef INTERNAL_WAIT
	while(lcdBusy() == 1);
#endif
	LCD_RS = 1;
	write(c);
}

char lcdBusy(){
	LCD_RS = 0;

	if ((read() & 0b10000000) == 0b10000000)
		return 1; //LCD is busy
	else
		return 0; //LCD is free
}

void lcdPutStr(char *str){
	while (*str != '\0'){
		lcdPutChar(*str);
		++str;
	}
}

void lcdSetAddr(char addr){
	addr |= 0x80;
	lcdCommand(addr);
}

void lcdNewChar(char pos, const char *ptr){
	char i;
	char addr = (pos << 3);
	lcdCommand(addr | 0b01000000);
	for (i = 0; i < 8; ++i){
		lcdPutChar(*ptr++);
	}
}

void lcdDisplay(char onOff){
	if (onOff == OFF)	displayMode &= 0b11111011;
	else displayMode |= 0b00000100;
	lcdCommand(displayMode);
}

void lcdCursor(char onOff){
	if (onOff == OFF) displayMode &= 0b11111101;
	else displayMode |= 0b00000010;
	lcdCommand(displayMode);
}

void lcdBlink(char onOff){
	if (onOff == OFF) displayMode &= 0b11111110;
	else displayMode |= 0b00000001;
	lcdCommand(displayMode);
}

void clockE(void){
	__delay_us(LCD_DELAY);
	LCD_E = 1;
	__delay_us(LCD_DELAY);
	LCD_E = 0;
	__delay_us(LCD_DELAY);
}


lcd.h içinde include edilen globals.h dosyası benim projeye özgü genel değişken ve fonksiyonları sakladığım bir header dosyası. Dosyanın içinde alakasız şeyler de olduğu için paylaşmıyorum ama yanlış hatırlamıyorsam içinden aldığım iki şey var:
#define _XTAL_FREQ  40000000ULL
void delayMS(unsigned int ms);

Bunlardan delayMS() fonksiyonunu kendim yazdım, zaten çok basit birşey. Programın ana .c dosyasında tanımlamıştım:
void delayMS(unsigned int ms){
	while (ms > 0){
		__delay_ms(1);
		ms--;
	}
}

__delay_ms() zaten kendi kütüphane fonksiyonu ama giriş değeri bir değerden büyük olamıyor (20 miydi neydi...) o sebeple kendi fonksiyonum ile bunu kullandım. Bekleme süresi çok hassas değil tabi ama benim için çok hassas olması da gerekmiyor zaten.

Ana programda da bu şekilde kullandım:
#include "lcd.h"
lcdInit();
lcdClear();
lcdPutStr("Satir 1");
lcdSetAddr(0x40);
lcdPutStr("Satir 2");

Portlarla ilgili yön tanımlamalarını (TRIS) senin ana programda yapman gerekiyor yanlış hatırlamıyorsam (programı yazalı biraz oldu). Data hatlarını kendisi hallediyor ama kontrol hatlarının yönlerini belirtmen lazım ana programda. Ayrıca, lcd.h içinde değiştirmen gereken tanımlamalar var.
Gökçe Tağlıoğlu