嵌入式学习笔记--GEC6818--bmp图片显示

2023-11-11

一、开发环境

1.ARM+linux

2.ubuntu16.04(安装了GCC,arm-linux-gcc 5.4.0)

安装方法ubuntu16.04
https://blog.csdn.net/qq_40592257/article/details/106296000

安装arm-linux-gcc 5.4.0

https://blog.csdn.net/weixin_42108484/article/details/84295214

3.GEC6818开发板

4、安装SecureCRT

二、bmp图片显示原理

1、bmp图片显示的格式

常见的图片格式有:bmp,jpg,png,gif

我们使用的是bmp图片
    计算机中用RGB表示每个像素点的颜色值
    bmp格式图片的编码方式:
    第一个:每个像素点占3个字节(24位二进制),分别存放的是BGR的数值(正常我们习惯的顺序RGB,但是bmp图片编码的时候是反的)
    第二个:lcd要求每个像素点占4个字节,多出来的一个字节(A存放的是透明度),也就是说lcd要求是ARGB
    第三个:bmp图片RGB的排列顺序并不是我们常规理解的RGB,而是BGR
    并且bmp图片像素点上下也是颠倒的
    第四个:bmp图片的宽所占的字节数如果不能被4整除,windows在保存的时候,会在每一行的后面添加垃圾数凑够4整除
    领悟道理:每种图片都有自己独特的编码方式,显示图片实际上先要了解图片的编码方式,然后使用文件IO配合算法解决图像显示的问题

2.分析bmp图片显示的思路
开发板的基本信息:

       cpu:  三星s5p6818芯片   基于ARM架构的

       ARM:英国一家半导体公司,设计芯片的内核和架构,自己不生产芯片
           高通
           联发科
           三星
           华为
       液晶屏: 7英寸,分辨率 800*480
思路:
(1)打开你要显示的bmp图片
打开lcd的驱动 --》文件IO可以对硬件设备进行操作
(2)读取bmp图片的像素点颜色值
(3)把读取的颜色值写入到lcd中
(4)关闭bmp,lcd驱动            
3.开发板的基本使用
设置字体大小:secure  CRT中的选项---》会话选项--》外观--》字体
(1)连接电脑,使用secure CRT软件通过串口线查看开发板系统中的内容
usb转串口线连接电脑,安装驱动
安装secureCRT软件,配置该软件(见day04图示)
(2)使用开发板
 第一:编译程序
 gcc  --》只适合编译得到X86平台的程序(电脑上运行)
 arm-linux-gcc(交叉编译工具) --》只适合编译得到ARM平台的程序(开发板上运行)

 arm-linux-gcc  hello.c   -o   hello

补充: file  文件名  //查看该文件的属性
交叉编译
程序在PC端编译,程序运行在开发板上运行(程序的编译和运行不在同一个平台)--》把这个过程叫做交叉编译
第二:下载程序到开发板
方法一:使用串口下载(下载速度慢)
    rx  要下载的文件名   回车 --》点击传输--》选择发送xmodem--》自动弹出对话框,你找到要下载的文件,双击自动下载、
    可以把文件打包之后下载(速度快)
    补充:  压缩(打包)      tar  -jcf  压缩包名字.tar.bz2   文件1  文件2  .....   
    tar  -zcf  压缩包名字.tar.gz     文件1  文件2  .....                                                                                             
    比如:  tar  -jcf  88.tar.bz2   1.bmp  2.bmp   3.bmp   
    解压               
    tar  -jxf  压缩包的名字.tar.bz2
    tar  -zxf  压缩包的名字.tar.gz
    常见的压缩包格式:两种bz2结尾和gz结尾
第三:安装交叉工具
第一步:解压压缩包
 tar  -xf   arm-linux-gnueabi-5.4.0.tar.xz
第二步:设置环境变量(为了让arm-linux-gcc可以在任何路径下使用)

环境变量:指的是系统的默认路径,你输入arm-linux-gcc,系统自动去这个路径下找到arm-linux-gcc
export  PATH=你刚才解压的arm-linux-gcc的路径:$PATH  //这样写是一次性,重启ubuntu窗口就失效了

永久设置:把刚才那句话写入到/etc/bash.bashrc的最后面即可
比如:export  PATH=/home/ubuntu/usr/local/arm/5.4.0/usr/bin:$PATH

4. 显示bmp出现的问题

           (1)bmp错乱

                     原因:bmp每个像素点3字节,但是lcd每个像素点4字节

                     解决方法(编程):C语言的按位或,配合左移,实现数据的拼接   

                                     二进制:   1101 0101

                                                     1010 1101<<8  位或

                                                     1101 1010<<16

                                                     0000 0000<<24

                                  0000 0000  1101 1010 1010 1101 1101 0101  结果

