你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

BMP图片解码 STM32+FATS+模拟U盘+OLED12864

[复制链接]
不吃肉的羊 发布时间:2018-2-10 20:50

之前做UI设计,每次用到特殊的字符,就要我重新做字库。

后面有几次要我贴图,可想而知,太鸡巴折腾了,做过的朋友都知道,后面就想着能不能让单片机虚拟U盘,然后图片拖进去,就直接显示出来。

PS:其实想做视频解码来着,后面懒了,先做图片解码。

折腾了一两天,最终还是实现了。

硬件组成:

1.STM32F4

2.OLED12864

3.W25Q64

软件组成:

1.DMA做SPI数据传输,基本底层驱动,就不解释了

2.W25Q64上做FATS文件系统,版本是

$ O; Q# q; h8 ?* T! `

3.将W25Q64虚拟成U盘

蛮久以前折腾的了

4.编码解码及屏幕显示

其实解码不难,难的是数据对应,解码我大概花了两三小时,数据对应显示花了将近一天。

因为是OLED12864,只能显示8位的数据,也就没有什么颜色好说的了。

简述一下使用步骤。

首先设备上电,看到我用单片机+W25Q64模拟的U盘


; f) Q7 G9 `' U" p. ]

然后,做张BMP图片,放到U盘里面

3 e2 n( X. z% @9 b

电脑打开图片是这样的,图片是我随便截图来的

, A( a% d; [, O5 a

然后,设备重启上电,OLED上面就显示这张图片。

6 T6 l3 r5 T, J" }: J  U6 D3 Z! x

这样就意味着我之后想贴图就可以直接贴了,不要再搞来搞去的做字库。

首先是了解BMP的组成结构:

* t1 ?' P, K( w: b# X9 [2 {
1:位图头文件数据结构,它包含BMP图像文件的类型、显示内容等信息;
& x) {. ]0 [+ o. E其结构定义如下:
3 ]  z# V# k7 {% R  z' N[size=1em]
[size=1em]1

. c: P- N  K+ d0 i0 ]; `/ |
[size=1em]2
/ k* W: a" S5 a! L/ Y( D
[size=1em]3
% S% ]! z+ v* ~2 l; Y/ o
[size=1em]4
' r3 m! S$ q" w0 p- I
[size=1em]5

