004-Zynq实现SD卡存储灰度图片(彩色图片存储正点已开源)


前言

最近在弄SD卡存储灰度图片,参考了正点原子的OV7725照相机实验,但发现最终存储出来打不开,用专门的软件去看发现其中的数据全部乱码。后面发现正点原子存储的是彩色24位深度的图片,与我存储灰度图片不符合,到网上搜了一下灰度bmp图片的存储格式,加上自己查看了一下灰度图片的二进制数据解析,最终解决了问题。


一、为什么参考ov7725照相机实验存储不了灰度?

按照我的理解,原因其实很简单。存储彩色图片时通过BMP文件的文件头已经告诉了这张图片是彩图,彩图是由24位RGB数据组成的,那么总共就有256256256种颜色数据,这个颜色数据事先电脑就已经知道了,而且通用的存储也是按照这个来的,所以我们不需要把每一个颜色数据录入进去。

但灰度图片不一样,搜索才知道八位的灰度图存储需要在BMP的文件头后面添加像素表,才能够正常存储。这个像素表就是按照0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x00这种格式写在BMP的头文件后面,一直写到0xff,0xff,0xff,0x00才结束,这样整个BMP的文件头就有256*4+原先的54位文件头数据=1078个八进制数据。后面的存储格式就按照彩色文件存储的格式来就行了,解决了这个问题以后灰度图片就能够顺利存储。

二、SD卡实现步骤

1.配置Zynq核中的SD卡接口

直接点击SD0或者点击MIO Configuration进入配置界面即可
在这里插入图片描述
根据你的需求选择SD卡对应电平,我的板载上是1.8V的电平,MIO40…45引脚都是必选的,至于CD引脚,查阅资料可知是对SD卡是否插入进行检测的引脚,如果你有检测的需求,且板子上也把这个引脚连接到了对应的MIO引脚上,那么你就可以把CD引脚进行一个检测,一般来说CD引脚是上拉到电源处。一旦接入到外壳里面,就会短接到地,通过检测低电平可以判断SD卡是否插入(具体还请看你自己的板子原理图,一般是这样的)。我的板载上面并没有对CD引脚进行检测,故此处不勾选,其他两个WP是检测你的SD卡是否处于写保护状态,如果是高电平就没有办法写入数据进去,power是电源,一般不用设置。
在这里插入图片描述
设置完这一切以后就进入到PS端的设置界面。

2.PS端勾选xilffs

右键你的bsp文件,选择board support package settings,就进入到了这个设计界面,勾选xilffs,同时点击左上角standalone里面的xilffs,进行更详细的配置。
在这里插入图片描述
我一般都是默认配置,但是今天忘记这个茬了,移植的时候发现出不来存储的图像。这个use_lfn默认是0,或者说是false。他这个玩意儿的作用是当你的文件命名字符超过8个字符或者中文字符特殊字符啥的以后,如果为false的话,图片就存储不了。如果这个为true或者1的时候,那么就没什么问题,今天移植的时候查出来最后的问题就是这个。配置完了以后就是咱们的代码单元了。
在这里插入图片描述

3.PS端代码

先引用两个头文件

#include "ff.h"
#include "xdevcfg.h"

把该定义的定义了,image_addr就是你想拍照的图片地址。bmp_addr就是我们拍照的图片地址+偏移的地址,这样相当于开辟出了一个新的存储空间。作用就是防止我们去写入的时候要拍照的那张图片被原先的数据覆盖。