触摸屏读写坐标

==================

    新款开发板(黑色): 坐标是1024*600 --》代码去修正了

    1. 思路:

                第一步: 打开触摸屏的驱动   /dev/input/event0

                第二步: 读取触摸屏的坐标

                第三步: 关闭触摸屏

    2. 输入子系统模型

               概念:linux把所有输入类型设备(键盘,鼠标,触摸屏)的驱动和应用程序抽象为统一的模型(输入子系统模型)

                         linux系统中定义一个头文件跟输入子系统模型有关  /usr/include/linux/input.h                   

               重要的结构体:

                        struct input_event {

	           struct timeval time; //事件响应的时间

	          __u16 type;  //事件类型,区分不同的输入设备,比如:EV_KEY 键盘事件   EV_ABS 触摸事件  

	          __u16 code; //按键   X,Y坐标ABS_X    ABS_Y

	          __s32 value; //键值  坐标值

                       };   





内存映射(把硬件设备在内存中对应的首地址告诉你)

===============

   1.相关的接口函数

             #include <sys/mman.h>

            void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

                    返回值:成功  返回映射得到的首地址

                                 失败  NULL

                       参数:addr --》一般设置为NULL,表示由操作系统自动给我分配硬件对应的首地址

                                 length --》你要映射的内存地址的长度,字节  比如:液晶屏大小是  800*480*4

                                 prot --》PROT_READ  可读

                                               PROT_WRITE 可写

                                 flags --》你映射的内存是否可以被其它程序共享

                                               MAP_SHARED 可以共享

                                               MAP_PRIVATE 不可以共享

                                 fd --》你要映射的那个硬件设备的文件描述符

                                 offset --》一般设置为0,表示地址偏移



           int munmap(void *addr, size_t length)   //解除映射

                     参数:addr --》你之前映射得到的首地址

                               length --》地址的长度 

三、循环显示bmp图片,可以点击上一张,下一张

main.c

#include"doublecycle.h"
#include"myhead.h"
#define BMP5 "5.bmp"
#define BMP1 "1.bmp"
#define BMP2 "2.bmp"
#define BMP3 "3.bmp"
#define BMP4 "4.bmp"
int show_xy(int *xy)
{
	int tsfd;
	//定义输入子系统模型有关的结构体变量
	struct 	input_event myevent;
	
	//打开触摸屏驱动
	tsfd=open("/dev/input/event0",O_RDWR);
	if(tsfd==-1)
	{
			perror("open failed!\n");
			return -1;
	}

	int flag=0;
	while(1)
	{
		//读取触摸屏的坐标
		read(tsfd,&myevent,sizeof(myevent));
		if(myevent.type==EV_ABS)
		{
			if(myevent.code==ABS_X)
			{
				flag++;
				xy[0]=myevent.value/1.28;
				//printf(" < %d,",xy[0]);
			}
			if(myevent.code==ABS_Y)
			{
				flag++;
				xy[1]=myevent.value/1.25;
				//printf("%d > \n",xy[1]);
				
			}
			
		}
		if(flag==2)
		{
			break;
		}
			
	}
	close(tsfd);
	return 0;
}

