linux上LCD应用程序编写 柏贵林

编写之前需要了解一些概念

1、linux一些皆文件的思想

2、帧缓存的概念

3、什么是虚拟像素什么是逻辑像素(为什么要刷逻辑像素)

4、什么是点阵图

5、BMP图片的格式

6、汉字库的使用

7、摄像头成像原理与bmp的关系(图像颠倒现象)


下面是我早期写的一段测试代码,在ubuntu10 gun上编译通过,在开发板1024*600的屏上测试ok,注意编译的时候需要连接线程库,另外如果不是1024*600的屏幕需要对应修改帧缓存的for循环的参数,否则直接段错误

bmp图像位深为32

欢迎读者对该代码进行优化,并重新发表,但请注明出处。


//----------------------------------------------------------------------------------------
// author by baiguilin
// Date 2015
//----------------------------------------------------------------------------------------
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include "lcd.h"
//----------------------------------------------------------------------------------------
// BMP文件信息
//----------------------------------------------------------------------------------------
typedef struct   //14byte文件头

char cfType[2]; //文件类型,"BM"(0x4D42)         
long cfSize; //文件大小(字节)         
long cfReserved; //保留,值为0     
long cfoffBits; //数据区相对于文件头的偏移量(字节)    
}__attribute__((packed)) BITMAPFILEHEADER;   //__attribute__((packed))的作用是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐


typedef struct //40byte信息头
{
char ciSize[4]; //BITMAPFILEHEADER所占的字节数
long ciWidth; //宽度       
long ciHeight; //高度      
char ciPlanes[2]; //目标设备的位平面数,值为1
int ciBitCount; //每个像素的位数
char ciCompress[4]; //压缩说明
char ciSizeImage[4]; //用字节表示的图像大小,该数据必须是4的倍数    
char ciXPelsPerMeter[4]; //目标设备的水平像素数/米
char ciYPelsPerMeter[4]; //目标设备的垂直像素数/米
char ciClrUsed[4]; //位图使用调色板的颜色数   
char ciClrImportant[4]; //指定重要的颜色数,当该域的值等于颜色数时(或者等于0时),表示所有颜色都一样重要
}__attribute__((packed)) BITMAPINFOHEADER;


typedef struct //16位域
{
unsigned short red:5;
unsigned short green:6;
unsigned short blue:5;
}__attribute__((packed)) PIXEL; //颜色模式,RGB565


//----------------------------------------------------------------------------------------
// 变量定义区
//----------------------------------------------------------------------------------------
BITMAPFILEHEADER FileHead;
BITMAPINFOHEADER InfoHead;


static char *fbp = 0;
static int xres = 0;
static int yres = 0;
static int bits_per_pixel = 0;


int fbfd = 0;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
long int screensize = 0;
//----------------------------------------------------------------------------------------
// 函数申明
//----------------------------------------------------------------------------------------
int show_bmp();


void clear_sector(int x0, int y0, int x, int y, char *fbp);//清除屏幕使用
void get_time(char *p_time);//获取现行时间


void show_words(int x0,int y0,const unsigned char *incode, char *fbp, unsigned color,int fsize);//显示一个汉字
void show_time(int x0,int y0,const unsigned char *incode, char *fbp, unsigned color,int fsize);//显示时间
void show_asc(int x0,int y0,const unsigned char *incode, char *fbp, unsigned color,int fsize);//显示ascll
void setmsg(int tmp,int sd,int tv_state);//设置温度湿度函数
void setcmr();//打开或关闭视频

void setcmr_addr(char *addr,long int size);


//----------------------------------------------------------------------------------------
// main  如果这里的main函数和其他文件main冲突,那么请调用nomain()
//----------------------------------------------------------------------------------------


#if 1
int main ( int argc, char *argv[] )
{


fbfd = open("/dev/fb0", O_RDWR); //打开显示设备
if (!fbfd)
{
//printf("Error: cannot open framebuffer device.\n");
exit(1);
}


if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))
{
//printf("Error:reading fixed information.\n");
exit(2);
}


if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo))
{
//printf("Error: reading variable information.\n");
exit(3);
}


//printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel );
xres = vinfo.xres;
yres = vinfo.yres;
bits_per_pixel = vinfo.bits_per_pixel;


//计算屏幕的总大小(字节)
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
//printf("screensize=%d\n",screensize);


