bmp_888

使用场景以及原理

参考文章:截屏!使用FatFs存储24位色BMP图像至SD卡

代码示例

语言:C
编译器:Keil5
stm32库:HAL-1.5.x
串口:UART1

//你的屏幕一共有多少像素点
#define BMP_BUFFER (320*240)
//RGB888格式数据结构体,注意在内存中存储是以BGR的顺序(非RGB)
typedef struct {
	u8 B;
	u8 G;
	u8 R;
} bmp_24bit;

/* BMP的信息头文件一共占54个字节,由于保存的是24bit的RGB888像素数据,所以不需要调色板结构体 */
//BMP头文件
typedef __packed struct
{
    u16  bfType ;     //文件标志.只对'BM',用来识别BMP位图类型
    u32  bfSize ;	  //文件大小,占四个字节
    u16  bfReserved1 ;//保留
    u16  bfReserved2 ;//保留
    u32  bfOffBits ;  //从文件开始到位图数据(bitmap data)开始之间的的偏移量
}BITMAPFILEHEADER ;

//BMP信息头
typedef __packed struct
{
    u32 biSize ;		   		//说明BITMAPINFOHEADER结构所需要的字数。
    long  biWidth ;		   	//说明图象的宽度,以象素为单位 
    long  biHeight ;	   	//说明图象的高度,以象素为单位 
    u16  biPlanes ;	   		//为目标设备说明位面数,其值将总是被设为1 
    u16  biBitCount ;	   	//说明比特数/象素,其值为1、4、8、16、24、或32
	/*说明图象数据压缩的类型。其值可以是下述值之一:
	BI_RGB:没有压缩;
	BI_RLE8:每个象素8比特的RLE压缩编码,压缩格式由2字节组成(重复象素计数和颜色索引);  
	BI_RLE4:每个象素4比特的RLE压缩编码,压缩格式由2字节组成
	BI_BITFIELDS:每个象素的比特由指定的掩码决定。*/
    u32 biCompression ;  	
    u32 biSizeImage ;		//说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0  
    long  biXPelsPerMeter ;	//说明水平分辨率,用象素/米表示
    long  biYPelsPerMeter ;	//说明垂直分辨率,用象素/米表示
    u32 biClrUsed ;	  	 	//说明位图实际使用的彩色表中的颜色索引数
    u32 biClrImportant ; 	//说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。 
}BITMAPINFOHEADER ;

//整体信息头
typedef __packed struct
{ 
	BITMAPFILEHEADER bmfHeader;
	BITMAPINFOHEADER bmiHeader;  
}BITMAPINFO; 


//定义接下来在主函数中使用的头文件变量
BITMAPINFO bmp_head;
//文件系统相关变量
FIL fnew;
FRESULT res_file;
UINT fnum;