int showbmp_mmap(char argv[50])
{
	int bmpfd;
	int lcdfd;
	
	
	int height;//高度
	int length;//长度
	
	//printf("The pirture's big \n length: height:\n");
	//scanf("%d%d",&length,&height);//scanf里面最好不要加换行符

	//打开你要显示的200*100大小的bmp 
	bmpfd=open(argv,O_RDWR);
	if(bmpfd==-1)
	{
		perror("打开图片失败!\n");
		return -1;
	}
	//打开lcd驱动
	lcdfd=open("/dev/fb0",O_RDWR);
	if(lcdfd==-1)
	{
		perror("打开lcd失败!\n");
		return -1;
	}
	lseek(bmpfd,18,SEEK_SET);
	read(bmpfd,&length,4);
	read(bmpfd,&height,4);
	lseek(bmpfd,54,SEEK_SET);//跳过头信息
	//定义一个数组,依据图片的大小
	char bmpbuf[height*length*3];
	if((length*3)%4!=0)//长度*3不能被4整除
	{
		//读取bmp图片的RGB数据
		for(int i=0;i<height;i++)
		{
			
			read(bmpfd,&bmpbuf[i*length*3],length*3);
	
			
			lseek(bmpfd,4-(length*3)%4,SEEK_CUR);
			
		}
		
		
	}
	else
	{
		//读取bmp图片的RGB数据
		read(bmpfd,bmpbuf,height*length*3);
	}
	
	int lcd_buf[800*480];//RGB变ABGR存放的地方
	int i=0;
	int x,y;
	
	//图片居中显示200*100
	for(y=(480-height)/2;y<(240+height/2);y++)
		for(x=((800-length)/2);x<((400+length/2));x++)
		{
			//RGB变ABGR
			lcd_buf[800*y+x]=(0x00<<24)+(bmpbuf[3*i+2]<<16)+(bmpbuf[3*i+1]<<8)+(bmpbuf[3*i+0]);
			i++;
		}
		
	int lcd_buf1[800*480];//上下颠倒
	bzero(lcd_buf1,800*480*4);
	/*
	for(x=0;x<800;x++)
		for(y=0;y<480;y++)
		{
			lcd_buf1[800*(480-y-1)+x]=lcd_buf[800*y+x];
		}
		*/
	
	//居中显示
	for(x=((800-length)/2);x<((400+length/2));x++)
		for(y=(480-height)/2;y<(240+height/2);y++)
		{
			lcd_buf1[800*(480-y-1)+x]=lcd_buf[800*y+x];
		}
	
	//write(lcdfd,lcd_buf1,800*480*4);
	
	//映射内存
	int *mmap_bmp = mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE, MAP_SHARED, lcdfd, 0);
	for(int i=0;i<480;i++)
		for(int j=0;j<800;j++)
			*(mmap_bmp+i*800+j)=lcd_buf1[800*i+j];
	munmap(mmap_bmp, 800*480*4);
	//lcd_buf[i] =(0x00<<24) + (bmpbuf[3*i+2]<<16) + (bmpbuf[3*i+1]<<8) + (bmpbuf[3*i+0]);
	//关闭
	
	close(bmpfd);
	close(lcdfd);
	return 0;
}
int main()
{
	struct siglelist *mylist=list_init();
	struct siglelist *data_n=list_init();
	stpcpy(mylist->names,BMP5);
	stpcpy(data_n->names,BMP1);
	insert_tail(data_n,mylist);
	stpcpy(data_n->names,BMP2);
	insert_tail(data_n,mylist);
	stpcpy(data_n->names,BMP3);
	insert_tail(data_n,mylist);
	stpcpy(data_n->names,BMP4);
	insert_tail(data_n,mylist);
	int xy[2]={0,0};
	char bmp_box[50];
	showbmp_mmap(BMP5);
	struct siglelist *p=mylist;
	/* show_xy(xy);
	printf("< %d,%d >\n",xy[0],xy[1]); */
	//show_xy(xy);
	
	while(1)
	{
		show_xy(xy);
		printf("< %d,%d >\n",xy[0],xy[1]);
		if(xy[0]>0&&xy[0]<150)
		{
			
			p=p->next;
			strcpy(bmp_box,p->names);
			showbmp_mmap(bmp_box);
			
		
		}
		if(xy[0]>600&&xy[0]<800)
		{
			
			p=p->pre;
			strcpy(bmp_box,p->names);
			showbmp_mmap(bmp_box);
			
		}
	}
		

	
	return 0;
}

doublecycle.h

#ifndef _MYHEAD_H
#define _MYHEAD_H

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/mman.h>
#include <linux/input.h>
#include <errno.h>
#include <dirent.h>


//定义结构体表示单链表
struct siglelist
{
	int data;//学号
	char names[10];//姓名
	int weight;//体重
	int high;//身高
	int grade[3];//成绩,语数英
	struct siglelist *pre;
	struct siglelist *next;
};
struct siglelist *list_init();//封装链表的初始化
int insert_tail(struct siglelist *data_n,struct siglelist *head);
int insert_mid(int newdata,int olddata,struct siglelist *data_n,struct siglelist *head);
int show_list(struct siglelist *head);
int delete_list(int olddata, struct siglelist *head);
#endif

myhead.h

#ifndef _MYHEAD_H
#define _MYHEAD_H

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/mman.h>//内存映射mmap()
#include <linux/input.h>
#include <errno.h>
#include <dirent.h>
#include <strings.h>
//输入子系统
#include<linux/input.h>

#endif

doublecycle.c

#include"doublecycle.h"

