欢迎光临
我的个人博客网站

Linux :LCD应用层编程


LCD屏幕简单概述

Linux :LCD应用层编程
 如上图所示,每个像素点都是由红绿蓝混色而成,目前市面上主流的屏幕每一个原色的色阶都是采用8位元来表示,所以每个像素点可以表示大约1600万中颜色,LCD屏幕由背光层,偏光层,电极层,液晶层,滤光片等组成,液晶是一种介于固体和液体之间的有机化合物,本身不会发光,而是作为一种可透光的物体,通过控制其偏转角度的大小,来控制透出光线的多少,通过控制不同原色透出光线的多少来表示出不同的颜色(需要通过滤光片)。

如何操作LCD

 linux下一切皆文件,同样对于外部设备也是通过读写对应的文件来操作设备,对于LCD的操作有如下步骤:
  1.打卡LCD对应的设备文件;
  2.写入RGB颜色值;
  3.关闭文件。

实验程序

#define     LCD_PATH    "/dev/fb0"  int main(int argc, char const *argv[]) {     // 打开lcd设备文件  /dev/fb0  --》 由驱动工程师完成     int fd  = open(LCD_PATH , O_WRONLY);     if (fd < 0 )     {        perror("open lcd error");        return -1 ;     }          // 写入颜色值     int color = 0x698b22 ;     int i ;     for ( i = 0; i < 800*480; i++)     {         write(fd , &color , sizeof(int));               }          // 关闭文件     close(fd);          return 0; } 

 由上程序可知,write向LCD设备写入RGB的值来控制LCD的显示。但是write函数需要进行一系列的系统调用才能将数据写入到设备文件,这会消耗大量的时间,实验现象也能看出屏幕从上而下,甚至从左到右的变化,实在是太慢了。使用系统调用mmap可以将文件映射至内存(进程空间),如此可以把对文件的操作转为对内存的操作,这点对于大文件或者频繁访问的文件尤其有用,提高了I/O效率。

mmap

mmap ( 建立内存映射 )     头文件:         #include <unistd.h>         #include <sys/mman.h>     定义函数:         void *mmap(void *start, size_t length, int prot,                                  int flags, int fd, off_t offsize);     参数分析:        start --> 指向欲对应的内存起始地址, 通常设为 NULL, 代表让系统自动选定地址        length --> 需要申请内存区域的大小        prot --> 代表映射区域的保护方式有下列组合             PROT_EXEC 映射区域可被执行             PROT_READ 映射区域可被读取             PROT_WRITE 映射区域可被写入             PROT_NONE 映射区域不能存取        flags -->会影响映射区域的各种特性             MAP_FIXED 如果参数 start 所指的地址无法成功建立映射时, 则放弃映射, 不对地址做修正.通常不鼓励用此旗标.             MAP_SHARED 对应射区域的写入数据会复制回文件内, 而且允许其他映射该文件的进程共享.             MAP_PRIVATE 对应射区域的写入操作会产生一个映射文件的复制, 即私人的"写入时复制" (copyon write)对此区域作的任何修改都不会写回原来的文件内容.             MAP_ANONYMOUS  建立匿名映射. 此时会忽略参数 fd, 不涉及文件, 而且映射区域无法和其他进程共享.             MAP_DENYWRITE  只允许对应射区域的写入操作, 其他对文件直接写入的操作将会被拒绝.             MAP_LOCKED  将映射区域锁定住, 这表示该区域不会被置换(swap:交换空间).        fd --> 需要映射的文件的文件描述符        offsize --> 偏移量, 一般设置为零,表示不需要偏移 文件与内存是一一对应的            返回值:        若映射成功则返回映射区的内存起始地址,         否则返回 MAP_FAILED(-1), 错误原因存于 errno 中. 

实验程序

#define     LCD_W       800 #define     LCD_H       480 #define     LCD_SIZE    LCD_W*LCD_H*4  #define     LCD_PATH    "/dev/fb0"  int main(int argc, char const *argv[]) {         int fd  = open(LCD_PATH , O_RDWR);     if (fd < 0 )     {        perror("open lcd error");        return -1 ;     }      // 内存映射     int * lcd_p = (int *)mmap(NULL ,   // 指向欲对应的内存起始地址, 通常设为 NULL, 代表让系统自动选定地址                             LCD_SIZE,  // 显示器的大小                             PROT_READ | PROT_WRITE,  // 配置内存区可读, 可写                             MAP_SHARED,    // 设置内存区为共享*(对内存的任何操作都会被复制到文件中)                             fd,        // 需要映射的文件                             0);        // 偏移量     if (NULL ==  lcd_p)     {         perror("mmap error ");         return -1 ;     }          // 写入颜色值     int color = 0xFF3030 ;     int i ;     for ( i = 0; i < 800*480; i++)     {         *(lcd_p+i) = color ;     }         close(fd);        return 0; } 

 将此程序编译到开发板上运行时,肉眼看不到屏幕变化的过程,建立内存映射能够大大提高I/O的效率。