#define image_addr 0x01000000
static FATFS fatfs;
//BMP图片文件头,八位的灰度图需要像素表才行
u8 bmp_head[1078] = {
     0x42,0x4d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x36,0x0,0x0,0x0,0x28,0x0,
	 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x08,0x0,0x0,0x0,
	 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x01,
	 0x0,0x0,0x0,0x0,0x0,0x0,0x00,0x00,0x00,0x00,
	 0x01,0x01,0x01,0x00,0x02,0x02,0x02,0x00,0x03,0x03,0x03,0x00,0x04,0x04,0x04,0x00,
	 0x05,0x05,0x05,0x00,0x06,0x06,0x06,0x00,0x07,0x07,0x07,0x00,0x08,0x08,0x08,0x00,
	 0x09,0x09,0x09,0x00,0x0A,0x0A,0x0A,0x00,0x0B,0x0B,0x0B,0x00,0x0C,0x0C,0x0C,0x00,
	 0x0D,0x0D,0x0D,0x00,0x0E,0x0E,0x0E,0x00,0x0F,0x0F,0x0F,0x00,0x10,0x10,0x10,0x00,
	 0x11,0x11,0x11,0x00,0x12,0x12,0x12,0x00,0x13,0x13,0x13,0x00,0x14,0x14,0x14,0x00,
	 0x15,0x15,0x15,0x00,0x16,0x16,0x16,0x00,0x17,0x17,0x17,0x00,0x18,0x18,0x18,0x00,
	 0x19,0x19,0x19,0x00,0x1A,0x1A,0x1A,0x00,0x1B,0x1B,0x1B,0x00,0x1C,0x1C,0x1C,0x00,
	 0x1D,0x1D,0x1D,0x00,0x1E,0x1E,0x1E,0x00,0x1F,0x1F,0x1F,0x00,0x20,0x20,0x20,0x00,
	 0x21,0x21,0x21,0x00,0x22,0x22,0x22,0x00,0x23,0x23,0x23,0x00,0x24,0x24,0x24,0x00,
	 0x25,0x25,0x25,0x00,0x26,0x26,0x26,0x00,0x27,0x27,0x27,0x00,0x28,0x28,0x28,0x00,
	 0x29,0x29,0x29,0x00,0x2A,0x2A,0x2A,0x00,0x2B,0x2B,0x2B,0x00,0x2C,0x2C,0x2C,0x00,
	 0x2D,0x2D,0x2D,0x00,0x2E,0x2E,0x2E,0x00,0x2F,0x2F,0x2F,0x00,0x30,0x30,0x30,0x00,
	 0x31,0x31,0x31,0x00,0x32,0x32,0x32,0x00,0x33,0x33,0x33,0x00,0x34,0x34,0x34,0x00,
	 0x35,0x35,0x35,0x00,0x36,0x36,0x36,0x00,0x37,0x37,0x37,0x00,0x38,0x38,0x38,0x00,
	 0x39,0x39,0x39,0x00,0x3A,0x3A,0x3A,0x00,0x3B,0x3B,0x3B,0x00,0x3C,0x3C,0x3C,0x00,
	 0x3D,0x3D,0x3D,0x00,0x3E,0x3E,0x3E,0x00,0x3F,0x3F,0x3F,0x00,0x40,0x40,0x40,0x00,
	 0x41,0x41,0x41,0x00,0x42,0x42,0x42,0x00,0x43,0x43,0x43,0x00,0x44,0x44,0x44,0x00,
	 0x45,0x45,0x45,0x00,0x46,0x46,0x46,0x00,0x47,0x47,0x47,0x00,0x48,0x48,0x48,0x00,
	 0x49,0x49,0x49,0x00,0x4A,0x4A,0x4A,0x00,0x4B,0x4B,0x4B,0x00,0x4C,0x4C,0x4C,0x00,
	 0x4D,0x4D,0x4D,0x00,0x4E,0x4E,0x4E,0x00,0x4F,0x4F,0x4F,0x00,0x50,0x50,0x50,0x00,
	 0x51,0x51,0x51,0x00,0x52,0x52,0x52,0x00,0x53,0x53,0x53,0x00,0x54,0x54,0x54,0x00,
	 0x55,0x55,0x55,0x00,0x56,0x56,0x56,0x00,0x57,0x57,0x57,0x00,0x58,0x58,0x58,0x00,
	 0x59,0x59,0x59,0x00,0x5A,0x5A,0x5A,0x00,0x5B,0x5B,0x5B,0x00,0x5C,0x5C,0x5C,0x00,
	 0x5D,0x5D,0x5D,0x00,0x5E,0x5E,0x5E,0x00,0x5F,0x5F,0x5F,0x00,0x60,0x60,0x60,0x00,
	 0x61,0x61,0x61,0x00,0x62,0x62,0x62,0x00,0x63,0x63,0x63,0x00,0x64,0x64,0x64,0x00,
	 0x65,0x65,0x65,0x00,0x66,0x66,0x66,0x00,0x67,0x67,0x67,0x00,0x68,0x68,0x68,0x00,
	 0x69,0x69,0x69,0x00,0x6A,0x6A,0x6A,0x00,0x6B,0x6B,0x6B,0x00,0x6C,0x6C,0x6C,0x00,
	 0x6D,0x6D,0x6D,0x00,0x6E,0x6E,0x6E,0x00,0x6F,0x6F,0x6F,0x00,0x70,0x70,0x70,0x00,
	 0x71,0x71,0x71,0x00,0x72,0x72,0x72,0x00,0x73,0x73,0x73,0x00,0x74,0x74,0x74,0x00,
	 0x75,0x75,0x75,0x00,0x76,0x76,0x76,0x00,0x77,0x77,0x77,0x00,0x78,0x78,0x78,0x00,
	 0x79,0x79,0x79,0x00,0x7A,0x7A,0x7A,0x00,0x7B,0x7B,0x7B,0x00,0x7C,0x7C,0x7C,0x00,
	 0x7D,0x7D,0x7D,0x00,0x7E,0x7E,0x7E,0x00,0x7F,0x7F,0x7F,0x00,0x80,0x80,0x80,0x00,
	 0x81,0x81,0x81,0x00,0x82,0x82,0x82,0x00,0x83,0x83,0x83,0x00,0x84,0x84,0x84,0x00,
	 0x85,0x85,0x85,0x00,0x86,0x86,0x86,0x00,0x87,0x87,0x87,0x00,0x88,0x88,0x88,0x00,
	 0x89,0x89,0x89,0x00,0x8A,0x8A,0x8A,0x00,0x8B,0x8B,0x8B,0x00,0x8C,0x8C,0x8C,0x00,
	 0x8D,0x8D,0x8D,0x00,0x8E,0x8E,0x8E,0x00,0x8F,0x8F,0x8F,0x00,0x90,0x90,0x90,0x00,
	 0x91,0x91,0x91,0x00,0x92,0x92,0x92,0x00,0x93,0x93,0x93,0x00,0x94,0x94,0x94,0x00,
	 0x95,0x95,0x95,0x00,0x96,0x96,0x96,0x00,0x97,0x97,0x97,0x00,0x98,0x98,0x98,0x00,
	 0x99,0x99,0x99,0x00,0x9A,0x9A,0x9A,0x00,0x9B,0x9B,0x9B,0x00,0x9C,0x9C,0x9C,0x00,
	 0x9D,0x9D,0x9D,0x00,0x9E,0x9E,0x9E,0x00,0x9F,0x9F,0x9F,0x00,0xA0,0xA0,0xA0,0x00,
	 0xA1,0xA1,0xA1,0x00,0xA2,0xA2,0xA2,0x00,0xA3,0xA3,0xA3,0x00,0xA4,0xA4,0xA4,0x00,
	 0xA5,0xA5,0xA5,0x00,0xA6,0xA6,0xA6,0x00,0xA7,0xA7,0xA7,0x00,0xA8,0xA8,0xA8,0x00,
	 0xA9,0xA9,0xA9,0x00,0xAA,0xAA,0xAA,0x00,0xAB,0xAB,0xAB,0x00,0xAC,0xAC,0xAC,0x00,
	 0xAD,0xAD,0xAD,0x00,0xAE,0xAE,0xAE,0x00,0xAF,0xAF,0xAF,0x00,0xB0,0xB0,0xB0,0x00,
	 0xB1,0xB1,0xB1,0x00,0xB2,0xB2,0xB2,0x00,0xB3,0xB3,0xB3,0x00,0xB4,0xB4,0xB4,0x00,
	 0xB5,0xB5,0xB5,0x00,0xB6,0xB6,0xB6,0x00,0xB7,0xB7,0xB7,0x00,0xB8,0xB8,0xB8,0x00,
	 0xB9,0xB9,0xB9,0x00,0xBA,0xBA,0xBA,0x00,0xBB,0xBB,0xBB,0x00,0xBC,0xBC,0xBC,0x00,
	 0xBD,0xBD,0xBD,0x00,0xBE,0xBE,0xBE,0x00,0xBF,0xBF,0xBF,0x00,0xC0,0xC0,0xC0,0x00,
	 0xC1,0xC1,0xC1,0x00,0xC2,0xC2,0xC2,0x00,0xC3,0xC3,0xC3,0x00,0xC4,0xC4,0xC4,0x00,
	 0xC5,0xC5,0xC5,0x00,0xC6,0xC6,0xC6,0x00,0xC7,0xC7,0xC7,0x00,0xC8,0xC8,0xC8,0x00,
	 0xC9,0xC9,0xC9,0x00,0xCA,0xCA,0xCA,0x00,0xCB,0xCB,0xCB,0x00,0xCC,0xCC,0xCC,0x00,
	 0xCD,0xCD,0xCD,0x00,0xCE,0xCE,0xCE,0x00,0xCF,0xCF,0xCF,0x00,0xD0,0xD0,0xD0,0x00,
	 0xD1,0xD1,0xD1,0x00,0xD2,0xD2,0xD2,0x00,0xD3,0xD3,0xD3,0x00,0xD4,0xD4,0xD4,0x00,
	 0xD5,0xD5,0xD5,0x00,0xD6,0xD6,0xD6,0x00,0xD7,0xD7,0xD7,0x00,0xD8,0xD8,0xD8,0x00,
	 0xD9,0xD9,0xD9,0x00,0xDA,0xDA,0xDA,0x00,0xDB,0xDB,0xDB,0x00,0xDC,0xDC,0xDC,0x00,
	 0xDD,0xDD,0xDD,0x00,0xDE,0xDE,0xDE,0x00,0xDF,0xDF,0xDF,0x00,0xE0,0xE0,0xE0,0x00,
	 0xE1,0xE1,0xE1,0x00,0xE2,0xE2,0xE2,0x00,0xE3,0xE3,0xE3,0x00,0xE4,0xE4,0xE4,0x00,
	 0xE5,0xE5,0xE5,0x00,0xE6,0xE6,0xE6,0x00,0xE7,0xE7,0xE7,0x00,0xE8,0xE8,0xE8,0x00,
	 0xE9,0xE9,0xE9,0x00,0xEA,0xEA,0xEA,0x00,0xEB,0xEB,0xEB,0x00,0xEC,0xEC,0xEC,0x00,
	 0xED,0xED,0xED,0x00,0xEE,0xEE,0xEE,0x00,0xEF,0xEF,0xEF,0x00,0xF0,0xF0,0xF0,0x00,
	 0xF1,0xF1,0xF1,0x00,0xF2,0xF2,0xF2,0x00,0xF3,0xF3,0xF3,0x00,0xF4,0xF4,0xF4,0x00,
	 0xF5,0xF5,0xF5,0x00,0xF6,0xF6,0xF6,0x00,0xF7,0xF7,0xF7,0x00,0xF8,0xF8,0xF8,0x00,
	 0xF9,0xF9,0xF9,0x00,0xFA,0xFA,0xFA,0x00,0xFB,0xFB,0xFB,0x00,0xFC,0xFC,0xFC,0x00,
	 0xFD,0xFD,0xFD,0x00,0xFE,0xFE,0xFE,0x00,0xFF,0xFF,0xFF,0x00
};
//BMP图片各参数偏移地址
UINT *bf_size    = (UINT *)(bmp_head + 0x2);
UINT *bmp_width  = (UINT *)(bmp_head + 0x12);
UINT *bmp_height = (UINT *)(bmp_head + 0x16);
UINT *bmp_size   = (UINT *)(bmp_head + 0x22);
//BMP图片编号
int  pic_cnt = 0;