//封装链表的初始化
struct siglelist *list_init()
{
	struct siglelist *myhead=malloc(sizeof(struct siglelist));
	myhead->next=myhead;
	myhead->pre=myhead;
	return myhead;
}
//尾部插入
int insert_tail(struct siglelist *data_n,struct siglelist *head)
{
	//找到链表的尾部
	struct siglelist *p=head;
	while(p->next!=head)
	{
		p=p->next;
	}
	//准备好新的节点
	struct siglelist *newnode=malloc(sizeof(struct siglelist));
	//写入数据
	newnode->data=data_n->data;
	strcpy(newnode->names,data_n->names);
	newnode->weight=data_n->weight;
	newnode->high=data_n->high;
	for(int i=0;i<3;i++)
	{
		newnode->grade[i]=data_n->grade[i];
	}
	newnode->next=NULL;
	newnode->pre=NULL;
	//p和newnode建立连接
	p->next=newnode;
	newnode->pre=p;
	//newnode和head链接
	newnode->next=head;
	head->pre=newnode;
}

//中间插入,把newdata学号插入到olddata学号的后面
int insert_mid(int newdata,int olddata,struct siglelist *data_n,struct siglelist *head)
{
	int flag=0;
	//找到olddata所在的节点
	struct siglelist *p=head;
	while(p->next!=head)
	{
		p=p->next;
		if(p->data==olddata)
		{
			flag++;
			break;
		}
			
	}
	if(flag==0)
	{
		printf("选择要插入的学号不存在\n");
		return -1;
	}
	//准备新节点
	struct siglelist *newnode=malloc(sizeof(struct siglelist));
	newnode->data=data_n->data;
	strcpy(newnode->names,data_n->names);
	newnode->weight=data_n->weight;
	newnode->high=data_n->high;
	for(int i=0;i<3;i++)
	{
		newnode->grade[i]=data_n->grade[i];
	}
	newnode->next=NULL;
	newnode->pre=NULL;
	//newnode和p->next链接
	p->next->pre=newnode;
	newnode->next=p->next;
	//newnode和p链接
	p->next=newnode;
	newnode->pre=p;
}