实验程序

 以下程序是一个”跑马灯程序”,将屏幕分成了不同颜色的八块,并按顺时针”跑动”。

#define     LCD_W       800 #define     LCD_H       480 #define     LCD_SIZE    LCD_W*LCD_H*4  #define     CYAN        0x00FFFF #define     PPuff       0xFFDAB9 #define     RED         0xFF0000 #define     YELLOW      0XFFFF00 #define     BLUE        0x0000FF #define     INRED       0xEE6363 #define     SNOW        0xFFFAFA #define     PURPLE      0xA020F0  #define     LCD_PATH    "/dev/fb0"  int color[8] = {CYAN, PPuff, RED, YELLOW, BLUE, INRED, SNOW, PURPLE};  bool draw_point(int *address, int color, int x, int y) //画点函数:x,y用来表示坐标值 {     if (NULL == address)     {         printf("draw_point msg:%sn", strerror(errno));           return false;     }      *(address + (x + (y*800))) = color;      return true; }  bool draw_line(int *address, int color, int len, int x, int y) //画线函数:以坐标(x,y)为起点,画一条长度为len的横线 {     if (NULL == address)     {         printf("draw_line msg:%sn", strerror(errno));                 return false;     }     while (len--)     {         draw_point(address, color, x, y);         address++;     }     return true; }  bool draw_surface(int *address, int color, int high, int len, int x, int y)//画面函数:以坐标(x,y)为起点,画一个长为len,高high的面 {     if (NULL == address)     {         printf("draw_surface msg:%sn", strerror(errno));          return false;     }     while (high--)     {        draw_line(address, color, len, x, y);        address = address + LCD_W;     }     return true; }  int main(int argc, char const *argv[]) {     int fd  = open(LCD_PATH , O_RDWR);     if (fd < 0 )     {        perror("open lcd error");        return -1 ;     }      // 内存映射     int * lcd_p = (int *)mmap(NULL ,   // 指向欲对应的内存起始地址, 通常设为 NULL, 代表让系统自动选定地址                             LCD_SIZE,  // 显示器的大小                             PROT_READ | PROT_WRITE,  // 配置内存区可读, 可写                             MAP_SHARED,    // 设置内存区为共享*(对内存的任何操作都会被复制到文件中)                             fd,        // 需要映射的文件                             0);        // 偏移量     if (NULL ==  lcd_p)     {         perror("mmap error ");         return -1 ;     }          int div_wide =  800 / 4;      int div_high =  480 / 2;       int i = 0;     int j = 0 ;     // 将屏幕分为八块,写入不同颜色值,并让其顺时针“跑”起来     while (1)     {                 draw_surface(lcd_p, color[i++], div_high, div_wide, 0, 0);j++;         if (7 <= i)         {             i = i % 8;         }         draw_surface(lcd_p, color[i++], div_high, div_wide, div_wide, 0);j++;         if (7 <= i)         {             i = i % 8;         }         draw_surface(lcd_p, color[i++], div_high, div_wide, div_wide*2, 0);j++;         if (7 <= i)         {             i = i % 8;         }         draw_surface(lcd_p, color[i++], div_high, div_wide, div_wide*3, 0);j++;         if (7 <= i)         {             i = i % 8;         }         draw_surface(lcd_p, color[i++], div_high, div_wide, div_wide*3, div_high);j++;         if (7 <= i)         {             i = i % 8;         }         draw_surface(lcd_p, color[i++], div_high, div_wide, div_wide*2, div_high);j++;         if (7 <= i)         {             i = i % 8;         }         draw_surface(lcd_p, color[i++], div_high, div_wide, div_wide, div_high );j++;         if (7 <= i)         {             i = i % 8;         }         draw_surface(lcd_p, color[i], div_high, div_wide, 0, div_high);j++;         if (7 <= i)          {             i = i % 8;         }          if (64 == j)//防止i,j无限增长         {             j = 0;             i = 0;         }         usleep(160000);      }     close(fd);          return 0; } 
赞(0) 打赏
未经允许不得转载:张拓的天空 » Linux :LCD应用层编程
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

专业的IT技术经验分享 更专业 更方便

联系我们本站主机

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