⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lcd.c

📁 该程序是在linux arm下实现的基于framebuffer的LCD驱动
💻 C
字号:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
/*#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
*/#include <string.h>
#include <linux/fb.h>
#include <linux/kd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <termios.h>
#include <sys/time.h>
#include <sys/ioctl.h>

#include "lcd.h"
#include "ascii.c"

struct  termios save;
int     current_vt;
int     con;


FILE 	*fp =NULL;
/* LCD screen routine for M68VZ328  */
unsigned char *lcd_base = 0;
unsigned char curFontColor=0x1f;
unsigned char curBackColor=0x0;

/*
 * 清空FB内容
 */
void cls(void)
{
	int i;
    memset(lcd_base , curBackColor , SCREEN_WIDTH * SCREEN_HEIGHT);
}

/*
 * FB的初始化:获取fb_var_screeninfo、fb_fix_screeninfo、
 * 字库等信息,并将FB映射到内存。
 */
int fb_init()
{
	struct fb_fix_screeninfo finfo;
	struct fb_var_screeninfo vinfo;
	struct termios current;
	
	tcgetattr(0, &save);
	current = save;

	current.c_lflag &= ~ICANON;
	current.c_lflag &= ~ECHO;

	current.c_cc[VMIN] = 1;
	current.c_cc[VTIME] = 0;  
    
	tcsetattr(0, TCSANOW, &current);
	current_vt = open("/dev/tty", O_RDWR);
	ioctl(current_vt, KDSETMODE, KD_GRAPHICS);

	//打开设备文件FB,用文件描述词con指向它
	con = open("/dev/fb0", O_RDWR, 0);  
	
	if (con < 0) {
		fprintf(stderr, "Can't open /dev/fb0\n");
		return 0;
	}//设备文件未打开,返回

	if ( ioctl(con, FBIOGET_FSCREENINFO, &finfo) < 0 ) {
		fprintf(stderr, "Can't get FSCREENINFO\n");
		close(con);
		return 0;
	}//获取fb_fix_screeninfo信息失败,返回

	if ( ioctl(con, FBIOGET_VSCREENINFO, &vinfo) < 0 ) {
      	fprintf(stderr, "Can't get VSCREENINFO\n");
		close(con);
	    return 0;
   	}//获取fb_var_screeninfo信息失败,返回

	if (vinfo.bits_per_pixel != 8) {
		vinfo.bits_per_pixel = 8;
		ioctl(con, FBIOPUT_VSCREENINFO, &vinfo);
	}//修正像素所占的字节数

	//将FB映射到内存中,并用lcd_base返回该内存的起始位置
	lcd_base = mmap(NULL, SCREEN_WIDTH * SCREEN_HEIGHT , PROT_READ|PROT_WRITE, MAP_SHARED, con, 0);
	if ( lcd_base == MAP_FAILED )
    {        
        fprintf(stderr, "Can't mmap\n");
		close(con);
	 	return 0;    
	}//映射失败,返回

    printf("Video memory address = 0x%x\n",lcd_base);
	cls();

	//以只读形式打开二进制文件FONT_FILE(字库)
	fp = fopen(FONT_FILE, "rb");
	if(!fp){
		printf("Open hzk failed!\n");
        close(con);
		return 0;
	}//文件打开失败,返回

	return -1;	
}

/*
 * 释放FB所占内存,关闭字库
 */
void fb_release(void)
{
   	munmap(lcd_base,FB_SIZE);    
   	if(fp)
        fclose(fp);
    if(con)
     	close(con);	
}
//////////////////

/* 设置字体颜色 */
int SetFrontColor(unsigned char clr)
{
    curFontColor = clr;    
}

/* 设置背景颜色 */
int SetBackColor(unsigned char clr)
{
    curBackColor = clr;
}

/* 一屏的数据容量(以字节计) */
int SysBytesPerScreen()
{
	return (SCREEN_WIDTH*SCREEN_HEIGHT*BPP/8);
}

/* 获取FB映射的内存的起始地址 */
int lcd_getdisplay()
{
	return (int)lcd_base;
}

/* 获取屏幕一行的像素数 */
int lcd_getx()
{
	return SCREEN_WIDTH;
}

/* 获取屏幕一列的像素数 */
int lcd_gety()
{
	return SCREEN_HEIGHT;
}

/* 为fbuf指向的区域中点(x,y)赋值color */
int _lcd_putpixel(
	char 			*fbuf,
	int 			x, 
	int 			y,
	unsigned char 	color,
	int 			xorm
)
{
	unsigned char *p;
	//找到点(x,y)在区域中对应的位置
	p = fbuf + y * SCREEN_WIDTH * BPP / 8 + x ;
	*p = curFontColor;
	return 0;
}

/* 设置屏幕上点(x,y)值为c */
int lcd_putpixel(short x, short y, unsigned char c, int xorm)
{
	return _lcd_putpixel(
		lcd_base,
		x,
		y,
		c,
		xorm
	);
}

/* 获取fbuf指向的区域中点(x,y)的值 */
char _lcd_getpixel(
	unsigned char 	*fbuf,
	int 			x, 
	int 			y
)
{
	unsigned char *p;
	p = fbuf + y * LINE_OFFSET + x;
	return (*p);
}

/* 获取屏幕上点(x,y)的值 */
char lcd_getpixel(
	short x, 
	short y
)
{
	return _lcd_getpixel(
		lcd_base,
		x,
		y
	);
}

/* quick method for hline */
/*
 * 从(x1,y)到(x2,y)画水平线,fbuf指向FB
 */
int _lcd_hline(unsigned char *fbuf, short x1, short y, short x2, unsigned char color, int xorm)
{
	unsigned long  startOffset;
	//找到水平线的起点
	startOffset = (y * LINE_OFFSET + x1) ;
	//设置水平线涉及的各个像素点的值
	memset((char*)((unsigned long)lcd_base + (unsigned long)startOffset), color, (x2 - x1) );
	return 0;
}

/* 在屏幕上画出水平线,从(x1,y)到(x2,y) */
int lcd_hline(
	short x1, 
	short y, 
	short x2, 
	unsigned char c,
	int xorm
)
{
	return _lcd_hline(
		(void *)lcd_base,
		x1,
		y,
		x2,
		c,
		xorm
	);
}

/*
 * 从(x,y1)到(x,y2)画竖线,fbuf指向FB
 */
int _lcd_vline(
	unsigned char *fbuf,
	int 	x, 
	int 	y1, 
	int 	y2, 
	unsigned char  	color,
	int	xorm
)
{
	int  startOffset, endOffset , i ; 
    char *point;
	//竖线的起点
	startOffset = (y1 * LINE_OFFSET + x) ;
	//竖线的终点
	endOffset = (unsigned long)lcd_base + (unsigned long)startOffset + (y2 - y1) * LINE_OFFSET ;
	//设置竖线涉及的各个像素点的值
	for (i = (unsigned long)lcd_base + (unsigned long)startOffset; i <= endOffset; i += LINE_OFFSET ) {
		*(point=(char*)i) =color;
	}	
  	return 0;
}

/* 在屏幕上画出竖线,从(x,y1)到(x,y2) */
int lcd_vline(
	short x, 
	short y1, 
	short y2, 
	unsigned char c, 
	int xorm
)
{
	return _lcd_vline(
		(void *)lcd_base,
		x,
		y1,
		y2,
		c,
		xorm
	);
}


/*
 * 在水平投影大于垂直投影时,画斜线,
 * 起始点为(x,y),水平投影为dx,垂直投影为dy
 * dir=1时由左向右画,dir=-1时反之
 */
static inline void draw_xish_line(short x, short y, short dx, short dy, short xdir,int color)
{
        short dyX2=dy+dy;
        short dyX2mdxX2=dyX2-(dx+dx);
        short error=dyX2-dx;

		//设置起始点的值
        lcd_putpixel(x, y, color, 0);

		//设置斜线上各点的值
        while (dx--) {
                if (error >= 0) {
                        y++;
                        error += dyX2mdxX2;
                } else {
                        error += dyX2;
                }
                x += xdir;//找到斜线上的下一个点
                lcd_putpixel(x,y,color,0);
        }
}

/*
 * 在水平投影小于垂直投影时,画斜线,
 * 起始点为(x,y),水平投影为dx,垂直投影为dy
 * dir=1时由上向下画,dir=-1时反之
 */
static inline void draw_yish_line(short x, short y, short dx, short dy,short xdir,int color)
{
        short dxX2=dx + dx;
        short dxX2mdyX2=dxX2-(dy+dy);
        short error=dxX2-dy;

		//设置起始点的值
        lcd_putpixel(x, y, color, 0);

		//设置斜线上的各个值
        while (dy--) {
                if (error >= 0) {
                        x+= xdir;//找到斜线上的下一个点
                        error += dxX2mdyX2;
                } else {
                        error += dxX2;
                }

                y++;
                lcd_putpixel(x,y, color, 0);
        }
}

