Đăng vào

MPLAB XC8: Hiển thị ký tự đặc biệt trên LCD

Tác giả

Để có thể hiển thị các ký tự đặc biệt trên LCD 16x2 bạn nên đọc trước bài hướng dẫn MPLAB XC8 – Lập trình LCD. Như chúng ta đã biết IC HD44780 dùng để điều khiển LCD cho phép chúng ta khai báo 8 ký tự đặc biệt để hiển thị bên cạnh các ký tự nằm trong bảng mã ASCII. Bài hướng dẫn này sẽ giúp các bạn lập trình hiển thị một vài ký tự đặc biệt trên LCD 16x2 dùng PIC16F877A và MPLAB XC8.

DDRAM, CGROM và CGRAM

CGROM – Character Generator ROM

Bộ nhớ CGROM lưu trữ các ma trận điểm 5x8 hoặc 5x10, mỗi ma trận là một ký tự đặc biệt dùng để hiển thị trên LCD. Nó có thể lưu trữ 205 ký tự kiểu 5x8 và 32 ký tự kiểu 5x10

DDRAM – Display Data RAM

This is the memory which holds the character data which is currently displayed on the LCD screen. Its capacity is 80×8 bits, ie 80 characters.

Bộ nhớ DDRAM lưu trữ ký tự đang được hiển thị trên màn hình LCD, nó có thể lưu trữ 80x8 bit, tương đương với 80 ký tự

CGRAM – Character Generator RAM

Bộ nhớ CGRAM tương tự với bộ nhớ CGROM nhưng đây là bộ nhớ RAM, chúng ta có thể thay đổi dữ liệu lưu trữ trên bộ nhớ này. Vì vậy các ký tự đặc biệt muốn hiển thị trên LCD sẽ được lưu trữ trên đây. Chúng ta có thể lưu được 8 ký tự kiểu 5x8 và 4 ký tự kiểu 5x10 trên CGRAM.

Cách tạo ký tự đặc biệt

Một ký tự hiển thị trên LCD là một ma trận điểm 5x8 howcj 5x10, thông thường là kiểu hiển thị 5x8. Chúng ta có thể dễ dàng tạo một ký tự đặc biệt bằng cách định nghĩa từng pixel trong ma trận. Ví dụ để tạo ký tự Ω theo kiểu ký tự 5x8:

MPLAB XC8 Code

lcd.h

lcd.h
/*
 * File:   lcd.h
 * Author: TienAnh
 *
 * Created on January 3, 2016, 1:41 PM
 */

#ifndef LCD_H
#define	LCD_H

#ifdef	__cplusplus
extern "C" {
#endif

#ifdef	__cplusplus
}
#endif

#endif	/* LCD_H */

//LCD Functions
void Lcd_Port(char a)
{
	if(a & 1)
		D4 = 1;
	else
		D4 = 0;

	if(a & 2)
		D5 = 1;
	else
		D5 = 0;

	if(a & 4)
		D6 = 1;
	else
		D6 = 0;

	if(a & 8)
		D7 = 1;
	else
		D7 = 0;
}
void Lcd_Cmd(char a)
{
	RS = 0;             // => RS = 0
	Lcd_Port(a);
	EN  = 1;             // => E = 1
        __delay_ms(4);
        EN  = 0;             // => E = 0
}

Lcd_Clear()
{
	Lcd_Cmd(0);
	Lcd_Cmd(1);
}

void Lcd_Set_Cursor(char a, char b)
{
	char temp,z,y;
	if(a == 1)
	{
	  temp = 0x80 + b - 1;
		z = temp>>4;
		y = temp & 0x0F;
		Lcd_Cmd(z);
		Lcd_Cmd(y);
	}
	else if(a == 2)
	{
		temp = 0xC0 + b - 1;
		z = temp>>4;
		y = temp & 0x0F;
		Lcd_Cmd(z);
		Lcd_Cmd(y);
	}
}

void Lcd_Init()
{
  Lcd_Port(0x00);
   __delay_ms(20);
  Lcd_Cmd(0x03);
	__delay_ms(5);
  Lcd_Cmd(0x03);
	__delay_ms(11);
  Lcd_Cmd(0x03);
  /////////////////////////////////////////////////////
  Lcd_Cmd(0x02);
  Lcd_Cmd(0x02);
  Lcd_Cmd(0x08);
  Lcd_Cmd(0x00);
  Lcd_Cmd(0x0C);
  Lcd_Cmd(0x00);
  Lcd_Cmd(0x06);
}

void Lcd_Write_Char(char a)
{
   char temp,y;
   temp = a&0x0F;
   y = a&0xF0;
   RS = 1;             // => RS = 1
   Lcd_Port(y>>4);             //Data transfer
   EN = 1;
   __delay_us(40);
   EN = 0;
   Lcd_Port(temp);
   EN = 1;
   __delay_us(40);
   EN = 0;
}

void Lcd_Write_String(char *a)
{
	int i;
	for(i=0;a[i]!='\0';i++)
	   Lcd_Write_Char(a[i]);
}

void Lcd_Shift_Right()
{
	Lcd_Cmd(0x01);
	Lcd_Cmd(0x0C);
}

void Lcd_Shift_Left()
{
	Lcd_Cmd(0x01);
	Lcd_Cmd(0x08);
}

main.c

main.c
#define _XTAL_FREQ 8000000

#define RS RD2
#define EN RD3
#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7

#include
#include "lcd.h";

// BEGIN CONFIG
#pragma config FOSC = HS   // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF  // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON  // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF   // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF   // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF   // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF    // Flash Program Memory Code Protection bit (Code protection off)
//END CONFIG

const unsigned short MyChar5x8[] = {
  0x00, 0x00, 0x0A, 0x1F, 0x1F, 0x0E, 0x04, 0x00, // Code for char num #0
  0x0E, 0x1B, 0x11, 0x11, 0x11, 0x11, 0x1F, 0x00, // Code for char num #1
  0x0E, 0x1B, 0x11, 0x11, 0x11, 0x1F, 0x1F, 0x00, // Code for char num #2
  0x0E, 0x1B, 0x11, 0x11, 0x1F, 0x1F, 0x1F, 0x00, // Code for char num #3
  0x0E, 0x1B, 0x11, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, // Code for char num #4
  0x0E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, // Code for char num #5
  0x00, 0x04, 0x02, 0x1F, 0x02, 0x04, 0x00, 0x00, // Code for char num #6
  0x00, 0x00, 0x0E, 0x11, 0x11, 0x0A, 0x1B, 0x00  // Code for char num #7
};
void InitCustomChars()
{
  char i;
  Lcd_Cmd(0x04);   // Set CGRAM Address
  Lcd_Cmd(0x00);   // .. set CGRAM Address
  for (i = 0; i <= 63 ; i++)
    Lcd_Write_Char(MyChar5x8[i]);
  Lcd_Cmd(0);      // Return to Home
  Lcd_Cmd(2);      // .. return to Home
}

int main()
{
  TRISD = 0x00;        // PORTD as Output
  Lcd_Init();
  InitCustomChars();   // Write custom characters to LCD memory
  while(1)
  {
    Lcd_Clear();
    Lcd_Set_Cursor(1,1);
    Lcd_Write_Char(0); // Display Custom Character 0
    Lcd_Write_Char(1); // Display Custom Character 1
    Lcd_Write_Char(2); // Display Custom Character 2
    Lcd_Write_Char(3); // Display Custom Character 3
    Lcd_Write_Char(4); // Display Custom Character 4
    Lcd_Write_Char(5); // Display Custom Character 5
    Lcd_Write_Char(6); // Display Custom Character 6
    Lcd_Write_Char(7); // Display Custom Character 7
    __delay_ms(1000);
  }
  return 0;
}

Sơ đồ mạch điện