//内存映射
fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
if ((int)fbp == -1)
{
//printf("Error: failed to map framebuffer device to memory.\n");
exit(4);
}


//5s的开机动画时间
clear_sector(0, 0, 1024, 600,fbp);
show_words(300,300,"这是测试",fbp, 0xffffffff,8);

sleep(5);
clear_sector(0, 0, 1024, 600,fbp);
//show_bmp();

//-----------------静态图像不重复刷新----------------
char p_time[60];
show_words(670,0,"这是测试",fbp, 0xffffffff,4);
show_words(650,50, "这是测试",fbp, 0xffffffff,4);
show_words(650,90,"这是测试",fbp, 0xffffffff,4);
show_words(650,130,"这是测试",fbp, 0xffffffff,4);
show_words(650,170,"这是测试",fbp, 0xffffffff,4);
show_words(650,210,"这是测试",fbp, 0xffffffff,4);
show_words(650,250,"这是测试",fbp, 0xffffffff,4);
show_words(650,290,"这是测试",fbp, 0xffffffff,4);
show_words(650,370,"这是测试",fbp, 0xffffffff,4);
//show_asc(800,370,"65",fbp, 255, 4);

show_words(650,410,"这是测试",fbp, 0xffffffff,4);
//show_asc(800,410,"65",fbp, 255, 4);
show_words(650,450,"这是测试",fbp, 0xffffffff,4);
show_words(650,330, "一一一一一一一一一一一",fbp, 0xffffffff,4);
//-------慢----------动态图像重复刷新----------------

pthread_t pth;
if(pthread_create(&pth,NULL,thread_func,NULL)<0)
{
//perror("pthread");
return 0;
}


while(1)//视屏刷新  重要!!
{
//模拟温湿度,到时需屏蔽
setmsg(55,21,1);
setcmr();//开始视屏
}
munmap(fbp, screensize);
close(fbfd);
return 0;
}


#endif
//子线程函数用于刷新更新不快的数据到屏幕上
void *thread_func(void *arg)
{
while(1)
{
char p_time[64];
get_time(p_time);
show_time(0,510,p_time, fbp,0xffffffff,4);
usleep(500000);
//printf("pthread\n");
}
}


int show_bmp()
{
FILE *fp;
int rc;
int line_x=0, line_y=0;
long int location = 0, BytesPerLine = 0;
char tmp[1024*600*4];


fp = fopen( "./21.bmp", "rb" );
if (fp == NULL)
{
return( -1 );
}


rc = fread( &FileHead, sizeof(BITMAPFILEHEADER),1, fp );
if ( rc != 1)
{
//printf("read header error!\n");
fclose( fp );
return( -2 );
}


if (memcmp(FileHead.cfType, "BM", 2) != 0)
{
//printf("it's not a BMP file\n");
fclose( fp );
return( -3 );
}


rc = fread( (char *)&InfoHead, sizeof(BITMAPINFOHEADER),1, fp );
if ( rc != 1)
{
//printf("read infoheader error!\n");
fclose( fp );
return( -4 );
}


//跳转的数据区
fseek(fp, FileHead.cfoffBits, SEEK_SET);
//每行字节数


while(!feof(fp))
{
PIXEL pix;
unsigned short int tmp;



// unsigned int t[1024 * 600];
// fread(t, 4, 1024*600*4, fp);
// unsigned int *p=(unsigned int *)fbp;
// for(line_y=0;line_y<600;line_y++)
// for(line_x=1023;line_x>-1;line_x--)
// {
// *(p+(599-line_y) * 1024 + line_x) = t[line_y*1024 + (line_x)];
// }


//640*480
int weight=640;
int hight=480;
unsigned int t[weight * hight];

fread(t, 4, weight*hight*4, fp);
unsigned int *p=(unsigned int *)fbp;
for(line_y=0;line_y<hight;line_y++)
for(line_x=weight-1;line_x>-1;line_x--)
{
*(p+((hight-1)-line_y) * 1024 + line_x) = t[line_y*1024 + (line_x)];
}

}

fclose( fp );
return( 0 );
}


//----------------------------------------------------------------------------------------
// 清除屏幕中的一块
//----------------------------------------------------------------------------------------
void clear_sector(int x0, int y0, int x, int y, char *fbp)
{
unsigned int location=(unsigned int)fbp+vinfo.xres*y0*4+x0*4;
//printf("---%ld---",location);
int i; 
for(i = 0; i < (y-y0); i++)
{
memset((long int *)location, 0,(x-x0)*4);
location = location + vinfo.xres*4;
}
}
//----------------------------------------------------------------------------------------
// 获取时间
//----------------------------------------------------------------------------------------
void get_time(char *p_time)
{
time_t t;
static time_t t1;

t = time(NULL);
struct tm *tm1 = NULL;
tm1 = localtime(&t);
strftime(p_time, 60, "%Y-%m-%d %H:%M:%S WD:%A", tm1);

if(t1 !=t)
{
clear_sector(0, 500, 1024, 600,fbp);
clear_sector(800, 370, 900, 500,fbp);
t1=t;
}

//printf("curr_buff_time=%s\n", p_time);
}
//----------------------------------------------------------------------------------------
// 显示汉字
//----------------------------------------------------------------------------------------

void show_words(int x0,int y0,const unsigned char *incode, char *fbp, unsigned color,int fsize)
{
unsigned char qh, wh;   
unsigned long offset; 
unsigned long location = 0;
location=(x0+vinfo.xoffset) * (vinfo.bits_per_pixel/8) + (y0+vinfo.yoffset) * finfo.line_length;
int tmp = location;
int n;
//循环显示所有汉字
for(n = 0; incode[n] != 0; n = n+2)
{
int bytes  = 128;
qh = incode[n]-0xa0; //获得区码            
wh = incode[n+1]-0xa0; //获得位码


offset = (94*(qh-1)+(wh-1))*bytes;//得到HZK16中的偏移位置

FILE *fp = NULL; 
unsigned char buf[bytes];
bzero(buf,bytes);
//GB2312字库文件hzk16
if((fp=fopen("hzk32", "rb")) == NULL)   
{   
//perror("fopen");   
exit(0);   
}  
fseek(fp, offset, SEEK_SET);   
int ret = fread(buf, bytes, 1, fp);//buf存放一个汉字,有32个字节
if(0 > ret)
exit(0);


//显示一个汉字
int i = 0, j = 0;
while(i < bytes)//一行两次扫描,每循环一次扫描8位,共扫描16行,即是16×16
{
for(j = 0; j <8; j++)
{
if(buf[i] & (0x80>>j))
{
*((unsigned *)(fbp + location)) = color;
location+=fsize;
}
else
{
location+=fsize;
}
}

if((++i%4) == 0)//扫描换行
{
location+=(1024-32)*fsize;
//location = location-48+1024*8;
}
}
bzero(buf,bytes);
tmp += 32*fsize;
location=tmp;
fclose(fp);

}
}
void show_time(int x0,int y0,const unsigned char *incode, char *fbp, unsigned color,int fsize)
{
unsigned char qh, wh;   
unsigned long offset; 
unsigned long location = 0;
location=(x0+vinfo.xoffset) * (vinfo.bits_per_pixel/8) + (y0+vinfo.yoffset) * finfo.line_length;
int tmp = location;
int n;



//循环显示所有汉字
for(n = 0; incode[n] != 0; n = n+1)
{
int bytes  = 144;
offset = (incode[n]-32)*bytes;//得到HZK16中的偏移位置

FILE *fp = NULL; 
unsigned char buf[bytes];
bzero(buf,bytes);
//GB2312字库文件hzk16
if((fp=fopen("ASC48", "rb")) == NULL)   
{   
//perror("fopen");   
exit(0);   
}  
fseek(fp, offset, SEEK_SET);   
int ret = fread(buf, bytes, 1, fp);//buf存放一个汉字,有32个字节
//printf("hanzi %s",buf);
if(0 > ret)
exit(0);


//显示一个汉字
int i = 0, j = 0;
while(i < bytes)//一行两次扫描,每循环一次扫描8位,共扫描16行,即是16×16
{
for(j = 0; j <8; j++)
{
if(buf[i] & (0x80>>j))
{

*((unsigned *)(fbp + location)) = color;
location+=fsize;
}
else
{
location+=fsize;
}
}

if((++i%3) == 0)//扫描换行
{
location+=(1024-24)*fsize;
//location = location-48+1024*8;
}
}
bzero(buf,bytes);
tmp += 16*fsize*2;
location=tmp;
fclose(fp);
}


}

//------------------------------------------------------

//显示ascii

