注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
四蹄踏雪II号的个人空间 https://home.eeworld.com.cn/space-uid-224269.html [收藏] [复制] [分享] [RSS]
日志

AVR学习日志(五十三)—学习使用LCD12864

已有 1257 次阅读2010-12-29 16:42

(330.91 K) 该附件被下载次数 7

好久没有搞液晶显示了,这两天学习了一下LCD12864点阵液晶,LCD12864在市面上主要分为两种,一种是带字库的,控制芯片一般是st7920,因为它带中文字库,所以价格自然就高一些了;还有一种是不带字库的,它的控制芯片一般是KS0108,虽不带字库,但由于是点阵式的所以一样可以让它显示汉字。关于它的驱动不是很难,其实就是单片机的IO口操作,但是在写它的驱动之前建议你好好看看它的数据手册,还有它的指令集及读写时序,这是非常重要的哦。附件中有我的调试程序时用的仿真电路,它仅仅是调试程序时用。具体硬件电路怎么设计,请参阅相关数据手册。

好了,硬件不多说了,不是把我的程序贴上来吧:

//---------------------------------------------------------------------------------

// 一些关于LCD的宏定义,方便调用

//---------------------------------------------------------------------------------

// 空指令延时

#define NOP() asm("nop")

// LCD起始行/页/列指令定义

#define LCD_START_ROW 0xC0 // 起始行

#define LCD_PAGE 0xB8 // 页指令

#define LCD_COL 0x40 // 列指令

// 液晶控制引脚定义

#define RW PC0 // 读写引脚

#define DI PC1 // 数据指令

#define EN PC2 // 使能

#define CS1 PC3 // 右半屏选择

#define CS2 PC4 // 左半屏选择

#define RST PC5 // 复位

// 液晶端口

#define LCD_PORT PORTA // 液晶DB0-DB7

#define LCD_DDR DDRA // 设置数据方向

#define LCD_PIN PINA // 读状态数据

#define LCD_CTRL PORTC // 液晶控制端口

// 液晶端口定义

#define RW_H() LCD_CTRL |= _BV(RW)

#define RW_L() LCD_CTRL &= ~_BV(RW)

#define DI_H() LCD_CTRL |= _BV(DI)

#define DI_L() LCD_CTRL &= ~_BV(DI)

#define EN_H() LCD_CTRL |= _BV(EN)

#define EN_L() LCD_CTRL &= ~_BV(EN)

#define CS1_H() LCD_CTRL |= _BV(CS1)

#define CS1_L() LCD_CTRL &= ~_BV(CS1)

#define CS2_H() LCD_CTRL |= _BV(CS2)

#define CS2_L() LCD_CTRL &= ~_BV(CS2)

#define RST_H() LCD_CTRL |= _BV(RST)

#define RST_L() LCD_CTRL &= ~_BV(RST)

//-----------------------The end-------------------------------------------------

//-------------------------------------------------------------------------------

// some functions about LCD

//-------------------------------------------------------------------------------

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

//函数名称:void wait_lcd_ready(void)

//功 能:等待LCD就绪

//入口参数:NULL

//出口参数:NULL

//备 注:NULL

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

void wait_lcd_ready(void)

{

unsigned char busy_check;

do{

LCD_DDR = 0x00; // 配置数据端口为输入

LCD_PORT = 0xff; // 设置内部上拉

RW_H();

NOP();

DI_L(); // 读状态寄存器

busy_check = (LCD_PIN & 0x80);

EN_H();

NOP();

EN_L();

}while(busy_check == 1);

}

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

//函数名称:void lcd_write_cmd(uint8_t cmd)

//功 能:向LCD发送命令

//入口参数:cmd -- 要写入的命令

//出口参数:NULL

//备 注:NULL

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

void lcd_write_cmd(unsigned char cmd)

{

wait_lcd_ready(); // 等待液晶就绪

LCD_DDR = 0xff; // 设置为输出方向

LCD_PORT = 0xff; // 初始时为全高

//CS1_H();

//CS2_H();

RW_L();

NOP();

DI_L(); // 写命令寄存器 0 -- 命令寄存器 1 -- 数据寄存器

LCD_PORT = cmd; // 要写入的命令

EN_H(); // 使能液晶,写入命令

NOP();

EN_L();

}

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

//函数名称:void lcd_write_dat(uint8_t dat)

//功 能:向LCD发送数据

//入口参数:dat -- 要写入的数据

//出口参数:NULL

//备 注:NULL

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

void lcd_write_dat(unsigned char dat)

{

wait_lcd_ready(); // 等待液晶就绪

LCD_DDR = 0xff; // 设置为输出方向

LCD_PORT = 0xff; // 初始时为全高

RW_L();

NOP();

DI_H(); // 写数据寄存器

if(Reverse_Display == 1)

{

LCD_PORT = dat;

}

else

{

LCD_PORT = ~dat;

}

//DI_L();

EN_H(); // 使能液晶,写入数据

NOP();

EN_L();

}

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

//函数名称:void lcd_init(void)

//功 能:LCD实始化

//入口参数:NULL

//出口参数:NULL

//备 注:NULL

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

void lcd_init(void)

