4.在gec6818开发板上设计电子相册----运算符和表达式、bmp图像文件解析与显示

运算符和表达式

运算符和表达式
1.表达式
C语言中,表达某一个问题的式子,合法的表达式都会有一个值
表达式一般是由运算符连接的式子

2.运算符
用来进行某一种运算的符号
主要研究运算符的以下一些属性:
带几个操作数
几目运算符?该运算符需要带几个操作数
单目运算符,该运算符只需要带一个操作数 ~,++,–
双目运算符,该运算符需要带两个操作数 +,-,*,/,%…
三目运算符,该运算符需要带三个操作数 ?:

	结合性:计算方向的问题,从左至右,从右至左(=)
		计算机计算操作数的值,不可能同时计算,先计算哪一个操作数
	
	*优先级:在含有多个运算符的表达式中,先计算哪一个运算符的问题
	单目运算符(~,++,--) > 算术运算符(+-*/) > 关系运算符(>,<,==) > 逻辑运算符(||,&&) > 条件运算符(?:) >赋值运算符 > 逗号运算符(,)
		写代码的时候,搞不清优先级,就打括号,
		
2.1 算术运算符:进行算术运算的运算符
		单目运算符:++ --
		双目运算符: * / % + -  结合性是从左至右的
	例子:
		3+5 ====> 8
		5/4 ====> 1(整数进行算术运算的结果一定是整数)
		5.0/4 ====> 1.25
		
		double(表达式);把表达式的值转换为double类型
		(类型)表达式; 把表达式转换为指定的类型
		
		double(3/2) ====> 1.0
		(double)3/2 ====> 1.5
		
		如何使用C语言的表达式来描述数学表达式a/b呢?
		a*1.0/b
		(double)a/b
		
		%:取余,要求两个操作数都必须是整数
		5%4 ====>1
		4%5 ====> 4
		%,/右边的操作数都不能为0
		
		a+b 与 b+a 在C语言中含义是不一样的!
			int i=5,j=6;
			(i++) + (i+j)  ---> 17  
			(i+j) + (i++)  ---> 16
		
		++:自增运算符
		--:自减运算符
		只要一个操作数,能作为左值(是一个可写的地址)
		int x = 1;
		x++; ===>x = x+1,后++,先取值,再+1
		++x; ===>x = x+1,前++,先+1,在取值
		
		int a,x = 1;
		a = x++; //a为1;x为2
		
		int a,x = 1;
		a = ++x; //a为2;x为2
		
		int a,x = 1;
		a = x--; //a为1;x为0
		
		int a,x = 1;
		a = --x; //a为0;x为0
		
		真值表:
		表达式		表达式的值		完成表达式后i的值
		i++				i				i+1
		++i				i+1				i+1
		i--				i				i-1
		--i				i-1				i-1


5++; //ERR

		int a,b;
		(a+b)++; //ERROR,(a+b)是一个值,
		
		int i;
		(i++)++; //ERROR
		
	int i = 5;	
	a = i++; //把表达式i++的值赋值给a,i++这个表达式的值就是i,a为5
	a = ++i; //把表达式++i的值赋值给a,++i这个表达式的值就是i+1,a为6
		
	用算计运算符连接的式子,是算术表达式
		算术表达式的值,就是计算之后的结果


int i = 100;
int sum = 0;
while(i–) //当括号内数据为真(非0),就执行循环体
{
sum = sum+i;
}
sum:4950
i:-1


int i = 100;
int sum = 0;
while(–i) //当括号内数据为真(非0),就执行循环体
{
sum = sum+i;
}
sum:4950
i:0



2.2 关系运算符:用来判断两个对象的大小关系
< <= > >= == !=
双目运算符,结合性都是从左至右
关系表示式就是使用关系运算符连接起来的式子
关系表示式的值,“关系成立(1)”,“关系不成立(0)”
如:
5>4 ----> 1
3<=4 ----> 1

	int i = 0;
	int sum = 0;
	while(i++ <= 100)  //当括号内数据为真(非0),就执行循环体
	{
		sum = sum+i;
	}
	sum:5151
	i:102



5>4>3 合法吗? 是一个合法的表达式
值:0
用表达式(5>4)的值与3进行比较
5>4>3 ---->(5>4) > 3
1>3 ===>0
在C语言中,5>4>3这个表达式和数学上的意思是不一样的
C语言中如何表达数学上的"5>4>3"
5>4 并且 4>3

	在C语言中,如何描述“并且”这个意思呢??	

2.3 逻辑运算符:用来表示逻辑关系的运算符
	! 逻辑非 单目运算符  "取反"
		!真  -----> 假
		!假  -----> 真
		
		!0  ----> 1
		!100 ----> 0
	
	&& 逻辑与,双目运算符,结合性从左至右   	"并且"
		必须两边都为真,结果才为真
		
	|| 逻辑或,双目运算符,结合性从左至右		"或者"
		任意一边为真,结果就为真	
		
	逻辑表达式就是使用逻辑运算符连接的式子
	逻辑表达式的值: 逻辑真(1,非0)  逻辑假(0)
	
	例子:
		a = 4, b= 5;
		a&&b   ----> 1
		a||b   ---->1
		4&&0||2   ----> 1
		
		优先级:
		! > && > ||
		
		5>3&&8<4-!0  ---->0
			
	练习:
	int a,b,c,d,m,n;
	a = 1;
	b = 2;
	c = 3;
	d = 4;
	m = n = 1;
	(m=a>b)&&(n=c>d)
	m:0
	n:1

	C语言中的"惰性运算"
	当逻辑表达式中结果已经确定的时候,后面的运算将不会进行了
	(1).a && b && c
		只有a为真的时候,才需要判断b的值
		只有a和b都为真的时候,才需要判断c的值
	(2).a || b || c
		只要a为真,就不需要判断b和c的值了
		只有a为假的时候,才需要判断b的值
		只有a和b都为假的时候,才需要判断c的值
		
	如果事先指定表达式的值了m那么后面的运算符(或者表达式)就不需要被执行了,这就是C语言的惰性运算

	练习:
	使用逻辑表达式来判断年份y是否为闰年
	(1).能被4整除,但是不能被100整除
	(2).能被4整除,又能被400整除
	满足上面的条件之一,则为闰年
	
	int year;
	if(表达式)  //表达式成立则执行if下面的语句
	{
		printf(是闰年!!!!);
	}
	
	(1) || (2)
		(1) 能被4整除 && 不能被100整除
			(year%4 == 0)&&(year%100 != 0)
			
		(2) 能被4整除 && 被400整除	
			(year%4 == 0)&&(year%400 == 0)
			====>
			(year%400 == 0)
			
			((year%4 == 0)&&(year%100 != 0)) || (year%400 == 0)
			
		if( ((year%4 == 0)&&(year%100 != 0)) || (year%400 == 0) )
		{
			printf("YES\n");
		}


不为闰年?
if( !((year%4 == 0)&&(year%100 != 0)) || (year%400 == 0) )
{
printf(“NO\n”);
}


2.4 位运算符 重点!!!
位运算符是指按照bit位来进行的运算(没有借位和进位),位运算有如下一些:
& 按位与
| 按位或
^ 按位异或
~ 按位取反
<< 按位左移
>> 按位右移
位运算一般只针对于整型数据

	除了~是单目运算符外,其他的都是双目运算符,结合性都是从左至右
	所有位运算都需要把操作数变成bit位的序列,然后在进行计算
	
	~	按位取反
		0 ----> 1
		1 ----> 0

		int a = ~3;
		printf("%d\n",a); // -4
		printf("%u\n",a); // 2^32 - 4
		
		~3:
			00000000 00000000 00000000 00000011  (3)
			11111111 11111111 11111111 11111100
		%d:
			11111111 11111111 11111111 11111100  是一个负数
			计算原码的绝对值
			11111111 11111111 11111111 11111011   -1
			00000000 00000000 00000000 00000100   (4)
		
		%u:
			11111111 11111111 11111111 11111100
			都是数值位
			
		int a = ~(-3);
		printf("%d\n",a); // 2
		printf("%u\n",a); // 2


00000000 00000000 00000000 00000011 (3)
11111111 11111111 11111111 11111100 (取反)
11111111 11111111 11111111 11111101 (-3在内存中的存放方式)

		~(-3)
		00000000 00000000 00000000 00000010   
		
	&  	按位与  双目运算符
		真值表
		a 		b   	a&b
		1		1		1
		1		0		0
		0		1		0
		0		0		0
		
		& 如果两个bit位操作数都为1,结果才为1,否则为0‘’
		3&5 == ?
			0000 0011  	(3)
		&	0000 0101	(5)
			0000 0001  	(1)
		
		清零:置为0
		置位:设置为1
		八位:从右至左,第0个bit~第7个bit
		
		假如有一个8位寄存器a,需要把a的第5个bit位清0,其他位不变怎么操作?
			a = a & 0xdf;
			=====>
			a = a & ~(1<<5);
		
		结论:
			一个bit位与0进行“按位与”操作,结果为0
			x & 0 -----> 0
			一个bit位与1进行“按位与”操作,结果不变
			x & 1 -----> x
			
	|  	按位或  双目运算符
		真值表
		a 		b   	a|b
		1		1		1
		1		0		1
		0		1		1
		0		0		0
		
		| 如果两个bit位操作数都为0,结果才为0,否则为1
		3|5 == ?
			0000 0011  	(3)
		|	0000 0101	(5)
			0000 0111  	(7)
		
		假如有一个8位寄存器a,需要把a的第5个bit位置位,其他位不变怎么操作?
			a = a | 0x20;
			a = a | (1<<5);


结论:
一个bit位与0进行“按位或”操作,结果不变
x | 0 -----> 0
一个bit位与1进行“按位或”操作,结果置位
x & 1 -----> 1


^ 按位异或 双目运算符
真值表
a b a^b
1 1 0
1 0 1
0 1 1
0 0 0

		^ 如果两个bit位操作数相同为0,不同为1
		3^5 == ?
			0000 0011  	(3)
		^	0000 0101	(5)
			0000 0110  	(6)
		
		假如有一个8位寄存器a,需要把a的第5个bit位保留,其他位取反怎么操作?
			a = a ^ 0xdf;
			a = a ^ ~(1<<5);


		结论:
			一个bit位与0进行“按位异或”操作,结果不变
			x ^ 0 -----> 0
			一个bit位与1进行“按位异或”操作,结果取反位
			x ^ 1 -----> ~x	
	
		练习:
			交换两个整数a与b的值,不使用临时变量。
			a = 3,b = 5;
			
			a = a+b;  //a = 8,b = 5;
			b = a-b;  //a = 8,b = 3;
			a = a-b;  //a = 5,b = 3;
			
			a = a^b;
			b = b^a;
			a = a^b;
			
			一个数异或同一个数两次,结果保持不变
			位运算只和当前位有关,没有借位和进位
			a	b	a=a^b	b=b^a	a=a^b
			1	1	0		1		1
			1	0	1		1		0
			0	1	1		0		1
			0	0	0		0		0
			
	<< 按位左移  双目运算符,按bit位整体向左边移动
		a << n 把a按bit位整体向左边移动n位
		高位左移后舍弃,低位补0
		如果舍弃的高位全部是0,那么左移n位,就标识原值乘以2的n次方
		如:
		3<<2
		0000 0011 <<2
	  000000 1100 ----> 0000 1100  (12)
	  
	>> 按位右移		双目运算符,按bit位整体向右边移动  
		a>>n 把a按bit位整体向右边移动n位
		低位右移后直接舍弃,高位补什么????
			对于有符号数,高位补符号位
			对于无符号数,高位补0
			
			“逻辑移位”  补0
			“算术移位” 	补符号位
			
		int a = -1;
		a = a >> 31;
		a:-1

		00000000 00000000 00000000 00000001	(1)
		11111111 11111111 11111111 11111110	
		11111111 11111111 11111111 11111111	 (-1) >>31
		
		11111111 11111111 11111111 11111111
		------------------------------------------------
		unsisned int a = -1;
		a = a >> 31;
		a:1
		
		00000000 00000000 00000000 00000001	(1)
		11111111 11111111 11111111 11111110	
		11111111 11111111 11111111 11111111	 赋值给a
		
		11111111 11111111 11111111 11111111  a >> 31
		a是一个无符号数,补0
		00000000 00000000 00000000 00000001

2.5 赋值运算符(=)
	双目运算符,从右至左,先计算右边的操作数,优先级排倒数第二,仅比逗号运算符高
	赋值运算符的左边(左操作数)必须是一个“可写的地址(左值)”
	
	int a;
	a = 5+3;
	
	5 = 5;//ERROR
	2+3=5;//ERROR
	i++ = 6; //ERROR
	
	赋值表达式:由赋值运算符连接起来的式子,叫做赋值表达式
	赋值表达式的值就是赋值后左边变量的那一个值。
	(为什么我们C语言支持连等号)
	a = b = 1;
	====>
		a = (b = 1);
		b = 1,这个表达式的值就是1
		
	(b=a)=6; //ERROR  


