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

📄 lcd12864.c

📁 AVR典型实例.rar
💻 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 
*/
#define F_CPU 4000000UL
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define CLI cli
#define SEI sei
#define BIT(A) (1<<A)
#define pgm8(A) ((typeof(A))pgm_read_byte(&(A)))

/* 当前行、列存储,行高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		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

struct typFNT_ASC16	/* 汉字字模显示数据结构 */
{
	unsigned char Index[1];
	char Msk[16];
};
PROGMEM 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},
};

#define ASC_HZ_WIDTH	12
//#define ASC_HZ_HEIGHT	12

struct typFNT_GB16	/*12*16 汉字字模显示数据结构 */
{
	unsigned char Index[2];
	char Msk[24];
};
PROGMEM struct typFNT_GB16  GB_16[] = {	/* 宋体 9小五 显示为12*16 */
"输",0x34,0x2c,0xf7,0x24,0xe8,0xa4,0xea,0x9,0xca,0x4,0xe8,0x8,0x2,0x2,0xf,0x1,0xf,0x2,0xf,0x0,0x3,0x8,0xf,0x0,
"入",0x0,0x0,0x0,0x81,0x71,0xe,0x30,0xc0,0x0,0x0,0x0,0x0,0x4,0x4,0x2,0x1,0x0,0x0,0x0,0x0,0x1,0x2,0x4,0x4,
"出",0x0,0x80,0x3c,0x20,0x20,0xff,0x20,0x20,0x20,0x3c,0x80,0x0,0x0,0xf,0x8,0x8,0x8,0xf,0x8,0x8,0x8,0x8,0xf,0x0,
"数",0xa8,0xae,0x98,0xff,0xac,0x8a,0x10,0xfc,0xb,0x88,0x78,0x8,0x8,0x8,0x5,0x2,0x2,0x5,0x8,0x4,0x3,0x2,0x4,0x8,
};


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<len;k++)
	{
		if(c == pgm8(ASC_16[k].Index[0]) ) break;
	}
	if(k<len)
	{
		
		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<width;j++)
			{
				SetPageCol(uPage,uCol+j);
				ch_w=pgm8(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<width;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=pgm8(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<width;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=pgm8(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<width;j++)
			{
				SetPageCol(uPage+1,uCol+j);
				
				ch_r=pgm8(ASC_16[k].Msk[j]);
				ch_w=pgm8(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<sizeof(GB_16)/sizeof(GB_16[0]);k++)
	{
	    // GB_16[k].Index[0]
		if(hz[0] == pgm8(GB_16[k].Index[0]) && hz[1] == pgm8(GB_16[k].Index[1]))
		{
			break;
		}
	}

	if(CurOffset==1) 
	{
	for(j=0;j<ASC_HZ_WIDTH;j++)
	{
		SetPageCol(uPage,uCol+j);
		ch_w=pgm8(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<ASC_HZ_WIDTH;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=pgm8(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<ASC_HZ_WIDTH;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=pgm8(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<ASC_HZ_WIDTH;j++)
	{
		SetPageCol(uPage+1,uCol+j);

		ch_r=pgm8(GB_16[k].Msk[j]);
		ch_w=pgm8(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 *p)
{
	unsigned char i=0;
	while(p[i]>0)
	{
		if(p[i] < 127)
		{	/* ASCII */
			disp_char(p[i]);
		}
		else
		{	/* 中文 */
			disp_hz(&p[i]);
			i++;
		}
		i++;
	}
}

⌨️ 快捷键说明

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