使用单片机驱动LCD屏幕显示文字或图像,一般是先得到文字的字模,再设置好字模要在屏幕上显示的位置,将字模数据通过接口传输到LCD驱动的显存中。屏幕的驱动便会开关LCD屏幕上的像素点,完成显示。

获取文字的字模

得到文字字模,可以使用取模软件或者使用自带字库的LCD液晶屏。此处使用的是JLX_256*64的液晶屏,自带中文字库,字库为SPI接口。

在屏幕上打印汉字字符串的函数:

display_GB2312_string(0, 0, 1, (unsigned char *)" 深圳市晶联讯电子有限公司 ");

输入参数为显示坐标xy、正显/反显参数0/1、要显示的字符串。

函数源代码


void display_GB2312_string(unsigned char column, unsigned char page, unsigned char mode, unsigned char *text) //显示GB2312字符
{
unsigned long fontaddr = 0;
unsigned char i = 0, temp1, temp2;
temp1 = column;
temp2 = page;
while ((text[i] > 0x00))
{
if (((text[i] >= 0xb0) && (text[i] <= 0xf7)) && (text[i + 1] >= 0xa1))
{
//国标简体(GB2312)汉字在晶联讯字库 IC 中的地址由以下公式来计算:
// Address = ((MSB - 0xB0) * 94 + (LSB - 0xA1)+ 846)*32+ BaseAdd;BaseAdd=0
//由于担心 8 位单片机有乘法溢出问题,所以分三部取地址
fontaddr = (text[i] - 0xb0) * 94;
fontaddr += (text[i + 1] - 0xa1) + 846;
fontaddr = (unsigned long)(fontaddr * 32);
RW_ROM_to_LCD_16x16(fontaddr, column, page, mode); //从指定地址读出数据写到液晶屏指定(page,column)座标中
i += 2;
column += 16;
if ((temp2 <= 15 && temp1 <= 256) && column > 248)
{
//自动换行,当遇到奇数个字母或符号就提前 8 个点
//设成符>256 时当有奇数个字符时就会显半个汉字,因为一个字符只占 8 个点(一个字节)
column = 1;
page += 2;
if (page > 15)
column = 1;
}
}
else if (((text[i] >= 0xa1) && (text[i] <= 0xa3)) && (text[i + 1] >= 0xa1))
{
//国标简体(GB2312)15x16 点的字符在晶联讯字库 IC 中的地址由以下公式来计算:
// Address = ((MSB - 0xa1) * 94 + (LSB - 0xA1))*32+ BaseAdd;BaseAdd=0
//由于担心 8 位单片机有乘法溢出问题,所以分三部取地址
fontaddr = (text[i] - 0xa1) * 94;
fontaddr += (text[i + 1] - 0xa1);
fontaddr = (unsigned long)(fontaddr * 32);

RW_ROM_to_LCD_16x16(fontaddr, column, page, mode); //从指定地址读出数据写到液晶屏指定(page,column)座标中
i += 2;
column += 16;

if ((temp1 <= 15 && temp2 <= 256) && column > 248)
{
//自动换行,当遇到奇数个字母或符号就提前 8 个点
//设成符>128 时当有奇数个字符时就会显半个汉字,因为一个字符只占 8 个点(一个字节)
column = 1;
page += 2;
if (page > 15)
column = 1;
}
}

else if ((text[i] >= 0x20) && (text[i] <= 0x7e))
{
fontaddr = (text[i] - 0x20);
fontaddr = (unsigned long)(fontaddr * 16);
fontaddr = (unsigned long)(fontaddr + 0x3cf80);
RW_ROM_to_LCD_8x16(fontaddr, column, page, mode); //从指定地址读出数据写到液晶屏指定(page,column)座标中
i += 1;
column += 8;

if ((temp1 <= 15 && temp2 <= 256) && column > 248)
{
//自动换行,当遇到奇数个字母或符号就提前 8 个点
//设成符>128 时当有奇数个字符时就会显半个汉字,因为一个字符只占 8 个点(一个字节)
column = 1;
page += 2;
if (page > 15)
column = 1;
}
}
else
i++;
}
}

此函数输入的GB2312字符数据,本质上对于编译器来说也是一个具体的数字:

所以函数取巧的地方就在于把输入字符当作地址变量,再经过字库内部文字的编址算法得到物理地址;再将物理地址送入字库中。字库收到地址后把字模数据输出给单片机。单片机把数据返回给LCD主控即可。

显示整形变量

显示整形变量的思路就很简单了,把INT整形变量,转换成字符串,再使用上面的display_GB2312_string打印到屏幕即可。代码:

void display_INT_Num(int x, int y, int num) //显示8字符的整数
{
    char str[8];
    unsigned char *str2312 = (unsigned char *)str;

    str[0] = num / 1000000 + 48;
    str[1] = num / 100000 % 10 + 48;
    str[2] = num / 10000 % 10 + 48;
    str[3] = num / 1000 % 10 + 48;
    str[4] = num / 100 % 10 + 48;
    str[5] = num / 10 % 10 + 48;
    str[6] = num % 10 + 48;
    str[7] = 0;
    display_GB2312_string(x, y, 1, str2312);
}

在这个转化过程中,需要进行数据类型的转换。Int值0转化为ASCII中的0,中间有48的差值,所以int取每一位都要+48;这样就对应到了相应的ASCII码。

显示浮点数

要显示浮点数,思路和显示整形变量是一样的,但是显示float变量会有一个小数点,因此需要确定小数点的位置。其次,float变量是无法直接转换成unsigned char。我的代码是:

/******************************************************************************
      函数说明:显示数字(m的n次幂)
      入口数据:m底数,n指数
      返回值:  uint32_t
******************************************************************************/
u32 mypow(u8 m,u8 n)
{
	u32 result=1;	 
	while(n--)result*=m;
	return result;
}

void display_float_Num(int x, int y, float num, unsigned char len) //显示若干位的浮点数,并且自动确定小数点的位置
{
	u8 point, i;
	u8 temp;
	int num2;
	float num1 ;
	unsigned char str[2];
  unsigned char *str2312 = (unsigned char *)str;	


	for(t=1;(num/mypow(10, point))>=1; point ++) //确定小数点位置
	{;
	}
		num2=num/1; //取出整数部分
		num1=num-num2; //取出小数位
		num1=num1*mypow(10,len- point);//小数位转换成整数
		
	display_GB2312_string(x+ point *8, y, 1, (unsigned char *)".");	
	
	for(i=0;i< point;i++)
	{
		temp=(num2/mypow(10, point -i-1))%10; //把整数数字一位一位取出来,例如234要取数,2 = 234/100%10 ; 3 = 234/10%10 ;4 = 234/1%10

	 	str[0] = temp+48 ;
		
		display_GB2312_string(x+i*8, y, 1, str2312);
	}

  num2 = num1; //float转换为int
	
		for(i=0;i<len- point;i++)
	{
		temp=(num2/mypow(10,len- point -1-i))%10;

	 	str[0] = temp+48 ;
		
		display_GB2312_string(x+( point s+1)*8+i*8, y, 1, str2312);
	}
	
}	

大致思路:

1,把float变量中整数部分分离出来,这样就知道小数点该显示在哪个位置了(变量point)。

2,同时把整数部分转换为INT型变量num2,通过上一小节的办法就能先把整数部分的显示出来。

3,再把小数部分扩大10^(point)倍,并再次赋值给num2转换为INT变量。这样就把变量中的小数部分剥离开了,重复前面的步骤这样就实现了小数点,整数部分,小数部分的显示。


懒惰是进步的催化剂,也是失败的引擎。