(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; } 附件是有源程序代码及仿真电路还有一些说明,需要的话可以下载下来看看,好了今天先到这吧,这只是开始,并不是结束,路还很长,懒猫该继续修行去了…… 再喊一下口号: 每天进步一点点,开心多一点^_^