//打印链表
int show_list(struct siglelist *head)
{
	struct siglelist *p=head;
	printf("学号\t 姓名\t 体重\t 身高\t 语文\t 数学\t 英语\n");
	while(p->next!=head)
	{
		p=p->next;
		
		printf("%d\t %s\t %d\t %d\t %d\t %d\t %d\n",p->data,p->names,p->weight,p->high,p->grade[0],p->grade[1],p->grade[2]);
		
	}
}
//删除链表(可以删除重复的数据)
int delete_list(int olddata, struct siglelist *head)
{
	int n = -1;	//标志位

	//遍历找到要删除节点所在
	struct siglelist *p = head->next;
	while(p!=head)
	{
		if(p->data==olddata)
			{
				
				p->next->pre=p->pre;
				p->pre->next=p->next;
				p=p->next;
				n++;
				
			}
		else
		{
			p=p->next;
		}
		
	}
	

	if(n<0)
	{
		printf("链表中不存在数据%d\n", olddata);
	}
	else
	{
		printf("删除了%d个数据\n", n+1);
	}
	
	return 0;
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

嵌入式学习笔记--GEC6818--bmp图片显示 的相关文章

随机推荐

  • 解码(二):音视频解码上下文创建配置和打开avcodec_open2打开演示

    如下代码 视频解码器打开 找到视频解码器 AVCodec vcodec avcodec find decoder ic gt streams videoStream gt codecpar gt codec id if vcodec cou
  • 远期与期货

    概述 期货合约与远期合约都是规定在将来的某一时间购买或者出售某项资产 这一点与期权类似 关键不同之处在于 期权持有者不会被强制购买或者出售资产 当无利可图时 可以选择放弃交易 但是 期货或者远期合约由必须履行事先约定的合约义务 远期 仅仅是
  • Java Lombok 报错(IllegalAccessError: class lombok.javac.apt.LombokProcessor)解决方法

    本文主要介绍Java 中 使用Lombok报错 java java lang IllegalAccessError class lombok javac apt LombokProcessor的解决方法及示例代码 原文地址 Java Lom
  • Java Swing 如何让界面更加美观

    文章目录 一 设置窗体的背景图 二 设置Button组件 三 设置字体大小和颜色 四 设置组件的背景色 五 综合测试案例 一 设置窗体的背景图 利用JLable类的构造方法或方法加载图片 ImageIcon image new ImageI
  • 设计一个雇员Employee类

    题目内容 设计一个雇员Employee类 具体要求如下 1 设计雇员Employee类 记录雇员的情况 包括姓名 年薪 受雇时间 String name double salary MyDate start 2 定义MyDate类作为日期
  • 装系统时提示 无法在驱动器0分区上安装windows

    先看提示 先看提示 先看提示 1 在重装系统时遇到一个问题 无法在驱动器0分区上安装windows 2 解决方法 1 在当前安装界面按住Shift F10调出命令提示符窗口 2 输入diskpart 按回车执行 3 进入DISKPART命令
  • 负数为什么要用补码来表示?

    上篇文章讲了 负数在计算机中是怎么存储的 看完之后 应该对原码 反码 补码有了基本的了解了 今天 我们深入探讨一下 为什么计算机中要用补码来表示负数 首先 我们应该清楚 原码是方便给人看的 看到一个数的原码 我们就能根据符号位和后边的二进制
  • [144]如何用VBS编写一个简单的恶搞脚本

    windows系统的电脑 首先右击桌面 选择新建 文本文档 在桌面上新建一个文本文档 随后打开计算机或者是我的电脑 点击其中的组织 xp系统多为工具 选择下面的文件夹和搜索选项 在弹出的窗口中点击查看 向下滚到 找到隐藏已知文件类型的扩展名
  • Android(Kotlin)获取应用全局上下文 ApplicationContext

    需求 Android Kotlin 获取应用全局上下文 ApplicationContext 有些场景下需要使用的 Context 是和页面无关的 仅和应用进程相关 比如 读写文件或访问数据库 这些场景下 我们希望可以在项目内任意位置 直接
  • Allegro PCB的布局

    1 手工导入元器件 place manually进入放置设置页面 在需要放置的元器件前面打勾 可以依次放置元器件 2 快速放置元器件 place Quickplace 使用快速放置功能需要先画好板宽outline才可以 3 设置room区域
  • c++实现数据结构栈和队列

    1 栈 头文件 ifndef ZHAN H define ZHAN H define MAX 8 include
  • laravel-admin安装及使用教程

    安装命令 安装 Laravel 安装器 composer global require laravel installer 创建名为 shopAdmin 项目 laravel new shopAdmin 经过漫长的等待已经安装好了 进入项目
  • springboot中注入FilterRegistrationBean不生效原因

    springboot中注入FilterRegistrationBean不生效原因 回顾 最近自定义了两个过滤器 接口请求返回加密和sql注入处理过滤器 因为在封装一些工具包 我在单独调好之后 就打算做成一个注解 像springboot启动类
  • 基于自注意力机制的LSTM多变量负荷预测

    1 引言 在之前使用长短期记忆网络构建电力负荷预测模型的基础上 将自注意力机制 Self Attention 融入到负荷预测模型中 具体内容是是在LSTM层后面接Self Attention层 在加入Self Attention后 可以将负
  • 计算机操作系统--文件管理

    文件与文件系统 1 文件 文件 File 是具有符号名的 在逻辑上具有完整意义的一组相关信息项的集合 例如 一个源程序 一个目标程序 编译程序 一批待加工的数据和各种文档等都可以各自组成一个文件 信息项是构成文件内容的基本单位 可以是一个字
  • 15_插入排序算法(附java代码)

    15 插入排序算法 一 基本介绍 插入式排序属于内部排序法 是对于欲排序的元素以插入的方式找寻该元素的适当位置 以达到排序的目的 二 插入排序算法 2 1 算法思想 插入排序 Insertion Sorting 的基本思想是 把n个待排序的
  • 每天五分钟机器学习:使用支持向量机的时候,如何选择模型参数?

    本文重点 上一章 我们学习了支持向量机的特征高维映射 也就是如何将特征映射到高维 在支持向量机中有两个参数需要调节 第一个参数是C 第二个参数是 C C 1 入 因此 C较大时 相当于 较小 意味着不使用正则化 可能会导致过拟合 高方差 C
  • kylin启动:Failed to create /kylin

    文章目录 一 当在ubuntu下执行check env sh时遇到问题 KYLIN HOME is set to usr local apache kylin 1 5 4 1 bin cat invalid option 1 Try cat
  • 用最少的线段覆盖点

    假设现有一平面网格 上有N个点 现用直线段把每个点都覆盖住 线段不能折 只能水平或者竖直方向 如何求出使用的线段最少 如下图所示 上面一个网格 有7个点 其中用三条线段就能覆盖住所有点 下图8个点 也是同样三条线段覆盖住8个点
  • 嵌入式学习笔记--GEC6818--bmp图片显示

    一 开发环境 1 ARM linux 2 ubuntu16 04 安装了GCC arm linux gcc 5 4 0 安装方法ubuntu16 04https blog csdn net qq 40592257 article detai