{

lcd_write_cmd(0x3f); //开显示, 关显示为 -- 0x3e

_delay_ms(15);

/*

lcd_write_cmd(0x38); //8位形式,两行字符。

_delay_ms(15);

lcd_write_cmd(0x0f); //开显示。

_delay_ms(15);

lcd_write_cmd(0x01); //清屏。

_delay_ms(15);

lcd_write_cmd(0x06); //画面不动,光标右移。

_delay_ms(15);

*/

lcd_write_cmd(LCD_START_ROW); //设置起始行。

_delay_ms(15);

}

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

//函数名称:void lcd_common_show(uint8_t P,uint8_t L, uint8_t n,uint8_t *r)

//功 能:通用显示函数,从P页的第L列显示n个字节数据

//入口参数:uint8_t P -- 第p页,取值范围0-7

// uint8_t len -- 第L列,取值范围0-127

// uint8_t n -- n个字节

// uint8_t *r -- r所指向的缓冲

//出口参数:NULL

//备 注:第字节8位是垂直显示的,高位在上,低位在下,每个8*128的矩形区域为一页

// 整个LCD又由64*64的左半屏和64*64的右半屏构成

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

void lcd_common_show(unsigned char P,unsigned char L, unsigned char n,unsigned char *r)

{

uint8_t i;

if(L < 64) //从左半屏显示

{

CS1_H(); //选择左半屏

CS2_L();

lcd_write_cmd(0x34); //扩展指令集

lcd_write_cmd(LCD_PAGE + P ); //选择起始页

lcd_write_cmd(LCD_COL + L ); //选择起始列

lcd_write_cmd(0x30); //绘图显示开

if((L + n)<64)

{

for(i=0; i

{

lcd_write_dat(r[i]);

}

}

//如果越界则跨越左右半屏显示

else

{

//左半屏显示部分

for(i=0; i<(64-L); i++)

{

lcd_write_dat(r[i]);

}

//右半屏显示处理

CS1_L();

CS2_H(); //选择右半屏

lcd_write_cmd(0x34); //扩展指令集

lcd_write_cmd(LCD_PAGE + P ); //选择起始页

lcd_write_cmd(LCD_COL); //右半屏起始列

lcd_write_cmd(0x30); //绘图显示开

for(i=(64-L); i

{

lcd_write_dat(r[i]);

}

}

}

//全部显示右半屏

else

{

CS1_L();

CS2_H(); //选择右半屏

lcd_write_cmd(0x34); //扩展指令集

lcd_write_cmd(LCD_PAGE + P ); //选择起始页

lcd_write_cmd(LCD_COL+L-64); //右半屏起始列

lcd_write_cmd(0x30); //绘图显示开

for(i=0; i

{

lcd_write_dat(r[i]);

}

}

}

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

//函数名称:void display_816_char(uint8_t P,uint8_t L,unit8_t *M)

//功 能:显示一个8*16点阵字符

//入口参数:uint8_t P -- 第P页

// uint8_t len -- 第L列

// uint8_t *M -- M所指向的缓冲

//出口参数:NULL

//备 注:NULL

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

void display_char(unsigned char P,unsigned char L,unsigned char *M)

{

lcd_common_show(P, L,8,M); //显示上半部分8*8

lcd_common_show(P+1,L,8,M+8); //显示下半部分8*8

}

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

//函数名称:void display_word(uint8_t P,uint8_t L,unit8_t *M)

//功 能:显示一个16*16点阵汉字

//入口参数:uint8_t P -- 第P页

// uint8_t len -- 第L列

// uint8_t *M -- M所指向的缓冲

//出口参数:NULL

//备 注:NULL

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

void display_word(unsigned char P,unsigned char L,unsigned char *M)

{

lcd_common_show(P, L,16,M); //显示上半部分16*8

lcd_common_show(P+1,L,16,M+16); //显示下半部分16*8

}

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

//函数名称:void display_word_string(uint8_t P,uint8_t L,unit8_t *M)

//功 能:显示一个16*16点阵汉字

//入口参数:uint8_t P -- 第P页

// uint8_t L -- 第L列

// uint8_t n -- n个汉字

// uint8_t *M -- M所指向的缓冲

//出口参数:NULL

//备 注:NULL

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

void display_word_string(unsigned char P,unsigned char L,unsigned char n,unsigned char *M)

{

uint8_t i;

for(i=0; i

{

display_word(P,L,M);

L = L+16; // 因为一个汉字占16*16个点阵,即一个汉字要点16列,16行

M = M+32; // 共需要32个字符

}

}

//-------------------------------The end-----------------------------------------

上面这些是关于液晶驱动的一些函数,至于其它的函数也没有什么了,就只剩下一些头文件与一个主函数了,下面是测试的主函数:

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

//函数名称:int main(void)

//功 能:主函数

//入口参数:NULL

//出口参数:NULL

//备 注:NULL

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

int main(void)

{

Reverse_Display = 1;

port_init(); // 端口初始化

lcd_init(); // LCD初始化

display_word_string(2,32,4,(uint8_t *)dis_code); //从第2页32列开始显示4个汉字

Reverse_Display = 0;

display_word_string(4,4,7,(uint8_t *)(dis_code+128)); //从第2页32列开始显示4个汉字

while(1);

return 0;

}

附件是有源程序代码及仿真电路还有一些说明,需要的话可以下载下来看看,好了今天先到这吧,这只是开始,并不是结束,路还很长,懒猫该继续修行去了……

再喊一下口号:

每天进步一点点,开心多一点^_^

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章