stm32驱动ov7670 数据转BMP格式再转JPEG存储
一.搞了几天摄像头终于搞出来了一点成果,本打算用BMP格式保存读出的数据但是数据太大达到225k,后来又将BMP数据转成JPEG格式就小了很多,jpeg是有损压缩图片会变得不那么清晰。
搞出来的成果:
二.摄像头小知识:XCLK是输入摄像头的时钟,看别的原理图接的是一个12M的晶振,初始化的时候4倍频达到48M,这里没有接,用PA8输出8M内部6倍频达到48M,PCLK是摄像头输出的时钟达到12M,图像输出的是QVGA,RGB565格式,用的是VGA时序,一个像素需要2个pclk.
行输出时序图:
HREF是一个行信号,这个信号和mcu的一个引脚连接在SN74LVC1G00D(与非门)上,和mcu一块控制fifo,当准备写fifo时,mcu发送高电平,这时fifo并没有被使能,只有当HREF产生高电平信号时,在PCLK的配合下将数据写到fifo中。
帧输出时序图:
VSYNC是帧同步信号,当摄像头采集到一帧数据,会发出帧同步信号,用外部中断捕获这个帧中断信号。
void EXTI4_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line4)==SET) //是4线的中断
{ if(OV7670_CS == 0)
{
if(ov_sta == 0)
{
OV7670_WRST=0; //复位写指针
OV7670_WRST=1;
OV7670_WREN=1; //允许写入FIFO
ov_sta=1;
}
else
{
OV7670_WRST=0; //复位写指针
OV7670_WRST=0;
OV7670_WREN=1; //允许写入FIFO
}
}
}
EXTI_ClearITPendingBit(EXTI_Line4); //清除EXTI4线路挂起位
}
三.读取数据并转换,也是仿照的别人的用的开源库。
void camera_refresh(void)
{
int width, height;
int j,i;
u16 color=0;
int col;
int t;
jpeg_compress_info *cinfo;
pt_buf = 0;
if(ov_sta)//有帧中断更新?
{
width = 320;//图像的宽度
height = 240;//图像的高度
cinfo = jpeg_create_compress();
if (!cinfo)
{
//printf("error in create cinfo, malloc faild!\n");
}
cinfo->image_width = width;
cinfo->image_height= height;
cinfo->output =(char *)JPG_enc_buf;//fopen("test.jpg", "wb");
jpeg_set_default(cinfo);
jpeg_start_compress(cinfo);
FLASH_SIZE1 = 8192;
OV7670_RRST=0; //开始复位读指针
OV7670_RCK_L;
OV7670_RCK_H;
OV7670_RCK_L;
OV7670_RRST=1; //复位读指针结束
OV7670_RCK_H;
for(j=0;j<240;j++)
{ //printf("第%u行",j);
for(i=319;i>=0;i--)
{
//高字节 数据位接的比较乱 根据实际情况修改
OV7670_RCK_L;
color = ((GPIOD->IDR&0xC000)>>14); //D14 D15
color |= ((GPIOD->IDR&0x0003)<<2); //D0 D1
color |= ((GPIOE->IDR&0x0780)>>3); //E7 8 9 10
OV7670_RCK_H;
color<<=8;
OV7670_RCK_L;
//低字节
color |= ((GPIOD->IDR&0xC000)>>14); //D14 D15
color |= ((GPIOD->IDR&0x0003)<<2); //D0 D1
color |= ((GPIOE->IDR&0x0780)>>3); //E7 8 9 10
OV7670_RCK_H;
R = (color>>8)&0xF8;
G = (color>>3)&0xFC;
B = (color<<3)&0xF8;
buffer[i*3+0] = R;//jpeg格式顺序RGB 如果是bmp格式写成BGR
buffer[i*3+1] = G;
buffer[i*3+2] = B;
}
jpeg_write_scanline(cinfo, buffer);//一行一行的压缩
}
jpeg_finish_compress(cinfo);
jpeg_destory_compress(cinfo);
//OV7670_CS=1;
ov_sta=0; //清零帧中断标记
//需要多少擦多少
for(i = 0;i<=(pt_buf/4096);i++)
{
W25QXX_Erase_Sector( 8192/4096+i );
}
for(t = 0;t<pt_buf;t++)
{
send_data(JPG_enc_buf[t]);//发送数据给上位机
}
W25QXX_Write_NoCheck((u8*)JPG_enc_buf,FLASH_SIZE1,pt_buf);//写到flash
}
}