//抓拍的图片显存地址
unsigned int const bmp_addr = (image_addr + 0x10000000);
//frame buffer的起始地址
unsigned int const frame_buffer_addr = image_addr;
//将显存图像以BMP格式写入SD卡
void write_sd_bmp(u8 *frame);

写入图片到SD卡的函数write_sd_bmp为

//向SD卡中写BMP图片
void write_sd_bmp(u8 *frame)
{
	FIL 	fil;			//文件对象
	UINT 	bw;				//写文件函数返回已写入的字节数
	char    pic_name[20];	//字符串,用于存储BMP文件名
	//给BMP图片的文件名编号
	sprintf(pic_name,"picture %04u.bmp",pic_cnt);
	//打开BMP文件,如果不存在则创建该文件
	f_open(&fil,pic_name,FA_CREATE_ALWAYS | FA_WRITE);
	//移动文件读写指针到文件开头
	f_lseek(&fil,0);
	//写入BMP文件头
	f_write(&fil,bmp_head,1078,&bw);
	//写入抓拍的图片
	f_write(&fil,frame,*bmp_size,&bw);
	//关闭文件
	f_close(&fil);
	xil_printf("write %s done! \n\r",pic_name);
}

所有的代码已经准备完毕,接下来就是到我们的主函数中调用。在主函数的初始化中,我们需要初始化以下的函数。这些初始化的内容是添加到你自己的初始化前面,加入进去即可。