//-----------------------------------------------------
void show_asc(int x0,int y0,const unsigned char *incode, char *fbp, unsigned color,int fsize)
{
unsigned char qh, wh;   
unsigned long offset; 
unsigned long location = 0;
location=(x0+vinfo.xoffset) * (vinfo.bits_per_pixel/8) + (y0+vinfo.yoffset) * finfo.line_length;
int tmp = location;
int n;



//循环显示所有汉字
for(n = 0; incode[n] != 0; n = n+1)
{
int bytes  = 144;
offset = (incode[n]-32)*bytes;//得到HZK16中的偏移位置

FILE *fp = NULL; 
unsigned char buf[bytes];
bzero(buf,bytes);
//GB2312字库文件hzk16
if((fp=fopen("ASC48", "rb")) == NULL)   
{   
//perror("fopen");   
exit(0);   
}  
fseek(fp, offset, SEEK_SET);   
int ret = fread(buf, bytes, 1, fp);//buf存放一个汉字,有32个字节
//printf("hanzi %s",buf);
if(0 > ret)
exit(0);


//显示一个汉字
int i = 0, j = 0;
while(i < bytes)//一行两次扫描,每循环一次扫描8位,共扫描16行,即是16×16
{
for(j = 0; j <8; j++)
{
if(buf[i] & (0x80>>j))
{

*((unsigned *)(fbp + location)) = color;
location+=fsize;
}
else
{
location+=fsize;
}
}

if((++i%3) == 0)//扫描换行
{
location+=(1024-24)*fsize;
//location = location-48+1024*8;
}
}
bzero(buf,bytes);
tmp += 16*fsize*2;
location=tmp;
fclose(fp);
}


}


//这里设置动态的温度和湿度函数,供server调用
void setmsg(int tmp,int sd,int tv_state)
{
char atem[10];
char asd[3];
char agz[3];

sprintf(atem,"%d",tmp);
// printf("%d\n",atem);
sprintf(asd,"%d",sd);




show_asc(800,370,atem,fbp, 255, 4);//温度
show_asc(800,410,asd,fbp, 255, 4);//湿度
if(tv_state == 0)
{
show_asc(800,450,"OFF",fbp, 255, 4);//湿度
}
else
{
show_asc(800,450,"ON",fbp, 255, 4);//湿度
}

}


//这里设置视屏    1s钟刷新50次   读取文件的方式 
void setcmr()
{
FILE *fptv;
int rc;
int line_x=0, line_y=0;
long int location = 0, BytesPerLine = 0;
char tmp[1024*600*4];
char filename[10];

static int index =1;
//printf("\n");//不可以删除
for(index=1;index<50;index++)
{
sprintf(filename,"%d.bmp",index);
//printf("%s\n",filename);

fptv = fopen(filename , "rb" );
if (fptv == NULL)
{
return;
}
rc = fread( &FileHead, sizeof(BITMAPFILEHEADER),1, fptv );
if ( rc != 1)
{
//printf("read header error!\n");
fclose( fptv );
return;
}


if (memcmp(FileHead.cfType, "BM", 2) != 0)
{
//printf("it's not a BMP file\n");
fclose( fptv );
return;
}


rc = fread( (char *)&InfoHead, sizeof(BITMAPINFOHEADER),1, fptv );
if ( rc != 1)
{
//printf("read infoheader error!\n");
fclose( fptv );
return;
}


//跳转的数据区
fseek(fptv, FileHead.cfoffBits, SEEK_SET);
//每行字节数


int weight=640;
int hight=480;
unsigned int t[weight * hight];
long Scansize=weight*hight*4;
unsigned int *p=(unsigned int *)fbp;
while(!feof(fptv))
{

//640*480


fread(t, 4, Scansize, fptv);
for(line_y=0;line_y<hight;line_y++)
for(line_x=weight-1;line_x>-1;line_x--)
{
*(p+(((hight-1)-line_y) << 10) + line_x) = t[line_y*640 + (line_x)];
}

}

fclose( fptv );
}


return;
}
//这里设置视屏    1s钟刷新50次   读取内存的方式    必须是640 *480
void setcmr_addr(int *addr,long int size)
{
int line_x=0, line_y=0;
long int location = 0, BytesPerLine = 0;

unsigned int *p=(unsigned int *)fbp;
int i=0;
for(line_y=0;line_y<480;line_y++)
for(line_x=640-1;line_x>-1;line_x--)
{
*(p+(((480-1)-line_y) << 10) + line_x) = addr[line_y*640 + (line_x)];
}
return;
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值