700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > I.MX6ULL之LCD显示

I.MX6ULL之LCD显示

时间:2023-05-16 14:39:56

相关推荐

I.MX6ULL之LCD显示

I.MX6ULL之LCD显示

代码放在git仓库,有需要的可以自行下载:Gitee

LCD的操作原理:

在Linux系统中通过Framebuffer驱动程序来控制LCD。我们只需要知道怎么获取LCD的参数,并且使用mmap映射到Framebuffer上,然后再Framebuffer中写入数据就可以了。

详细的流程如下图所示:

对于上图的32bpp,我们要引入RGB的显示格式,其中包括RGB888,RGB565,RGB555。本文中使用的时RGB565。他们的不同点就是在于后面根据FrameBuff取出来的数据要进行不同的处理,比如使用RGB565时,代码的配置如下:

red = (color >> 16) & 0xff;green = (color >> 8) & 0xff;blue = (color >> 0) & 0xff;color = (((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3));/* 分别取出R的高5位,G的高6位,B的高6位,组成一个数据 */

API函数:具体函数使用请参考man手册

1.open函数:

描述:用于打开一个文件,并且返回文件描述符(系统的一些宏定义,非负整数),如果失败了会返回-1

参数:pathname是要打开或创建的文件的名字。oflag参数可用来说明此函数的多个选择项,用一些宏来传入。

2.ioctl函数:

描述:针对设备的控制操作,可以传数据给驱动程序,也可以从驱动程序中读出数据。。

参数:fd 参数为某个设备或文件已打开的文件描述符, request 参数指定了将在 fd 上执行的控制操作。具体设备的头文件定义了可传递给 request 参数的常量 。

3.mmap函数:

描述:在调用进程的虚拟地址空间中创建一个新映射。

参数:addr 参数指定了映射被放置的虚拟地址。length 参数指定了映射的字节数。port参数是一个位掩码,它制定了施加于映射之上的保护信息,其取值为一些宏。flags 参数是一个控制映射操作各个方面的选项的位掩码(私有映射/共享映射)。fd参数是一个标识被映射的文件的文件描述符。offset参数指定了映射在文件中的起点。

4.close函数:

描述:关闭一个打开的文件描述符,并将其释放回调用进程。

参数:文件描述符

5.munmap函数:

描述:从调用进程的虚拟地址空间中删除一个映射。

获取LCD的参数

包含在#include<linux/fb.h>

字符的编码格式

编码与字体:

1.编码:编码是信息从一种形式或格式转换为另一种形式的过程,也称为计算机编程语言的代码简称编码。此处使用的编码即为将一个字符采用什么ascii码来显示。

1️⃣ASCII:是American Standard Code for Information Interchange的缩写,美国信息交换标准代码。

​ 即采用一个数值来表示对应的字符。

2️⃣ANSI:ANSI是一种字符代码,为使计算机支持更多语言,通常使用0x00~0x7f范围的1 个字节来表示 1 个英文字符。超出此范围的使用0x80~0xFFFF来编码,即扩展的ASCII编码。

​ 对于ASCII字符仍以一个字节来表示,对于非ASCII字符则使用2字节来表示。其实ANSI并不是某一种特定的字符编码,而是在不同的系统中,ANSI表示不同的编码。

3️⃣UNICODE:统一码,也叫万国码、单一码(Unicode).Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位。码位就是可以分配给字符的数字。

ASCII编码中,使用一个字节来表示一个字符,只用到其中的7位,最高位恒为0;

ANSI编码中,对于ASCII字符仍使用一个字节来表示(BIT7是0),对于非ASCII字符一般使用2个字节来表示,非ASCII字符的数值BIT7都是1。

UNICODE编码中,对不同范围的字符使用不同长度的编码。常用UTF-8

2.ASCII字符的显示

​ 要在LCD中显示一个ASCII字符,即英文字母这些字符,首先是要找到字符对应的点阵。在Linux内核源码中有这个文件:lib\fonts\font_8x16.c,里面以数组形式保存各个字符的点阵。

3.中文字符的点阵显示:

手动指定编码格式,以及手动指定可执行程序的编码格式,默认为UTF-8

#编译时的编码格式-finput-charset=GB2312-finput-charset=UTF-8#编译出来的可执行程序的编码格式-fexec-charset=GB2312-fexec-charset=UTF-8

4.代码实现:

static int fd_fb;static struct fb_var_screeninfo var;/* Current var */static int screen_size;static unsigned char *fb_base;static unsigned int line_width;static unsigned int pixel_width;int fd_hzk16;struct stat hzk_stat;unsigned char *hzkmem;/*description:在(x,y)处画颜色可修改的点int x:x坐标int y:y坐标unsigned int color:颜色(采用RGB)*/void lcd_put_pixel(int x, int y, unsigned int color){/* 字号大小 */unsigned char *pen_8 = fb_base+y*line_width+x*pixel_width;unsigned short *pen_16;unsigned int *pen_32;unsigned int red, green, blue;pen_16 = (unsigned short *)pen_8;pen_32 = (unsigned int *)pen_8;switch(var.bits_per_pixel)/* 选择BPP */{case 8:{*pen_8 = color;break;}case 16: {/* 565格式 */red = (color >> 16) & 0xff;green = (color >> 8) & 0xff;blue = (color >> 0) & 0xff;color = (((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3));*pen_16 = color;break;}case 32:{*pen_32 = color;break;}default:{printf("can't surport %dbpp\n", var.bits_per_pixel);break;}}}/*********************************************************************** 函数名称: lcd_put_ascii* 功能描述: 在LCD指定位置上显示一个8*16的字符* 输入参数: x坐标,y坐标,ascii码,颜色* roygcbp* 红橙黄绿青蓝紫* 输出参数: 无* 返 回 值: 无***********************************************************************/ void lcd_put_ascii(int x,int y,unsigned char c,unsigned int rgb){unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];/* 获取一个字符的首地址 */int i,b;/* i->16行 b->8列 */unsigned char byte;/* 用于中间存储每一行的byte数值 */unsigned int color;switch(rgb){case 'r':color = 0xff0000;break;case 'o':color = 0xffa500;break;case 'y':color = 0xffff00;break;case 'g':color = 0x00ff00;break;case 'c':color = 0x00ffff;break;case 'b':color = 0x0000ff;break;case 'p':color = 0x800080;break;default:break;}for(i = 0; i < 16;i++){byte = dots[i];/* 指针数组 */for(b = 0;b < 8;b++){if(byte & (1<<b))/* 如果这一位为1:点亮 */lcd_put_pixel(x+7-b,y+i, color);/* 因为X轴是低位在前,高位在后 */elselcd_put_pixel(x+7-b,y+i, 0);}}}/*********************************************************************** 函数名称: lcd_put_string* 功能描述: 在LCD指定位置上显示8*16的字符串* 输入参数: x坐标,y坐标,字符串,颜色* roygcbp* 红橙黄绿青蓝紫* 输出参数: 无* 返 回 值: 无***********************************************************************/ void lcd_put_string(int x,int y,unsigned char *c,unsigned int rgb){while(*c != '\0'){lcd_put_ascii(x,y,*c++,rgb);x += 8;}}/*********************************************************************** 函数名称: lcd_put_chinese* 功能描述: 在LCD指定位置上显示一个16*16的汉字* 输入参数: x坐标,y坐标,ascii码* 输出参数: 无* 返 回 值: 无***********************************************************************/void lcd_put_chinese(int x,int y,unsigned char *str,unsigned int rgb){unsigned int area = str[0] - 0xa1;/* 区码 从0xa1开始,避免和ascii码冲突 */unsigned int where = str[1] - 0xa1;/* 位码 */unsigned char *dots = hzkmem + (area * 94 + where)*32;/* 从HZK的映射地址开始,每个区94个汉字+位的地址,一个汉字占32个字节 */unsigned char byte;unsigned int color;int i,j,b;switch(rgb){case 'r':color = 0xff0000;break;case 'o':color = 0xffa500;break;case 'y':color = 0xffff00;break;case 'g':color = 0x00ff00;break;case 'c':color = 0x00ffff;break;case 'b':color = 0x0000ff;break;case 'p':color = 0x800080;break;default:break;}for(i = 0;i < 16;i++){/* 判断是哪个字节 */for(j = 0;j < 2;j++){byte = dots[i*2 + j];for(b = 0;b < 7;b++){if(byte & (1 << b)){lcd_put_pixel(x+j*8+7-b, y+i, color); /* 白 */}else{lcd_put_pixel(x+j*8+7-b, y+i, 0); /* 黑 */}}}}}int main(int argc, char **argv){int i,j;unsigned char *str = "中";unsigned char *str1 = "国";fd_fb = open("/dev/fb0",O_RDWR);/* 以可读可写的方式打开/dev/fb0 */if(fd_fb < 0){printf("can't open /dev/fb0\n");/* 返回值为-1,表示打开文件失败! */return -1;}if(ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))/* get var screen info:获取屏幕的可变信息 */{printf("can't get var\n");return -1;}line_width = var.xres * var.bits_per_pixel / 8;/* 行宽 = X*BPP/8 */pixel_width = var.bits_per_pixel / 8;/* 列宽 = BPP/8 */screen_size = var.xres * var.yres * var.bits_per_pixel / 8;/* FrameBuffer的总大小 */fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);if(fb_base == (unsigned char *)-1){printf("can't mmap\n'");return -1;}fd_hzk16 = open("HZK16", O_RDONLY);/* 打开字体库 */if (fd_hzk16 < 0){printf("can't open HZK16\n");return -1;}if(fstat(fd_hzk16,&hzk_stat)){printf("can't get fstat\n");return -1;}/* mmap的返回结果保存在hzkmem中,作为字库的基地址 */hzkmem = (unsigned char *)mmap(NULL,hzk_stat.st_size,PROT_READ, MAP_SHARED,fd_hzk16,0);if(hzkmem == (unsigned char *)-1){printf("can't mmap for hzk16\n'");return -1;}// /* 清屏: 全部设为白色 */// memset(fb_base, 0xff, screen_size);/* 在fb_base地址上的screen_size大小的区域全部设为1 *//* 清屏: 全部设为黑色 */memset(fb_base, 0, screen_size);/* 在fb_base地址上的screen_size大小的区域全部设为1 */// /* 随便设置出100个为红色 */// for (i = 0; i < 500; i++)// {// for(j=0; j < 100;j++)// {// lcd_put_pixel(var.xres/2+i, var.yres/2+j, 0x800080);/* 在中间X轴画100个点 */// // lcd_put_pixel(var.xres+i, var.yres+j, 0x800080);/* 在中间X轴画100个点 */// }// }// lcd_put_ascii(var.xres/2,var.yres/2,'S','r');/* 在屏幕中间显示一个8*16的字母S */// lcd_put_string(var.xres/2,var.yres/2,"hello world!",'r');lcd_put_chinese(var.xres/2 + 8, var.yres/2, str,'r');lcd_put_chinese(var.xres/2 + 32, var.yres/2, str1,'r');munmap(fb_base , screen_size);/* 取消映射 */close(fd_fb);/* 关掉文本 */return 0;}

// }

// }// lcd_put_ascii(var.xres/2,var.yres/2,'S','r');/* 在屏幕中间显示一个8*16的字母S */// lcd_put_string(var.xres/2,var.yres/2,"hello world!",'r');lcd_put_chinese(var.xres/2 + 8, var.yres/2, str,'r');lcd_put_chinese(var.xres/2 + 32, var.yres/2, str1,'r');munmap(fb_base , screen_size);/* 取消映射 */close(fd_fb);/* 关掉文本 */return 0;

}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。