操作系统嵌入式图片显示课程设计.docx
《操作系统嵌入式图片显示课程设计.docx》由会员分享,可在线阅读,更多相关《操作系统嵌入式图片显示课程设计.docx(28页珍藏版)》请在冰点文库上搜索。
操作系统嵌入式图片显示课程设计
操作系统课程设计报告
课题:
____嵌入式系统文件显示_____
组长:
罗平
学号:
20151703021_________
同组姓名:
刘照、杜威、周玉辉、胡玉珍
专业班级:
网工15102_
指导教师:
丁德红____________
设计时间:
2017-06-12__________
评阅意见:
评定成绩:
指导老师签名:
年月日
1.前言
本课程设计是学生学习完《计算机操作系统》课程后,进行的一次全面的综合训练,通过课程设计,让学生更好地掌握操作系统的原理及实现方法,加深对操作系统基础理论和重要算法的理解,加强学生的动手能力。
随着嵌入式技术的迅猛发展,人机交互界面也越来越显示出它的重要性。
本次课程设计主要以TFTLCD的LCD显示模块,完整的实现了图片的循环显示。
TFT-LCD即薄膜晶体管液晶显示器。
其英文全称为:
ThinFilmTransistor-LiquidCrystalDisplay。
TFT-LCD与无源TN-LCD、STN-LCD的简单矩阵不同,它在液晶显示屏的每一个象素上都设置有一个薄膜晶体管(TFT),可有效地克服非选通时的串扰,使显示液晶屏的静态特性与扫描线数无关,因此大大提高了图像质量。
目前,显示技术和显示工业的发展迅速。
显示技术是传递视觉的信息技术。
液晶显示器件LCD是当今最有发展前途的一种平板显示器件,它具有很多独到的优异特性。
它具有显示信息多、易于多彩化、体积小、重量轻、功耗低、寿命长、价格低、无辐射、无污染、接口控制方便等优点。
2.课程设计内容
2.1课程要求
1、开发环境:
Keilc5.0,阿波罗开发板
2、开机的时候先检测字库,然后检测SD卡是否存在,如果SD卡存在,则开始查找SD卡根目录下的PICTURE文件夹,如果找到则显示该文件夹下面的图片文件(支持bmp、jpg、jpeg或gif格式),循环显示,通过按KEY0和KEY2可以快速浏览下一张和上一张,KEY_UP按键用于暂停/继续播放,DS1用于指示当前是否处于暂停状态。
如果未找到PICTURE文件夹/任何图片文件,则提示错误。
同样我们也是用DS0来指示程序正在运行。
整体效果就是一个精简版的数码相框。
3、界面上有自己的学校、班级、姓名字样。
2.2组员任务分工
罗平(18):
代码修改、关键算法和主要函数实现的理解
杜威(02):
PPT的制作、代码运行试验、相关知识简介
胡玉珍(05):
代码理解、组员任务分工、实现功能及操作简介
刘照(16):
代码运行试验、实验结果及结果分析
周玉辉(36):
word文档制作、代码运行试验、相关知识简介
3.背景
3.1图片格式简介
图片有一般图片格式有许多种,一般常用的有四种,JEPG(或者说JPG),BMP格式的,这三种是静态图片,以及GIF格式的动态格式图。
下面简单介绍一下这三种图片格式。
3.1.1BMP图片格式
BMP(全称Bitmap)是Window操作系统中的标准图像文件格式,文件后缀名为“.bmp”,使用非常广。
它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大,但是没有失真。
BMP文件的图像深度可选lbit、4bit、8bit、16bit、24bit及32bit。
BMP文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。
典型的BMP图像文件由四部分组成:
1、位图头文件数据结构,它包含BMP图像文件的类型、显示内容等信息;
2、位图信息数据结构,它包含有BMP图像的宽、高、压缩方法,以及定义颜色等信息;
3、调色板,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24位的BMP)就不需要调色板;
4、位图数据,这部分的内容根据BMP位图使用的位数不同而不同,在24位图中直接使用RGB,而其他的小于24位的使用调色板中颜色索引值。
3.1.2JPEG文件格式
JPEG是JointPhotographicExpertsGroup(联合图像专家组)的缩写,文件后辍名为“.jpg”或“.jpeg”,是最常用的图像文件格式,由一个软件开发联合会组织制定,同BMP格式不同,JPEG是一种有损压缩格式,能够将图像压缩在很小的储存空间,图像中重复或不重要的资料会被丢失,因此容易造成图像数据的损伤(BMP不会,但是BMP占用空间大)。
比如可以把1.37Mb的BMP位图文件压缩至20.3KB。
当然也可以在图像质量和文件尺寸之间找到平衡点。
JPEG格式压缩的主要是高频信息,对色彩的信息保留较好,适合应用于互联网,可减少图像的传输时间,可以支持24bit真彩色,也普遍应用于需要连续色调的图像。
JPEG/JPG的解码过程可以简单的概述为如下几个部分:
1、从文件头读出文件的相关信息。
JPEG文件数据分为文件头和图像数据两大部分,其中文件头记录了图像的版本、长宽、采样因子、量化表、哈夫曼表等重要信息。
所以解码前必须将文件头信息读出,以备图像数据解码过程之用。
2、从图像数据流读取一个最小编码单元(MCU),并提取出里边的各个颜色分量单元。
3、将颜色分量单元从数据流恢复成矩阵数据。
使用文件头给出的哈夫曼表,对分割出来的颜色分量单元进行解码,把其恢复成8×8的数据矩阵。
4、8×8的数据矩阵进一步解码。
此部分解码工作以8×8的数据矩阵为单位,其中包括相邻矩阵的直流系数差分解码、使用文件头给出的量化表反量化数据、反Zig-zag编码、隔行正负纠正、反向离散余弦变换等5个步骤,最终输出仍然是一个8×8的数据矩阵。
5、颜色系统YCrCb向RGB转换。
将一个MCU的各个颜色分量单元解码结果整合起来,将图像颜色系统从YCrCb向RGB转换。
6、排列整合各个MCU的解码数据。
不断读取数据流中的MCU并对其解码,直至读完所有MCU为止,将各MCU解码后的数据正确排列成完整的图像。
本课程设计程采用TjpgDec作为JPG/JPEG的解码库。
BMP和JPEG这两种图片格式均不支持动态效果,而GIF则是可以支持动态效果。
3.1.3GIF图片格式
GIF(GraphicsInterchangeFormat)是CompuServe公司开发的图像文件存储格式,1987年开发的GIF文件格式版本号是GIF87a,1989年进行了扩充,扩充后的版本号定义为GIF89a。
GIF图像文件以数据块(block)为单位来存储图像的相关信息。
一个GIF文件由表示图形图像的数据块、数据子块以及显示图形图像的控制信息块组成,称为GIF数据流(DataStream)。
数据流中的所有控制信息块和数据块都必须在文件头(Header)和文件结束块(Trailer)之间。
GIF文件格式采用了LZW(Lempel-ZivWalch)压缩算法来存储图像数据,定义了允许用户为图像设置背景的透明(transparency)属性。
如果在GIF文件中存放有多幅图,它们可以像演幻灯片那样显示或者像动画那样演示。
一个GIF文件的结构可分为文件头(FileHeader)、GIF数据流(GIFDataStream)和文件终结器(Trailer)三个部分。
文件头包含GIF文件署名(Signature)和版本号(Version);GIF数据流由控制标识符、图象块(ImageBlock)和其他的一些扩展块组成;文件终结器只有一个值为0x3B的字符(';')表示文件结束。
4.流程设计
4.1系统的结构框
STM32
4.1系统结构框图
4.2程序流程图设计
图4.2程序流程图
5.硬件设计
5.1硬件介绍
开机的时候先检测字库,然后检测SD卡是否存在,如果SD卡存在,则开始查找SD卡根目录下的PICTURE文件夹,如果找到则显示该文件夹下面的图片文件(支持bmp、jpg、jpeg或gif格式),循环显示,通过按KEY0和KEY2可以快速浏览下一张和上一张,KEY_UP按键用于暂停/继续播放,DS1用于指示当前是否处于暂停状态。
如果未找到PICTURE文件夹/任何图片文件,则提示错误。
同样我们也是用DS0来指示程序正在运行。
所要用到的硬件资源如下:
1)指示灯DS0和DS1
2)KEY0、KEY2和KEY_UP三个按键
3)串口
4)LCD模块
5)SD卡
6)SPIFLASH
这几部分,在之前的实例中都介绍过了,我们在此就不介绍了。
需要注意的是,我们在SD卡根目录下要建一个PICTURE的文件夹,用来存放JPEG、JPG、BMP或GIF等图片。
5.2芯片介绍
STM32开发板主要采用STM32F103RBT6作为MCU,STM32F103的型号众多,我们选择这款的原因是看重其性价比,作为一款低端开发板,选择STM32F103RBT6是最佳的选择。
128KFLASH、20KSRAM、2个SPI、3个串口、1个USB、1个CAN、2个12位的ADC、RTC、51个可用IO脚…,这样的配置无论放到哪里都是很不错的了,更重要的是其价格,不到13元的批量价,足以秒杀很多其他芯片了,所以我们选择了它作为我们的主芯片。
6.算法实现
6.1功能函数
首先在HARDWARE文件夹所在的文件夹下新建一个PICTURE的文件夹。
在该文件夹里面新建bmp.c、bmp.h、tjpgd.c、tjpgd.h、integer.h、gif.c、gif.h、piclib.c和piclib.h等9个文件。
并将PICTURE文件夹加入头文件包含路径。
其中bmp.c和bmp.h用于实现对bmp文件的解码;tjpgd.c和tjpgd.h用于实现对jpeg/jpg文件的解码;gif.c和gif.h用于实现对gif文件的解码;这几个代码太长了,所以我们在这里不贴出来,请大家参考光盘本例程的源码
piclib.c代码如下:
_pic_infopicinfo;//图片信息
_pic_phypic_phy;//图片显示物理接口
//lcd.h没有提供划横线函数,需要自己实现
voidpiclib_draw_hline(u16x0,u16y0,u16len,u16color)
{
if((len==0)||(x0>lcddev.width)||(y0>lcddev.height))return;
LCD_Fill(x0,y0,x0+len-1,y0,color);
}
//填充颜色
//x,y:
起始坐标
//width,height:
宽度和高度。
//*color:
颜色数组
voidpiclib_fill_color(u16x,u16y,u16width,u16height,u16*color)
{
u16i,j;
if(lcdltdc.pwidth!
=0&&lcddev.dir==0)//RGB屏,且竖屏,则填充函数不可直接用
{
for(i=0;i{
for(j=0;j{
*(u16*)((u32)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*
(lcdltdc.pwidth*(lcdltdc.pheight-x-j-1)+y+i))=color[i*width+j];
}
}
}elseLCD_Color_Fill(x,y,x+width-1,y+height-1,color);//其他情况,直接填充
}
//画图初始化,在画图之前,必须先调用此函数
//指定画点/读点
voidpiclib_init(void)
{
pic_phy.read_point=LCD_ReadPoint;//读点函数实现,仅BMP需要
pic_phy.draw_point=LCD_Fast_DrawPoint;//画点函数实现
pic_phy.fill=LCD_Fill;//填充函数实现,仅GIF需要
pic_phy.draw_hline=piclib_draw_hline;//画线函数实现,仅GIF需要
pic_phy.fillcolor=piclib_fill_color;//颜色填充函数实现,仅TJPGD需要
picinfo.lcdwidth=lcddev.width;//得到LCD的宽度像素
picinfo.lcdheight=lcddev.height;//得到LCD的高度像素
picinfo.ImgWidth=0;//初始化宽度为0
picinfo.ImgHeight=0;//初始化高度为0
picinfo.Div_Fac=0;//初始化缩放系数为0
picinfo.S_Height=0;//初始化设定的高度为0
picinfo.S_Width=0;//初始化设定的宽度为0
picinfo.S_XOFF=0;//初始化x轴的偏移量为0
picinfo.S_YOFF=0;//初始化y轴的偏移量为0
picinfo.staticx=0;//初始化当前显示到的x坐标为0
picinfo.staticy=0;//初始化当前显示到的y坐标为0
}
//快速ALPHABLENDING算法.
//src:
源颜色
//dst:
目标颜色
//alpha:
透明程度(0~32)
//返回值:
混合后的颜色.
u16piclib_alpha_blend(u16src,u16dst,u8alpha)
{
u32src2;
u32dst2;
//Convertto32bit|-----GGGGGG-----RRRRR------BBBBB|
src2=((src<<16)|src)&0x07E0F81F;
dst2=((dst<<16)|dst)&0x07E0F81F;
//PerformblendingR:
G:
Bwithalphainrange0..32
//Notethatthereasonthatalphamaynotexceed32isthatthereareonly
//5bitsofspacebetweeneachR:
G:
Bvalue,anyhighervaluewilloverflow
//intothenextcomponentanddeliveruglyresult.
dst2=((((dst2-src2)*alpha)>>5)+src2)&0x07E0F81F;
return(dst2>>16)|dst2;
}
//初始化智能画点
//内部调用
voidai_draw_init(void)
{
floattemp,temp1;
temp=(float)picinfo.S_Width/picinfo.ImgWidth;
temp1=(float)picinfo.S_Height/picinfo.ImgHeight;
ALIENTEK阿波罗STM32F429开发板教程
673
STM32F429开发指南(寄存器版)
if(tempif(temp1>1)temp1=1;
//使图片处于所给区域的中间
picinfo.S_XOFF+=(picinfo.S_Width-temp1*picinfo.ImgWidth)/2;
picinfo.S_YOFF+=(picinfo.S_Height-temp1*picinfo.ImgHeight)/2;
temp1*=8192;//扩大8192倍
picinfo.Div_Fac=temp1;
picinfo.staticx=0xffff;
picinfo.staticy=0xffff;//放到一个不可能的值上面
}
//判断这个像素是否可以显示
//(x,y):
像素原始坐标
//chg:
功能变量.
//返回值:
0,不需要显示.1,需要显示
u8is_element_ok(u16x,u16y,u8chg)
{
if(x!
=picinfo.staticx||y!
=picinfo.staticy)
{
if(chg==1){picinfo.staticx=x;picinfo.staticy=y;}
return1;
}elsereturn0;
}
//智能画图
//FileName:
要显示的图片文件BMP/JPG/JPEG/GIF
//x,y,width,height:
坐标及显示区域尺寸
//fast:
使能jpeg/jpg小图片(图片尺寸小于等于液晶分辨率)快速解码,0,不使能;1,使能.
//图片在开始和结束的坐标点范围内显示
u8ai_load_picfile(constu8*filename,u16x,u16y,u16width,u16height,u8fast)
{
u8res;//返回值
u8temp;
if((x+width)>picinfo.lcdwidth)returnPIC_WINDOW_ERR;//x坐标超范围了.
if((y+height)>picinfo.lcdheight)returnPIC_WINDOW_ERR;//y坐标超范围了.
//得到显示方框大小
if(width==0||height==0)returnPIC_WINDOW_ERR;//窗口设定错误
picinfo.S_Height=height;
picinfo.S_Width=width;
//显示区域无效
if(picinfo.S_Height==0||picinfo.S_Width==0)
{
picinfo.S_Height=lcddev.height;
picinfo.S_Width=lcddev.width;
returnFALSE;
}
if(pic_phy.fillcolor==NULL)fast=0;//颜色填充函数未实现,不能快速显示
//显示的开始坐标点
picinfo.S_YOFF=y;
picinfo.S_XOFF=x;
//文件名传递
temp=f_typetell((u8*)filename);//得到文件的类型
switch(temp)
{
caseT_BMP:
res=stdbmp_decode(filename);break;//解码bmp
caseT_JPG:
caseT_JPEG:
res=jpg_decode(filename,fast);break;//解码JPG/JPEG
caseT_GIF:
res=gif_decode(filename,x,y,width,height);break;//解码gif
default:
res=PIC_FORMAT_ERR;break;//非图片格式!
!
!
}
returnres;
}
//动态分配内存
void*pic_memalloc(u32size)
{
return(void*)mymalloc(SRAMIN,size);
}
//释放内存
voidpic_memfree(void*mf)
{
myfree(SRAMIN,mf);
}
此段代码总共9个函数,其中,piclib_draw_hline和piclib_fill_color函数因为LCD驱动,代码没有提供,所以在这里单独实现,如果LCD驱动代码有提供,则直接用LCD提供的即可。
piclib_init函数,该函数用于初始化图片解码的相关信息,其中_pic_phy是我们在piclib.h里面定义的一个结构体,用于管理底层LCD接口函数,这些函数必须由用户在外部实现。
_pic_info则是另外一个结构体,用于图片缩放处理。
piclib_alpha_blend函数,该函数用于实现半透明效果,在小格式(图片分辨率小于LCD分辨率)bmp解码的时候,可能被用到。
ai_draw_init函数,该函数用于实现图片在显示区域的居中显示初始化,其实is_element_ok函数,该函数用于判断一个点是不是应该显示出来,在图片缩放的时候该函数是必须用到的。
ai_load_picfile函数,该函数是整个图片显示的对外接口,外部程序,通过调用该函数,可以实现bmp、jpg/jpeg和gif的显示,该函数根据输入文件的后缀名,判断文件格式,然后交给相应的解码程序(bmp解码/jpeg解码/gif解码),执行解码,完成图片显示。
注意,这里我们用到一个f_typetell的函数,来判断文件的后缀名,f_typetell函数在exfuns.c里面实现,最后,pic_memalloc和pic_memfree分别用于图片解码时需要用到的内存申请和释放,通过调用mymalloc和myfreee来实现。
保存piclib.c,然后在工程里面新建一个PICTURE的分组,将bmp.c、gif.c、tjpgd.c和piclib.c等4个c文件加入到PICTURE分组下。
然后打开piclib.h,在该文件输入如下代码:
#ifndef__PICLIB_H
#define__PICLIB_H
#include"sys.h"
#include"lcd.h"
#include"malloc.h"
#include"ff.h"
#include"exfuns.h"
#include"bmp.h"
#include"tjpgd.h"
#include"gif.h"
#definePIC_FORMAT_ERR0x27//格式错误
#definePIC_SIZE_ERR0x28//图片尺寸错误
#definePIC_WINDOW_ERR0x29//窗口设定错误
#definePIC_MEM_ERR0x11//内存错误
#ifndefTRUE
#defineTRUE1
#endif
#ifndefFALSE
#defineFALSE0
#endif
//图片显示物理层接口
//在移植的时候,必须由用户自己实现这几个函数
typedefstruct
{
u16(*read_point)(u16,u16);
//u16read_point(u16x,u16y)读点函数
void(*draw_point)(u16,u16,u16);
//voiddraw_point(u16x,u16y,u16color)画点函数
void(*fill)(u16,u16,u16,u16,u16);
///voidfill(u