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
}
}