目录
本节我们学习的是照相机实验,主要的功能就是将照片拍下,然后把数据解码,最后将图片数据保存到SD卡里,在运用上节课的图片显示实验来显示。
BMP文件头
BMP文件头(14字节):BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。BMP文件头结构体定义如下:
//BMP文件头
typedef __packed struct
{
u16 bfType; //文件标志,只对‘B’‘M’,用来识别BMP位图类型
u32 bfSize; //文件大小,占四个字节
u16 bfReserved1;//保留
u16 bfReserved2;//保留
u32 bfOffBits; //从文件开始到位图数据(bitmap data)开始之间的偏移量
}BITMAPFILEHADER;位图信息头
位图信息头(40字节):BMP位图信息头数据用于说明位图的尺寸等信息。 BMP位图信息头结构体定义如下: 设置biCompression的值时一般不会设置为BI_RLE84和BI_RLE8,经常设置为BI_BITFIELDS如果是16位图时会直接设置为BI_BITFIELDS。biSizeImage是根据biWidth、 biHeight、biBitCount计算出一个字节数来设置。剩下的几个一般设置为0。
typedef __packed struct
{
u32 biSize ; //说明BITMAPINFOHEADER结构(本结构体)所需要的字数。
long biWidth ; //说明图象的宽度,以象素为单位
long biHeight ; //说明图象的高度,以象素为单位
u16 biPlanes ; //为目标设备说明位面数,其值将总是被设为1
u16 biBitCount ; //说明比特数/象素,其值为1、4、8、16、24、或32
u32 biCompression ; //说明图象数据压缩的类型。其值可以是下述值之一:
//0:BI_RGB:没有压缩;
//1:BI_RLE8:每个象素8比特的RLE压缩编码,压缩格式由2字节组成
//2:BI_RLE4:每个象素4比特的RLE压缩编码,压缩格式由2字节组成
//3:BI_BITFIELDS:每个象素的比特由指定的掩码决定。
u32 biSizeImage ; //说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0
long biXPelsPerMeter ; //说明水平分辨率,用象素/米表示
long biYPelsPerMeter ; //说明垂直分辨率,用象素/米表示
u32 biClrUsed ; //说明位图实际使用的彩色表中的颜色索引数
u32 biClrImportant ; //说明对图象显示有重要影响的颜色索引的数目,
//如果是0,表示都重要。 颜色表
颜色表(调色板):颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色,如下所示:
typedef __packed struct
{
u8 rgbBlue ; //指定蓝色强度
u8 rgbGreen ; //指定绿色强度
u8 rgbRed ; //指定红色强度
u8 rgbReserved ; //保留,设置为0
}RGBQUAD ;RGBQUAD结构数据的个数由biBitCount来确定:当biBitCount=1、4、8时,分别有2、16、256个表项;当biBitCount大于8时,没有颜色表项。
BMP文件头、位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下:
typedef __packed struct
{
BITMAPFILEHADER bmfHeader;
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
}BITMAPINFO;位图数据
位图数据:记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图一个像素值所占字节数:
当biBitCount=1时,8个像素占1个字节; 当biBitCount=4时,2个像素占1个字节; 当biBitCount=8时,1个像素占1个字节; 当biBitCount=16时,1个像素占2个字节; 当biBitCount=24时,1个像素占3个字节; 当biBitCount=32时,1个像素占4个字节;
biBitCount=16,即高彩色(65K色)。当biCompression=BI_RGB(0),则采用RGB555格式,最高位恒为0;当biCompression= BI_BITFIELDS(3),则在原来调色板位置用3个DWORD类型的掩码替换,分别代表红、绿、蓝三色的掩码,一般是: 0X7C00(高5位)、0X03E0(中6位)、0X001F(低5位)。
我们采用16位BMP编码(因为LCD就是16位色的,而且16位BMP编码比24位BMP编码更省空间),故我们需要设置biBitCount的值为16,这样得到新的位图信息(BITMAPINFO)结构体。
typedef __packed struct
{
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bmiHeader;
u32 RGB_MASK[3]; //调色板用于存放RGB掩码
}BITMAPINFO; RGB_MASK[3],即颜色掩码,分别代表红、绿、蓝三色的掩码,分别是: 0X7C00、0X03E0、0X001F。
本例程使用DMA的双缓冲机制来读取,DMA双缓冲读取JPEG数据框图如下图:

给出main函数的部分代码。
while(1)
{
key=KEY_Scan(0);//不支持连按
if(key)
{
DCMI_Stop(); //停止显示
if(key==WKUP_PRES)
{
scale=!scale;
if(scale==0)
{
if(lcddev.id == 0X5510)
{
SCCB_WR_Reg(0xd3,0x02);
}
OV2640_ImageWin_Set((1600-lcddev.width)/2,(1200-lcddev.height)/2,lcddev.width,lcddev.height);//1:1真实尺寸
OV2640_OutSize_Set(lcddev.width,lcddev.height);
sprintf((char*)msgbuf,"Full Size 1:1");
}else
{
OV2640_ImageWin_Set(0,0,1600,1200); //全尺寸缩放
OV2640_OutSize_Set(lcddev.width,lcddev.height);
sprintf((char*)msgbuf,"Scale");
}
LCD_ShowString(30,50,210,16,16,msgbuf);//显示提示内容
delay_ms(800);
}else if(sd_ok)//SD卡正常才可以拍照
{
sw_sdcard_mode(); //切换为SD卡模式
if(key==KEY0_PRES) //BMP拍照
{
camera_new_pathname(pname,0);//得到文件名
res=bmp_encode(pname,0,0,lcddev.width,lcddev.height,0);
}else if(key==KEY1_PRES)//JPG拍照
{
camera_new_pathname(pname,1);//得到文件名
res=ov2640_jpg_photo(pname);
if(scale==0)
{
OV2640_ImageWin_Set((1600-lcddev.width)/2,(1200-lcddev.height)/2,lcddev.width,lcddev.height);//1:1真实尺寸
OV2640_OutSize_Set(lcddev.width,lcddev.height);
}else
{
OV2640_ImageWin_Set(0,0,1600,1200); //全尺寸缩放
}
OV2640_OutSize_Set(lcddev.width,lcddev.height);
}
sw_ov2640_mode(); //切换为OV2640模式
if(res)//拍照有误
{
Show_Str(30,130,240,16,"写入文件错误!",16,0);
}else
{
Show_Str(30,130,240,16,"拍照成功!",16,0);
Show_Str(30,150,240,16,"保存为:",16,0);
Show_Str(30+42,150,240,16,pname,16,0);
BEEP=1; //蜂鸣器短叫,提示拍照完成
delay_ms(100);
}
}else //提示SD卡错误
{
Show_Str(30,130,240,16,"SD卡错误!",16,0);
Show_Str(30,150,240,16,"拍照功能不可用!",16,0);
}
BEEP=0; //关闭蜂鸣器
if(key!=WKUP_PRES)delay_ms(1800);//非尺寸切换,等待1.8秒钟
DCMI_Start(); //停止显示
}
if (hsync_int) //刚刚产生帧中断,可以延时
{
delay_ms(10);
hsync_int = 0;
}
i++;
if(i==20)//DS0闪烁.
{
i=0;
LED0=!LED0;
}本实验还是挺有趣的,和前面结合在一起,但没能完全掌握,还得慢慢理解。