6 m. t2 l) H2 d5 }) w  c( {1 x  v: J
[size=1em]6

2 {: @) v6 Z& e0 ^
[size=1em]7

" c1 D- L# h$ d. F+ f
[size=1em]8

8 n9 i0 H1 o+ T/ Z! }
[size=1em]9
& Y7 {2 Z" u' U6 ^# `4 L6 e
[size=1em][size=1em]typedef struct tagBITMAPFILEHEADER
8 X, ^/ m- a( e- @. d+ s6 d. w[size=1em]{8 Q- s2 Z2 ]# T0 O4 w, i1 @
[size=1em]    WORD bfType;//位图文件的类型,必须为BM(1-2字节)
- C( k: W5 W3 R0 W2 K[size=1em]    DWORD bfSize;//位图文件的大小,以字节为单位(3-6字节,低位在前)
4 Y7 @& g: S2 j9 S/ k  S* @! L[size=1em]    WORD bfReserved1;//位图文件保留字,必须为0(7-8字节)
, ^4 H- `! Z" X% q[size=1em]    WORD bfReserved2;//位图文件保留字,必须为0(9-10字节)
0 p+ ~, W* X& A" v[size=1em]    DWORD bfOffBits;//位图数据的起始位置,以相对于位图(11-14字节,低位在前)) [* \5 c4 F4 r/ Y2 z! _: ]
[size=1em]    //文件头的偏移量表示,以字节为单位
" p) e; T  T1 m" O) b5 ]9 [[size=1em]}__attribute__((packed)) BITMAPFILEHEADER;
5 T! `$ [1 t& l% a. A4 N8 ~3 M. j: F; n
! F- r- `  p# F" N, s; U
9 t7 l, [$ Y& {2 f) v' A2 y
% r" b2 q& z" D( Y' Z5 y- t+ F9 B
2:位图信息数据结构,它包含有BMP图像的宽、高、压缩方法,以及定义颜色等信息;
3 v* F, w/ ~' i/ v, E2 S% LBMP位图信息头数据用于说明位图的尺寸等信息。  K* T; y; R8 _# G3 A* y3 L
[size=1em]
[size=1em]1

1 z7 z& }* F* J& \
[size=1em]2
* E& h# O# b: k5 W& M& ^# O
[size=1em]3

" `3 o; l3 `2 k4 v% E' n
[size=1em]4
0 Q4 [/ ^" s# q% E$ X6 Q
[size=1em]5

5 q: z; V. g. n  f# h" v
[size=1em]6

5 S/ m: t( H7 \6 i2 {# A$ v# y4 z
[size=1em]7
. s& D' J( B4 O$ N( g! F% M
[size=1em]8

- h7 q- f+ A9 L$ P
[size=1em]9
8 t  y5 |! R# P8 `( Q: p( L
[size=1em]10
# z  O8 k* C8 e" t' t
[size=1em]11
" y: _) }1 j1 J3 U* k0 w; s: p
[size=1em]12

% `" }0 o# o  J+ ]
[size=1em]13

; I% h6 b, O+ e7 e; d; [' D
[size=1em]14
( Y! `& p) r3 ?& o8 a
[size=1em]15

6 G- Z5 {* g: Q
[size=1em][size=1em]typedef struct tagBITMAPINFOHEADER{
; G* z% B4 x, W3 T2 Y. x4 M+ \[size=1em]DWORD biSize;//本结构所占用字节数(15-18字节)
! W5 @/ H" V. {4 V5 K[size=1em]LONG biWidth;//位图的宽度,以像素为单位(19-22字节)" W+ J: x! M- X- {# r) B3 G+ I" x
[size=1em]LONG biHeight;//位图的高度,以像素为单位(23-26字节)- \/ f8 I' w5 j, N/ G, B' t" C
[size=1em]WORD biPlanes;//目标设备的级别,必须为1(27-28字节)
+ A7 F4 T, S( S1 T. c9 W: k; C8 X[size=1em]WORD biBitCount;//每个像素所需的位数,必须是1(双色),(29-30字节)
0 E0 T6 e5 S- ~" \: _[size=1em]//4(16色),8(256色)16(高彩色)或24(真彩色)之一
( V6 u- G$ k1 W/ I& P[size=1em]DWORD biCompression;//位图压缩类型,必须是0(不压缩),(31-34字节)/ H1 R" ^3 [( Z
[size=1em]//1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一; g7 q/ e$ `/ \, E
[size=1em]DWORD biSizeImage;//位图的大小(其中包含了为了补齐行数是4的倍数而添加的空字节),以字节为单位(35-38字节)9 s2 b8 \; A7 N( z- `9 f
[size=1em]LONG biXPelsPerMeter;//位图水平分辨率,每米像素数(39-42字节)* Y& o& o# O; Q* `5 \
[size=1em]LONG biYPelsPerMeter;//位图垂直分辨率,每米像素数(43-46字节)
& n$ s3 i' i; m5 g5 c. ~2 @[size=1em]DWORD biClrUsed;//位图实际使用的颜色表中的颜色数(47-50字节)
0 }) p# o8 ~; ]/ \2 n* A+ c+ M[size=1em]DWORD biClrImportant;//位图显示过程中重要的颜色数(51-54字节)# d' Y* Q9 `4 ?6 A
[size=1em]}__attribute__((packed)) BITMAPINFOHEADER;
7 c" @. K1 m+ }* [2 A+ ~
. n; f: U1 \/ E: i( d

  [. m1 v/ Z$ C' ]3 F. Q4 Z
% Q9 z# b: N" h3 R$ {

* L+ m+ Z0 T: o) }+ P# f9 X3:调色板,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24位的BMP)就不需要调色板;
6 p( J6 j7 P( ]& }! J+ Q颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下:
( M% }, h- f+ D+ T# h[size=1em]
[size=1em]1

& x, G$ A& N! \
[size=1em]2
& U6 ?6 B& n7 s
[size=1em]3

9 f2 Q7 Q1 C3 h: z6 Q; o8 |+ F) r
[size=1em]4

5 i* K; P9 {) g- R1 O
[size=1em]5

0 [% K, T5 j! ]0 E- d) G
[size=1em]6

0 T. E* X6 u+ j6 O
[size=1em][size=1em]typedef struct tagRGBQUAD{
: l( h3 v( B* ]! W! k[size=1em]BYTE rgbBlue;//蓝色的亮度(值范围为0-255)
7 Q; ]& y6 z8 V5 n' V[size=1em]BYTE rgbGreen;//绿色的亮度(值范围为0-255). C" N% f; i% j+ C/ ~6 H1 e7 V3 a
[size=1em]BYTE rgbRed;//红色的亮度(值范围为0-255)
- h2 C  Q- ?1 U: P: z* M[size=1em]BYTE rgbReserved;//保留,必须为09 C: {5 _8 Z; K( y( e( e7 b# m/ Q
[size=1em]}__attribute__((packed)) RGBQUAD;9 K1 w8 Z! \6 a2 }$ S
9 m; ~- a8 B% T2 Q0 o" Q
" D$ p- Q6 K) T  @7 f! \7 U

1 p4 J* l* Q% @颜色表中RGBQUAD结构数据的个数有biBitCount来确定:8 w8 w; s. g8 Y1 M7 K. J
当biBitCount=1,4,8时,分别有2,16,256个表项;
- C6 r% p# J6 J7 @1 K4 m当biBitCount=24时,没有颜色表项。
. g$ k+ _! Q- L7 U  C# d. Y. B位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下:! X! ]9 @# Z2 ]2 }8 A
[size=1em]
[size=1em]1
- v2 X7 l/ H% ]' t4 F
[size=1em]2

: b' ?; C! [2 D% G' N
[size=1em]3

# N; b2 I9 G* g
[size=1em]4

3 w# _# l& [( @
[size=1em][size=1em]typedef struct tagBITMAPINFO{* V7 y4 V  c* p; C; l" A! Q: p2 e
[size=1em]BITMAPINFOHEADER bmiHeader;//位图信息头, {+ w; g8 e9 c% `/ R* l$ a
[size=1em]RGBQUAD bmiColors[1];//颜色表4 l5 V2 g) ^( R; |4 P
[size=1em]}__attribute__((packed)) BITMAPINFO;; e) x0 V$ V1 ?/ i( O  q
, `  {5 N# k3 c7 z( v

! L  ^0 X: N  O/ p  e* h

5 H- x2 u7 [" G9 I9 T& V2 C1 X  I0 |) v! h- w% v8 x4 y( o

' l' c/ Q6 _% R* A  n- M4:位图数据,这部分的内容根据BMP位图使用的位数不同而不同,在24位图中直接使用RGB,而其他的小于24位的使用调色板中颜色索引值。$ |! w" w3 j( M/ V) |# {/ ?3 W. _
位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:
$ s# C9 G4 O8 ?当biBitCount=1时,8个像素占1个字节;/ [+ K* q3 `% R' m2 l
当biBitCount=4时,2个像素占1个字节;% x' _3 M# i+ F" |# _% x
当biBitCount=8时,1个像素占1个字节;1 Y$ y# N' U; o8 p
当biBitCount=24时,1个像素占3个字节,按顺序分别为B,G,R;4 N# F' U" j$ e: q1 Y
Windows规定一个扫描行所占的字节数必须是! X) ^5 d1 `, d1 o' K
4的倍数(即以long为单位),不足的以0填充,
' {/ n3 N# B( }& {# D) n5 x! k, ybiSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight;
2 L) l8 v5 v3 }6 P: {. ^

以上内容网上大同小异,都是一样的。

根据以上信息,首先我在程序里面做了一个结构体,存放除显示数据外的所有东西。

- {) S: ^' D* W2 U

我不需要调色板,也就没用结构体了。

计算上面的数据,一共是62个8位数据,用来存放BMP的定义信息。

程序很简单,首先是U盘读取数据

ret = f_open(&fp, "246.bmp", FA_OPEN_ALWAYS | FA_WRITE | FA_READ);
! r' ^/ D7 H% y# g. m- ?9 X3 k

                        ret = f_read(&fp, readbuff, picsize, &unt); //读取文件头信息

然后提取前62个数据保存到上面说的结构体

Getpicture(readbuff);
% @) G$ O8 s8 z/ @5 \8 `


) g2 \0 Y( c- r6 Q

仿真确认数据正确性

然后是提取图片信息


5 k: r; u6 I- g5 G1 n4 j/ @

一个简单的嵌套逻辑。


0 F# l4 {. _0 Q2 r

最后是花了我将近一天的东西,数据显示对应

void Display_BMP_DOT(uint8_t bmp[64][16])2 g1 X+ m- i* r9 S% M+ p
{( E! I6 s+ V! y8 d( W; O
        unsigned char x,y,z,n,m;* m" ?) v, H9 y; B; `- y4 A7 T+ X
        uint8_t Oled_Draw_BMP_buff[128];
4 l+ ?. v2 u5 t/ u% Y; x8 h' J7 J! e) S
7 Q0 K$ ~, d7 J1 z1 T/ e
        for(m=0;m<64;m++)/ ?- N6 j' u( r' m+ O& t/ [
        {
2 H0 L6 v2 V) |5 L& Q6 d0 L! E                for(n=0;n<16;n++)
1 a, P5 ]! A, P- I                {
8 q' w2 W' G9 d* e                        z = 0x80;
( p$ ?0 r" B1 d7 X4 F4 I                        for(x=0;x<8;x++)
9 T+ a% K3 V0 X% j1 x$ ^; j                        {        
3 z7 o- s! n# M( o+ {6 j                                Oled_Dot(x+8*n-1,63-m,bmp[m][n]&(z>>x));       
$ N, U: A8 [& b. y8 A$ X                        }
9 e" x. J! _  g- h( i. f& _. x                }) G8 a& u) ?# C7 R4 q# |+ E4 m
        }
' E( |+ c% v# r$ C7 `$ v        Display_Process(OLED_Display_Data);        0 c) ^. K4 [1 e$ c

}

这一步的难度在

OLED12864支持的是页写,之前做驱动的时候,刷屏是从左至右从上到下,但是WINDOWS上面,图片提取是,从左至右,从下至上。


9 F' T2 c9 o% d) L
赞 收藏 1 评论3 发布时间:2018-2-10 20:50

举报

3个回答
hello_bug 回答时间:2018-2-11 09:15:10
这各厉害,解码速度如何,刷屏效果呢?
不吃肉的羊 回答时间:2018-2-11 12:36:03
12864总共才128*64个点,要不了多久,具体时间没测,效果跟做字库一样的
zero99 回答时间:2018-2-12 14:17:34
感谢分享,已汇总到2月技术原创  https://www.stmcu.org.cn/module/forum/thread-614799-1-1.html
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版