⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lcd12864.c

📁 AT89S52单片机驱动带字库的LCD12864液晶屏实现图形显示
💻 C
字号:
/***************************************************************************

 12864液晶模块(ST7920控制器) Keil C51 并行口驱动程序

 s_yqzhan@stu.edu.cn
 OFourME@163.com                                                        2007-9-29

/**************************************************************************/

#include"LCD12864.h"
//  #define NOP

/*  通过define NOP 决定是否在程序中插入nop指令
**  因为LCD可能对电平保持时间有一定的要求 */


/*////////////////////////////////////////////////////////////////////////*/

#ifdef NOP
#include<intrins.h>
#endif

/*////////////////////////////////////////////////////////////////////////*/
/* 初始化12864液晶模块 */

void init_LCD(void)
{
    RST = 0;
    delay(10);
    RST = 1;
#ifdef NOP
    _nop_();
#endif
    PSB = 1;/*H:8位或4位并口方式,L:串口方式*/
    send_i(ext8);
    send_i(bas8);
    send_i(clr);
    send_i(cursor_1);
    send_i(texton);
}

/*////////////////////////////////////////////////////////////////////////*/
/* 等待,直到12864液晶模块处于就绪状态 */

void chk_busy(void)
{
    BF = 1;	/*DI=L.RW=H,读出忙标志(BF)及地址记数器(AC)的状态*/
    DI = 0;	/*BF标志提供内部工作情况.BF=1表示模块在进行内部操作,*/
    RW = 1;	/*此时模块不接受外部指令和数据.BF=0时,模块为准备状态,*/
    E  = 1;	/*随时可接受外部指令和数据.*/
    while(BF);
    E  = 0;
}

/*////////////////////////////////////////////////////////////////////////*/
/* 向12864液晶模块传输指令 */

void send_i(cmd12864 instrution)
{
    chk_busy();
    DI = 0;
    RW = 0;
    DB = instrution;
    E = 1;
#ifdef NOP
    _nop_();
    _nop_();
#endif
    E = 0;
}

/*////////////////////////////////////////////////////////////////////////*/
/* 向12864液晶模块传输数据 */

void send_d(int8u dt)
{
    chk_busy();
    DI = 1;	/* 数据(1)/指令(0) */
    RW = 0;	/* 读(1)/写(0) */
    DB = dt;/* P0口,作为数据总线 */
    E = 1;/* 使能-写(H->L)/读(H) */
#ifdef NOP
    _nop_();
    _nop_();
#endif
    E = 0;
}

/*////////////////////////////////////////////////////////////////////////*/
/* 从12864液晶模块读取数据 */

int8u read_d()
{
    int8u dt;

    chk_busy();
    DI = 1;
    RW = 1;
    E  = 1;
#ifdef NOP
    _nop_();
#endif
    dt = DB;
    E  = 0;
    return dt;
}
/*////////////////////////////////////////////////////////////////////////*/
/* 从12864液晶模块读取指令、状态 */

int8u read_i()
{
    int8u dt;

    chk_busy();
    DI = 0;
    RW = 1;
    E  = 1;
#ifdef NOP
    _nop_();
#endif
    dt = DB;
    E  = 0;
    return dt;
}

/*////////////////////////////////////////////////////////////////////////*/
/* 设置文本输出位置;x取值范围:0~7;y取值范围:0~3 */

void gotoxy(int8u x, int8u y)
{
    switch(y)
    {
        case 0: send_i(0x80+x);break;
        case 1: send_i(0x90+x);break;
        case 2: send_i(0x88+x);break;
        case 3: send_i(0x98+x);break;
    }
}

/*////////////////////////////////////////////////////////////////////////*/
/* 设置图形模式输出位置;x取值范围(byte):0~7,单位为16位/2个字节,共128位;
   y取值范围(bit):0~63
*/

void setxy(int8u x, int8u y)
{
    send_i(ext8);
    if( y & 0xe0 )		/* y>=32 */
    {
        send_i(gdbas+y-32);
        send_i(page1+x);
    }
    else
    {
        send_i(gdbas+y);
        send_i(page0+x);
    }
	 send_i(bas8);
}

/*////////////////////////////////////////////////////////////////////////*/
/* 屏幕闪烁 */