/*
 * 在屏幕上画出(x1,y1)到(x2,y2)的连线
 */
void lcd_line(short x1, short y1, short x2, short y2,int color)
{
        short dx,dy;

        if ( y1 > y2) {
                short t = y1;
                y1 = y2;
                y2 = t;
                t = x1;
                x1 = x2;
                x2 = t;
        }//保证起点在终点的下方

        dx = x2-x1;
        dy = y2-y1;

        if (dx > 0) {
			//起点在终点的左边
                if (dx > dy)
                        draw_xish_line(x1, y1, dx, dy, 1,color);
                else
                        draw_yish_line(x1, y1, dx, dy, 1,color);
        } else {
			//起点在终点的右边
                dx = -dx;
                if (dx > dy)
                        draw_xish_line(x1, y1, dx, dy, -1,color);
                else
                        draw_yish_line(x1, y1, dx, dy, -1,color);
        }


}

/*
 * 用逐列扫描的方式绘出一个矩形 
 * (x,y),(x1,y1)分别为矩形的对角线的两端点
 */	
int _lcd_fillrect(
	unsigned char *fbuf,
	int 	x, 
	int 	y, 
	int 	x1, 
	int 	y1, 
	int 	color
)
{
	int tmp, w, h;
	
	if (x1 < x){
		tmp = x;
		x = x1;
		x1 = tmp;
	}//保证(x,y)在(x1,y1)左边
	
	if (y1 < y){
		tmp = y;
		y = y1;
		y1 = tmp;
	}//保证(x,y)在(x1,y1)下边

	w  = x1 - x + 1;
	h = y1 - y + 1;
	
	//逐列画竖线
  	for (h += y; y < h; y++) {
		lcd_hline(x,y,x1,color,0);
	}
	return 0;
}

/*
 * 在屏幕上绘出矩形
 */
int lcd_fillrect(short x1, short y1, short x2, short y2, int c)
{
	return _lcd_fillrect(
		(unsigned char *)lcd_base,
		x1,
		y1,
		x2,
		y2,
		c
	);
}

/*
 * 将buf指向的文本显示到屏幕上(x,y)开始的位置
 */
int lcd_textout(short x, short y, unsigned char* buf,int color)
{
	unsigned char	CH, CL;
	int				Pos;
	char			pixel[256];//存放显示到屏幕上的每个字符的信息16*16B
	char            pData[32];//存放显示字符的各个点的亮灭16*16/2=32B
    char*           pBuf=NULL;    
	int				i=0,j=0;
	unsigned short  mask=0x8000;//对各个像素进行分析
	short           *pVal;
	int             offset =0,val;

	pVal = (short *)buf;

	//逐字符读入
	while (*buf)
	{
        //初始化pixel,设置底色,为显示字符做准备
		memset(pixel, curBackColor, sizeof(unsigned char)*sizeof(pixel));

		CH = buf[0];
		CL = buf[1];
		if (CH >= 0xA0 && CH < 0xF8 && CL >= 0xA0 && CL < 0xFF) 
		{
			//按区位号找到汉字的位置
           	Pos = ((CH - 0xA1) * 94 + (CL - 0xA1)) * 32;
			fseek(fp, Pos, SEEK_SET);

			//将该汉字存入pBuf中
            pBuf = pData;
			fread(pBuf, 32, 1, fp);
			offset = 2;
		}//字符为汉字
		else
		{
			pBuf = (char*)(FontLib[CH]);
			offset = 1;
		}//字符为ascii码

		for(i=0; i<16; i++)
		{
            //将每个显示在屏幕上的字符第i行像素亮灭信息(16bits)存入val中
			val = (pBuf[2*i]<<8) | (pBuf[2*i+1]);

            for(j=0;j<16;j++)
			{
				//当像素点有信息要显示,即与屏幕底色不同时,
				//更改该像素的颜色为设定值color
				if( val & (mask>>j) )
				{
					pixel[i*16+j] = color;
				}
			}//对每行中的每个像素进行分析
		}//逐行分析

		//将pixel的内容显示到屏幕上
		lcd_bitmap(x, y, 16, 16, pixel, 0);
		x += 16;
		buf += offset;//对下一个汉字或ascii码进行操作
	}
	return  1;
}

/*
 * 在屏幕上用相邻的4个像素组成的正方形表示一个“大像素点” 
 */
static int lcd_putbigpixel(short x, short y, unsigned char c, int xorm){
//	lcd_putpixel(x, y,  c, xorm);	lcd_fillrect(x, y, x+1, y+1, c);
}

/*
 * 以(x,y)为中心、以a为半横轴、b为半纵轴在屏幕上画椭圆
 */
int lcd_ellipse(
	short x, 
	short y, 
	short a,
	short b, 
	unsigned char c, 
	int xorm
)
{
	int wx, wy;
	int thresh;
	int asq = a * a;
	int bsq = b * b;
	int xa, ya;

	//画出纵轴两个端点#if 1	lcd_putbigpixel(x, y+b, c, xorm);
	lcd_putbigpixel(x, y-b, c, xorm);
#endif
	
	wx = 0;
	wy = b;
	xa = 0;
	ya = asq * 2 * b;
	thresh = asq / 4 - asq * b;
	
	//画出椭圆中旋转角在45~90、245~270的部分
	for (;;) {
		thresh += xa + bsq;
		
		if (thresh >= 0) {
			ya -= asq * 2;
			thresh -= ya;
			wy--;
		}
		
		xa += bsq * 2;
		wx++;
		
		if (xa >= ya)
		  break;		
		
#if 1		lcd_putbigpixel(x+wx, y-wy, c, xorm);
		lcd_putbigpixel(x-wx, y-wy, c, xorm);
		lcd_putbigpixel(x+wx, y+wy, c, xorm);
		lcd_putbigpixel(x-wx, y+wy, c, xorm);
#endif	}
	//画出横轴两个端点#if 1	lcd_putbigpixel(x+a, y, c, xorm);
	lcd_putbigpixel(x-a, y, c, xorm);
#endif	
	wx = a;
	wy = 0;
	xa = (bsq * a) << 1;
	
	ya = 0;
	thresh = (bsq >> 2) - bsq * a;
	
	//画出椭圆中旋转角在-45~45、135~245的部分
	for (;;) {
		thresh += ya + asq;
		
		if (thresh >= 0) {
			xa -= bsq + bsq;
			thresh = thresh - xa;
			wx--;
		}
		
		ya += asq + asq;
		wy++;
		
		if (ya > xa)
		  break;		 
#if 1		lcd_putbigpixel(x+wx, y-wy, c, xorm);
		lcd_putbigpixel(x-wx, y-wy, c, xorm);
		lcd_putbigpixel(x+wx, y+wy, c, xorm);
		lcd_putbigpixel(x-wx, y+wy, c, xorm);
#endif 	} 

}


/*
 * 将bitmap指向的区域内容保存至FB中(x,y)开始的、长width、宽height区域
 */
int _lcd_bitmap(
	void				*fbuf,
	int 				x,
	int 				y, 
	int					width,
	int					height,
	unsigned char 		*bitmap,
	int					xorm
) 
{
    unsigned char 	*dst;
    unsigned char 	*src;
    int 			width_bytes;
    int	 			xi, yi;
 
	//在FB中找到(x,y)点对应的信息
    dst = fbuf + y * LINE_OFFSET + x ;
    width_bytes = width;
    src = bitmap;

    /*	speedcode */
    for (yi = 0; yi < height; yi++) {
       for (xi = 0; xi < width_bytes; xi++) {
        	dst[xi] = *src++;
	   }//扫描一行信息
       dst += LINE_OFFSET;
    }//逐行扫描信息
    return 0;
}


/*
 * 将ppc指向的区域内容显示到屏幕上(x0,y0)开始的、长width、宽height区域
 */
int lcd_bitmap(
	short x0, 
	short y0, 
	short width, 
	short height, 
	unsigned char *pcc, 
	int xorm
)
{
	return _lcd_bitmap(
		lcd_base,
		x0,
		y0,
		width,
		height,
		pcc,
		xorm
	);
}	

/*
 * 显示屏幕色彩
 */
void show_palette()
{
    int i , j ;

	//在屏幕开头显示文本:system palette
    lcd_textout(0,0,"system palette",0x3f);

    i=50000;
    while(i--);

	//将256种颜色以20*13的颜色块分别显示
    for(i=0;i<16;i++)
    {
        for(j=0;j<16;j++)
        {
            SetFrontColor(i*16+j);
            lcd_fillrect(j*20,i*13,(j+1)*20,(i+1)*13,0);
        }
    }
    
	SetFrontColor(0x0);
	SetFrontColor(0x15);
	SetBackColor(0x9);
	//输出文本
	lcd_textout(110,190,"系统调色板",0x4f);
	lcd_textout(50,220,"linux palette!",0x5f);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -