之前做UI设计,每次用到特殊的字符,就要我重新做字库。
后面有几次要我贴图,可想而知,太鸡巴折腾了,做过的朋友都知道,后面就想着能不能让单片机虚拟U盘,然后图片拖进去,就直接显示出来。
PS:其实想做视频解码来着,后面懒了,先做图片解码。
折腾了一两天,最终还是实现了。
硬件组成:
1.STM32F4
2.OLED12864
3.W25Q64
软件组成:
1.DMA做SPI数据传输,基本底层驱动,就不解释了
2.W25Q64上做FATS文件系统,版本是
3.将W25Q64虚拟成U盘
蛮久以前折腾的了
4.编码解码及屏幕显示
其实解码不难,难的是数据对应,解码我大概花了两三小时,数据对应显示花了将近一天。
因为是OLED12864,只能显示8位的数据,也就没有什么颜色好说的了。
简述一下使用步骤。
首先设备上电,看到我用单片机+W25Q64模拟的U盘
然后,做张BMP图片,放到U盘里面
电脑打开图片是这样的,图片是我随便截图来的
然后,设备重启上电,OLED上面就显示这张图片。
这样就意味着我之后想贴图就可以直接贴了,不要再搞来搞去的做字库。
首先是了解BMP的组成结构:
1
2
3
4
5
6
7
8
9
|
typedef
struct
tagBITMAPFILEHEADER
{
WORD
bfType;
//位图文件的类型,必须为BM(1-2字节)
DWORD
bfSize;
//位图文件的大小,以字节为单位(3-6字节,低位在前)
WORD
bfReserved1;
//位图文件保留字,必须为0(7-8字节)
WORD
bfReserved2;
//位图文件保留字,必须为0(9-10字节)
DWORD
bfOffBits;
//位图数据的起始位置,以相对于位图(11-14字节,低位在前)
//文件头的偏移量表示,以字节为单位
}__attribute__((packed)) BITMAPFILEHEADER;
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
typedef
struct
tagBITMAPINFOHEADER{
DWORD
biSize;
//本结构所占用字节数(15-18字节)
LONG
biWidth;
//位图的宽度,以像素为单位(19-22字节)
LONG
biHeight;
//位图的高度,以像素为单位(23-26字节)
WORD
biPlanes;
//目标设备的级别,必须为1(27-28字节)
WORD
biBitCount;
//每个像素所需的位数,必须是1(双色),(29-30字节)
//4(16色),8(256色)16(高彩色)或24(真彩色)之一
DWORD
biCompression;
//位图压缩类型,必须是0(不压缩),(31-34字节)
//1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
DWORD
biSizeImage;
//位图的大小(其中包含了为了补齐行数是4的倍数而添加的空字节),以字节为单位(35-38字节)
LONG
biXPelsPerMeter;
//位图水平分辨率,每米像素数(39-42字节)
LONG
biYPelsPerMeter;
//位图垂直分辨率,每米像素数(43-46字节)
DWORD
biClrUsed;
//位图实际使用的颜色表中的颜色数(47-50字节)
DWORD
biClrImportant;
//位图显示过程中重要的颜色数(51-54字节)
}__attribute__((packed)) BITMAPINFOHEADER;
|
1
2
3
4
5
6
|
typedef
struct
tagRGBQUAD{
BYTE
rgbBlue;
//蓝色的亮度(值范围为0-255)
BYTE
rgbGreen;
//绿色的亮度(值范围为0-255)
BYTE
rgbRed;
//红色的亮度(值范围为0-255)
BYTE
rgbReserved;
//保留,必须为0
}__attribute__((packed)) RGBQUAD;
|
1
2
3
4
|
typedef
struct
tagBITMAPINFO{
BITMAPINFOHEADER bmiHeader;
//位图信息头
RGBQUAD bmiColors[1];
//颜色表
}__attribute__((packed)) BITMAPINFO;
|
以上内容网上大同小异,都是一样的。
根据以上信息,首先我在程序里面做了一个结构体,存放除显示数据外的所有东西。
我不需要调色板,也就没用结构体了。
计算上面的数据,一共是62个8位数据,用来存放BMP的定义信息。
程序很简单,首先是U盘读取数据
ret = f_open(&fp, "246.bmp", FA_OPEN_ALWAYS | FA_WRITE | FA_READ);
ret = f_read(&fp, readbuff, picsize, &unt); //读取文件头信息
然后提取前62个数据保存到上面说的结构体
Getpicture(readbuff);
仿真确认数据正确性
然后是提取图片信息
一个简单的嵌套逻辑。
最后是花了我将近一天的东西,数据显示对应
void Display_BMP_DOT(uint8_t bmp[64][16])
{
unsigned char x,y,z,n,m;
uint8_t Oled_Draw_BMP_buff[128];
for(m=0;m<64;m++)
{
for(n=0;n<16;n++)
{
z = 0x80;
for(x=0;x<8;x++)
{
Oled_Dot(x+8*n-1,63-m,bmp[m][n]&(z>>x));
}
}
}
Display_Process(OLED_Display_Data);
}
这一步的难度在
OLED12864支持的是页写,之前做驱动的时候,刷屏是从左至右从上到下,但是WINDOWS上面,图片提取是,从左至右,从下至上。