Picproje Elektronik Sitesi

DERLEYİCİLER => Microchip XC Serisi => Microchip XC8 => Konuyu başlatan: a.zorba - 06 Temmuz 2012, 09:16:35

Başlık: XC8 HD44780
Gönderen: a.zorba - 06 Temmuz 2012, 09:16:35
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.
Başlık: Ynt: XC8 HD44780
Gönderen: Tagli - 06 Temmuz 2012, 19:10:44
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.