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

前面一讲我们焊接了C51的最小系统。这讲里我们将继续焊接上液晶显示相关电路,并分别实现用12864显示一个汉字,字符串,数字,浮点数以及可调节的电子时钟。

概念

点阵式液晶显示模块(LCD)广泛应用于单片机控制系统,比数码管、段式液晶能模块显示更多、更直观的信息,如汉字、曲线、图片等。点阵液晶显示模块集成度很高,一般都内置控制芯片、行驱动芯片和列驱动芯片,点阵数量较大的LCD还配置RAM芯片,带汉字库的LCD还内嵌汉字库芯片,有负压输出的LCD还设有负压驱动电路等。单片机读写LCD实际上就是对LCD的控制芯片进行读写命令和数据。编程驱动LCD时,不需要对LCD的结构和点阵行列驱动原理深入了解,只要理解LCD接口的定义和LCD的控制芯片的读写时序和命令就可以了。
12864LCD属于点阵图形液晶显示模块,不但能显示字符,还能显示汉字和图形,分带汉字库和不带那字库两种,价格也有差别。带汉字库的12864LCD使用起来非常方便,不需要编写复杂的汉字显示程序,只要按时序写入两个字节的汉字机内码,汉字就能显示出来了,驱动程序简单许多。本文例程就是基于带汉字库的12864液晶显示模块。DM12864M 汉字图形点阵液晶显示模块,可显示汉字及图形,内置 8192 个中文汉字(16X16 点阵)、128
个字符(8X16 点阵)及 64X256 点阵显示 RAM(GDRAM)。

第二讲 单片机C语言之12864液晶显示_第1张图片

12864有如下特点:
1. 128点X 64行=8192点。
2. 12864有两种工作模式。
(1)文本工作模式
整屏平均分成32个显示区(每个显示区是16X16点阵),每个显示区可显示一个中文,每个显示区可显示两个英文ASCII字符。下图为汉字显示坐标即地址。

第二讲 单片机C语言之12864液晶显示_第2张图片

(2)绘图工作模式

         整屏按水平方向每16个点分为一组,所以整屏共有8192/16=512组,每次可控制任意一组的16个点。图形显示坐标:水平方向 X—以字节单位,垂直方向 Y—以位为单位。

第二讲 单片机C语言之12864液晶显示_第3张图片

3. 12864的硬件接口

第二讲 单片机C语言之12864液晶显示_第4张图片

第二讲 单片机C语言之12864液晶显示_第5张图片

第二讲 单片机C语言之12864液晶显示_第6张图片

总共20个引脚。其中引脚4-14是连接到MCU的。4.5.6引脚有两种功能,分别对应不同串并驱动模式。当为串行驱动时,4.5.6分别为CS,SID,CLK,且此时8位数据并行线无效;当为并行驱动时,4.5.6分别为RS,RW,E,且此时8位并行数据线有效。而15脚则是用于选择串并模式的。


汉字显示实验
好了现在我们来显示一个汉字。首先明确思路,初始化液晶屏,切换到文本模式,设置要显示汉字的地址,写入显示汉字。新建工程,分别建立三个文件main.c, 12864.c, 12864.h。

main.c

#include "12864.h"

void main()
{
	LCD_Init();
	LCD_SetAddText(0x93);
	LCD_WriteDat(0XC4);
	LCD_WriteDat(0Xe3);
	LCD_SetAddText(0x94);
	LCD_WriteDat(0XBa);
	LCD_WriteDat(0XC3);

	while(1)
	{
	
	}
}
12864.c

#include "12864.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;
		LCDWR_SID=dat&(1<<7);
		LCDE_CLK=1;	
		dat<<=1;

	}
}

void LCD_EntryText()  //LCD进入文本模式
{
	LCD_WriteCmd(0x30);	
}

void LCD_EntryDraw() //LCD进入绘图模式
{
	
}

 voidLCD_SetAddText(u8 add)	//设置LCD文本模式显示地址
{
	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绘图模式显示地址
{	
	x=y;
}

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 LCD_Init()
{
	LCD_EntryText();
	delay(50);
	LCD_WriteCmd(0x01);	//清屏
	delay(5000);
	LCD_WriteCmd(0x0c);	 //开显示
	delay(50);
}
12864.h

#ifndef _12864_
#define _12864_

 #include "reg51.h"
 #define u8 unsigned char
 #define u16 unsigned int
 void delay(u16 x);
 void LCD_EntryText();
 void LCD_EntryDraw();
 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 LCD_Init();

 #endif
这个程序显示了两个汉字,在地址0x93和0x94处装入了“你好”两个汉字。我们一步一步来分析整个程序,所有的驱动都放在了12864.c里面。首先程序刚开始定义了三个IO口分别对应4.5.6脚,因为我们这里要采用串行模式。接下来液晶屏是要工作在文本模式还是绘图模式呢,所以我们又新建了两个函数LCD_EntryText()和LCD_EntryDraw(),暂时不管绘图模式,然后查看数据手册,得知进入绘图模式需要发送指令0x30给液晶,因此我们需要新建一个发送命令的函数。这样的话这个函数可以在这里被调用,也可以在其他地方被调用。这个函数为LCD_WriteCmd(u8 cmd),然而命令是怎么被发送的呢?这就得回到串行连接时序图了。

第二讲 单片机C语言之12864液晶显示_第7张图片

如图SID总共发送了三个字节,其中第一个字节的RW位用来表明数据传送方向,1则为数据从LCD到MCU,0相反。显然我们这里是写数据到LCD所以这位为0。RS位则表明数据的类型,1表示数据是显示数据,0表示数据是控制指令。显然我们是发送指令因此这位为0。因此第一个字节就是0Xf8。第二个字节发送的是目标数据的高4位,如果发送的命令为cmd,那么取cmd的高4位构成这第二个字节,即为cmd&0xf0。同理第三个字节发的是目标数据低4位,cmd<<4。CS和SCLK的时序就不具体讲了。但是LCD_WriteCmd(u8 cmd)函数要完成,前面说的三个字节具体又是怎么发送的呢?因此我们还需要内嵌一个函数来发送一个字节。这样我们就又新建一个函数LCD_Send8bit(u8 dat)。根据前面的时序图,要发送一个位,首先当SCLK为低时,拉高CS并保持,准备好要发送的位(这里取要发送的字节dat的最高位,即右移7位),在SCLK由低跳变到高时,发送这位。然后再拉低SCLK,以此循环直到8个位都发完。

切换到文本模式后,我们就要选择显示的地址了。怎么选择地址呢,MCU就需要把一个地址数据发送给LCD,然后LCD就知道接下来要在这个地址上放MCU发来的显示数据。因此又新建一个函数LCD_SetAddText(u8 add)。前面我们讲了怎么发送命令,实际上发送地址也是使用相同的程序(液晶能识别命令和地址),这里就不再赘述了。

再接下来就是发送显示数据了。因此又新建一个函数 LCD_WriteDat(u8 dat)。显然还是跟发送命令和地址一个模式,唯一的区别就是第一个字节这时候变成了0xfa。好了讲解完毕。

引申:

如果是要发送数字和浮点数,我们可以在12864.c中引入如下函数,然后载主函数作相应调用即可。

void Show_String(u8 add, u8 *str)	//lcd显示字符串
{
	LCD_EntryText(); //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);	
}

电子时钟实验

相关代码可查看我的代码片。


你可能感兴趣的:(C51实践篇)