4_12864液晶屏使用文档

文件网盘链接:https://pan.baidu.com/s/158e_RyHuAqLyWNqZZhgi2A?pwd=1111 提取码:1111

一、12864液晶屏的使用逻辑

image

二、12864液晶屏硬件说明

12864液晶屏的引脚说明如下表所示:
image

12864液晶屏内部使用ST7920芯片作为控制芯片,它内置了五种存储器如下表所示:
image

三、在液晶屏上显示字符

在液晶屏上显示字符的步骤:先给DDRAM写地址,然后给该地址写字符编码数据。液晶屏的DDRAM地址分布如下图所示
image

每个DDRAM地址可以存储2个字节编码数据(编码数据分为高8位和低8位),一个ASCII码字符要1个字节数据,一个汉字要2个字节数据。不能在同一个地址同时写入ASCII码和汉字,例如在地址0x81高8位写入一个ASCII码的1字节编码数据,在地址0x81低8位和0x82高8位写入一个汉字的2字节编码数据,此时会出错,DDRAM地址与字符编码数据关系如下表所示
image

显示汉字需要注意:
如果汉字编码以0xFD结尾,此时要在汉字后面手动加上\xfd,否则会显示乱码。因为KEIL的编译器会自动忽略0xFD这个数据。如汉字“三”的编码是0xC8FD,编译后会变成0xC8,为了显示正常,我们要在代码中手动写成三\xfd,如下图所示
image

四、在液晶屏上画图

在液晶屏上画图的步骤:使用扩展功能指令,关闭画图显示,给GDRAM写行地址,然后写列地址,然后给该地址写图形数据,最后打开画图显示。GDRAM地址如下表所示
image

五、12864液晶屏指令表

12864液晶屏常用指令如下表所示
image

六、12864液晶屏写码时序图

1、复位时序

image

2、8位并行模式写时序

image

3、8位并行模式读时序

image

4、4位并行模式时序

image

5、串行模式时序

image

七、原理图

本次例程以8位并行模式操作12864液晶屏。原理图如下图所示
image

八、代码

1、delay延时代码h文件

点击查看代码
#ifndef __DELAY_H__
#define __DELAY_H__

#define uint16 unsigned int
void delay1ms(uint16 z);
#endif

2、delay延时代码c文件

点击查看代码
#include "delay.h"

void delay1ms(uint16 z)
{
  uint16 x,y;
    for(x=z;x>0;x--)
    for(y=114;y>0;y--);   
}

3、12864驱动代码h文件

点击查看代码
#ifndef __LCD12864_H__
#define __LCD12864_H__

#define uint8 unsigned char
#define uint32 unsigned long
void Init_12864();
void ClearScreen_12864();
void CheckBusy_12864();
void write_order_12864(uint8 order_12864);
void write_data_12864(uint8 data_12864);
void Display_Number_12864(uint8 y_12864,uint8 x_12864,uint32 number);
void Display_String_12864(uint8 y_12864, uint8 x_12864, uint8 *p_str);
void Display_Picture_12864(uint8 *p_picture);
#endif

4、12864驱动代码c文件

点击查看代码
#include <reg52.h>
#include "delay.h"
#include "LCD12864.h"

sbit EA_12864=P2^4;
sbit RS_12864=P2^5;
sbit RW_12864=P2^6;
sbit PSB_12864=P1^3;
sbit RST_12864=P1^5;
#define LCD12864_DATA P0 //P0口传输LCD12864的8位数据

/**********************************************************
函数名:Init_12864()
函数功能:LCD12864初始化设置
参数列表:无
函数返回值:无
注意:初始化过程看具体厂家的规格书,不同厂家步骤可能不同
***********************************************************/
void Init_12864()
{ 
    PSB_12864=1; //并行模式
    RST_12864=0; //复位LCD12864
    delay1ms(30);
    RST_12864=1;
    delay1ms(20);
    
    write_order_12864(0x30); //8位数据口、基本指令集
    //write_order_12864(0x30); //实测可以同时设置8位数据口和基本指令集
    write_order_12864(0x08); //关液晶屏显示
    write_order_12864(0x01); //清屏,地址计数器(AC)归0
    write_order_12864(0x06); //DDRAM地址计数器(AC)自动加一、光标右移
    write_order_12864(0x0c); //开液晶屏显示
}

/**********************************************************
函数名:void ClearScreen_12864()
函数功能:清屏
参数列表:无
函数返回值:无
***********************************************************/
void ClearScreen_12864()
{
    write_order_12864(0x01); //清屏,地址计数器(AC)归0
}

/**********************************************************
函数名:CheckBusy_12864()
函数功能:判忙函数,检测液晶屏是否可以进行读/写操作
参数列表:无
函数返回值:无
***********************************************************/
void CheckBusy_12864()
{ 
    uint8 Busy_data=0; //暂存IO口读的8位数据
    LCD12864_DATA=0xff; //IO口读数据前手动置1释放总线
    //读指令时序
    //每次读指令都要改变一次时序,但不用每次都改变3个引脚的时序,只要改变其中一个脚的时序即可
    RS_12864=0;
    RW_12864=1;
    do
    {
        EA_12864 = 1;
        Busy_data = LCD12864_DATA; //暂存IO口读到的数据
        EA_12864 = 0; //读完指令后将EA手动置0,等下一轮再用
    } while (Busy_data & 0x80); //STA7为0时允许对液晶屏进行读/写,此时结束循环
    LCD12864_DATA=0xff; //IO口读完数据后手动置1释放总线
}

