`

12864液晶驱动源码,独创中英文混合输出

LCD 
阅读更多

 控制器7920
 代码没啥好说,我尽量多写了注释,播放动画也很流畅的
 亮点就是支持中英文混合输出,其他没啥
 

昨天发现座的公交车上用的也是这种12864 ,显示温度和时间...

 

#ifndef  _LCD12864_H 
#define	 _LCD12864_H 
#include "my51.h"

#define LCD_dataBus  P0	   //总线
sbit LCD_EN = P3^4;		   //使能控制
sbit LCD_RS = P3^5;		   //数据_命令选择端
sbit LCD_RW = P3^6;		   //读写控制
sbit LCD_PSB= P3^7;		   //串并选择,H并行,L串行


extern bool bShowPicFlag;  //绘图时图像显示控制(仅控制GDRAM)

/*************************基本功能函数*********************************************/
extern void LCD12864_init();					//初始化,必须置顶调用
extern void LCD12864_setPos(u8 row, u8 cols);	//设置光标位置
extern void LCD12864_writeByte(u8 dat);			//写一个字节
extern void LCD12864_writeCmd(u8 cmd);			//写指令
extern   u8 LCD12864_readByte();				//读一个字节ram
extern   u8 LCD12864_readIR();					//读暂存器
extern bool LCD12864_isBusy();					//判忙

/*************************调用基本字库显示文字**************************************/	
//独创支持全角半角字符及中英混合的字符串,或字符串的子串,起始行号row(0-3)和列坐标cols(0-15),写满屏幕为止
//行号4-7行是滚动区
extern void LCD12864_writeData(u8 row, u8 cols,u8* pBuf,u8 dataSize);//写一堆数据
extern void LCD12864_earseSomeDDRam(u8 row,u8 cols,u8 dataSize);	//擦除N字节DDRam

/*************************用户自定义图标字体****************************************/
extern void LCD12864_writeCGRAM(u8 userRamNum,u8* pCGRAM_userCode); //写自定义图标字体
extern void LCD12864_showCGRAM(u8 row,u8 cols,u8 num) ;	//显示自定义图标字体,row(0-3),cols(0-15)
extern void LCD12864_clearCGRAM(u8 CGRAM_groupNum) ;    //CGRAM清零(初始化也可清0)

/*************************图像显示功能函数**********************************************/
extern void LCD12864_showGDRAM(bool bShowImage); 	 //GDRAM绘图显示开关
extern void LCD12864_clearGDRAM();		   			 //液晶整个可视区的GDRAM快速清0
//前4参数:起始点x(0-7)位址,y(0-63)坐标,要显示的宽度(1-128)和高度(1-64)[可显示从图像左上角开始的部分区域]
//后4参数:图像代码地址,图像本身的宽度(1-128)和高度(1-64), 反白(true反白,false不反白)
//画图填充GDRAM	,注:显示的区域或者图像本身宽度必须是8的倍数
extern u8 LCD12864_drawGDRAM(u8 x,u8 y,u8 width,u8 height,u8 *pImageCode,u8 imageWidth,u8 imageHight,bool bReverse);
extern void LCD12864_drawDot(u8 x,u8 y,u8 flag);	   	//打点,x(0-127),y(0-63),flag(0正常,1反白,2清0)
extern bool LCD12864_drawXYLine(u8 x1, u8 y1,u8 x2, u8 y2,u8 flag);		  //画水平或垂直直线
extern void LCD12864_drawAnyLine(u8 x1, u8 y1,u8 x2, u8 y2,u8 flag) ;	  //画任意直线
extern void LCD12864_drawRectangle(u8 x,u8 y ,u8 width,u8 height,u8 flag);//画矩形
extern void LCD12864_drawFillRect(u8 x,u8 y, u8 width,u8 hight,u8 flag);  //填充矩形,可对矩形区反白或清0
extern void LCD12864_drawVerticalSquare(u8 x,u8 y,u8 r,u8 flag)	; 		  //画站立的正方形
extern void LCD12864_drawCircle(u8 x0,u8 y0,u8 r,u8 flag);		  		  //画圆

//打点法全屏画图有点慢了,打点法反白矩形区还可以,建议矩形范围小一些,不然比较慢
//打点法效果最好,因为文字的矩形区比较小,速度很快
//不过绘图法反白文字效率高,flash空间充裕的建议用绘图法

/***************************全屏滚动*******************************************/
//需要滚动时,用LCD12864_writeScrollData()函数,参数和LCD12864_writeData()一样
extern void LCD12864_writeScrollData(u8 row,u8 cols,u8* pBuf,u8 dataSize);//写数据 (滚动模式)
extern void LCD12864_setScrollPos(u8 row, u8 cols);		//设置滚动模式的坐标
extern void LCD12864_showScrollCGRAM(u8 row,u8 cols,u8 CGRAM_groupNum);//用于CGRAM滚动显示前执行
extern void LCD12864_startScroll(u8 scrollNum,u16 delay_ms);  //滚动开始
#endif															 	

 

#include "lcd12864.h"
//图像与文字,图像与用户图标,像素重合时是异或关系
//文字与用户图标是覆盖关系
bool bShowPicFlag=false;		  //绘图时图像显示控制

/*
u8 LCD12864_table[]={"123456789"};
*/

void LCD12864_drawFillRect(u8 x,u8 y, u8 width,u8 hight,u8 flag)//填充任意位置的整个矩形
{//矩形起始坐标x(0-127),y(0-63),宽(1-128)高(1-64),flag有3种值,0正常填充,1反色,2清0
	u8 i=0;
	u8 j=0;
	if(0==width||0==hight)	 //矩形宽度或高度为0时返回
	{
		return ;
	}
	if( (x+width>128 ||(y+hight)>64)  )
	{
		led2=0;
		return;
	}
	for(j=0;j<hight;j++)
	{		
		for(i=0;i<width;i++)
		{
			LCD12864_drawDot(x+i, y+j,flag);		
		}
	}			
}


void LCD12864_drawRectangle(u8 x,u8 y, u8 width,u8 hight,u8 flag)//画矩形
{	//矩形起始坐标x(0-127),y(0-63),宽度(1-128)和高度(1-64)	flag有3种值,0正常写1,1反色,2清0
	if(0==width||0==hight)	 //矩形宽度或高度为0时返回
	{
		return ;
	}
	width--;hight--;
	LCD12864_drawXYLine(x, y,x+width, y, flag);
	LCD12864_drawXYLine(x+width, y,x+width, y+hight, flag);
	LCD12864_drawXYLine(x, y,x, y+hight, flag);
	LCD12864_drawXYLine(x, y+hight,x+width, y+hight, flag);	
}

bool LCD12864_drawXYLine(u8 x1,u8 y1,  u8 x2, u8 y2,  u8 flag)//画水平或垂直直线
{	//起始点坐标和终点坐标,x(0-127),y(0-63),  flag有3种值,0正常写1,1反色,2清0
	u8 n=0;
	if(flag>2|| x1>127||x2>127||y1>63||y2>63)
	{
		return false;
	}

	if(x1==x2)
	{
		for(n=0;n<abs(y2-y1)+1;n++)
		{
			LCD12864_drawDot( x1,y1+(y2>=y1?n:-n) ,flag);	
		}
	}

	if(y1==y2)
	{
		for(n=0;n<abs(x2-x1)+1;n++)
		{
			 LCD12864_drawDot(x1+(x2>=x1?n:-n),y1,flag)	;
		}
	}
	return true;	
}

void LCD12864_drawCircle(u8 x0,u8 y0,u8 r,u8 flag)
{
	s8 a,b;
	s8 di;
	if(r>31 ||r==0) return;    //参数过滤,次液晶显示的最大圆半径为31
	a=0;
	b=r;
	di=3-2*r;       //判断下个点位置的标志
	while(a<=b)
	{
		LCD12864_drawDot(x0-b,y0-a,flag);  //3           
		LCD12864_drawDot(x0+b,y0-a,flag);  //0           
		LCD12864_drawDot(x0-a,y0+b,flag);  //1       
		LCD12864_drawDot(x0-b,y0-a,flag);  //7           
		LCD12864_drawDot(x0-a,y0-b,flag);  //2             
		LCD12864_drawDot(x0+b,y0+a,flag);  //4               
		LCD12864_drawDot(x0+a,y0-b,flag);  //5
		LCD12864_drawDot(x0+a,y0+b,flag);  //6 
		LCD12864_drawDot(x0-b,y0+a,flag);             
		a++;
		//使用Bresenham算法画圆     
		if(di<0)
		di +=4*a+6;
		else
		{
			di +=10+4*(a-b);   
			b--;
		} 
		LCD12864_drawDot(x0+a,y0+b,flag);
	}
}


void LCD12864_drawVerticalSquare(u8 x,u8 y,u8 r,u8 flag)	//画站立的正方形
{
    u8 a,b;
    float c=0;
    a = 0;
    b = r;
    c = 3 - 2*r;
    while(a < b)
    {
        LCD12864_drawDot(x+a,y+b,flag);
        LCD12864_drawDot(x-a,y+b,flag);
        LCD12864_drawDot(x+a,y-b,flag);
        LCD12864_drawDot(x-a,y-b,flag);
        
        LCD12864_drawDot(x+b,y+a,flag);
        LCD12864_drawDot(x-b,y+a,flag);
        LCD12864_drawDot(x+b,y-a,flag);
        LCD12864_drawDot(x-b,y-a,flag);
        
        if(c < 0)
        {
            c = c+4*a + 6; 
        }
        else
        {
            c= c + 4*(a - b) + 10;
            b-=1;
        }
        a = a + 1;  //控制打点间隔
        
    }
    if(a == b)
    {
        LCD12864_drawDot(x+a,y+b,flag);
        LCD12864_drawDot(x-a,y+b,flag);
        LCD12864_drawDot(x+a,y-b,flag);
        LCD12864_drawDot(x-a,y+b,flag);
        
        LCD12864_drawDot(x+b,y+a,flag);
        LCD12864_drawDot(x-b,y+a,flag);
        LCD12864_drawDot(x+b,y-a,flag);
        LCD12864_drawDot(x-b,y-a,flag);       
    }
}


void LCD12864_drawAnyLine(u8 StartX, u8 StartY,u8 EndX, u8 EndY, u8 flag)  //画任意直线
{
    u8 t, distance ;      /*根据屏幕大小改变变量类型(如改为int型)*/
    s16 x = 0 , y = 0 ;
    s8 incx, incy, dx, dy ;
	if((StartX==EndX) ||(StartY==EndY))
	{
		LCD12864_drawXYLine(StartX,StartY,EndX,EndY,flag);
		return;
	}

    dx = EndX - StartX ;
    dy = EndY - StartY ;		
	incx = dx > 0 ?1:-1;
	incy = dy > 0 ?1:-1;

    dx = abs( dx );
    dy = abs( dy );
    if( dx > dy )
    {
        distance = dx ;
    }
    else
    {
        distance = dy ;
    }
    LCD12864_drawDot( StartX, StartY, flag ) ;		  //反白补点
    for( t = 0 ; t <= distance+1 ; t++ )
    {
        LCD12864_drawDot( StartX, StartY, flag ) ;
        x += dx ;
        y += dy ;
        if( x > distance )
        {
            x -= distance ;
            StartX += incx ;
        }
        if( y > distance )
        {
            y -= distance ;
            StartY += incy ;
        }
    }
}

void LCD12864_drawDot(u8 x, u8 y,u8 flag)	//画点,0打点,1反色,2清0
{  //x(0-127),y(0-63),flag有3种值,0正常写1,1反色,2清0
    u8 x_word=0;		 //水平(0-127)个像素中的哪个字,一字16位
    u8 x_mode=0;		 //取余
    u8 y_part=0;
    u8 y_bit=0;
    u8 tempH=0;
    u8 tempL=0;
	x_word=x>>4;    	//在哪一个字(0-7)	      ,x_word=x/16 
    x_mode=x&0x0f;      //在该字的哪一位		  ,x_mode= x%16 
    y_part=y>>5;        //在哪个屏0或1			  ,y_part=y/32 
    y_bit= y&0x1f;      //垂直方向,y_bit范围(0-31),y_bit=y%32 
    bShowPicFlag?LCD12864_writeCmd(0x36):LCD12864_writeCmd(0x34);
    LCD12864_writeCmd(0x80+y_bit);	//垂直坐标
    LCD12864_writeCmd(0x80+8*y_part+x_word);		   //水平位址
  
    LCD12864_readByte();
    tempH=LCD12864_readByte();  //先将该字16位数据保存
    tempL= LCD12864_readByte();
    
    LCD12864_writeCmd(0x80+y_bit);	                   //重设地址,因为AC计数器变了
    LCD12864_writeCmd(0x80+8*y_part+x_word);		   //水平位址
	if(0==flag)								   		//不反白,打1,
	{
	    if(x_mode<8)  //如果x_mode小于8,说明点应位于该字的左边高8位中
	    {
	        LCD12864_writeByte( tempH | bit(7- x_mode) );
	        //LCD12864_writeByte(tempL);
	    }
	    else
	    {
	        //LCD12864_writeByte(tempH);
			LCD12864_readByte();	 //让AC走半步
	        LCD12864_writeByte(tempL|bit(15-x_mode));
	    } 	
	}
	else if(1==flag)			//反白,该点与原来的状态相反
	{
		if(x_mode<8)  //如果x_mode小于8,说明点应位于该字的左边高8位中
	    {
			if(tempH & bit(7- x_mode))	     //原来是1
			{
				LCD12864_writeByte( tempH&~bit(7- x_mode) );	//写0
			}
			else							 //原来是0
			{
				LCD12864_writeByte( tempH | bit(7- x_mode) );	//写1
			}
	        
	    }
	    else
	    {
			LCD12864_readByte();	 //让AC走半字
			if(tempL& bit(15-x_mode))	  //原来是1的写0
			{
				
				LCD12864_writeByte(tempL&~bit(15-x_mode));	 //写0
			}
			else
			{
				LCD12864_writeByte(tempL|bit(15-x_mode));	 //写0
			}
	        
	    }
	}
	else if(2==flag)			  //清0
	{
		if(x_mode<8)  //如果x_mode小于8,说明点应位于该字的左边高8位中
	    {
	        LCD12864_writeByte( tempH&~bit(7- x_mode) );
	    }
	    else
	    {
			LCD12864_readByte();	 //让AC走半字
	        LCD12864_writeByte(tempL&~bit(15-x_mode));
	    }	
	}  
}

void LCD12864_showGDRAM(bool bShowImage)	//GDRAM图像显示开关
{
	if(bShowImage)		 //开启显示
	{
	    LCD12864_writeCmd(0x36);
	    LCD12864_writeCmd(0x30);		
	}
	else				 //关闭显示
	{
	    LCD12864_writeCmd(0x34);
	    LCD12864_writeCmd(0x30);		
	}
}


//填充GDRAM
u8 LCD12864_drawGDRAM(u8 x,u8 y,u8 width,u8 height,u8* pImageCode,u8 imageWidth,u8 imageHight,bool bReverse)
{//前4参数:起始点x(0-7)位址,y(0-63)坐标,要显示的宽度(1-128)和高度(1-64)[可显示从图像左上角开始的部分区域]
 //后4参数:图像代码地址,图像本身的宽度(1-128)和高度(1-64), 反白(true反白,false不反白)
	u8 i=0;
	u8 j=0;
	if( height > imageHight )	   //检测显示高度,宽度不检测不会乱码
	{							   //显示的高度不能超过图片本身高度
		return 0x01;			   //也就是说可显示图像的部分区域(从图像左上角开始的部分区域)
	}
	width>>=3;					   //像素宽度转化为字节个数,所以width必须是8的整数倍
	imageWidth>>=3;				   //像素宽度转化为字节个数,所以width必须是8的整数倍
	if(bShowPicFlag)				
	{
		LCD12864_writeCmd(0x36);	//改写GDRAM时,开启绘图显示,可防止动画显示时闪动	 	
	}
	else
	{
		LCD12864_writeCmd(0x34);	//改写GDRAM时,关闭绘图显示
	}

	for(j=0;j<height;j++)		   //写GDRAM
	{
		if(y+j>31)							//地址变换
		{
			LCD12864_writeCmd(0x80+y+j-32);	//垂直坐标
			LCD12864_writeCmd(0x88+x);		//水平位址
		}
		else
		{
			LCD12864_writeCmd(0x80+y+j);	
			LCD12864_writeCmd(0x80+x);
		}
		for(i=0;i<width;i++)				//水平方向写数据,带反白控制
		{
			LCD12864_writeByte(bReverse?~pImageCode[imageWidth*j+i]:pImageCode[imageWidth*j+i]);	
		}	
	}
	LCD12864_writeCmd(0x30);
	return 0x02;
}


void LCD12864_clearGDRAM()      	//液晶可视区的绘图GDRAM清0
{    
    u8 j=0;
    u8 i=0;
    LCD12864_writeCmd(0x34);        //扩展指令
    for(j=0;j<64;j++)       		//垂直方向地址手动增加,当j=64时清整个GDram
    {								//我们只要清可视区的GDRAM就可以了
        LCD12864_writeCmd(0x80+j);  //y轴坐标
        LCD12864_writeCmd(0x80);    //x轴坐标
        for(i=0;i<32;i++)           //水平方向位址自动增加
        {
            LCD12864_writeByte(0x00);
        }
    }
    LCD12864_writeCmd(0x30);  //回到基本指令
}	  


/*--------------------------------CGRAM start----------------------------------------------*/
void LCD12864_clearCGRAM(u8 CGRAM_groupNum)//将用户自定义编码区CGRAM清0	 
{	//参数一是CGRAM的4组用户空间组号码(0~3) ,参数二是用户自定义图表或汉字的编码
    u8 i,addr=0;	
	bShowPicFlag?LCD12864_writeCmd(0x36):LCD12864_writeCmd(0x34);//扩展指令,绘图开关保持								
    LCD12864_writeCmd(0x02);    	//SR等于0,允许设置卷动地址
    LCD12864_writeCmd(0x30);    	//恢复为8位并行,基本指令集
    addr=(CGRAM_groupNum<<4)|0x40;	//将CGRAM空间号转换为相应存储地址
    LCD12864_writeCmd(addr);		//定位到该位址(用户空间位址范围0x40-0x7F共128字节)
    for(i=0;i<16;i++)				//将用户自定义编码写入该16*16位元组空间
    {
        LCD12864_writeByte(0);		//连续写2个字节共16位
        LCD12864_writeByte(0);
    }    
}

void LCD12864_writeScrollCGRAM(u8 CGRAM_groupNum, u8* pUserCode)//将用户自定义编码写入CGRAM	 
{	//参数一是CGRAM的4组用户空间组号码(0~3) ,参数二是用户自定义图表或汉字的编码
    u8 i,addr=0;
	if(bShowPicFlag)				
	{
		LCD12864_writeCmd(0x36);	//开启绘图显示,可流畅播放动画	 	
	}
	else
	{
		LCD12864_writeCmd(0x34);	//默认关闭绘图显示
	}				
    LCD12864_writeCmd(0x02);    	//SR等于0,允许设置卷动地址
    LCD12864_writeCmd(0x30);    	//恢复为8位并行,基本指令集
    addr=(CGRAM_groupNum<<4)|0x40;	//将CGRAM空间号转换为相应存储地址
    LCD12864_writeCmd(addr);		//定位到该位址(用户空间位址范围0x40-0x7F共128字节)
    for(i=0;i<16;i++)				//将用户自定义编码写入该16*16位元组空间
    {
        LCD12864_writeByte(pUserCode[i*2]);		 //连续写2个字节共16位
        LCD12864_writeByte(pUserCode[i*2+1]);
    }    
}

void LCD12864_writeCGRAM(u8 CGRAM_groupNum, u8* pUserCode)//将用户自定义编码写入CGRAM	 
{	//参数一是CGRAM的4组用户空间组号码(0~3) ,参数二是用户自定义图表或汉字的编码
    u8 i,addr=0;
	if(bShowPicFlag)				
	{
		LCD12864_writeCmd(0x36);	//开启绘图显示,可流畅播放动画	 	
	}
	else
	{
		LCD12864_writeCmd(0x34);	//默认关闭绘图显示
	}				
    LCD12864_writeCmd(0x02);    	//SR等于0,允许设置卷动地址
    LCD12864_writeCmd(0x30);    	//恢复为8位并行,基本指令集
    addr=(CGRAM_groupNum<<4)|0x40;	//将CGRAM空间号转换为相应存储地址
    LCD12864_writeCmd(addr);		//定位到该位址(用户空间位址范围0x40-0x7F共128字节)
    for(i=0;i<16;i++)				//将用户自定义编码写入该16*16位元组空间
    {
        LCD12864_writeByte(pUserCode[i*2]);		 //连续写2个字节共16位
        LCD12864_writeByte(pUserCode[i*2+1]);
    }    
}

void LCD12864_showScrollCGRAM(u8 row,u8 cols,u8 CGRAM_groupNum)//滚动CGRAM
{	//row(0-3),	cols(0-15)
	//第三个参数是用户空间号码(0~3共4组空间号码),该号码乘2就是它所对应的[调用用户空间编码]
    LCD12864_setScrollPos(row,cols);
    LCD12864_writeByte(0x00);//4组用户空间的编码的高字节都固定为0,我猜这是为和E文ASCII码区分开
    LCD12864_writeByte(CGRAM_groupNum*2);	//对应编码00h,02h,04h,06h
	LCD12864_showCGRAM(row,cols,CGRAM_groupNum);
}

void LCD12864_showCGRAM(u8 row,u8 cols,u8 CGRAM_groupNum)//定位液晶光标,并显示自定义内容
{	//row(0-3),	cols(0-15)
	//第三个参数是用户空间号码(0~3共4组空间号码),该号码乘2就是它所对应的[调用用户空间编码]
    LCD12864_setPos(row,cols);
    LCD12864_writeByte(0x00);//4组用户空间的编码的高字节都固定为0,我猜这是为和E文ASCII码区分开
    LCD12864_writeByte(CGRAM_groupNum*2);	//对应编码00h,02h,04h,06h
}
/*--------------------------------CGRAM end----------------------------------------------*/

/*--------------------------------DDRAM start----------------------------------------------*/
void LCD12864_earseSomeDDRam(u8 row,u8 cols,u8 dataSize) //擦除N个字节DDRam
{	//row(0-3),cols(0-15),如果起始地址是汉字的低字节,则会一同擦除汉字的高字节
	LCD12864_setPos(row, cols);				   //定位							   
	if(cols%2!=0)							   //如果从奇数列开始
	{
		LCD12864_readByte();				   //空读一次,让位址指针移动半字
		if(LCD12864_readByte()>127)			   //检测高位是否是汉字码
		{
			LCD12864_setPos(row, cols);		   //是汉字码的话要擦除,不然要乱码
			LCD12864_writeByte(' ');		   //其实是写空格,看不到了就等于擦除了
		}									   //连续写2个0的话是乱码
	}	
	while(dataSize--)						   //擦除
	{
		if(cols)							   //cols>0
		{
			if(0==cols%16)					   //如果一行满了
			{
				row++;						   //准备将光标移到下一行
				cols=0;						   //列坐标置于行首
				LCD12864_setPos(row, cols);	   //设置新光标
			}				
		}
		LCD12864_writeByte(' ');			   //其实是写空格,但为啥不写0呢
		cols++;								   //因为0与是CGRAM重码了,写2个0会乱码的
	}
	
}


/*****************************************************************************************
pBuf如果用来修饰字符串,dataSize=strlen(pBuf);
pBuf如果是一个字符数组,dataSize=sizeof(pBuf);
strlen()虽然也可以用来计算字符数组长度,但遇到'\0'时就会返回,不会再计算后面的其他字符
在VC中strlen()只能计算字符串长度,不能计算字符数组,否则编译出错
sizeof("你好5"),sizeof("你好56"),最终液晶光标位置是一样的,故不要用sizeof计算字符串
*****************************************************************************************/
void LCD12864_writeData(u8 row,u8 cols,u8* pBuf,u8 dataSize)//写数据
{	//支持全角半角字符及中英混合的字符串,也可写入字符串的子串,(行坐标0~3,列坐标0~15)
	u8 flag=0;									//液晶低字节ram数据检测标志,0不检测
    LCD12864_setPos(row, cols);					//设置光标    
	if(cols%2!=0)								//列号不为偶数(汉字在液晶上要偶对齐)
	{	//要让位址空移一个字节,执行下面这句读操作后,效果是达到了
		LCD12864_readByte();//但AC值没变,我怀疑除了这个AC字型指针,另有一个标志位没公开)
		flag=1;									//此时需要检测液晶低位字节ram	
	}											//因为高位字节现在可能是汉字码

    while(dataSize--)							//循环处理目标字节流
    {											
		if(0==cols%2)							//偶对齐时,对于ram高字节
		{
			if(*pBuf>127)						//如果写入ram的高字节是汉字码
			{
				flag=0;							//下一次不要检测低字节,因为肯定是汉字了
			}
			else								//如果高字节是半角字符
			{
				flag=1;							//若在低字节ram写入汉字就乱码了,故检测
			}				
		}

		if(cols%2!=0)					    	//对于液晶低字节
		{
			if(flag)							//如果要检测低字节
			{
				if(*pBuf>127)					//如果低字节是汉字码
				{
					LCD12864_writeByte(0x20);	//插入一个空格
					cols++;						//字节计数器++
					flag=0;						//清检测标志
				}					
			}	
		}      
		
		if(cols)								//行尾检测
		{
			if(0==cols%16)						//如果一行满了
			{
				row++;							//准备将光标移到下一行
				cols=0;							//列坐标置于行首
				LCD12864_setPos(row, cols);		//设置新位址
			}				
		} 

		LCD12864_writeByte(*pBuf++);			//终于可以写数据了
		cols++;								    //列号累加
    }
}


//滚屏模式的写数据函数
void LCD12864_writeScrollData(u8 row,u8 cols,u8* pBuf,u8 dataSize)//写数据,卷动模式
{	//支持全角半角字符及中英混合的字符串,也可写入字符串的子串,(行坐标0~3,列坐标0~15)
	u8 flag=0;									//液晶低字节ram数据检测标志,0不检测
	LCD12864_writeData(row,cols,pBuf,dataSize);
    LCD12864_setScrollPos(row, cols);					//设置光标    
	if(cols%2!=0)								//列号不为偶数(汉字在液晶上要偶对齐)
	{	//要让位址空移一个字节,执行下面这句读操作后,效果是达到了
		LCD12864_readByte();//但AC值没变,我怀疑除了这个AC字型指针,另有一个标志位没公开)
		flag=1;									//此时需要检测液晶低位字节ram	
	}											//因为高位字节现在可能是汉字码

    while(dataSize--)							//循环处理目标字节流
    {											
		if(0==cols%2)							//偶对齐时,对于ram高字节
		{
			if(*pBuf>127)						//如果写入ram的高字节是汉字码
			{
				flag=0;							//下一次不要检测低字节,因为肯定是汉字了
			}
			else								//如果高字节是半角字符
			{
				flag=1;							//若在低字节ram写入汉字就乱码了,故检测
			}				
		}

		if(cols%2!=0)					    	//对于液晶低字节
		{
			if(flag)							//如果要检测低字节
			{
				if(*pBuf>127)					//如果低字节是汉字码
				{
					LCD12864_writeByte(0x20);	//插入一个空格
					cols++;						//字节计数器++
					flag=0;						//清检测标志
				}					
			}	
		}      
		
		if(cols)								//行尾检测
		{
			if(0==cols%16)						//如果一行满了
			{
				row++;							//准备将光标移到下一行
				cols=0;							//列坐标置于行首
				LCD12864_setScrollPos(row, cols);		//设置新位址
			}				
		} 

		LCD12864_writeByte(*pBuf++);			//终于可以写数据了
		cols++;								    //列号累加
    }
}

void  LCD12864_startScroll(u8 scrollNum,u16 delay_ms)  //滚动
{	//scrollNum建议值为64
	u8 i;
	LCD12864_writeCmd(0x34); 	
	LCD12864_writeCmd(0x03);
	for(i=0x40;i<0x40+scrollNum;i++) 
	{  
		LCD12864_writeCmd(i); //设置卷动地址
		delayms(delay_ms); 		   //实际使用时建议用定时器处理
	}
	LCD12864_writeCmd(0x40);  //补滚一行
	LCD12864_writeCmd(0x30);
}

void LCD12864_setScrollPos(u8 row, u8 cols)		//设置光标位置 ,卷动模式
{												//row行坐标0~3
	u8 newPos=0;								//cols列坐标0~15
	switch(row)
	{
		case 0:
		{
			row=0xa8;	
		}
		break;
		case 1:
		{
			row=0xb8;
		}
		break;
		case 2:
		{
			row=0xa0;
		}
		break;
		case 3:
		{
			row=0xb0;
		}
		break;
		default:		//如果需要检测行坐标范围,可在这里加代码
		break;			
	}
	newPos=row+cols/2;	//液晶写指令坐标只能8级,我的函数中列坐标是16级的,支持半角全角混合
	LCD12864_writeCmd(newPos);
}


void LCD12864_setPos(u8 row, u8 cols)			//设置光标位置
{												//row行坐标0~3
	u8 newPos=0;								//cols列坐标0~15
	switch(row)
	{
		case 0:
		{
			row=0x80;	
		}
		break;
		case 1:
		{
			row=0x90;
		}
		break;
		case 2:
		{
			row=0x88;
		}
		break;
		case 3:
		{
			row=0x98;
		}
		break;
		case 4:
		{
			row=0xa0;
		}
		break;
		case 5:
		{
			row=0xb0;
		}
		break;
		case 6:
		{
			row=0xa8;
		}
		break;
		case 7:
		{
			row=0xb8;
		}
		break;

		default:		//如果需要检测行坐标范围,可在这里加代码
		break;			
	}
	newPos=row+cols/2;	//液晶写指令坐标只能8级,我的函数中列坐标是16级的,支持半角全角混合
	LCD12864_writeCmd(newPos);
}
/*
void LCD12864_setPos(u8 row, u8 cols)			//设置光标位置
{												//row行坐标0~3
	u8 newPos=0;								//cols列坐标0~15
	switch(row)
	{
		case 0:
		{
			row=0x80;	
		}
		break;
		case 1:
		{
			row=0x90;
		}
		break;
		case 2:
		{
			row=0x88;
		}
		break;
		case 3:
		{
			row=0x98;
		}
		break;
		default:		//如果需要检测行坐标范围,可在这里加代码
		break;			
	}
	newPos=row+cols/2;	//液晶写指令坐标只能8级,我的函数中列坐标是16级的,支持半角全角混合
	LCD12864_writeCmd(newPos);
}
 	*/



void LCD12864_init()				  //初始化
{
	delayms(40);					  //rst由低到高后保持40ms以上,我们的rst接VCC
	LCD_PSB= 1;					  	  //选择并口方式

	LCD12864_writeCmd( B(110000) );	  //0x30,启用基本指令集
	delayXus(15);					  //要求延时100us以上,(8+6x)*1.085=106us

	LCD12864_writeCmd( B(110000) );   //0x30,要求写2次该指令
	delayXus(5); 					  //要求延时37us以上,(8+6x)*1.085=41us

    LCD12864_writeCmd( B(1100) );	  //0x0f,整体显示,游标,游标反白
	delayXus(15);					  //要求延时100us以上

	LCD12864_writeCmd( B(0001) );	  //0x01,清屏指令,整屏幕写满空格
	delayms(10);				 	  //要求延时10ms以上

	LCD12864_writeCmd( B(110) );	  //0x06,进入模式设置,游标自动指向下一位置,
                                                
	delayms(5);					  	  //手册上没说这里要延时,额,还是加上吧
}


void LCD12864_writeCmd(u8 cmd)	  	  //写指令
{
	while(LCD12864_isBusy());
	LCD_EN=0;				 		  //使能 拉低
	LCD_RW=0;				 		  //写
	LCD_RS=0;_nop_();				  //命令
		
	LCD_EN=1;						  //使能
	LCD_dataBus=cmd;				  //送指令
	_nop_();_nop_();	    		  //稳定

	LCD_EN=0;_nop_();	         	  //取走
}

void LCD12864_writeByte(u8 dat)	   	  //写一个字节
{
	while(LCD12864_isBusy());
	LCD_EN=0;				 //使能先拉低
	LCD_RW=0;				 //写
	LCD_RS=1;_nop_();		 //数据
	
	LCD_EN=1;
	LCD_dataBus=dat;
	_nop_();_nop_();		 //延时大于1.5us

	LCD_EN=0;_nop_();		 //下降沿取走数据
}

u8 LCD12864_readByte()	 	 //读数据暂存器Data Register
{							 //用的时候要空操作一次
	u8 temp=0;
	while(LCD12864_isBusy());//忙检测
	LCD_dataBus=0xff;		 //用总线读数据时必须先置为输入模式
	LCD_EN=0;				 //使能线拉低
	LCD_RW=1;				 //读
	LCD_RS=1;_nop_();		 //数据					 
	LCD_EN=1;_nop_();		 //使能
	temp=LCD_dataBus;		 //取走数据
	
	_nop_();
	LCD_EN=0;				 //使能恢复
	return temp;
}

bool LCD12864_isBusy()	  	 //检测液晶是否忙
{
	if(LCD12864_readIR() & 0x80) //检测BF位
	{
		return TRUE;	 	 //忙
	}
	return FALSE;		 	 //不忙
}

u8 LCD12864_readIR()		 //读指令暂存器Instruction Register
{
	u8 temp=0;
	LCD_EN=0;				 //使能准备
	LCD_RW=1;				 //读
	LCD_RS=0;_nop_();		 //命令字
	LCD_dataBus=0xff;      	 //准备输入
	LCD_EN=1;_nop_();    	 //使能
	temp=LCD_dataBus;		 //提取数据

	_nop_();
	LCD_EN=0;				 //使能拉低
	return temp;	          
}





 

1
1
分享到:
评论
1 楼 bewithme 2015-02-03  
不明觉厉

相关推荐

    stm32f1+LCD12864 液晶驱动源码

    在给定的“stm32f1+LCD12864 液晶驱动源码”项目中,我们将探讨如何在STM32F1上实现对LCD12864液晶显示器的驱动。 LCD12864是一种常见的字符型液晶显示屏,具有128x64像素的分辨率,常用于嵌入式系统的用户界面显示...

    MCS51单片机液晶12864并行驱动源码(有注释很详细)

    在描述中提到的源码,是与MCS51单片机配合使用的12864液晶驱动程序。这个程序包含了详细的注释,可以帮助开发者理解每一部分的功能和工作原理。这对于初学者或者经验不足的开发者来说,是非常宝贵的资源,能够加速...

    LCD12864液晶源代码+资料

    LCD12864液晶源代码+资料LCD12864液晶源代码+资料LCD12864液晶源代码+资料LCD12864液晶源代码+资料LCD12864液晶源代码+资料LCD12864液晶源代码+资料LCD12864液晶源代码+资料LCD12864液晶源代码+资料LCD12864液晶源...

    JLX12864液晶显示驱动

    标题中的“JLX12864液晶显示驱动”指的是使用JLX12864型号的液晶显示屏,并且这个显示屏具有专门的驱动程序。JLX12864是一种常见的图形点阵液晶模块,通常用于嵌入式系统,它提供了128列和64行的像素点,可用于显示...

    液晶电视驱动源码瑞昱(realtek)方案

    液晶电视驱动源码是电视硬件系统中的核心组成部分,它负责控制液晶显示屏的显示效果,确保图像清晰、流畅。瑞昱(Realtek)是一家知名的集成电路设计公司,提供了多种针对液晶电视的解决方案。本方案针对1920*1080...

    单片机源码学习参考-51单片机12864大液晶屏proteus仿真.zip

    在这个“单片机源码学习参考-51单片机12864大液晶屏proteus仿真.zip”压缩包中,主要包含了一个与51单片机和12864液晶屏相关的项目。12864液晶屏通常指的是128x64像素的图形点阵液晶显示屏,它可以显示文本、图形...

    LCD12864液晶显示电子钟设计

    液晶显示屏中的业态光电显示材料,利用液晶的电光效应把电信号转换成数字符、图像等可见信号。 如图1-1,液晶正常情况下,其分子排列很有秩序,显得清澈透明,一旦加上直流电场后,分子的排列被打乱,一部分液晶变...

    (51单片机) 12864 液晶LCD 图文菜单显示控制系统源码

    在12864 LCD的驱动中,单片机需要通过SPI(Serial Peripheral Interface)或I2C接口与液晶屏通信,发送指令和数据以控制显示内容。 图文菜单显示控制系统的核心在于菜单的设计和操作逻辑。通常,它会包含多个层级的...

    MzLH04 12864 液晶STM32驱动程序

    STM32驱动MzLH04 12864液晶屏的知识点解析: STM32是一款基于ARM Cortex-M内核的微控制器,广泛应用于嵌入式系统设计。MzLH04 12864液晶屏是一种常用的显示设备,其特点在于拥有128x64像素的分辨率,支持SPI...

    STM32串行方式驱动LCD12864、画点、画线、画图等工程源码.zip

    STM32串行方式驱动LCD12864是一种常见的微控制器应用,它涉及嵌入式系统中的硬件接口设计和软件编程技术。STM32是一款基于ARM Cortex-M内核的微控制器,而LCD12864则是一种具有128x64像素分辨率的点阵液晶显示器,常...

    基于STC89C52 单片机的12864液晶并行传输数据驱动软件例程源码.zip

    基于STC89C52 单片机的12864液晶并行传输数据驱动软件例程源码.zip

    12位AD-DS1621与12864液晶的C语言开发-源码

    本项目聚焦于使用C语言对12位ADC(模拟数字转换器)AD-DS1621与12864液晶显示器进行驱动开发。AD-DS1621是一款高性能的温度传感器,它能够将环境温度转换为数字信号,便于微控制器处理。12864液晶显示器则常用于显示...

    虚拟声卡驱动 源码 wdk源码 .sys

    标题中的“虚拟声卡驱动源码”指的是该压缩包中包含了实现虚拟声卡功能的源代码。源码是程序员可以阅读和修改的编程语言文本,对于学习和定制驱动程序功能至关重要。"wdk源码"表明这部分源代码是按照WDK的规范和接口...

    19264液晶屏及驱动代码

    详细描述了液晶屏资料,对照代码更清楚具体原理。...注意:你们只看驱动液晶屏的几个函数代码就行了,因为这个代码是用在我的项目上的。其实main()函数的while()循环不用看。可以保证液晶显示非常OK 。

    基于STM32单片机控制液晶LCD12864显示开机画面多级菜单显示软件例程源码.rar

    在这个项目中,我们重点讨论如何利用STM32单片机控制液晶LCD12864来实现开机画面和多级菜单的显示。 LCD12864是一种常见的点阵字符型液晶显示器,它拥有128x64像素的显示区域,能够清晰地显示文本和简单的图形。在...

    12864液晶程序!!!!

    " 暗示了这个压缩包包含的是针对12864液晶显示屏的编程代码或驱动程序。这种显示屏通常用于嵌入式系统和电子项目,如Arduino或STM32等微控制器平台,以提供可视化输出。 12864液晶显示器是一种具有128列和64行显示...

    单片机源码学习参考-12位AD_DS1621与12864液晶.zip

    在这个项目中,源码会包含对12864液晶屏的初始化、清屏、设置坐标和写入字符等功能的实现。学习这部分源码可以帮助开发者理解如何控制液晶显示屏,并在实际项目中创建定制的用户界面。 在实际应用中,单片机不仅要...

    LCD12864显示屏C51单片机驱动源码KEIL工程文件.zip

    LCD12864显示屏C51单片机驱动源码KEIL工程文件,可做为你的学习设计参考。 void main() { LCD12864_Reset(); //初始化液晶 LCD12864_HAIZI_SET(); //设置为普通模式 Delay_ms(100); LCD12864_...

    12864液晶 原理图+C源程序.rar

    在开发过程中,12864液晶屏的驱动程序通常需要根据具体的微控制器和开发环境进行适配。例如,如果使用的是基于Arduino的平台,源代码可能需要包含特定的库函数调用;如果是裸机编程,那么可能需要直接操作GPIO引脚...

    51单片机课设实验源码-LCD12864液晶屏图片动画显示效果例程源码.zip

    在提供的源码中,你可以找到关于初始化LCD12864、设置通信接口、发送指令和数据、以及实现动画效果的具体实现。通过阅读和理解这些代码,你可以深入了解51单片机如何控制LCD12864,以及如何利用有限的硬件资源实现...

Global site tag (gtag.js) - Google Analytics