void flash()
{
    send_i(textoff);	/* 关闭显示 */
    delay(250);
    send_i(texton);	/* 开显示,关光标,不闪烁 */
    delay(250);
    send_i(textoff);
    delay(250);
    send_i(texton);
    delay(250);
    send_i(textoff);
    delay(250);
    send_i(texton);
}

/*////////////////////////////////////////////////////////////////////////*/
/* 清屏 */

void clrddram()
{
    send_i(clr);
    send_i(ext8);
    send_i(bas8);
}

/*////////////////////////////////////////////////////////////////////////*/
/* 连续向LCD发送string指向的num个数据 */

void LCD_puts(TAB* string, int8u num)
{
    while(num--)
    {
        send_d(*string++);//向12864液晶模块传输数据
    }
}

/*////////////////////////////////////////////////////////////////////////*/
/* 全屏显示图形子程序 */

void pho_disp(BMP12864* tab)
{
    int8u i, j, k, lcd_x, lcd_y;

    lcd_x = 0x80;
    for(i=0 ; i<2; i++)
    {
        for(j=0, lcd_y=0x80; j<32; j++, lcd_y++)
        {
            send_i(ext8);
            send_i(lcd_y);
            send_i(lcd_x);
            send_i(bas8);
            for(k=16; k; k--)
                send_d(*(tab++));
        }
        lcd_x = 0x88;
    }
    send_i(grapon);
    send_i(bas8);
}

/*////////////////////////////////////////////////////////////////////////*/
/* 显示点阵子程序,以lcd_data填充图形显示空间(GDRAM) */

void lat_disp(int8u lcd_data)
{
    int8u i, j, k;
    int8u lcd_x, lcd_y;
 
    lcd_x=0x80;
    i=2;
    do
    {   j=32; lcd_y=0x80;
        do
        {   send_i(ext8);
            send_i(lcd_y);
            send_i(lcd_x);
            send_i(bas8);
            k=16;
            do
            {   send_d(lcd_data);
            }while(k--);
            lcd_y++;
        }while(--j);
        lcd_x = 0x88;
    }while(--i);

    send_i(grapon);
    send_i(bas8);
}

/*////////////////////////////////////////////////////////////////////////*/
/* 造字功能,最多自定义4的字,word的范围为0~3 */

void setcgram(int8u word, BMP1616* map)
{
    int i;

    send_i(cgbas+16*word);
    for(i=0; i<32; i++)
		  send_d( *map++ );

}

/*////////////////////////////////////////////////////////////////////////*/

void clrgdram()
{
    lat_disp(0);
}

/*//////////////////////////////////////////////////////////////////////////
  原型:void putpixel(int8u x, int8u y, int8u mode);

  功能:在屏幕的指定位置上画点

  说明:(x,y)为屏幕上点的坐标,mode值含义如下:
        mode=0:清除(x,y)处的点
             1:在(x,y)处画点
             2:将(x,y)处的点的状态取反
//////////////////////////////////////////////////////////////////////////*/
/* 本程序可能是错误的,因为read_d()读取的GDRAM的内容并不完全,
    这可能是因为本人的12864液晶模块故障,或是因为其并无此功能。
*/

void putpixel(int8u x, int8u y, int8u mode)
{
    int8u i;
    union
    {   int16u D;
    	struct
        {   int8u c1;
            int8u c2;
        }C;
	 }t;

    int16u code an[] = {
        0x7fff, 0xbfff, 0xdfff, 0xefff, 0xf7ff, 0xfbff, 0xfdff, 0xfeff,
        0xff7f, 0xffbf, 0xffdf, 0xffef, 0xfff7, 0xfffb, 0xfffd, 0xfffe };
    int16u code or[] = {
        0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100,
        0x0080, 0x0040, 0x0020, 0x0010, 0x0008, 0x0004, 0x0002, 0x0001 };
    int16u code * const xo = or;

    setxy(x/16,y);
    read_d();
    t.C.c1 = read_d();
    t.C.c2 = read_d();

    i = x & 0x0f;
    switch(mode)
    {
        case 0: t.D &= an[i]; break;
        case 1: t.D |= or[i]; break;
        default:t.D ^= xo[i];
    }
    setxy(x/16,y);
    send_d(t.C.c1);
    send_d(t.C.c2);
}

/*////////////////////////////////////////////////////////////////////////*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -