一、部分基础知识
1、操作6818开发板的一些基础理论
1) LCD 屏幕原理
在linux下面,万物皆文件,所以操作LCD屏幕,也就是
操作LCD对应的文件
**开发板LCD的文件名: /dev/fb0**
开发板屏幕的分辨率为:800*480
表示开发板由480行像素点,每一行有800个像素点组成
什么是像素点?
像素点就是能够显示某种颜色的点
在屏幕上去显示图像,其实就是给对应的像素点赋一个相应的颜色即可
颜色怎么保存的?
计算机的三原色: 红(red) 蓝(blue) 绿(green),每种基色占1个字节,
给基色的每一位赋不一样的值,就表现出不同的颜色
将颜色值进行了量化处理(数量化)
red;0~255
blue:0~255
green:0~255
问: 三种基色可以表示多少种颜色?
2^8 * 2^8 * 2^ 8 = 2^24 ~ 1600万
2)LCD 像素点组成
LCD 上,每个像素点都是由 ARGB组成,其中,A代表透明度(为0代表没有)
一个像素点占4字节
发现: LCD上一个像素点占4字节,我们可以用一个int 型的变量来存储一个像素点
常见的一些颜色举例:
红色: int color = 0x00FF0000 = 0xff0000
蓝色: = 0x000000FF = 0XFF
绿色: = 0x0000FF00 = 0XFF00
....
3)操作LCD显示屏
//1.打开LCD显示屏文件
//2.写入像素点信息
//3.关闭文件
2、解决write函数效率问题
===> mmap函数(虚拟进程地址空间映射)
SYNOPSIS
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
参数列表:
@addr:
指定虚拟映射空间的起始地址,一般让系统自己指定,填 NULL
@length:
要映射区域的大小(单位:字节),800*480*4
@prot:
映射的权限,一般跟打开文件的权限一样:
PROT_READ
PROT_WRITE
PROT_EXEC
要操作虚拟进程地址空间,必须要有可写的权限,那如果你需要多个权限,如:
PROT_READ | PROT_WRITE
@flags:
映射标志,映射方式,有如下两种:
MAP_SHARED :共享映射,你对映射区域的操作,会立即反馈到文件或内核中
MAP_PRIVATE:私有映射,你对映射区域的操作,仅你自己可见
@fd:
文件描述符,open函数的返回值
@offset:
偏移量,表示你想要从文件的哪个位置开始映射,一般来说置0,表示不偏移
如果你想要指定偏移量,必须是4K的整数倍字节大小
返回值:
成功返回虚拟映射进程空间的首地址,失败返回NULL,并且errno会设置
int munmap(void *addr, size_t length);
函数功能:
解除虚拟映射
参数列表:
@addr:需要解除映射的空间首地址,mmap函数的返回值
@length:要解除映射区域的大小 :800*480*4
#include"lcd.h"
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include<string.h>
#include <stdlib.h>
#include <sys/mman.h>
/*
初始化LCD,开启映射
*/
void LCD_init(void)
{
fd=open(LCD_path,O_RDWR);
perror("");
plcd=mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);//打开映射
perror("");
}
/*
关闭LCD文件,关闭映射
*/
void LCD_free(void)
{
close(fd);
munmap(plcd,800*480*4);
}
/*
给LCD开发板画颜色
@fd:文件描述符
@color:颜色
*/
void draw_color(int color)
{
for(int i=0;i<480;i++)
{
for(int j=0;j<800;j++)
{
*(plcd+800*i+j) = color;
}
}
}
//画点函数
//@x:画点的横坐标,对应LCD的列
//@y:画点的纵坐标,对应LCD的行
void LCD_draw_print(int x,int y,int color)
{
if(x>=0&&x<800&&y>=0&&y<480)
*(plcd+800*y+x)=color;
}
3、获取屏幕信息
像手指的点击、滑动、键盘的输入、鼠标的移动、点击....统称为 输入事件
每次产生一个输入事件,都会保存到开发板的: /dev/input/event0 这个文件中
/dev/input/event0这个文件中的所有内容都是以一个结构体保存的:
头文件 : <linux/input.h>
struct input_event
{
struct timeval time;
_u16 type;//保存事件的类型,由宏定义定义:
EV_KEY 按键事件
EV_REL 鼠标点击事件
EV_ABS 触摸事件
_u16 code;//对事件的进一步描述,具体由type决定
if(type == EV_KEY) --> code == 按键的键值
if(type == EV_REL) --> code == 鼠标点击的坐标(REL_X 或 REL_Y)
if(type == EV_ABS) --> code == 触摸点的绝对坐标(ABS_X 或 ABS_Y)
_u32 value;//事件的值,对于事件的再进一步描述,具体由type决定
if(type == EV_KEY) // value == 0 代表松开 ,value == 1 代表按下
if(type == EV_REL) // value == 鼠标点击的横坐标 或 纵坐标
重点: 我要获取触摸点的横坐标:if(type == EV_ABS && code == ABS_X) -->value 就是横坐标的值
我要获取触摸点的纵坐标: if(type == EV_ABS && code == ABS_Y) -->value 就是纵坐标的值
};
#include "touch.h"
#include<linux/input.h>
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
int x_start=-1,y_satart=-1;
int x_end=-1,y_end=-1;
/*
获取触摸屏坐标
*/
void get_touch()
{
//1.打开文件
int fd=open(TOUCH_PATH,O_RDONLY);
perror("");
//2.解析文件
//2.1定义结构体变量,接收信息
struct input_event ev;
//2.2读文件信息
while(1)
{
int ret=read(fd,&ev,sizeof(ev));
//如果读的内容不完整,就跳过
if(ret!=sizeof(ev))
{
continue;
}
//2.3解析内容
//2.3.1先读x的坐标
if(ev.type==EV_ABS&&ev.code==ABS_X)//触摸事件
{
if(x_start==-1)
x_start=ev.value;
x_end=ev.value;
}
//2.3.2再读y的坐标
if(ev.type==EV_ABS&&ev.code==ABS_Y)
{
if(y_satart==-1)
y_satart=ev.value;
y_end=ev.value;
}
if(ev.type==EV_KEY && ev.code==BTN_TOUCH && ev.value==0) //按键事件 ,按键松开
{
printf("start:<%d,%d>\n",x_start,y_satart);
printf("end:<%d,%d>\n",x_end,y_end);
x_start=-1,y_satart=-1;
//break;
}
}
//关闭文件
close(fd);
}
//获取滑动方向
int get_dirction(void)
{
//1.打开文件
int fd=open(TOUCH_PATH,O_RDONLY);
perror("");
//2.解析文件
//2.1定义结构体变量,接收信息
struct input_event ev;
//2.2读文件信息
while(1)
{
int ret=read(fd,&ev,sizeof(ev));
//如果读的内容不完整,就跳过
if(ret!=sizeof(ev))
{
continue;
}
//2.3解析内容
//2.3.1先读x的坐标
if(ev.type==EV_ABS&&ev.code==ABS_X)//触摸事件
{
if(x_start==-1)
{
x_start=ev.value;
}
x_end=ev.value;
}
//2.3.2再读y的坐标
if(ev.type==EV_ABS&&ev.code==ABS_Y)
{
if(y_satart==-1)
{
y_satart=ev.value;
}
y_end=ev.value;
}
if(ev.type==EV_KEY && ev.code==BTN_TOUCH && ev.value==0) //按键事件,按键松开
{
//按键松开是终止坐标
printf("start:<%d,%d>\n",x_start,y_satart);
printf("end:<%d,%d>\n",x_end,y_end);
//确定滑动方向
int x=abs(x_end-x_start);
int y=abs(y_end-y_satart);
//横向移动
if(x>y)
{
if(x_end-x_start>0)//向右
{
close(fd);
return RIGHT;
}
else//向左
{
close(fd);
return LEFT;
}
}
else if(x<y)
{
if(y_end-y_satart>0)//向下
{
close(fd);
return DOWN;
}
else//向上
{
close(fd);
return UP;
}
}
else
{
//无效滑动
continue;
}
}
}
}
4、获取一个随机数
rand
SYNOPSIS
#include <stdlib.h>
int rand(void);
函数功能:
产生一个随机数返回
实现:
需要系统提供一个随机数因子,用来产生随机数,电脑开机之后,默认随机数因子是固定的
这个时候你获取到的随机数是一个“伪随机数”,为了解决这个 ---> srand()来提供一个随机数因子
void srand(unsigned int seed);
函数功能:
根据参数来生成一个随机数因子,如果默认参数,那么srand()函数只会默认产生一个1的随机因子
也达不到效果,所以,想到以系统时间作为参数,那么获取到的因子也会随时间的变化而变化 --> time(NULL)来获取时间
获取随机数步骤:
1> 获取随机数因子
srand(time(NULL));
2> 生成随机数
int ret = rand();
5、BMP图片显示
1.读取图片的像素点信息
2.写入到LCD文件中
1>读取图片信息
BMP图片的组成:
BITMAP文件头
DIB头
调色板
像素数组
BMP图片的像素组成:
BGRA -----》需要转换成 ARGB的数据(位操作)
==》 A << 24 | R << 16 | G << 8 | B
```
注:图片像素不能超过 800*480 !!!
显示图片之前,先确定两点:
1) 你的图片是bmp图片
2)图片像素合格
BMP图片格式
#include"bmp.h"
#include"lcd.h"
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include<linux/input.h>
/*
显示图片内容
@x:图片的显示起始横坐标
@y:图片的显示起始纵坐标
@pathname:要显示的图片的路径名
*/
void show_bmp(int x,int y,const char* pathname)
{
//1.读取图片的像素点信息
//1.1打开图片
int fd=open(pathname,O_RDONLY);
perror("open_bmp:");
//1.2计算图片的大小
//1.2.1读取图片的宽度,高度,色深
int width;//保存宽度
int heigh;//保存高度
short depth;//色深
/*图片信息以小端模式保存,读取后需要用位运算偏移的到正确结果*/
//读取宽度
unsigned char buf[4]={0};//保存图片的信息
lseek(fd,0x12,SEEK_SET);//从头开始偏移0x12个字节到宽度地址
read(fd,buf,4);
width=buf[3]<<24|buf[2]<<16|buf[1]<<8|buf[0];
//读取高度,因为宽度后面的地址就是高度,地址连续可以不用手动偏移
read(fd,buf,4);
heigh=buf[3]<<24|buf[2]<<16|buf[1]<<8|buf[0];
//读色深
lseek(fd,0x2,SEEK_CUR);//以当前位置偏移两个字节到色深的地址
read(fd,buf,2);
depth=buf[1]<<8|buf[0];
printf("wigth:%d,heigh:%d,depth:%d\n",width,heigh,depth);
//1.2.2计算图片的一行字节大小,判断是否需要填充
int line_size=abs(width)*depth/8;
int laizi=0;//填充
if(line_size%4)//要把图片字节长度填充位4的倍数
{
laizi=4-line_size%4;
}
//1.2.3计算图片一行的最终大小
int line_r_size=line_size+laizi;
//1.2.4图片的最终大小
int bmp_size=line_r_size*abs(heigh);
//1.3读取图片的像素信息
lseek(fd,0x36,SEEK_SET);//偏移0x36个字节到像素数组
char* p=malloc(bmp_size);//动态分配空间,保存图片的像素信息
read(fd,p,bmp_size);
//2.将图片信息写入到LCD文件
//图片里的像素点保存方式:BGRA -------在开发板中位ARGB
//2.1提取出每一个像素点的实际数据
int color;//保存像素点的信息
unsigned char a,r,g,b;
int m=0;//遍历动态空间
for(int i=0;i<abs(heigh);i++)//遍历行
{
for(int j=0;j<abs(width);j++)//遍历列
{
b=p[m++];
g=p[m++];
r=p[m++];
if(depth==32)//色深位32则表示有透明度
{
a=p[m++];
}
else
{
a=0;
}
color=a<<24|r<<16|g<<8|b;//一个像素点实际写入LCD的内容
LCD_draw_print(width>0?j+x:abs(width)-1-j+x,
heigh>0?abs(heigh)-1-i+y:y+i,color);
}
m=m+laizi;
}
//3.关闭图片
close(fd);
}