上一讲我们探索了12864的文本模式,这一讲我们来看看绘图模式。上一讲中我们给出了绘图模式的点阵图(见下图),是由512组每组16个点构成的点阵。屏幕分为上下两半,其中每一半占256组;上半部分X轴方向(0-7),Y轴方向(0-31);下半部分X轴方向(8-15),Y轴方向(0-31)。如果一个点为高电平,则被点亮。12864只能以组为单位控制,因此我们只要给一个16位的二进制,就可以驱动一组的16个点。下面我们就通过两个实验来演示12864是如何显示一幅图形的。
实验一 点亮点阵的四角的四个组,先上程序。
main.c
#include "reg51.h"
#include "12864.h"
void main()
{
LCD_Init();
Clean_Draw();
Show_Group(0, 0, 0xaaaa);
Show_Group(7, 0, 0xaaaa);
Show_Group(8, 31, 0xaaaa);
Show_Group(15, 31, 0xaaaa);
while(1)
{
}
}
12864.c
#include "12864.h"
#include "stdio.h"
sbit LCDRS_CS=P3^5;
sbit LCDWR_SID=P3^6;
sbit LCDE_CLK=P3^7;
/*
数据 0xfa
命令 地址 0xf8
*/
void delay(u16 x)
{
while(x--);
}
void LCD_Send8bit(u8 dat) //向LCD发送一个字节
{
u8 i;
for(i=0;i<8;i++)
{
LCDE_CLK=0;
LCDWR_SID=dat>>7;
LCDE_CLK=1;
dat<<=1;
}
}
void LCD_EntryText() //LCD进入文本模式
{
LCD_WriteCmd(0x30);
}
void LCD_EntryDraw(u8 sw) //LCD进入绘图模式
{
if(sw==0)
{
LCD_WriteCmd(0x34);
}
else
{
LCD_WriteCmd(0x36);
}
}
void LCD_SetAddText(u8 add) //设置LCD文本模式显示地址
{
LCD_WriteCmd(0x30);
LCDE_CLK=0;
LCDRS_CS=1;
LCD_Send8bit(0Xf8);
LCD_Send8bit(add&0xf0);
LCD_Send8bit(add<<4);
LCDE_CLK=0;
LCDRS_CS=0;
}
void LCD_SetAddDraw(u8 x, u8 y) //设置LCD绘图模式显示地址
{
LCD_WriteCmd(y|0x80);
LCD_WriteCmd(x|0x80);
}
void LCD_WriteDat(u8 dat) //向LCD写入显示数据
{
LCDE_CLK=0;
LCDRS_CS=1;
LCD_Send8bit(0Xfa);
LCD_Send8bit(dat&0xf0);
LCD_Send8bit(dat<<4);
LCDE_CLK=0;
LCDRS_CS=0;
}
void LCD_WriteCmd(u8 cmd) //向LCD发送一条命令
{
LCDE_CLK=0;
LCDRS_CS=1;
LCD_Send8bit(0Xf8);
LCD_Send8bit(cmd&0xf0);
LCD_Send8bit(cmd<<4);
LCDE_CLK=0;
LCDRS_CS=0;
}
void Show_Chinese(u8 add, u8 mh, u8 ml) //在LCD上显示一个中文
{
LCD_EntryText(); //lcd进入文本模式
LCD_SetAddText(add);
LCD_WriteDat(mh);
LCD_WriteDat(ml);
}
void Show_String(u8 add, u8 *str) //lcd显示字符串
{
LCD_SetAddText(add);
while(*str)
{
LCD_WriteDat(*str++);
}
}
void Show_Number(u8 add, u16 n) //lcd显示一个数字
{
char s[6];
sprintf(s,"%05d",n);
Show_String(add, s);
}
void Show_Float(u8 add, float n) //lcd显示一个浮点数
{
char s[6];
sprintf(s,"%03.2f",n);
Show_String(add, s);
}
void LCD_Init()
{
LCD_EntryText(); //lcd进入文本模式
delay(50);
LCD_WriteCmd(0x01); //清屏
delay(5000);
LCD_WriteCmd(0x0c); //开显示
delay(50);
Clean_Draw();
}
//-----------------------------------------//
//-------------------绘图模式--------------//
//-----------------------------------------//
void Show_Group(u8 x, u8 y,u16 dat) //显示LCD绘图模式的一组点
{
LCD_EntryDraw(0); // 进入绘图模式 关闭
LCD_SetAddDraw(x,y); //
LCD_WriteDat(dat>>8); // 不能用等于号,否则改变dat
LCD_WriteDat(dat); //
LCD_EntryDraw(1); // 进入绘图模式 打开
}
void Clean_Draw()
{
u8 i;
u8 j;
for(i=0;i<16;i++)
{
for(j=0;j<32;j++)
{
Show_Group(i,j,0); //调用512次,每次都有关闭打开,会在下个实验改进
}
}
}
12864.h
#include "reg51.h"
#include "stdio.h"
#define u8 unsigned char
#define u16 unsigned int
void delay(u16 x);
void LCD_EntryText();
void LCD_EntryDraw(u8 sw);
void LCD_SetAddText(u8 add);
void LCD_SetAddDraw(u8 x, u8 y);
void LCD_WriteDat(u8 dat);
void LCD_WriteCmd(u8 cmd);
void LCD_Send8bit(u8 dat);
void Show_Chinese(u8 add, u8 mh, u8 ml);
void Show_String(u8 add, u8 *str);
void Show_Number(u8 add, u16 n);
void Show_Float(u8 add, float n);
void LCD_Init();
void Show_Group(u8 x, u8 y,u16 dat); //显示LCD绘图模式的一组点
void Clean_Draw();
#endif
程序分析:整个程序的目标是要能控制一个组的16个点阵,那么首先我们要进入绘图模式,然后设置显示地址(x,y), 再就是写16位数据。先看进入绘图模式,由12864数据手册知道,绘图模式进入后有绘图显示on与绘图显示off两种操作,这个on打开与off关闭又是怎么操作的?数据手册规定如下。
因此我们首先要关闭绘图显示,也就是写指令LCD_WriteCmd(0x34),我们把这两个关闭与打开指令都放到了LCD_EntryDraw(u8 sw)函数,其中sw为1时打开,为0时关闭。接下来要设置地址,我们新建LCD_SetAddDraw(x,y)函数,分别写入XY地址,注意最高位始终为1(如下图)所以要并上0x80。
接下来便是写入16位数据,分两次,先写高8位,因此先要将数据右移8位,再写低8位,只需整个数据写入即可,因为writedat函数会自动截取低8位。最好再打开绘图显示,完成。整个过程我们放在Show_Group(u8 x, u8 y,u16 dat) 函数。
void Show_Group(u8 x, u8 y,u16 dat) //显示LCD绘图模式的一组点
{
LCD_EntryDraw(0); // 进入绘图模式 关闭
LCD_SetAddDraw(x,y); //
LCD_WriteDat(dat>>8); // 不能用等于号,否则改变dat
LCD_WriteDat(dat); //
LCD_EntryDraw(1); // 进入绘图模式 打开
}
最后还要注意新建一个清屏函数Clean_Draw(),在每次显示之前清屏,其实就是令所有点为0,这样可以保持整个屏幕不出现乱码。
实验二 显示一幅图片
前面我们分析了LCD的点阵分布,分上下两块,而每一块正好有128X32个点,对应一幅128X32的像素图。因此如果我们有一幅128X64个像素点图,那么完全可以用12864来表达。因此首先要将这样一幅图导入到画图软件,生成后缀名为.bmp的128X64黑白、单色文件,再用PCtoLCD2002软件生成一个二进制文件,再将二进制数值复制到工程文件picture.c中,并做成一个数组保存到ROM中。如下:
#include "picture.h"
code unsigned char pic1[]={
0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x01,0xFC,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0xFC,0x00,0x00,0x00,0x00,0x00,0x07,0xFE,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x01,0xF8,0x00,0x00,0x00,0x00,0x00,0x1F,0xFF,0x00,0x00,0x00,0x00,0x00,0x3C,0x00,0x07,0xE0,0x00,0x00,0x00,0x00,0x00,0x3F,0x87,0x80,0x00,0x00,0x00,0x00,0x1E,0x00,
0x1F,0xC0,0x00,0x00,0x00,0x00,0x00,0x7E,0x03,0xC0,0x00,0x00,0x00,0x00,0x0F,0x00,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x01,0xC0,0x00,0x00,0x00,0x00,0x07,0xC0,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x01,0xC0,0x00,0x00,0x00,0x00,0x03,0xE0,0xF8,0x00,0x00,0x00,0x00,0x00,0x01,0xE0,0x01,0xE0,0x00,0x00,0x00,0x00,0x01,0xF0,0xE0,0x00,0x00,0x00,0x00,0x00,0x01,0xE0,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x7C,
0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xC0,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xC0,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x80,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x01,
0x00,0x00,0x00,0x00,0x00,0x01,0xF0,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xF8,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xF8,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xFC,0x00,0x3F,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x07,0xC0,0x00,0xFF,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x07,0xFF,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x0F,0xF0,0x01,0xC0,0x3F,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xFC,0x00,0x3F,0x80,0x01,0xC0,0x03,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xF8,0x00,0x7E,0x0F,0xFF,0xFC,0x00,0x70,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x07,0xC0,0x00,0x78,0x1F,0xFF,0xFE,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x00,0xF0,0x1F,0xFF,0xFF,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0xE0,0x1F,0x87,0x8F,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x00,0xE0,0x1F,0xC7,0x3F,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x00,0xE0,0x0F,0xC7,0xFF,0x00,0x1C,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x1C,0x00,0x00,0xFF,0xFF,0xFF,0xFC,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x00,0x7F,0xFF,0xFF,0xE0,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x00,0x00,0x3F,0xFF,0xFF,0x80,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x1E,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x00,0x00,0x00,0x1C,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x07,0xE0,0x00,0x00,0x00,0x3C,0x00,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xFC,0x00,0x00,0x00,0x38,0x00,0x01,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF8,0x00,0x00,0x78,0x00,0x0F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xFF,0xFC,0x00,0x78,0x03,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x07,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x0F,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x1F,0x00,0x00,0x01,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x0F,0x80,0x00,0x07,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xC0,0x00,0x00,0x07,0xC0,0x00,0x1F,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x01,0xF0,0x00,0xFF,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xF8,0x00,0x00,0x00,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x7C,0x00,0x00,0x00,0x7F,0xFF,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x3E,0x00,0x00,0x00,0x1F,0xFF,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,
0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x0F,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x07,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x01,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xF0,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xE0,
0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xC0,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x00};
接下来我们要将数组中的每两个数据(也就是16位)去驱动一个组,这样数组的1024个数据便可覆盖LCD的512组。新建一个图片显示函数到12864.c中,另外我们修改Show_Group函数成Show_GroupX函数,这样做的好处不用频繁地进行关闭和打开绘图显示。另外一个要注意的地方是Show-Picture函数中指针的使用。如何将数组中相邻的两个数据组合成一个16位数据呢?我们可以使用中间变量t,t=*p++; t<<=8;t|=*p++;,这样完全行得通。但是使用指针的话,则避免了重复性的操作,减轻了系统负担。
void Show_GroupX(u8 x, u8 y,u16 dat) //显示LCD绘图模式的一组点
{
LCD_SetAddDraw(x,y); //
LCD_WriteDat(dat>>8); // 不能用等于号,否则改变dat
LCD_WriteDat(dat); //
}
void Show_Picture(u8 *p)// 显示一幅128*64的图片
{
u16 *u;
u8 x,y;
u=(u16*) p;
LCD_EntryDraw(0);
for(y=0;y<32;y++)
{
for(x=0;x<8;x++)
{
Show_GroupX(x,y,*u++);
}
}
for(y=0;y<32;y++)
{
for(x=8;x<16;x++)
{
Show_GroupX(x,y,*u++);
}
}
LCD_EntryDraw(1);
}
最后我们只需要在main函数中显示图片即可。
#include "12864.h"
#include "picture.h"
void main()
{
LCD_Init();
Clean_Draw();
Show_Picture((u8*)pic1);
while(1)
{
}
}
picture.h
#ifndef _picture_
#define _picture_
code unsigned char pic1[];
#endif