int a = 0;
if(a=1) //如果 if后面的表达式为真,就会执行if后面的语句
{
printf(“hehe\n”);
}else //否则
{
printf(“haha\n”);
}

	选择:
	A.不知道 B.编译错误 C.hehe D.haha E.以上都不对

	C,a=1是一个合法的表达式,合法的表达式都有一个值,
	
	可以使用复合的赋值运算符:赋值运算符可以和算术运算符,位运算符组成复合的赋值运算符
		+= -= *= %= /=
		<<= >>= |= &= ^= ....
		如:
		a += b; ====>a = a+b;
		a += 5+6 =====> a=a+(5+6);
	
2.6 条件运算符
	?: 三目运算符
	条件运算符具有右结合性
	基本形式:
	expression?a:b
		如果expression为真(非0),则整个表达式的值为a
		如果expression为假(0),则整个表达式的值为b
		
	a = 5>4?4:3;  a:4
	
2.7 逗号运算符
	双目运算符,优先级是最低的,结合性从左至右
	表达式1,表达式2
	逗号表达式的求值顺序,先计算表达式1的值,然后再计算表达式2的值
	整个逗号表达式的值是表达式2的值
	
	int a=5,b=6;
	a = (a=6,a+b);
		a=12
		
	逗号表达式扩展
		表达式1,表达式2,表达式3.....表达式n
		求值顺序,先求表达式1的值,再求表达式2的值....求表达式n的值,
		整个表达式的值就是表达式n的值
	
2.8 指针运算符(*,&) 指针的时候再讲

2.9 求字节运算符(sizeof)
	sizeof(表达式)
	计算表达式的类型占用的内存大小,不管对象存不存在,只有后面的类型正确就可以了
	
	sizeof计算类型占用的内存大小。
	
	sizeof(int) == 4
	sizeof(float) == 4
	sizeof(1) == 4
	sizeof(1.0) == 8
	sizeof(1.0f) == 4
	sizeof(1.0l) == 16
	sizeof('A') == 4   C语言中,字符其实是使用整数实现的
	sizeof(char) == 1
	
	int a = 1;
	sizeof(a+1.0) == 8  数据会自动的往高精度转换


2.10 分量运算符(.,->) 结构体的时候讲

2.11 下标运算符([]) 数组的时候讲

2.12 函数调用运算符  函数的时候讲

2.13 强制类型转换
	(类型)值;
		把对应的值转换为指定的类型
	
	float f = 3.6;
	(int)f+3.5 = 6.5
	(int)(f+3.5) =  7





BMP图像文件解析与显示

bmp图像文件它是一种简单也是常见的图像数据存储格式

BMP是将图像的数据不经过任何压缩处理就直接存储在文件中的一种存储格式

即文件中的数据就是图像每个像素点的颜色值

BMP图片文件的数据存储格式如下图所示:

在这里插入图片描述

BITMAP文件头:记录文件信息

BMP是一种二进制文件,所谓的二进制文件是一种用来给计算机看的文件,其文件内容是以二进制数的ASCII形式存储在文件中,并且是在特定文字存储特定长度的数据来表示特定的含义

比如:在BMP文件的0X02位置,以小端模式存储了四个字节数据,表示文件的大小
在这里插入图片描述

虽然打开二进制文件直接看我们看不懂,但我们应当可以写一个程序来解析文件中的数据

用到的函数:open read close lseek

NAME
       lseek - reposition read/write file offset

SYNOPSIS
       #include <sys/types.h>
       #include <unistd.h>
		lseek用来控制文件中的文件偏移量(光标)的位置
       off_t lseek(int fd, off_t offset, int whence);
		@fd:文件描述符,指定要操作的文件
        @offset:指定偏移量,即将"光标"移动多少个字节
         	正数 表示将"光标"向后移动
            负数 表示将"光标"向前移动
            0 表示不动
       	@whence 整数,表示将"光标"从那个地方开始移动
            SEEK_SET:从文件头开始移动
            SEEK_END:从文件末尾开始移动
            SEKK_CUR:从"光标"当前所在位置开始移动
       	返回值
                成功返回光标距离文件头从距离,单位 字节
                失败返回-1,并且errno被设置

