KS0108 128*64 LCD C语言驱动
扫描二维码
随时随地手机看文章
/*
KS0108 128*64 LCD C语言驱动
参考ICCAVR资料和网上的资料改写
LCD引脚定义
1---GND
2---VCC
3---VLCD
4---D/I
5---R/W
6---E
7到14 D0-D7
15--CS1
16--CS2
17--RESET
18--VEE
19--SW
20--NC
*/
#include
#include
/* 当前行、列存储,行高16点,列宽8点 */
unsigned char CurOffset,CurRow,CurPage,CurCol;
/* 常量定义 */
#define LCD_STATUS_BUSY 0x80 //忙状态
#define START_LINE0 0xc0 //
#define DISPLAY_ON 0x3f //使能
#define DISPLAY_OFF 0x3e //禁止
#define PARA1 0x40 //
//PORTA---数据口 PORTB----控制口
#define LCD_DIR_PORT DDRA
#define LCD_IP_PORT PINA
#define LCD_OP_PORT PORTA
#define LCD_EN_PORT PORTF
#define LCD_CS2_PORT PORTF
#define LCD_CS1_PORT PORTF
#define LCD_RW_PORT PORTF
#define LCD_DI_PORT PORTF
#define LCD_DI_BIT BIT(0)//0x80
#define LCD_RW_BIT BIT(1)//0x40
#define LCD_EN_BIT BIT(2)//0x20
#define LCD_CS1_BIT BIT(3)//0x10
#define LCD_CS2_BIT BIT(4)//0x08
//#define LCD_EN_PORT PORTC
//#define LCD_CS2_PORT PORTC
//#define LCD_CS1_PORT PORTC
//#define LCD_RW_PORT PORTC
//#define LCD_DI_PORT PORTC
//#define LCD_DI_BIT BIT(7)//0x80
//#define LCD_RW_BIT BIT(6)//0x40
//#define LCD_EN_BIT BIT(5)//0x20
//#define LCD_CS1_BIT BIT(4)//0x10
//#define LCD_CS2_BIT BIT(3)//0x08
#define SET_LCD_E LCD_EN_PORT |= LCD_EN_BIT //LCD使能
#define CLEAR_LCD_E LCD_EN_PORT &= ~LCD_EN_BIT //LCD禁止
#define SET_LCD_DATA LCD_DI_PORT |= LCD_DI_BIT //选择指令端口
#define SET_LCD_CMD LCD_DI_PORT &= ~LCD_DI_BIT //选择数据端口
#define SET_LCD_READ LCD_RW_PORT |= LCD_RW_BIT //读模式
#define SET_LCD_WRITE LCD_RW_PORT &= ~LCD_RW_BIT //写模式
#define SET_LCD_CS2 LCD_CS2_PORT |= LCD_CS2_BIT //左屏选择禁止
#define CLEAR_LCD_CS2 LCD_CS2_PORT &= ~LCD_CS2_BIT //左屏选择使能
#define SET_LCD_CS1 LCD_CS1_PORT |= LCD_CS1_BIT //左屏选择禁止
#define CLEAR_LCD_CS1 LCD_CS1_PORT &= ~LCD_CS1_BIT //左屏选择使能
///////////////////////////////////////////////////////////////////
#define LEFT 0
#define RIGHT 1
#define CMD 0
#define DATA 1
///////////////////////////////////////////////////////////////////
//ASCII 字模宽度及高度
#define ASC_CHR_WIDTH 8
#define ASC_CHR_HEIGHT 12
#define ASC_HZ_WIDTH 12
//#define ASC_HZ_HEIGHT 12
typedef struct typFNT_GB16 /*12*16 汉字字模显示数据结构 */
{
char Index[2];
char Msk[24];
};
typedef struct typFNT_ASC16 /* 汉字字模显示数据结构 */
{
char Index[1];
char Msk[16];
};
struct typFNT_ASC16 const ASC_16[] = { /* 显示为8*16 Curier 10 常规*/
"1",0x00,0x00,0x08,0x08,0xFC,0x00,0x00,0x00,0x00,0x00,0x04,0x04,0x07,0x04,0x04,0x00,
"2",0x00,0x00,0x08,0x04,0x84,0x44,0x38,0x00,0x00,0x00,0x06,0x05,0x04,0x04,0x04,0x00,
"3",0x00,0x00,0x08,0x04,0x44,0x44,0xB8,0x00,0x00,0x00,0x02,0x04,0x04,0x04,0x03,0x00,
"4",0x00,0x00,0x80,0x60,0x18,0xFC,0x00,0x00,0x00,0x00,0x01,0x01,0x05,0x07,0x05,0x00,
"5",0x00,0x00,0x7C,0x44,0x44,0x44,0x84,0x00,0x00,0x00,0x02,0x04,0x04,0x04,0x03,0x00,
"6",0x00,0x00,0xF0,0x48,0x44,0x44,0x80,0x00,0x00,0x00,0x03,0x04,0x04,0x04,0x03,0x00,
"7",0x00,0x00,0x0C,0x04,0x84,0x64,0x1C,0x00,0x00,0x00,0x00,0x06,0x01,0x00,0x00,0x00,
"8",0x00,0x00,0xB8,0x44,0x44,0x44,0xB8,0x00,0x00,0x00,0x03,0x04,0x04,0x04,0x03,0x00,
"9",0x00,0x00,0x38,0x44,0x44,0x44,0xF8,0x00,0x00,0x00,0x00,0x04,0x04,0x02,0x01,0x00,
"0",0x00,0x00,0xF8,0x04,0x04,0x04,0xF8,0x00,0x00,0x00,0x03,0x04,0x04,0x04,0x03,0x00,
".",0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x06,0x00,0x00,0x00,
":",0x00,0x00,0x00,0x0C,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x00,0x00,
" ",0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
"(",0x00,0x00,0x00,0xE0,0x18,0x04,0x00,0x00,0x00,0x00,0x00,0x03,0x0C,0x10,0x00,0x00,
")",0x00,0x00,0x00,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x00,0x10,0x0C,0x03,0x00,0x00,
};
struct typFNT_GB16 const GB_16[] = { /* 宋体 9小五 显示为12*16 */
"液",0x19,0xE2,0x14,0x42,0xF2,0x2E,0x72,0x8F,0xAA,0x7A,0x02,0x00,0x01,0x07,0x00,0x00,0x07,0x04,0x04,0x02,0x01,0x02,0x04,0x00,
"晶",0x00,0xC0,0x40,0x5F,0xD5,0x15,0xD5,0x55,0x5F,0x40,0xC0,0x00,0x00,0x07,0x05,0x05,0x07,0x00,0x07,0x05,0x05,0x05,0x07,0x00,
"显",0x00,0x40,0x9F,0x15,0xD5,0x15,0xD5,0x15,0x1F,0xC0,0x00,0x00,0x04,0x04,0x05,0x04,0x07,0x04,0x07,0x06,0x05,0x04,0x04,0x00,
"示",0x10,0x12,0x92,0x52,0x12,0xF2,0x12,0x12,0x53,0x92,0x10,0x00,0x02,0x01,0x00,0x04,0x04,0x07,0x00,0x00,0x00,0x00,0x03,0x00,
"的",0xFC,0x44,0x46,0x45,0xFC,0x10,0x2C,0xC7,0x04,0x04,0xFC,0x00,0x07,0x02,0x02,0x02,0x07,0x00,0x00,0x04,0x04,0x04,0x03,0x00,
"第",0x04,0xEA,0xAB,0xAE,0xAA,0xFC,0xAA,0xAB,0xAE,0xBA,0x82,0x00,0x04,0x04,0x02,0x01,0x00,0x07,0x00,0x02,0x02,0x02,0x01,0x00,
"一",0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x30,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
"行",0x48,0x24,0xF3,0x08,0x09,0x09,0x09,0x09,0xF9,0x09,0x08,0x00,0x00,0x00,0x07,0x00,0x00,0x04,0x04,0x04,0x07,0x00,0x00,0x00,
"二",0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x06,0x04,0x00,0x00,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00,
"三",0x00,0x02,0x22,0x22,0x22,0x22,0x22,0x22,0x23,0x02,0x00,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x06,0x04,0x00,
"四",0x00,0xFF,0x81,0x41,0x3F,0x01,0x01,0xFF,0x81,0x81,0xFF,0x00,0x00,0x07,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x07,0x00,
"五",0x00,0x11,0x11,0x91,0x7F,0x11,0x11,0x11,0xF1,0x01,0x00,0x00,0x04,0x04,0x04,0x07,0x04,0x04,0x04,0x04,0x07,0x04,0x04,0x00,
};
void LCD_BUSY(unsigned char lr) //判断忙标志
{
unsigned char status;
CLI();
if(lr==LEFT)
{
CLEAR_LCD_CS2; //cs2=0
SET_LCD_CS1; //cs1=1
}
else
{
SET_LCD_CS2; //cs2=1
CLEAR_LCD_CS1; //cs1=0
}
SET_LCD_CMD;
LCD_DIR_PORT = 0x00;
LCD_OP_PORT = 0xff;
SET_LCD_READ;
SET_LCD_E;
asm("nop"); asm("nop");
asm("nop"); asm("nop");
while((LCD_IP_PORT) & LCD_STATUS_BUSY)
{
CLEAR_LCD_E;
asm("nop"); asm("nop");
asm("nop"); asm("nop");
SET_LCD_E;
asm("nop"); asm("nop");
asm("nop"); asm("nop");
}
CLEAR_LCD_E;
SET_LCD_WRITE;
LCD_OP_PORT = 0xff;
SEI();
}
void write_LCD(unsigned char lr,unsigned char cd,unsigned char data) /*写入指令或数据*/
{
CLI();
LCD_BUSY(lr);
if(cd==CMD)
SET_LCD_CMD;
else
SET_LCD_DATA;
SET_LCD_WRITE;
SET_LCD_E;
LCD_DIR_PORT = 0xff;
LCD_OP_PORT = data;
asm("nop"); asm("nop");
asm("nop"); asm("nop");
CLEAR_LCD_E;
LCD_OP_PORT = 0xff;
SEI();
}
unsigned char read_LCD(unsigned char lr) /* 读显示数据 */
{
unsigned char data;
CLI();
LCD_BUSY(lr);
SET_LCD_DATA;
LCD_DIR_PORT = 0x00;
LCD_OP_PORT = 0xff;
SET_LCD_READ;
SET_LCD_E;
asm("nop"); asm("nop");
asm("nop"); asm("nop");
data=LCD_IP_PORT;
CLEAR_LCD_E;
SET_LCD_WRITE;
LCD_BUSY(lr);
SET_LCD_DATA;
LCD_DIR_PORT = 0x00;
LCD_OP_PORT = 0xff;
SET_LCD_READ;
SET_LCD_E;
asm("nop"); asm("nop");
asm("nop"); asm("nop");
data=LCD_IP_PORT;
CLEAR_LCD_E;
SET_LCD_WRITE;
SEI();
return data;
}
void set_start_line_L(unsigned char line) /*设置显示起始行*/ //0-63
{
write_LCD(LEFT,CMD,0xc0|line);
}
void set_start_line_R(unsigned char line) /*设置显示起始行*/ //0-63
{
write_LCD(RIGHT,CMD,0xc0|line);
}
void set_page_L(unsigned char page) /*设置X地址 设置页*/ //0-7
{
write_LCD(LEFT,CMD,0xb8|page);
}
void set_page_R(unsigned char page) /*设置X地址 设置页*/ //0-7
{
write_LCD(RIGHT,CMD,0xb8|page);
}
void set_col_addr_L(unsigned char col) /*设置Y地址*/ //0-63
{
write_LCD(LEFT,CMD,0x40|col);
}
void set_col_addr_R(unsigned char col) /*设置Y地址*/ //0-63
{
write_LCD(RIGHT,CMD,0x40|col);
}
void init_lcd(void) /*初始化函数*/
{
set_start_line_L(0); /*显示起始行为0*/
set_start_line_R(0); /*显示起始行为0*/
write_LCD(LEFT,CMD,DISPLAY_ON); /* 开显示 */
write_LCD(RIGHT,CMD,DISPLAY_ON); /* 开显示 */
}
void clr_lcd(void) /*清屏函数*/
{
unsigned char pages,i;
for(pages=0;pages<8;pages++)
{
set_page_L(pages); /* X 页地址 */
set_page_R(pages); /* X 页地址 */
for(i=0;i<64;i++)
{
set_col_addr_L(i);//Y
set_col_addr_R(i);//Y
write_LCD(LEFT,DATA,0x0);
write_LCD(RIGHT,DATA,0x0);
}
}
}
/*************************************/
/* 绘点函数 */
/*************************************/
void pixel(unsigned char xx,unsigned char yy,unsigned char flag)
{
unsigned int y,ch;
ch=yy%8; //余数
y=1;
for(;ch!=0;)
{
y=y*2;
ch--;
}
if(xx<64)
{
set_page_L(yy/8);
set_col_addr_L(xx);
ch=read_LCD(LEFT);
set_col_addr_L(xx);
if(flag)
write_LCD(LEFT,DATA,ch|y);
else
{
y=~y;
ch&=y;
write_LCD(LEFT,DATA,ch|y);
}
}
else
{
set_page_R(yy/8);
set_col_addr_R(xx-64);
ch=read_LCD(RIGHT);
set_col_addr_R(xx-64);
if(flag)
write_LCD(RIGHT,DATA,ch|y);
else
{
y=~y;
ch&=y;
write_LCD(RIGHT,DATA,ch|y);
}
}
}
unsigned char GetPage(void) /*得到当前页*/
{
return CurPage;
}
unsigned char GetCol(void) /*得到当前列*/
{
return CurCol;
}
void SetPageCol(unsigned char upage, unsigned char ucol) /* 设置液晶的页和列 */
{
CurPage = upage;
CurCol = ucol;
if(ucol<64)
{
set_page_L(upage);
set_col_addr_L(ucol);
}
else
{
set_page_R(upage);
set_col_addr_R(ucol-64);
}
}
/* 设置当前显示的页和列 */
void SetRowCol(unsigned char urow, unsigned char ucol)
{
unsigned char page;
CurRow = urow;
CurCol = ucol;
switch(urow)
{
case 1:
page=0;
CurOffset=1;
break;
case 2:
page=1;
CurOffset=2;
break;
case 3:
page=3;
CurOffset=1;
break;
case 4:
page=4;
CurOffset=2;
break;
case 5:
page=6;
CurOffset=1;
break;
}
SetPageCol(page,ucol);
}
void disp_char(unsigned char c)
{
unsigned char k,j,uPage,uCol,ch_r,ch_w;
unsigned char width;
unsigned char len;
uPage = GetPage();
uCol = GetCol();
len=sizeof(ASC_16)/sizeof(ASC_16[0]);
for(k=0;k
if(c == ASC_16[k].Index[0] ) break;
}
if(k
if(c=='-'||c==':')
width=ASC_CHR_WIDTH-2;
else if(c=='|')
width=ASC_HZ_WIDTH-ASC_CHR_WIDTH;
else
width=ASC_CHR_WIDTH;
if(CurOffset==1) //下半部是写半个字节
{
for(j=0;j
SetPageCol(uPage,uCol+j);
ch_w=ASC_16[k].Msk[j];
if(uCol+j<64) write_LCD(LEFT,DATA,ch_w);
else write_LCD(RIGHT,DATA,ch_w);
}
SetPageCol(uPage+1,uCol);
for(j=0;j
SetPageCol(uPage+1,uCol+j);
if(uCol+j<64) ch_r=read_LCD(LEFT);
else ch_r=read_LCD(RIGHT);
ch_r&=0xf0;
ch_w=ASC_16[k].Msk[ASC_CHR_WIDTH+j]&0x0f;
ch_w|=ch_r;
SetPageCol(uPage+1,uCol+j);
if(uCol+j<64) write_LCD(LEFT,DATA,ch_w);
else write_LCD(RIGHT,DATA,ch_w);
}
}
else //上半部是写半个字节
{
for(j=0;j
SetPageCol(uPage,uCol+j);
if(uCol+j<64) ch_r=read_LCD(LEFT);
else ch_r=read_LCD(RIGHT);
ch_r&=0x0f;
ch_w=ASC_16[k].Msk[j];
ch_w=ch_w<<4;
ch_w|=ch_r;
SetPageCol(uPage,uCol+j);
if(uCol+j<64) write_LCD(LEFT,DATA,ch_w);
else write_LCD(RIGHT,DATA,ch_w);
}
SetPageCol(uPage+1,uCol);
for(j=0;j
SetPageCol(uPage+1,uCol+j);
ch_r=ASC_16[k].Msk[j];
ch_w=ASC_16[k].Msk[ASC_CHR_WIDTH+j];
ch_r=ch_r>>4;
ch_w=ch_w<<4;
ch_w|=ch_r;
SetPageCol(uPage+1,uCol+j);
if(uCol+j<64) write_LCD(LEFT,DATA,ch_w);
else write_LCD(RIGHT,DATA,ch_w);
}
}
}
SetPageCol(uPage,uCol+width);
}
void disp_hz(unsigned char const *hz)
{
unsigned char k,j,uPage,uCol,ch_r,ch_w;
uPage = GetPage();
uCol = GetCol();
for(k=0;k
if(hz[0] == GB_16[k].Index[0] && hz[1] == GB_16[k].Index[1])
break;
}
if(CurOffset==1)
{
for(j=0;j{
SetPageCol(uPage,uCol+j);
ch_w=GB_16[k].Msk[j];
if(uCol+j<64) write_LCD(LEFT,DATA,ch_w);
else write_LCD(RIGHT,DATA,ch_w);
}
SetPageCol(uPage+1,uCol);
for(j=0;j{
SetPageCol(uPage+1,uCol+j);
if(uCol+j<64) ch_r=read_LCD(LEFT);
else ch_r=read_LCD(RIGHT);
ch_r&=0xf0;
ch_w=GB_16[k].Msk[ASC_HZ_WIDTH+j]&0x0f;
ch_w|=ch_r;
SetPageCol(uPage+1,uCol+j);
if(uCol+j<64) write_LCD(LEFT,DATA,ch_w);
else write_LCD(RIGHT,DATA,ch_w);
}
SetPageCol(uPage,uCol+ASC_HZ_WIDTH);
}
else //汉字上半部是写半个字节
{
for(j=0;j{
SetPageCol(uPage,uCol+j);
if(uCol+j<64) ch_r=read_LCD(LEFT);
else ch_r=read_LCD(RIGHT);
ch_r&=0x0f;
ch_w=GB_16[k].Msk[j];
ch_w=ch_w<<4;
ch_w|=ch_r;
SetPageCol(uPage,uCol+j);
if(uCol+j<64) write_LCD(LEFT,DATA,ch_w);
else write_LCD(RIGHT,DATA,ch_w);
}
SetPageCol(uPage+1,uCol);
for(j=0;j{
SetPageCol(uPage+1,uCol+j);
ch_r=GB_16[k].Msk[j];
ch_w=GB_16[k].Msk[ASC_HZ_WIDTH+j];
ch_r=ch_r>>4;
ch_w=ch_w<<4;
ch_w|=ch_r;
SetPageCol(uPage+1,uCol+j);
if(uCol+j<64) write_LCD(LEFT,DATA,ch_w);
else write_LCD(RIGHT,DATA,ch_w);
}
SetPageCol(uPage,uCol+ASC_HZ_WIDTH);
}
}
void disp_str(unsigned char const *p)
{
unsigned char i=0;
while(p[i]>0)
{
if(p[i] < 128)
{ /* ASCII */
disp_char(p[i]);
}
else
{ /* 中文 */
disp_hz(&p[i]);
i++;
}
i++;
}
}
void main()
{
unsigned char i;
DDRF = 0xff;
init_lcd();
clr_lcd();
SetRowCol(1,0);
disp_str("液晶显示的第一行1234");
SetRowCol(2,0);
disp_str("液晶显示的第二行2345");
SetRowCol(3,0);
disp_str("液晶显示的第三行3456");
SetRowCol(4,0);
disp_str("液晶显示的第四行5678");
SetRowCol(5,0);
disp_str("液晶显示的第五行6789");
for(i=0;i<64;i++)
pixel(127,i,1);
for(i=0;i<64;i++)
pixel(0,i,1);
for(i=0;i<128;i++)
pixel(i,0,1);
for(i=0;i<128;i++)
pixel(i,63,1);
while(1);
}