int main()
{
	unsigned int rd_fram_addr;	//VDMA读通道操作的帧缓存地址
	//SD卡协议定义
	*bmp_width  = 1280;
	*bmp_height = 720;
	*bmp_size   = 1280 * 720;
	*bf_size    = *bmp_size + 1078;
	//挂载文件系统
	f_mount(&fatfs,"",1);
    return 0;
}

调用的格式为以下,那么这个wr_index_one是我的帧缓存号,我设置了三帧缓存,所以根据wr_index_one的大小,比如为3,代表我正在写入第三帧缓存,这个时候我就去读取前一帧,也就是第二帧。如果为1的话,我就去读第三帧,也就是21280720的一个帧偏移地址,我存储图片的基地址是0x01000000。如果你们有确认的地址了,就直接把确定的地址赋值给rd_fram_addr即可。最终通过write_sd_bmp函数将图片数据写入到bmp文件中,同时pic_cnt加1,相当于图片编号加1。

if(wr_index_one>1)
{
	rd_fram_addr = 0x01000000+(wr_index_one-2)*1280*720;
}
else
{
	rd_fram_addr = 0x01000000+2*1280*720;
}
//将当前帧的图像拷贝到抓拍图片缓存区域
memcpy((void *)bmp_addr,(void *)rd_fram_addr,1280*720);
//将抓拍图片缓存区域中的图像以BMP格式写入SD卡
write_sd_bmp((u8 *)bmp_addr);
pic_cnt++;
xil_printf("image_memory_status_sucess\r\n");

4.读卡器读取SD卡结果呈现

我大概是以30帧的速率去拍,因此很短的时间内就存储了比较多的图片,可以看到编号是以此递增的,也就是提到的pic_cnt,跟我们的命名规范有关系,你可以根据自己的需求去命名,在这个基础上去改动。
在这里插入图片描述


总结

今天在新板子上把以太网和SD卡移植成功了,好心情。临近正午,太阳火热,就去了食堂吃饭,吃的牛肉+韭菜炒蛋,我发誓,这韭菜炒蛋我再吃我就是猪,难吃死了,破坏我的好心情,下次再也不吃韭菜炒蛋了。又贵,两个加在一起17.5,真是一次不愉快的用餐体验~~~

  • 18
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值