解析二进制文件的步骤:

1 打开二进制文件

2 移动光标到我们需要的数据所在的位置

3 读取我们需要的数据内容

4 按照数据格式对数据进行解析

end (如果不再解析别的数据),关闭文件

eg:解析BMP图片中记录的位图数据的宽度

//读取位图数据宽度
	lseek(bmpfd,0x12,SEEK_SET);//光标移动到0X12的位置
	read(bmpfd,ch,4);
	width = ch[0]&0xff |(ch[1]&0xff)<<8 |(ch[2]&0xff)<<16 |(ch[3]&0xff)<<24;
	printf("BMP width:%d\n",width );

任务:

编写bmp.c和bmp.h的文件,用于解析bmp文件,并且尝试结合lcd.c和lcd.h将解析到的像素数组的颜色值显示到屏幕对应的位置

注意

1 bmp文件需要解析的内容有:魔数(用来判断是不是bmp文件)、像素数组的起始位置、位图宽度、高度、色深(一个像素点在像素数组中对应几个字节)

2 如果宽度和高度都是正数,则我们从像素数组中解析出来的第一个像素点是左下角的第一个点的颜色值

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>

int main (void)
{
	int bmpfd=0;
	ssize_t rsize = 0;
	int file_size = 0;
	int width = 0;
	unsigned char ch[10] = {0};
	int x,y;
	//打开bmp图片
	bmpfd = open("./../pic/2.bmp",O_RDONLY);
	if (-1 == bmpfd)
	{
		perror("open bmp error");
		return -1;
	}
	//读取bmp图片的前两个字节=》bmp文件魔数
	rsize = read(bmpfd,ch,2);
	if (-1 == rsize)
	{
		perror("read bmp error");
		close(bmpfd);
		return -1;
	}
	printf("BMP: %c %c\n",ch[0] ,ch[1]);
	//读取bmo文件的大小
	rsize = read(bmpfd,ch,4);
	if (-1 == rsize)
	{
		perror("read bmp error");
		close(bmpfd);
		return -1;
	}
	printf("BMP: %x %x %x %x\n",ch[0] ,ch[1],ch[2],ch[3]);
	file_size = ch[0]&0xff |(ch[1]&0xff)<<8 |(ch[2]&0xff)<<16 |(ch[3]&0xff)<<24;
	//&0xff其实是避免ch有符号,运算时只取数据的低八位,避免短型和长型运算时,短型数据高位补位的干扰
	printf("BMP file sizd %d\n", file_size);

	//读取位图数据宽度
	lseek(bmpfd,0x12,SEEK_SET);//光标移动到0X12的位置
	read(bmpfd,ch,4);
	width = ch[0]&0xff |(ch[1]&0xff)<<8 |(ch[2]&0xff)<<16 |(ch[3]&0xff)<<24;
	printf("BMP width:%d\n",width );

	//......

	//像素数组的解析
	unsigned char *data = (unsigned char*)malloc(width*hight*pix_bit/8);
	//申请一个数组空间用来保存从图片中读取到的像素数组的数据
	int color = 0;//解析得到的颜色
	unsigned char a,r,g,b;//用来临时保存从数组中获取到的颜色分量
	int i = 0;//用来计数

	lseek(bmpfd,pix_offset,SEEK_SET);//pix_offset是解析0x0a处的四个字节得到的地址
	read(bmpfd,data,width*hight*pix_bit/8);//读取整个像素数组的颜色数据,保存到data指向的数组
	
	//解析每一个像素点的颜色值
	for ( y = 0; y < hight; y++)
	{
		for ( x = 0; x < width; x++)
		{
			b = data[i++];
	g = data[i++];
	r = data[i++];
	a =((pix_bit == 32)?data[i++]:0);
	color = (a&0xff)<<24|(r&0xff)<<16|(g&0xff)<<8|b&0xff
		}
	}
	
	close(bmpfd);

}
width = ch[0]&0xff |(ch[1]&0xff)<<8 |(ch[2]&0xff)<<16 |(ch[3]&0xff)<<24;

ch[0]=0x11 ch[1]=0x02 ch[2]=0x03 ch[3]=0x04
    widht =				0x 00 00 00 00
	ch[0]&0xff			0x 00 00 00 11 
   |(ch[1]&0xff)<<8		0x 00 00 02 00
   |(ch[2]&0xff)<<16 	0x 00 03 00 00
   |(ch[3]&0xff)<<24	0x 04 00 00 00
   widht =				0x 04 03 02 11

