专家
公告
财富商城
电子网
旗下网站
首页
问题库
专栏
标签库
话题
专家
NEW
门户
发布
提问题
发文章
STM32
ALIENTEK MINISTM32 扩展实验13 内部FLASH图片显示实验_AN1103(告诉你如何用LCD显示image2lcd生成的图像数据)
2019-07-20 22:07
发布
×
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
站内问答
/
STM32/STM8
19035
49
922
AN1103
内部
FLASH
图片显示
本应用文档(
AN1103
)将向大家展示
,
如何将直接存放在
STM32
内部
FLASH
的图片数据(解码后的数据)显示到
LCD
上
.
以及介绍图片数据生成工具
image2lcd V2.9
的一些用法。本实验以
ALIENTEK MiniSTM32
开发板为实验对象。
本文档分为如下几部分:
1,
图片显示原理。
2,
Image2lcd
简介。
3,
软件实现。
一,
图片显示原理。
在
LCD
上显示图片无非就是画点。原理就这么简单。画点需要
2
个要素:
1
,坐标。
2
,颜 {MOD}。知道了这两个要素,画图就简单了,一副图片在
LCD
上显示出来,我们只需要在正确的位置写入正确的颜 {MOD}即可。就像你用铅笔在本子上画图一样,本子就是
LCD
,铅笔就是你的画点函数。
图片显示另外一个重要的特点就是他的数据量很大,比如画一幅
320*240
的图像,以
16
位 {MOD}计算,那么光颜 {MOD}的数据量就有:
320*240*2=153600
字节。这其中还不包括设置坐标的过程,如果加上坐标设置,数据量就是颜 {MOD}数据量的
5
倍(每次坐标设置需要发送
5
次命令
/
数据)以上。所以尽量优化画点过程,才能使你的图片显示得流畅。
单纯的画点,显然无法做太多优化,因为坐标设置是必须的。幸好,我们
ALIENTEK
所使用的液晶都是支持开窗显示以及坐标自增显示的。这样,我们只需要设置一次窗口,然后设置一次坐标,就可以不停的往
LCD
写颜 {MOD}数据,而不需要再做地址设置了。这样可以使得速度比单纯的画点显示要快至少
5
倍以上。
开窗也有几个条件:
1
,窗大小。
2
,
GRAM
自增方向(就是扫描方向)。
开窗的概念:如图
1
所示:
图
1
我们本来的液晶是分辨率是
240*320.
对图
1
的
0X00~0XEF
(
x
坐标),
0X00~0X13F
(
y
坐标)。图一中我们开辟了一个灰 {MOD}区域的窗口,它的范围为
XSTA~XEND
,
YSTA~YEND
。这样我们开辟窗口以后,再往
LCD
写数据,它就只会在这个窗口范围内地址按照设定的方向自增。比如从左到右,从上到下的扫描方式,规律为:从
(XSTA,YSTA)
开始
,x
坐标递增,每次遇到
XEND
地址则
y
坐标增
1
,同时
x
坐标重设为
XSTA
,直到
y
坐标递增到大于
YEND
,此时坐标又变为
(XSTA,YSTA)
。
所以,只要我们预先知道图片数据的生成格式,以及图片尺寸,那么我们就可以采用开窗方式来画图,从而提高效率。
二,
Image2lcd
简介。
Image2Lcd
是一款非常好的图像工具软件,它能把各种来源的图片转换成特定的数据格式以用来匹配单片机系统所需要的显示数据格式。
Image2Lcd
支持的输入图像格式包括:
BMP, WBMP, JPG, GIF, WMF, EMF, ICO,
等等。
Image2Lcd
的输出数据类型包括定制的二进制类型、
C
语言数组类型和标准的
BMP
格式、
WBMP
格式。
Image2Lcd
能可视调节输入图象的数据扫描方式、灰度
(
颜 {MOD}数
)
、图像数据排列方式、亮度、对比度、等等。对于包含了图像头数据保存的图像数据文件,
Image2Lcd
能重新打开作为输入图像。
因为
image2lcd
能生成带图像数据头的数据文件,使得我们处理起来方便很多,这里我们仅以
16
位真彩 {MOD}为例进行说明。
在该软件的帮助文件查到对“
4096
{MOD}
/16
位真彩 {MOD}
/18
位真彩 {MOD}
/24
位真彩 {MOD}
/32
位真彩 {MOD}”图片,其生成的图像数据头的结构为:
typedef struct _HEADCOLOR
{
unsigned char scan;
unsigned char gray;
unsigned short w;
unsigned short h;
unsigned char is565;
unsigned char rgb;
}HEADCOLOR;
各个成员的功能描述如下:
scan:
扫描模式
Bit7: 0:
自左至右扫描,
1:
自右至左扫描。
Bit6: 0:
自顶至底扫描,
1:
自底至顶扫描。
Bit5: 0:
字节内象素数据从高位到低位排列,
1:
字节内象素数据从低位到高位排列。
Bit4: 0:WORD
类型高低位字节顺序与
PC
相同,
1:WORD
类型高低位字节顺序与
PC
相反。
Bit3~2:
保留。
Bit1~0: [00]
水平扫描,
[01]
垂直扫描,
[10]
数据水平
,
字节垂直,
[11]
数据垂直
,
字节水平。
gray:
灰度值
灰度值,
1:
单 {MOD},
2:
四灰,
4:
十六灰,
8:256
{MOD},
12:4096
{MOD},
16:16
位彩 {MOD},
24:24
位彩 {MOD},
32:32
位彩 {MOD}。
w:
图像的宽度。
h:
图像的高度。
is565:
在
4096
{MOD}模式下为
0
表示使用
[16bits(WORD)]
格式,此时图像数据中每个
WORD
表示一个象素;为
1
表示使用
[12bits(
连续字节流
)]
格式,此时连续排列的每
12Bits
代表一个象素。
在
16
位彩 {MOD}模式下为
0
表示
R G B
颜 {MOD}分量所占用的位数都为
5Bits
,为
1
表示
R G B
颜 {MOD}分量所占用的位数分别为
5Bits,6Bits,5Bits
。
在
18
位彩 {MOD}模式下为
0
表示
"6Bits in Low Byte"
,为
1
表示
"6Bits in High Byte"
。
在
24
位彩 {MOD}和
32
位彩 {MOD}模式下
is565
无效。
rgb:
描述
R G B
颜 {MOD}分量的排列顺序,
rgb
中每
2Bits
表示一种颜 {MOD}分量,
[00]
表示空白,
[01]
表示
Red
,
[10]
表示
Green
,
[11]
表示
Blue
。
在
HEADCOLOR
中,
scan
,
w
,
h
这三个参数对我们的图片显示尤为有用。直到了
w
和
h
,就可以直到开窗的大小。而
scan
的最高两位,则代表了图片数据生成时的扫描方向,也就是我们开窗后地址自增的方向。直到了这几个参数,我们就可以很方便的解析各种大小,各种扫描方式的图片数据了。
下面我们以图
2
为例,按从左到右,从上到下的扫描方式,生成
16
位真彩(
RGB:565
)格式的图像数据。
图
2
该图片的尺寸为
200*168
。我们用
image2lcd V2.9
打开此图片,设置如图
3
所示:
图
3
图
3
中,我们设置如上图。我们要生成的的图像数据为
16
位真彩,所以在
2
处选择
16
位真彩 {MOD},然后扫描方式为水平扫描,在
3
处选中包含头像数据头选项
(注意:不能选择“高位在前(
MSB First
)”这个选项!!!)
。在
5
处选中
16
位彩 {MOD}选项卡,然后在颜 {MOD}位数(
4
处)选择
RGB565
(因为我们的液晶刚好也是
RGB565
格式)。然后点击保存,命名为
image1
,可以得到图像数组如下:
const unsigned char gImage_image1[67208] = {
0X00,0X10,0XC8,0X00,0XA8,0X00,0X01,0X1B
,
0X6B,0X6E,0XD1,0X9F,0XF5,0XB7,0XD3,0XAF,0XF3,0XAF,0X0F,0X8F,0XCE,0X86,0XF3,0XAF,
……
0X73,0XB7,0XF6,0XCF,0XF9,0XD7,0X98,0XCF,0X71,0XAE,0XD6,0XDF,0XFA,0XE7,0XF8,0XCF,
0XF6,0XC7,0X10,0X9F,0X53,0XB7,0XD5,0XC7,0XF6,0XCF,0X74,0XBF,0XD1,0XA6,0XF7,0XD7,
};
其中红 {MOD}数字为图像头数据,一共是
8
个字节,刚好是
HEADCOLOR
的大小。紧随其后的就是按设定的方向顺序存放的图像数据(颜 {MOD}数据)。这样我们只需要在软件上对这个数组(
gImage_image1
)的数据进行解析,就可以还原图像了。
三,
软件实现。
在第二节的介绍中,我们得到了一个数组(
gImage_image1
),而从第一节的介绍,我们需要一个开窗函数,以及一个扫描方向设置函数,这里提供这两个函数的代码如下:
//
设置
LCD
的自动扫描方向
//0~7
:代表
8
个方向
(
具体定义见
lcd.h)
//9320/9325/9328/4531/1505/b505/8989
等
IC
已经实际测试
void LCD_Scan_Dir(u8 dir)
{
u16 regval=0;
u8 dirreg=0;
#if USE_HORIZONTAL//
使用横屏
switch(dir)//
方向转换
{
case 0:dir=6;break;
case 1:dir=7;break;
case 2:dir=4;break;
case 3:dir=5;break;
case 4:dir=1;break;
case 5:dir=0;break;
case 6:dir=3;break;
case 7:dir=2;break;
}
#endif
if(DeviceCode==0x8989)//8989 IC
{
dirreg=0X11;
regval=0X6040;//65K
}else//
其他驱动
IC
{
dirreg=0X03;
regval=1<<12;
}
switch(dir)
{
case L2R_U2D://
从左到右
,
从上到下
regval|=(1<<5)|(1<<4)|(0<<3);
break;
case L2R_D2U://
从左到右
,
从下到上
regval|=(0<<5)|(1<<4)|(0<<3);
break;
case R2L_U2D://
从右到左
,
从上到下
regval|=(1<<5)|(0<<4)|(0<<3);
break;
case R2L_D2U://
从右到左
,
从下到上
regval|=(0<<5)|(0<<4)|(0<<3);
break;
case U2D_L2R://
从上到下
,
从左到右
regval|=(1<<5)|(1<<4)|(1<<3);
break;
case U2D_R2L://
从上到下
,
从右到左
regval|=(1<<5)|(0<<4)|(1<<3);
break;
case D2U_L2R://
从下到上
,
从左到右
regval|=(0<<5)|(1<<4)|(1<<3);
break;
case D2U_R2L://
从下到上
,
从右到左
regval|=(0<<5)|(0<<4)|(1<<3);
break;
}
LCD_WriteReg(dirreg,regval);
}
//
设置窗口
//sx,sy,ex,ey
窗口坐标
//
窗口大小
ex-sx+1)*(ey-ex+1)
//
注意
,
确保
ex>=sx;ey>=sy!!!!
//9320/9325/9328/4531/1505/b505/8989
等
IC
已经实际测试
void LCD_Set_Window(u16 sx,u16 sy,u16 ex,u16 ey)
{
u8 hsareg,heareg,vsareg,veareg;
u16 hsaval,heaval,vsaval,veaval;
#if USE_HORIZONTAL
//
使用横屏
//
窗口值
hsaval=sy;
heaval=ey;
vsaval=319-ex;
veaval=319-sx;
#else
//
竖屏
//
窗口值
hsaval=sx;
heaval=ex;
vsaval=sy;
veaval=ey;
#endif
if(DeviceCode==0X8989)//8989 IC
{
hsareg=0X44;heareg=0X44;//
水平方向窗口寄存器
(1289
的由一个寄存器控制
)
hsaval|=(heaval<<8);
//
得到寄存器值
.
heaval=hsaval;
vsareg=0X45;veareg=0X46;//
垂直方向窗口寄存器
}else
//
其他驱动
IC
{
hsareg=0X50;heareg=0X51;//
水平方向窗口寄存器
vsareg=0X52;veareg=0X53;//
垂直方向窗口寄存器
}
//
设置寄存器值
LCD_WriteReg(hsareg,hsaval);
LCD_WriteReg(heareg,heaval);
LCD_WriteReg(vsareg,vsaval);
LCD_WriteReg(veareg,veaval);
}
这两个函数已经添加到
ILI93xx.c
的源码中,具体请看本应用文档的对应扩展实验(
ALIENTEK MINISTM32
扩展实验
13
内部
FLASH
图片显示实验)。更新后的
ILI93xx.c
版本为
V1.6
。同时该实验的
USMART
部分也有了更新,最新版本的
USMART
为
V2.6
。
扩展实验
13
的源码是在标准实验
10
的基础上修改而来的,加入了
usmart
组建以及新建了
IMAG2LCD
的组。见图
4
:
图
4
有了
LCD_Set_Window
和
LCD_Scan_Dir
这两个函数,做起来就方便多了(通过画点的方式也可以实现),根据第一节的原理,编写出的
flash->lcd
函数部分即
image2lcd.c
的内容如下:
//
从
8
位数据获得
16
位颜 {MOD}
//mode:0,
低位在前
,
高位在后
.
//
1,
高位在前
,
低位在后
.
//str:
数据
u16 image_getcolor(u8 mode,u8 *str)
{
u16 color;
if(mode)
{
color=((u16)*str++)<<8;
友情提示:
此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
49条回答
xurids
2019-07-24 22:49
回复【35楼】正点原子:
---------------------------------
回复【35楼】正点原子:
---------------------------------
板子是今年4月份的。途中液晶坏了换过一次液晶,现在的驱动是ILI9341
加载中...
查看其它49个回答
一周热门
更多
>
相关问题
STM32F4上I2C(在PROTEUS中模拟)调试不通的问题
6 个回答
芯片供应紧张,准备换个MCU,MM32L系列替换STM32L系列的怎么样?
7 个回答
STM32同时使用两个串口进行数据收发时数据丢包的问题
5 个回答
STM32F103串口通信死机问题
4 个回答
STM32WLE5CC连接SX1268在LoRa模式下能与 SX1278互通吗?
2 个回答
相关文章
ST公司第一款无线低功耗单片机模块有效提高物联网设计生产效率
0个评论
如何实现对单片机寄存器的访问
0个评论
通过USB用STM32片内自带Bootloader下载程序及注意事项
0个评论
欲练此功必先自宫之STM32汇编启动,放慢是为了更好的前行
0个评论
×
关闭
采纳回答
向帮助了您的知道网友说句感谢的话吧!
非常感谢!
确 认
×
关闭
编辑标签
最多设置5个标签!
STM32
保存
关闭
×
关闭
举报内容
检举类型
检举内容
检举用户
检举原因
广告推广
恶意灌水
回答内容与提问无关
抄袭答案
其他
检举说明(必填)
提交
关闭
×
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
×
付费偷看金额在0.1-10元之间
确定
×
关闭
您已邀请
0
人回答
查看邀请
擅长该话题的人
回答过该话题的人
我关注的人
---------------------------------
回复【35楼】正点原子:
---------------------------------
板子是今年4月份的。途中液晶坏了换过一次液晶,现在的驱动是ILI9341
一周热门 更多>