第三讲 单片机C语言之12864液晶显示

上一讲我们探索了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




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值