案例1:在gec6818开发板上显示bmp图片

bmp.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
 
//off_t lseek(int fd, off_t offset, int whence);
//ssize_t read(int fd, void *buf, size_t count);
//ssize_t write(int fd, const void *buf, size_t count);
//int open(const char *pathname, int flags);
 
 
int main()
{
	//1.打开屏幕
	int fd=0; //接受open的返回值 
	fd=open("/dev/fb0", O_RDWR);
	if(fd==-1) //做错误判断
	{
		perror("open fb0 fail");
	}
	//打开图片
	int bmp_fd=0; //接受open的返回值 
	bmp_fd=open("./func.bmp", O_RDWR);//修改图片路径
	if(bmp_fd==-1) //做错误判断
	{
		perror("open func.bmp fail");
	}
	
	
	//2.偏移54字节
	lseek(bmp_fd,54,SEEK_SET);
 
	//3.读取像素数据 800*480
	unsigned char bmp[800*480*3]={0};
	
	read(bmp_fd,bmp,sizeof(bmp));
	//4.数据处理
/*
bmp[0]--B
bmp[1]--G
bmp[2]--R
bmp[3]--B
....
lcd[0]=bmp[0] | bmp[1]<<8 | bmp[2]<<16;
lcd[1]=bmp[3] | bmp[4]<<8 | bmp[5]<<16;
lcd[2]=bmp[6] | bmp[7]<<8 | bmp[8]<<16;
*/	
	unsigned int temp[800*480]={0};
	unsigned int lcd[800*480]={0};
	int i=0;
	int j=0;
	for(i=0;i<800*480;i++)
	{
		temp[i]=bmp[3*i] | bmp[3*i+1]<<8 | bmp[3*i+2]<<16;
	}
	
	for(i=0;i<480;i++)
	{
		for(j=0;j<800;j++)
		{
			lcd[(480-1-i)*800+j]=temp[i*800+j];
		}
		
	}
	//5.写入屏幕
	int w_ret=0;
	w_ret=write(fd, lcd, sizeof(lcd));
	if(w_ret==-1)//做错误判断
	{
		perror("write fail");
	}
	
	//6.关闭文件
	close(bmp_fd);
	close(fd);
}

案例2:在gec6818开发板上显示电子相册

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/input.h>
 
 
//void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
 
//off_t lseek(int fd, off_t offset, int whence);
//ssize_t read(int fd, void *buf, size_t count);
//ssize_t write(int fd, const void *buf, size_t count);
//int open(const char *pathname, int flags);
//函数声明
int show_bmp(const char *bmpname);
int show_anybmp(const char *bmpname);
int show_anywherebmp(int x0,int y0,const char *bmpname);
int get_xy(int *x,int *y);
 
int main()
{
	int x=-1;
	int y=-1;
    	int tmp=0;
	char photo[][30]={"./1.bmp","./2.bmp","./3.bmp"};
	//1.显示主界面
	show_anybmp("./func.bmp"); //规则界面
	while(1)
	{
		//2.获取坐标
		get_xy(&x,&y);
 
		if(x>=400) //下一张
		{
			tmp=(tmp+1)%3;
			show_bmp(photo[tmp]);
		}
		else if(x<400) //上一张
		{
			tmp=tmp-1;
			if(tmp==-1){
				tmp=2;
			}
			show_bmp(photo[tmp]);
		}
		
		//用完坐标得清零 坐标
		x=-1;
		y=-1;
	}
	
	
}
 
//函数实现
//显示800*480的图片
int show_bmp(const char *bmpname)
{
	//1.打开屏幕
	int fd=0; //接受open的返回值 
	fd=open("/dev/fb0", O_RDWR);
	if(fd==-1) //做错误判断
	{
		perror("open fb0 fail");
	}
	
	//建立屏幕映射
	unsigned int* lcd = mmap(NULL, 800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
	
	
	//打开图片
	int bmp_fd=0; //接受open的返回值 
	bmp_fd=open(bmpname, O_RDWR);
	if(bmp_fd==-1) //做错误判断
	{
		perror("open func.bmp fail");
	}
	
	
	//2.偏移54字节
	lseek(bmp_fd,54,SEEK_SET);
 
	//3.读取像素数据 800*480
	unsigned char bmp[800*480*3]={0};
	
	read(bmp_fd,bmp,sizeof(bmp));
	//4.数据处理
/*
bmp[0]--B
bmp[1]--G
bmp[2]--R
bmp[3]--B
....
lcd[0]=bmp[0] | bmp[1]<<8 | bmp[2]<<16;
lcd[1]=bmp[3] | bmp[4]<<8 | bmp[5]<<16;
lcd[2]=bmp[6] | bmp[7]<<8 | bmp[8]<<16;
*/	
	unsigned int temp[800*480]={0};
	int i=0;
	int j=0;
	for(i=0;i<800*480;i++)
	{
		temp[i]=bmp[3*i] | bmp[3*i+1]<<8 | bmp[3*i+2]<<16;
	}
	
	//解决上下颠倒  把一维数组 二维化思考
	for(i=0;i<480;i++)
	{
		for(j=0;j<800;j++)
		{
			lcd[(480-1-i)*800+j]=temp[i*800+j];
		}
		
	}
	
	
	//解除映射
	munmap(lcd,800*480*4);
	
	//6.关闭文件
	close(bmp_fd);
	close(fd);	
}
 
 
//显示任意大小图片
int show_anybmp(const char *bmpname)
{
	//1.打开屏幕
	int fd=0; //接受open的返回值 
	fd=open("/dev/fb0", O_RDWR);
	if(fd==-1) //做错误判断
	{
		perror("open fb0 fail");
	}
	
	//建立屏幕映射
	unsigned int* lcd = mmap(NULL, 800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
	
	
	//打开图片
	int bmp_fd=0; //接受open的返回值 
	bmp_fd=open(bmpname, O_RDWR);
	if(bmp_fd==-1) //做错误判断
	{
		perror("open func.bmp fail");
	}
	
	
	
	
	//2.偏移54字节
	//先提取到宽
	lseek(bmp_fd,18,SEEK_SET);
	int w=0;
	read(bmp_fd,&w,4);
	//printf("w=%d\n",w);//打印宽度信息
	//再提取高
	lseek(bmp_fd,22,SEEK_SET);
	int h=0;
	read(bmp_fd,&h,4);
	//printf("h=%d\n",h);//打印宽度信息
	
	
	lseek(bmp_fd,54,SEEK_SET);
 
	//3.读取像素数据 800*480
	unsigned char bmp[w*h*3];
	
	read(bmp_fd,bmp,sizeof(bmp));
	//4.数据处理
/*
bmp[0]--B
bmp[1]--G
bmp[2]--R
bmp[3]--B
....
lcd[0]=bmp[0] | bmp[1]<<8 | bmp[2]<<16;
lcd[1]=bmp[3] | bmp[4]<<8 | bmp[5]<<16;
lcd[2]=bmp[6] | bmp[7]<<8 | bmp[8]<<16;
*/	
	unsigned int temp[800*480]={0};
	int i=0;
	int j=0;
	for(i=0;i<w*h;i++)
	{
		temp[i]=bmp[3*i] | bmp[3*i+1]<<8 | bmp[3*i+2]<<16;
	}
	
	//解决上下颠倒  把一维数组 二维化思考
	for(i=0;i<h;i++)
	{
		for(j=0;j<w;j++)
		{
			lcd[(h-1-i)*800+j]=temp[i*w+j];
		}
		
	}
	
	
	//解除映射
	munmap(lcd,800*480*4);
	
	//6.关闭文件
	close(bmp_fd);
	close(fd);
} 
 
//在指定位置显示图片 x0,y0为起点坐标
int show_anywherebmp(int x0,int y0,const char *bmpname)
{
	//1.打开屏幕
	int fd=0; //接受open的返回值 
	fd=open("/dev/fb0", O_RDWR);
	if(fd==-1) //做错误判断
	{
		perror("open fb0 fail");
	}
	
	//建立屏幕映射
	unsigned int* lcd = mmap(NULL, 800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
	
	
	//打开图片
	int bmp_fd=0; //接受open的返回值 
	bmp_fd=open(bmpname, O_RDWR);
	if(bmp_fd==-1) //做错误判断
	{
		perror("open func.bmp fail");
	}
	
	
	
	
	//2.偏移54字节
	//先提取到宽
	lseek(bmp_fd,18,SEEK_SET);
	int w=0;
	read(bmp_fd,&w,4);
	printf("w=%d\n",w);//打印宽度信息
	//再提取高
	lseek(bmp_fd,22,SEEK_SET);
	int h=0;
	read(bmp_fd,&h,4);
	printf("h=%d\n",h);//打印宽度信息
	
	
	lseek(bmp_fd,54,SEEK_SET);
 
	//3.读取像素数据 800*480
	unsigned char bmp[w*h*3];
	
	read(bmp_fd,bmp,sizeof(bmp));
	//4.数据处理
/*
bmp[0]--B
bmp[1]--G
bmp[2]--R
bmp[3]--B
....
lcd[0]=bmp[0] | bmp[1]<<8 | bmp[2]<<16;
lcd[1]=bmp[3] | bmp[4]<<8 | bmp[5]<<16;
lcd[2]=bmp[6] | bmp[7]<<8 | bmp[8]<<16;
*/	
	unsigned int temp[800*480]={0};
	int i=0;
	int j=0;
	for(i=0;i<w*h;i++)
	{
		temp[i]=bmp[3*i] | bmp[3*i+1]<<8 | bmp[3*i+2]<<16;
	}
	
	//解决上下颠倒  把一维数组 二维化思考
	for(i=0;i<h;i++)
	{
		for(j=0;j<w;j++)
		{
			lcd[(h-1-i+y0)*800+j+x0]=temp[i*w+j];
		}
		
	}
	
	
	//解除映射
	munmap(lcd,800*480*4);
	
	//6.关闭文件
	close(bmp_fd);
	close(fd);	
}
 
int get_xy(int *x,int *y)
{
 
	int count=0;
	//1.打开触摸屏
	int tsfd =open("/dev/input/event0",O_RDWR);
	if(tsfd == -1)
	{
		perror("open ts fail");
	}
	
	//2.read
	struct input_event ts;
	
	while(1)
	{
		read(tsfd,&ts,sizeof(struct input_event));
		
		//筛选
		if(ts.type ==EV_ABS && ts.code==ABS_X )
		{ 
			*x=ts.value; //适合蓝底屏幕
			//*x= ts.value*800/1024;   //适合黑底屏幕
			count++;
		}
		
		if(ts.type ==EV_ABS && ts.code==ABS_Y )
		{
			*y=ts.value; //适合蓝底屏幕
			//*y= ts.value*480/600;   //适合黑底屏幕
			
			count++;
		}
		if(count == 2)
		{
			break;
		}
	}
	
	//关闭触摸屏
	close(tsfd);
}
 
 
 
 

在这里插入图片描述

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
基于粤嵌gec6818开发板的小游戏有五子棋、2048游戏、扫雷、飞机大战、钢琴游戏、刮刮乐等。这些小游戏都可以通过简单的程序设计和硬件驱动来实现。 五子棋是一种简单而又经典的棋类游戏,玩家通过下棋子来争夺胜利。通过gec6818的触摸屏幕输入,可以实现玩家与电脑的对战,或者两个玩家之间的互动。 2048游戏是一款数学益智类游戏,玩家通过上下左右的滑动操作,将相同数值的方块合并,最终得到2048这个数值的方块。通过gec6818的触摸屏幕输入,可以实现玩家的滑动操作,将方块进行合并。 扫雷是一款经典的益智类游戏,玩家通过点击格子,来揭示隐藏的雷,避免踩雷。通过gec6818的触摸屏幕输入,可以实现玩家的点击操作,将雷揭示出来。 飞机大战是一款横版射击游戏,玩家通过控制飞机,射击敌方飞机和敌方炮台,躲避敌方的攻击。通过gec6818的按键输入,可以实现玩家的控制操作,进行射击和躲避。 钢琴游戏是一款音乐类游戏,玩家通过按下不同的琴键,发出不同的音符,弹奏出美妙的音乐。通过gec6818的按键输入,可以实现玩家的按键操作,发出不同的音符。 刮刮乐是一种益智类游戏,玩家通过刮开卡片上的涂层,获得隐藏的奖品。通过gec6818的触摸屏幕输入,可以实现玩家的刮卡操作,揭开涂层,看到奖品。 以上这些游戏都是基于粤嵌gec6818开发板设计的,通过合理的硬件和软件开发,可以让人们在休闲娱乐中享受到游戏乐趣。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黎明的前夜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值