/**********************************************************
函数名:write_order_12864(uint8 order_12864)
函数功能:给液晶屏写指令
参数列表:
        order_12864,8位指令码
函数返回值:无
***********************************************************/
void write_order_12864(uint8 order_12864)
{ 
    CheckBusy_12864(); //判忙,液晶屏空闲后才能写指令
    //写指令时序
    RW_12864=0;
    RS_12864=0;
    EA_12864=0;
    LCD12864_DATA = order_12864; //把要发送的指令存入IO口准备发送
    EA_12864=1; //发送指令
    //发送后的时序
    EA_12864=0;
    RW_12864=1;
    RS_12864 = 1;
    LCD12864_DATA = 0xff; //释放总线
}

/**********************************************************
函数名:write_data_12864(uint8 data_12864)
函数功能:给液晶屏写数据
参数列表:
        data_12864,8位数据
函数返回值:无
***********************************************************/
void write_data_12864(uint8 data_12864)
{
    CheckBusy_12864(); //判忙,液晶屏空闲后才能写指令
    //写数据时序
    RW_12864=0;
    RS_12864=1;
    EA_12864=0;
    LCD12864_DATA = data_12864; //把要发送的数据存入IO口准备发送
    EA_12864=1; //发送数据
    //发送后的时序
    EA_12864=0;
    RW_12864=1;
    RS_12864 = 0;
    LCD12864_DATA = 0xff; //释放总线
}

/***********************************************************
函数名:void Display_Number_12864(uint8 y_12864,uint8 x_12864,uint32 number,uint8 count_12864)
函数功能:在液晶屏上指定位置写一个十进制数
参数列表:
            y_12864,行坐标(取值范围1~4)
            x_12864,列坐标(取值范围1~8)
            number,在液晶屏上显示的十进制数(不超过10位)(uint32是32位,取值范围0~4294967296)
函数返回值:无
***********************************************************/
void Display_Number_12864(uint8 y_12864,uint8 x_12864,uint32 number)
{
    uint8 row; //液晶屏行地址
    uint32 tmp=number; //暂存number的值
    uint8 number_arr[10]={0}; //将tmp按位存入number_arr[]中
    uint8 count_12864 = 0, i = 0; //count_12864记录本次要显示的十进制位数
    do
    {
        number_arr[count_12864++]=tmp%10; //将tmp从低位到高位存入number_arr[]中
        tmp/=10; //舍弃tmp的个位
    }while(tmp!=0); //当tmp等于0时结束循环
    write_order_12864(0x30); //选择基本指令
    write_order_12864(0x06); //设置读/写数据后DDRAM地址计数器(AC)自动加一,光标右移
    switch (y_12864) //根据行号选择行地址
    {
    case 1: row = 0x80; break; //DDRAM第一行首地址
    case 2: row = 0x90; break; //DDRAM第二行首地址
    case 3: row = 0x88; break; //DDRAM第三行首地址
    case 4: row = 0x98; break; //DDRAM第四行首地址
    default: ; 
   }
   write_order_12864(row + x_12864 - 1); //写DDRAM列地址,x_12864从1开始,而地址下标从0开始,因此要手动减一
   for (i; i < count_12864;i++)
   {
        //液晶屏显示的数字是ASCII码,而number_arr[]存储的是十进制数
        //因此要将number_arr[]存储的十进制数加上0x30转换为ASCII码(0的ASCII码是0x30)
        //前面使用了0x06指令,写完数据后DDRAM的AC会自动加一,因此每次写完数据不需要手动改DDRAM地址
        write_data_12864(number_arr[count_12864 - 1 - i] + 0x30); //从高位到低位输出要显示的十进制数
   }
}

/**********************************************************
函数名:void Display_String_12864(uint8 y_12864,uint8 x_12864,uint8 *p_str)
函数功能:在液晶屏上指定位置显示字符串(汉字和ASCII码字符)
参数列表:
            y_12864,行坐标(取值范围1~4)
            x_12864,列坐标(显示汉字,取值范围1~8。显示ASCII字符,取值范围1~16)
            *p_str,指向要显示的字符串的指针
函数返回值:无
LCD12864显示规则:
(1)显示汉字:每行8个,可以显示4行,总共32个汉字,一个地址1个汉字
(2)显示ASCII码字符,每行16个,可以显示4行,总共64个字符,一个地址2个字符
***********************************************************/
void Display_String_12864(uint8 y_12864,uint8 x_12864,uint8 *p_str)
{
     uint8 row,n=0;
     write_order_12864(0x30); //选择基本指令
     write_order_12864(0x06); //设置读/写数据后DDRAM地址计数器(AC)自动加一,光标右移
    switch (y_12864) //根据行号选择行地址
    {
    case 1: row = 0x80; break; //DDRAM第一行首地址
    case 2: row = 0x90; break; //DDRAM第二行首地址
    case 3: row = 0x88; break; //DDRAM第三行首地址
    case 4: row = 0x98; break; //DDRAM第四行首地址
    default: ; 
    }
    write_order_12864(row + x_12864 - 1); //写DDRAM列地址,x_12864从1开始,而地址下标从0开始,因此要手动减一
    while(*p_str!='\0') //当指向字符串末尾空字符时结束循环
    {
        write_data_12864(*p_str++); //写数据,写完指针加一指向下一个要显示的字符
    }
}

/**********************************************************
函数名:void Display_Picture_12864(uint8 *p_picture)
函数功能:显示128*64像素的图片
参数列表:
        p_picture,指向存储图片数据数组的指针
函数返回值:无
LCD12864实际硬件是纵向32点*横向256点,一列有16个点(16位数据),即32行*16列
显示图片时把第1~8列看作上半屏,第9~16列看作下半屏,单片机要按相应位置将图片数据输出到液晶屏上
***********************************************************/
void Display_Picture_12864(uint8 *p_picture)
{
    uint8 i,j;
    write_order_12864(0x34); //8位数据口、使用扩展指令、关画图显示
    //先显示上半屏
    for (i = 0; i < 32;i++) //32行
    {
        write_order_12864(0x80 + i); //先写GDRAM行地址
        write_order_12864(0x80); //再写上半屏GDRAM首列地址0x80
        for (j = 0; j < 16;j++) //8列,每个列地址写2个字节图片数据,共16字节数据
        {
            //初始化设置了每次写完一个地址的数据后AC自动加一,因此不需要手动修改列地址
            write_data_12864(*p_picture++); //写图片数据,写完当前数据后指针指向下一个数据
        }
    }
    //再显示下半屏
    for (i = 0; i < 32;i++)
    {
        write_order_12864(0x80 + i); //先写GDRAM行地址
        write_order_12864(0x88); //再写下半屏GDRAM首列地址0x88
        for (j = 0; j < 16;j++)
        {
            write_data_12864(*p_picture++);
        }
    }
    write_order_12864(0x36); //开画图显示
    write_order_12864(0x30); //画图结束恢复使用基本指令,关画图显示
}

5、图片数据h文件

点击查看代码
#ifndef __PICTURE_H__
#define __PICTURE_H__

#define uint8 unsigned char

//图片是这样的:O_O,图片尺寸纵向64*横向128(每个地址2个字节数据)
uint8 code picture[]={
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x0F,0xFC,0x00,0x00,0x00,0x00,0x03,0xFF,0x80,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x18,0x06,0x00,0x00,0x00,0x00,0x06,0x00,0xC0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x30,0x03,0x00,0x00,0x00,0x00,0x0C,0x00,0x60,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x30,0x01,0x80,0x00,0x00,0x00,0x18,0x00,0x30,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x60,0x00,0xC0,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x60,0x00,0xC0,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x30,0x01,0x80,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x1E,0x0F,0x00,0x00,0x00,0x00,0x18,0x00,0x30,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x03,0xF8,0x00,0x00,0x00,0x00,0x07,0x81,0xE0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x07,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};

#endif

6、示例main函数

点击查看代码
#include <reg52.h>
#include "delay.h"
#include "LCD12864.h"
#include "picture.h"

/*
12864显示字符注意事项
1、同一个地址只能写2个ASCII码或1个汉字,不能1个ASCII码加1个汉字
2、显示汉字时,如果汉字编码以0xFD结尾,要在这个汉字后面手动加上\xfd,否则显示乱码。因为KEIL编译器会自动忽略0xFD这个数据,导致乱码。
    如汉字“三”的编码是0xC8FD,编译后会变成0xC8,为了显示正常,要写成三\xfd
*/
uint8 *str1="一二三四五六七八"; //错误,“三”和在“三”后面的字符都会乱码
uint8 *str2="一二三\xfd四五六七八"; //正确,手动加上\xfd后就不会乱码 
uint8 *str3="abcd1二"; //错误,同一个地址不能写1个ASCII码加1个汉字
uint8 *str4="abcd12二"; //正确

void main()
{
    //显示十进制数
    Display_Number_12864(1,1,4294967295);
    delay1ms(1000);
    
    //显示字符串
    Display_String_12864(1,1,str1); //显示字符串1,乱码
    Display_String_12864(2,1,str2); //显示字符串2,正确
    Display_String_12864(3,1,str3); //显示字符串3,最后的汉字错误
    Display_String_12864(4,1,str4); //显示字符串4,正确
    delay1ms(1000);
    //显示图片
    ClearScreen_12864(); //清屏
    Display_Picture_12864(picture);
    delay1ms(1000);
    ClearScreen_12864(); //清屏
    while(1)
    {

    }
}

posted @ 2022-07-05 21:50  zhaoo_o  阅读(665)  评论(0编辑  收藏  举报