1. 程式人生 > >linux上LCD應用程式編寫 柏貴林

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;
}