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码,颜色* r o   y   g   c   b   p* 红    橙   黄   绿   青   蓝   紫* 输出参数: 无* 返 回 值: 无***********************************************************************/
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坐标,字符串,颜色* r o   y   g   c   b   p* 红    橙   黄   绿   青   蓝   紫* 输出参数: 无* 返 回 值: 无***********************************************************************/
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;

}

I.MX6ULL之LCD显示相关推荐

  1. bmp文件头_「正点原子FPGA连载」第十九章SD卡读BMP图片LCD显示

    1)摘自[正点原子]领航者 ZYNQ 之嵌入式开发指南 2)实验平台:正点原子领航者ZYNQ开发板 3)平台购买地址:https://item.taobao.com/item.htm?&id= ...

  2. LCD显示异常分析——开机闪现花屏【转】

    转自LCD显示异常分析--开机闪现花屏 最近在工作中,有同事遇到LCD开机瞬间会闪现雪花屏的问题,而这类问题都有个共同点,那就是都发生在带GRAM的屏上,同样的问题,在休眠唤醒时也会出现. 其实这类问 ...

  3. WINCE5.0+S3C2443系统每隔几分钟会自动关闭LCD显示

    这几天在调试WINCE5.0+S3C2443系统的时候,发现大概每隔6分钟的时候,系统就会自动关闭LCD屏的显示,这时候如果去点击触摸屏就会恢复显示.刚开始我还以为是系统进入了sleep状态了,发现在 ...

  4. ds18b20温度传感器 lcd C语言,基于AVR单片机的18B20温度传感器及LCD显示的C语言程序设计...

    ***************************************************/ #include #include #define uchar unsigned char # ...

  5. 产业链人士:LCD显示驱动芯片价格有望趋于稳定

    8月18日消息,据国外媒体报道,在汽车.消费电子等多领域芯片供不应求,芯片代工商产能普遍紧张的情况下,LCD显示驱动芯片的供应也受到了影响. 今年3月份,产业链方面的人士就透露,LCD面板需求强劲,拉 ...

  6. TFT LCD显示原理详解

    <什么是液晶> 我们一般认为物体有三态:固态.液态.气态,其实这只是针对水而言,有一些有机化和物 还有介于固态和液态中间的状态 就是液晶态,如下图(一):                 ...

  7. 嵌入式linux调试dsi,做嵌入式开发时,你是怎么实现LCD显示的?

    原标题:做嵌入式开发时,你是怎么实现LCD显示的? 1.本文目的 做嵌入式图形开发,我们往往都会利用到各种GUI进行交互设计,但是对于GUI的字符串处理与中文字库显示,也许并不会特别关注,因为GUI已 ...

  8. 单片机 c语言百位加上小数点,51单片机水温控制LCD显示加VB上位机温度曲线绘制...

    现功能,1L水由1KW电炉加热,要求水温在一定范围内人工设定,并能随着环境温度改变自动调节,以维持设定的温度不变. 矩阵键盘输入设定温度,LCD1602显示温度值,VB上位机绘制温度曲线 /***** ...

  9. LCD显示异常分析——撕裂(tear effect)

    概述 在上一篇<LCD显示异常分析--开机闪现花屏>中,我们一起分析了开机花屏的问题,在这一篇中,我将对LCD撕裂(tear effect)问题进行详细分析,以及给出这类问题的常用解决方法 ...

最新文章

  1. 百度实名制后如何进行网站优化?
  2. 我的问道游戏主题皮肤
  3. VS 打包升成可自动升级的安装包
  4. Python TypeError: takes no arguments
  5. numpy基础(part3)--加载文件
  6. 设计模式记--Observer Pattern观察者模式
  7. 使用WAMP5搭建Apache+MySQL+PHP环境
  8. python_day9 异常处理
  9. 浅谈JobExecutionContext JobDataMap
  10. 13.2 Question Answering 问答系统意境级讲解
  11. 算法设计与分析复习——第四章:贪心算法
  12. java基础之测试类
  13. 荣耀安装google谷歌服务框架_荣耀V20怎么下载安装谷歌服务助手,GMS框架安装教程...
  14. 读书摘录---《李嘉诚成功语录 》
  15. vscode缓存清理
  16. 中南大学计算机学院复试2021,中南大学2021年硕士研究生拟录取名单汇总
  17. jsonviewer
  18. Python函数命名-PEP8编码规范的说明及IDE提示的忽略
  19. Docker实现Canal MySQL增量日志订阅消费环境搭建
  20. 怎样用计算机告白,计算机学科的告白情话

热门文章

  1. 10G万兆光模块怎么用?组网方案详解
  2. spring boot微服务项目搭建
  3. 凯悦250家店数据外泄 多家高端酒店存安全漏洞
  4. python伪装浏览器https_Selenium中通过修改User-Agent标识将PhantomJS伪装成Chrome浏览器...
  5. 桂 林 理 工 大 学实 验 报 告实验五 数组
  6. 70条正则表达式的整理汇总
  7. iPhone 13 不带 Touch ID、搭载 M1X 的 Mac mini 将发布?2021 苹果秋季发布会预测
  8. 消息队列MQ常见面试题
  9. 一文看懂计算机视觉!7个专业术语别说你不知道!
  10. 记录个js调用浏览器打印功能的代码