int main(void)
{
	//省略
	LCD_Init();                     //初始化LCD
	SRAM_Init();					//初始化外部SRAM  
	//省略
	my_mem_init(SRAMIN);			//初始化内部内存池
	my_mem_init(SRAMEX);			//初始化外部内存池
	//省略挂载Fatfs,默认SD卡挂载到":0"

	//给bmp_data开辟内存空间
	bmp_data = (bmp_24bit *)mymalloc(SRAMEX,BMP_BUFFER*sizeof(bmp_24bit));

	//填写文件信息头信息  
	bmp_head.bmfHeader.bfType = 0x4D42;			//bmp_head类型  "BM"
	bmp_head.bmfHeader.bfSize= sizeof(BITMAPINFO) + BMP_BUFFER*sizeof(bmp_24bit);	//文件大小(信息结构体+像素数据)
	printf("bfSize = 0x%x \r\n",bmp_head.bmfHeader.bfSize);
	bmp_head.bmfHeader.bfReserved1 = 0x0000;		//保留,必须为0
	bmp_head.bmfHeader.bfReserved2 = 0x0000;  		//保留,必须为0	
	bmp_head.bmfHeader.bfOffBits=sizeof(BITMAPINFO);				//位图信息结构体所占的字节数
	
	//填写位图信息头信息  
	bmp_head.bmiHeader.biSize=40;  			//位图信息头的大小(固定)
	bmp_head.bmiHeader.biWidth=240;  		//位图的宽度
	bmp_head.bmiHeader.biHeight=320;  		//图像的高度
	bmp_head.bmiHeader.biPlanes=1;  		//目标设别的级别,必须是1
	bmp_head.bmiHeader.biBitCount=24;       //每像素位数
	bmp_head.bmiHeader.biCompression=0;  	//RGB888格式,不用压缩
	bmp_head.bmiHeader.biSizeImage= 0;		//实际位图所占用的字节数(仅考虑位图像素数据)
	bmp_head.bmiHeader.biXPelsPerMeter=0;	//水平分辨率
	bmp_head.bmiHeader.biYPelsPerMeter=0; 	//垂直分辨率
	bmp_head.bmiHeader.biClrImportant=0;   	//说明图像显示有重要影响的颜色索引数目,0代表所有的颜色一样重要
	bmp_head.bmiHeader.biClrUsed=0;  		//位图实际使用的彩色表中的颜色索引数,0表示使用所有的调色板项

	/*--------------------- 文件系统测试:写测试 -----------------------*/
	/* 打开文件,如果文件不存在则创建它 */
	printf("》写bmp头文件!\r\n");
	res_file = f_open(&fnew, "0:bmp测试.bmp",FA_CREATE_ALWAYS|FA_WRITE);
	if(res_file == FR_OK)
	{
		printf("》正在写bmp头中...!\r\n");
		res_file = f_write(&fnew, &bmp_head,sizeof(bmp_head), &fnum);
		if(res_file == FR_OK)
		{
			printf("》文件写入成功,写入字节数据:%d\n",fnum);
		}
		else
		{
			printf("!!文件写入失败:(%d)\n",res_file);
		}
		f_close(&fnew);
	}
	else
	{
		printf("!!创建文件失败:(%d)\n",res_file);
	}

	p_bmp = bmp_data;
	//获取LCD显示数据
	for(temp_y = 319;temp_y != 0xffff;temp_y --)
	{
		for(temp_x = 0;temp_x < 240;temp_x ++)
		{
			rgb_16bit = LCD_ReadPoint(temp_x,temp_y);
			p_bmp->R = (u8)((rgb_16bit & 0xF800) >> 8); 
			p_bmp->G = (u8)((rgb_16bit & 0x07E0) >> 3);
			p_bmp->B = (u8)((rgb_16bit & 0x001F) << 3);
			//·printf("p_bmp = 0X%x, R = 0X%x, G = 0X%x, B = 0X%x \r\n",(uint32_t )p_bmp, (uint32_t )p_bmp->R, (uint32_t )p_bmp->G, (uint32_t )p_bmp->B);
			p_bmp ++;
		
		}
	}
	//printf("bmp_data = 0X%x, R = 0X%x, G = 0X%x, B = 0X%x \r\n",(uint32_t )bmp_data, (uint32_t )bmp_data->R, (uint32_t )bmp_data->G, (uint32_t )bmp_data->B);
	printf("\n\r 》写bmp数据!\r\n");
	res_file = f_open(&fnew, "0:bmp测试.bmp",FA_OPEN_EXISTING|FA_WRITE);
	
	if(res_file == FR_OK)
	{
		//寻找到打开文件的末尾,添加数据
		f_lseek(&fnew,f_size(&fnew));
		printf("》寻找文件的结尾成功,写入bmp数据中...!\r\n");
		//这里注意第二个参数直接填写数组名就可以,默认指向最开始的地址        
		res_file = f_write(&fnew, bmp_data, BMP_BUFFER*sizeof(bmp_24bit), &fnum);
		if(res_file == FR_OK)
		{
			printf("》文件写入成功,写入字节数据:%d\n",fnum);
		}
		else
		{
			printf("!!文件写入失败:(%d)\n",res_file);
		}
		f_close(&fnew);
	}
	else
	{
		printf("!!写入数据失败:(%d)\n",res_file);
	}

}

待解决问题

在开辟内存空间bmp_data = (bmp_24bit )mymalloc(SRAMEX,320240*sizeof(bmp_24bit));的时候,如果开辟到SRAMIN的话就会出现错误,但是SRAMEX就没有BUG,待解决。

注意

指向新开辟内存的指针不能动,比如bmp_data,可以设置一个p_bmp,使用这个指针对bmp_data数组进行修改等操作。