今天在写LCD的显示,用的是51单片机和Proteus仿真,但是Proteus中没有以前写的LCD5110所以只能用库中的HDG12864F-1,后来才发现这个好像是写LCM的,搞了一晚上总算是弄出来了一下贴出代码
每一个LCD驱动都要有命令和数据的写入首先是这两个代码
//CE 片选信号
//LCD_CE_OL 置低,表示选中芯片
//LCD_CE_OH 置高,表示未选中芯片
//DC 数据命令选择
//LCD_DC_OL 置低:数据
//LCD_DC_OH 置高:数据
//SCLK 时钟 每个时钟的上升沿写入数据
void LCD_WrDat(uint8_t dat)
{
uint8_t i = 8;
LCD_CE_OL;//片选信号置低,表示选中芯片
LCD_DC_OH;//数据命令 置高:数据
LCD_SCLK_OL;
while (i --)
{
if (dat & 0x80)
{
LCD_SDIN_OH;
}
else
{
LCD_SDIN_OL;
}
LCD_SCLK_OH;
LCD_SCLK_OL;
dat <<= 1;
}
LCD_CE_OH;
}
void LCD_WrCmd(uint8_t cmd)
{
uint8_t i = 8;
LCD_CE_OL;
LCD_DC_OL;
LCD_SCLK_OL;
while (i --)
{
if (cmd & 0x80)
{
LCD_SDIN_OH;
}
else
{
LCD_SDIN_OL;
}
LCD_SCLK_OH;
LCD_SCLK_OL;
cmd <<= 1;
}
LCD_CE_OH;
}
其次,设定要写的位置,位置要根据芯片手册确定LCD5110和HDG12864F-1的是不一样的,一开始怎么都不对,后来看了芯片手册才发现原来就不一样
void LCD_Set_XY(uint8_t X, uint8_t Y)
{
LCD_WrCmd(Y | 0xB0);
LCD_WrCmd(0x10|((0xf0 & X) >> 4));//设定列地址高4位为0
LCD_WrCmd(0x00|(0x0f & X)); //设定列地址低4位为0
}
然后是清屏函数,这个没什么大问题,只要把所有的格格写入0就可以了
void LCD_Clear(void)
{
uint8_t t,k;
LCD_Set_XY(0,0);
for(t = 0; t < (HEIGHT >> 3); t++)
{
for(k = 0;k < WIDTH; k++)
{
LCD_WrDat(0x00);
}
}
}
初始化函数,这个问题就大了,不同的芯片初始化是不一样的,开始怎么都出来,后来看了一下手册,duangduang的。
void LCD_Init(void)
{
LCD_RST_OL; //LCD(低电平)复位
LCD_WrCmd(0xae);
LCD_RST_OH; // RES置高
LCD_WrCmd(0xa2); // LCD偏压设置:1/9 BIAS
LCD_WrCmd(0xa1); //列地址选择为从右到左对应0~127;0xa1:列地址从左到右;0xa0:列地址从右到左
LCD_WrCmd(0xc0); // 行地址从上到下为0~63;0xc0:行地址从上到下;0xc8:行地址从下到上
LCD_WrCmd(0x26); // V5电压内部电阻调整设置
LCD_WrCmd(0x81); //亮度调整命令0~63(暗到亮)
LCD_WrCmd(0x10); //亮度调节为双字节命令,前一个参数控制字的深浅
LCD_WrCmd(0x2f); //上电控制,打开调压器、稳压器和电压跟随
LCD_WrCmd(0xaf); //0xae:set display off。0xaf:set display on
//LCD_WrCmd(0x60); //其实行设置
}
接着是写入字符,我这里用的是小字符,宽度占6个点
void LCD_Write_Char(uint8_t x, uint8_t y, uint8_t c)
{
uint8_t i = 0;
if ((c >= 'A') && (c <= 'Z'))
{
c = c - 'A' + 10;
}
else if ((c >= 'a') && (c <= 'z'))
{
c = c - 'a' + 44;
}
else if (c == ' ')
{
c = 36;
}
else if (c == ':')
{
c = 37;
}
else if (c == '-')
{
c = 38;
}
else if (c == '/')
{
c = 39;
}
else if(c == '.')
{
c = 40;
}
else if (c == ',')
{
c = 41;
}
else if (c == '^')
{
c = 42;
}
if (x > 126)
{
x = 0;
y ++;
}
LCD_Set_XY(x * 6, y);
for (i = 0; i < 6; i++)
{
LCD_WrDat(SmallChars[c * 6 + i]);
}
}
void LCD_Write_Num5(uint8_t x, uint8_t y, int num)
{
LCD_Write_Char(x, y, num / 10000);
LCD_Write_Char(x + 1, y, num % 10000 / 1000);
LCD_Write_Char(x + 2, y, num % 1000 / 100);
LCD_Write_Char(x + 3, y, num % 100/10);
LCD_Write_Char(x + 4, y, num % 10);
}
void LCD_Write_String(uint8_t x, uint8_t y, uint8_t *s)
{
uint8_t i;
for (i=0; s[i]!='\0'; i++)
{
LCD_Write_Char(x + i, y, s[i]);
}
}
//这里的字符是16*16大小的
void LCD_Write_Chinese(uint8_t x,uint8_t y,uint8_t *China)
{
uint8_t ii = 0;
LCD_Set_XY(x, y);
for(ii = 0; ii < 16; ii++)
{
LCD_WrDat(China[ii]);
}
LCD_Set_XY(x, y + 1);
for(ii = 0; ii < 16; ii++)
{
LCD_WrDat(China[16 + ii]);
}
}
接着是防止闪屏写的“双缓冲”.其实这段代码在51上没有试过,32上的内存空间很大,51上定义了一个字符数组就没有空间了,也懒的删再去试。原理是吧所有的点写到一个数组里面,然后全部写出来,这样清屏的时候只要把数组清一下就可以了,不需要刷屏,就可以防止屏闪
uint8_t data buff[HEIGHT][WIDTH]={0};
void LCD_Write_Point(uint8_t hang,uint8_t lie)
{
buff[hang][lie] = 1;
}
void LCD_Draw(void)
{
uint8_t dat = 0;
uint8_t i,j,k;
unsigned short t = 0;
for(j = 0; j < (HEIGHT >> 3); j++)//hang
{
for(i = 0; i < WIDTH; i++)//lie
{
for(k = 0; k < 7; k++)
{
if(buff[(j << 3) + k][i])
dat |= (1 << k);
}
LCD_WrDat(dat);
dat = 0;
}
}
}
void LCD_ClearBuff(void)
{
uint8_t i = 0, j = 0;
for(i = 0; i < WIDTH; i++)
for(j = 0; j < HEIGHT; j++)
buff[j][i] = 0;
}
//TFT上画出的线很漂亮,但是这个上面。。。。。不知道为什么
void LCD_DrawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
{
char t;
char xerr = 0,yerr = 0,delta_x,delta_y,distance;
char incx,incy,uRow,uCol;
delta_x = x2 - x1;
delta_y = y2 - y1;
uRow = x1;
uCol = y1;
if(delta_x > 0)
incx = 1;
else if(delta_x == 0)
incx=0;
else
{
incx = -1;
delta_x = -delta_x;
}
if(delta_y > 0)
incy = 1;
else if(delta_y == 0)
incy = 0;
else
{
incy = -1;
delta_y = -delta_y;
}
if(delta_x > delta_y)
distance = delta_x;
else
distance = delta_y;
for(t = 0;t <= distance + 1; t++ )
{
LCD_Write_Point(uRow,uCol);
xerr += delta_x ;
yerr += delta_y ;
if(xerr > distance)
{
xerr -= distance;
uRow += incx;
}
if(yerr > distance)
{
yerr -= distance;
uCol += incy;
}
}
}
这个东西真的很有收获,一个收获就是知道数据手册的重要性,另一个数关于双缓冲的,下一步想要来重定向