基于STM32的OV7725摄像头拍照实验
生活随笔
收集整理的這篇文章主要介紹了
基于STM32的OV7725摄像头拍照实验
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
平臺:STM32ZET6(核心板)+ST-LINK/V2+SD卡+USB串口線+鷹眼OV7725攝像頭(注意,為了減少攝像頭連線的麻煩,建議初學者選取單片機時選用帶有攝像頭接口的板子)
工程介紹:需要移植FatFs文件系統,同時需要了解BMP位圖的存儲數據結構,從而實現將攝像頭輸出的RGB565像素數據直接輸出到sd卡上,保存為*.bmp文件。
1. BMP位圖的存儲
1.1?數據結構介紹
//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 {u8 rgbBlue ; ????//指定藍色強度u8 rgbGreen ; //指定綠色強度 u8 rgbRed ; //指定紅色強度 u8 rgbReserved ;????//保留,設置為0 }RGBQUAD ; //整體信息頭(以上數據結構的組合) typedef __packed struct { BITMAPFILEHEADER bmfHeader;BITMAPINFOHEADER bmiHeader; RGBQUAD RGB_MASK[3]; //調色板用于存放RGB掩碼. }BITMAPINFO;1.2 設置方法
//提前檢查是否需要保存圖片if(ov_sta && KEY_Scan(S1))//按鍵1按下(拍照){printf("開始保存圖片\r\n");//打開文件,若不存在就創建res_sd = f_open(&fnew, "0:test1.bmp", FA_OPEN_ALWAYS | FA_WRITE);//文件打開成功if(res_sd == FR_OK){//填寫文件信息頭信息 bmp.bmfHeader.bfType = 0x4D42; //bmp類型 bmp.bmfHeader.bfSize= 54 + 320*240*2; ????????//文件大小(信息結構體+像素數據)bmp.bmfHeader.bfReserved1 = 0x0000; //保留,必須為0bmp.bmfHeader.bfReserved2 = 0x0000; bmp.bmfHeader.bfOffBits=54; //位圖信息結構體所占的字節數//填寫位圖信息頭信息 bmp.bmiHeader.biSize=40; ????????????//位圖信息頭的大小bmp.bmiHeader.biWidth=320; ????//位圖的寬度bmp.bmiHeader.biHeight=240; //圖像的高度bmp.bmiHeader.biPlanes=1; ????????????//目標設別的級別,必須是1bmp.bmiHeader.biBitCount=16; ????????????//每像素位數bmp.bmiHeader.biCompression=0; ?????//RGB555格式bmp.bmiHeader.biSizeImage=320*240*2; ???????????? //實際位圖所占用的字節數(僅考慮位圖像素數據)bmp.bmiHeader.biXPelsPerMeter=0; //水平分辨率bmp.bmiHeader.biYPelsPerMeter=0; //垂直分辨率bmp.bmiHeader.biClrImportant=0; ??????????//說明圖像顯示有重要影響的顏色索引數目,0代表所有的顏色一樣重要bmp.bmiHeader.biClrUsed=0; //位圖實際使用的彩色表中的顏色索引數,0表示使用所有的調色板項//RGB565格式掩碼bmp.RGB_MASK[0].rgbBlue = 0;bmp.RGB_MASK[0].rgbGreen = 0xF8;bmp.RGB_MASK[0].rgbRed = 0;bmp.RGB_MASK[0].rgbReserved = 0;bmp.RGB_MASK[1].rgbBlue = 0xE0;bmp.RGB_MASK[1].rgbGreen = 0x07;bmp.RGB_MASK[1].rgbRed = 0;bmp.RGB_MASK[1].rgbReserved = 0;bmp.RGB_MASK[2].rgbBlue = 0x1F;bmp.RGB_MASK[2].rgbGreen = 0;bmp.RGB_MASK[2].rgbRed = 0;bmp.RGB_MASK[2].rgbReserved = 0;//寫文件頭進文件 res_sd= f_write(&fnew, &bmp, sizeof(bmp), &fnum);}//讀指針復位OV7725_RRST=0; //開始復位讀指針OV7725_RCK_L;OV7725_RCK_H;OV7725_RCK_L;OV7725_RRST=1; //復位讀指針結束 OV7725_RCK_H; /*圖像花屏的原因在于讀取時的干擾和讀取時漏掉幾個像素*/for(i=0;i<240;i++){for(j=0;j<320;j++){OV7725_RCK_L;color=GPIOC->IDR&0XFF; //讀數據OV7725_RCK_H; color<<=8; OV7725_RCK_L;color|=GPIOC->IDR&0XFF; //讀數據OV7725_RCK_H; //寫位圖信息頭進內存卡(FatFs中的方法)f_write(&fnew, &color, sizeof(color), &fnum);}}//關閉文件f_close(&fnew);delay_ms(1000);return;}2. OV7725驅動程序設計
2.1 OV7725寄存器設置
#ifndef _OV7725CFG_H #define _OV7725CFG_H #include "ov7725.h" /* OV7725寄存器宏定義 */ #define GAIN 0x00 #define BLUE 0x01 #define RED 0x02 #define RED 0x02 #define GREEN 0x03 #define BAVG 0x05 #define GAVG 0x06 #define RAVG 0x07 #define AECH 0x08 #define COM2 0x09 #define PID 0x0A #define VER 0x0B #define COM3 0x0C #define COM4 0x0D #define COM5 0x0E #define COM6 0x0F #define AEC 0x10 #define CLKRC 0x11 #define COM7 0x12 #define COM8 0x13 #define COM9 0x14 #define COM10 0x15 #define REG16 0x16 #define HSTART 0x17 #define HSIZE 0x18 #define VSTRT 0x19 #define VSIZE 0x1A #define PSHFT 0x1B #define MIDH 0x1C #define MIDL 0x1D #define LAEC 0x1F #define COM11 0x20 #define BDBase 0x22 #define BDMStep 0x23 #define AEW 0x24 #define AEB 0x25 #define VPT 0x26 #define REG28 0x28 #define HOutSize 0x29 #define EXHCH 0x2A #define EXHCL 0x2B #define VOutSize 0x2C #define ADVFL 0x2D #define ADVFH 0x2E #define YAVE 0x2F #define LumHTh 0x30 #define LumLTh 0x31 #define HREF 0x32 #define DM_LNL 0x33 #define DM_LNH 0x34 #define ADoff_B 0x35 #define ADoff_R 0x36 #define ADoff_Gb 0x37 #define ADoff_Gr 0x38 #define Off_B 0x39 #define Off_R 0x3A #define Off_Gb 0x3B #define Off_Gr 0x3C #define COM12 0x3D #define COM13 0x3E #define COM14 0x3F #define COM16 0x41 #define TGT_B 0x42 #define TGT_R 0x43 #define TGT_Gb 0x44 #define TGT_Gr 0x45 #define LC_CTR 0x46 #define LC_XC 0x47 #define LC_YC 0x48 #define LC_COEF 0x49 #define LC_RADI 0x4A #define LC_COEFB 0x4B #define LC_COEFR 0x4C #define FixGain 0x4D #define AREF1 0x4F #define AREF6 0x54 #define UFix 0x60 #define VFix 0x61 #define AWBb_blk 0x62 #define AWB_Ctrl0 0x63 #define DSP_Ctrl1 0x64 #define DSP_Ctrl2 0x65 #define DSP_Ctrl3 0x66 #define DSP_Ctrl4 0x67 #define AWB_bias 0x68 #define AWBCtrl1 0x69 #define AWBCtrl2 0x6A #define AWBCtrl3 0x6B #define AWBCtrl4 0x6C #define AWBCtrl5 0x6D #define AWBCtrl6 0x6E #define AWBCtrl7 0x6F #define AWBCtrl8 0x70 #define AWBCtrl9 0x71 #define AWBCtrl10 0x72 #define AWBCtrl11 0x73 #define AWBCtrl12 0x74 #define AWBCtrl13 0x75 #define AWBCtrl14 0x76 #define AWBCtrl15 0x77 #define AWBCtrl16 0x78 #define AWBCtrl17 0x79 #define AWBCtrl18 0x7A #define AWBCtrl19 0x7B #define AWBCtrl20 0x7C #define AWBCtrl21 0x7D #define GAM1 0x7E #define GAM2 0x7F #define GAM3 0x80 #define GAM4 0x81 #define GAM5 0x82 #define GAM6 0x83 #define GAM7 0x84 #define GAM8 0x85 #define GAM9 0x86 #define GAM10 0x87 #define GAM11 0x88 #define GAM12 0x89 #define GAM13 0x8A #define GAM14 0x8B #define GAM15 0x8C #define SLOP 0x8D #define DNSTh 0x8E #define EDGE0 0x8F #define EDGE1 0x90 #define DNSOff 0x91 #define EDGE2 0x92 #define EDGE3 0x93 #define MTX1 0x94 #define MTX2 0x95 #define MTX3 0x96 #define MTX4 0x97 #define MTX5 0x98 #define MTX6 0x99 #define MTX_Ctrl 0x9A #define BRIGHT 0x9B #define CNST 0x9C #define UVADJ0 0x9E #define UVADJ1 0x9F #define SCAL0 0xA0 #define SCAL1 0xA1 #define SCAL2 0xA2 #define SDE 0xA6 #define USAT 0xA7 #define VSAT 0xA8 #define HUECOS 0xA9 #define HUESIN 0xAA #define SIGN 0xAB #define DSPAuto 0xAC//初始化寄存器序列及其對應的值 const u8 ov7725_init_reg_tb1[][2]= { /*輸出窗口設置*/{CLKRC, 0x00}, //clock config{COM7, 0x06}, //VGA RGB565{HSTART, 0x3f}, //水平起始位置{HSIZE, 0x50}, //水平尺寸{VSTRT, 0x03}, //垂直起始位置{VSIZE, 0x78}, //垂直尺寸{HREF, 0x00},{HOutSize, 0x50}, //輸出尺寸{VOutSize, 0x78}, //輸出尺寸/*DSP control*/{TGT_B, 0x7f},{FixGain, 0x09},{AWB_Ctrl0, 0xe0},{DSP_Ctrl1, 0xff},{DSP_Ctrl2, 0x00},{DSP_Ctrl3, 0x00},{DSP_Ctrl4, 0x00},/*AGC AEC AWB*/{COM8, 0xf0},{COM4, 0x81}, /*Pll AEC CONFIG*/{COM6, 0xc5},{COM9, 0x11},{BDBase, 0x7F},{BDMStep, 0x03},{AEW, 0x40},{AEB, 0x30},{VPT, 0xa1},{EXHCL, 0x9e},{AWBCtrl3, 0xaa},{COM8, 0xff},/*matrix shapness brightness contrast*/{EDGE1, 0x08},{DNSOff, 0x01},{EDGE2, 0x03},{EDGE3, 0x00},{MTX1, 0xb0},{MTX2, 0x9d},{MTX3, 0x13},{MTX4, 0x16},{MTX5, 0x7b},{MTX6, 0x91},{MTX_Ctrl, 0x1e},{BRIGHT, 0x08},{CNST, 0x20},{UVADJ0, 0x81},{SDE, 0X06},{USAT, 0x65},{VSAT, 0x65},{HUECOS, 0X80},{HUESIN, 0X80},/*GAMMA config*/{GAM1, 0x0c},{GAM2, 0x16},{GAM3, 0x2a},{GAM4, 0x4e},{GAM5, 0x61},{GAM6, 0x6f},{GAM7, 0x7b},{GAM8, 0x86},{GAM9, 0x8e},{GAM10, 0x97},{GAM11, 0xa4},{GAM12, 0xaf},{GAM13, 0xc5},{GAM14, 0xd7},{GAM15, 0xe8},{SLOP, 0x20},{COM3, 0x50},/*Horizontal mirror image*///注:datasheet默認0x10,即改變YUV為UVY格式。但是攝像頭不是芯片而是模組時,//要將0X10中的1變成0,即設置YUV格式。/*night mode auto frame rate control*/ {COM5, 0xf5}, /*在夜視環境下,自動降低幀率,保證低照度畫面質量*///{COM5, 0x31}, /*夜視環境幀率不變*/}; #endif2.2 OV7725初始化
#define OV7725_MID 0X7FA2 #define OV7725_PID 0X7721#define OV7725_VSYNC PAin(8) ????????//同步信號檢測IO #define OV7725_WRST PDout(6) //寫指針復位 #define OV7725_WREN PBout(3) //寫入FIFO使能 #define OV7725_RCK_H GPIOB->BSRR=1<<4????????????????//設置讀數據時鐘高電平 #define OV7725_RCK_L GPIOB->BRR=1<<4 ????????????????//設置讀數據時鐘低電平 #define OV7725_RRST PGout(14) //讀指針復位 #define OV7725_CS PGout(15) //片選信號(OE)#define OV7725_DATA GPIO_ReadInputData(GPIOC,0x00FF) //數據輸入端口 #include "sys.h" #include "ov7725.h" #include "ov7725config.h" #include "delay.h" #include "usart.h" #include "sccb.h" //初始化OV7725 //返回0:成功 //返回其他值:錯誤代碼 u8 OV7725_Init(void) {u16 i=0;u16 reg=0;//設置IOGPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOG|RCC_APB2Periph_AFIO, ENABLE);//使能相關端口時鐘GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //PA8 輸入 上拉GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_SetBits(GPIOA,GPIO_Pin_8);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4; // 端口配置GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB,GPIO_Pin_3|GPIO_Pin_4); GPIO_InitStructure.GPIO_Pin = 0xff; //PC0~7 輸入 上拉GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(GPIOC, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOD, &GPIO_InitStructure);GPIO_SetBits(GPIOD,GPIO_Pin_6);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14|GPIO_Pin_15; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOG, &GPIO_InitStructure);GPIO_SetBits(GPIOG,GPIO_Pin_14|GPIO_Pin_15);GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //SWDSCCB_Init(); //初始化SCCB 的IO口 if(SCCB_WR_Reg(0x12,0x80))return 1; //軟復位OV7725delay_ms(100); reg=SCCB_RD_Reg(0X1c); //讀取廠家ID 高八位reg<<=8;reg|=SCCB_RD_Reg(0X1d); //讀取廠家ID 低八位if(reg!=OV7725_MID){printf("MID:%d\r\n",reg);return 1;}reg=SCCB_RD_Reg(0X0a); //讀取廠家ID 高八位reg<<=8;reg|=SCCB_RD_Reg(0X0b); //讀取廠家ID 低八位if(reg!=OV7725_PID){printf("HID:%d\r\n",reg);return 2;}//初始化 OV7725,采用QVGA分辨率(320*240) for(i=0;i<sizeof(ov7725_init_reg_tb1)/sizeof(ov7725_init_reg_tb1[0]);i++){SCCB_WR_Reg(ov7725_init_reg_tb1[i][0],ov7725_init_reg_tb1[i][1]);} printf("HID:%d\r\n",reg);return 0x00; //ok }2.3 OV7725其他功能設置
//OV7725功能設置 //白平衡設置 //0:自動模式 //1:晴天 //2,多云 //3,辦公室 //4,家里 //5,夜晚 void OV7725_Light_Mode(u8 mode) {switch(mode){case 0: //Auto,自動模式SCCB_WR_Reg(0x13, 0xff); //AWB on SCCB_WR_Reg(0x0e, 0x65);SCCB_WR_Reg(0x2d, 0x00);SCCB_WR_Reg(0x2e, 0x00);break;case 1://sunny,晴天SCCB_WR_Reg(0x13, 0xfd); //AWB offSCCB_WR_Reg(0x01, 0x5a);SCCB_WR_Reg(0x02, 0x5c);SCCB_WR_Reg(0x0e, 0x65);SCCB_WR_Reg(0x2d, 0x00);SCCB_WR_Reg(0x2e, 0x00);break; case 2://cloudy,多云SCCB_WR_Reg(0x13, 0xfd); //AWB offSCCB_WR_Reg(0x01, 0x58);SCCB_WR_Reg(0x02, 0x60);SCCB_WR_Reg(0x0e, 0x65);SCCB_WR_Reg(0x2d, 0x00);SCCB_WR_Reg(0x2e, 0x00);break; case 3://office,辦公室SCCB_WR_Reg(0x13, 0xfd); //AWB offSCCB_WR_Reg(0x01, 0x84);SCCB_WR_Reg(0x02, 0x4c);SCCB_WR_Reg(0x0e, 0x65);SCCB_WR_Reg(0x2d, 0x00);SCCB_WR_Reg(0x2e, 0x00);break; case 4://home,家里SCCB_WR_Reg(0x13, 0xfd); //AWB offSCCB_WR_Reg(0x01, 0x96);SCCB_WR_Reg(0x02, 0x40);SCCB_WR_Reg(0x0e, 0x65);SCCB_WR_Reg(0x2d, 0x00);SCCB_WR_Reg(0x2e, 0x00);break; case 5://night,夜晚SCCB_WR_Reg(0x13, 0xff); //AWB onSCCB_WR_Reg(0x0e, 0xe5);break;} } //色度設置 //sat:-4~+4 void OV7725_Color_Saturation(s8 sat) {if(sat>=-4 && sat<=4){ SCCB_WR_Reg(USAT,(sat+4)<<4); SCCB_WR_Reg(VSAT,(sat+4)<<4);} } //亮度設置 //bright:-4~+4 void OV7725_Brightness(s8 bright) {u8 bright_value,sign;switch(bright){case 4:bright_value = 0x48;sign = 0x06;break;case 3:bright_value = 0x38;sign = 0x06; break; case 2:bright_value = 0x28;sign = 0x06; break; case 1:bright_value = 0x18;sign = 0x06; break;case 0:bright_value = 0x08;sign = 0x06; break; case -1:bright_value = 0x08;sign = 0x0e; break; case -2:bright_value = 0x18;sign = 0x0e; break; case -3:bright_value = 0x28;sign = 0x0e; break; case -4:bright_value = 0x38;sign = 0x0e; break; }SCCB_WR_Reg(BRIGHT, bright_value);SCCB_WR_Reg(SIGN, sign); } //對比度設置 //contrast:-4~+4 void OV7725_Contrast(s8 contrast) {if(contrast >= -4 && contrast <=4){SCCB_WR_Reg(CNST,(0x30-(4-contrast)*4));} } //特效設置 //0:普通模式 //1,負片 //2,黑白 //3,偏紅色 //4,偏綠色 //5,偏藍色 //6,復古 void OV7725_Special_Effects(u8 eft) {switch(eft){case 0://正常SCCB_WR_Reg(0xa6, 0x06);//TSLB設置SCCB_WR_Reg(0x60, 0x80);//MANV,手動V值SCCB_WR_Reg(0x61, 0x80);//MANU,手動U值break;case 1://負片SCCB_WR_Reg(0xa6, 0x46);break;case 2://黑白SCCB_WR_Reg(0xa6, 0x26);SCCB_WR_Reg(0x60, 0x80);SCCB_WR_Reg(0x61, 0x80);break; case 3://偏紅SCCB_WR_Reg(0xa6, 0x1e);SCCB_WR_Reg(0x60, 0x80);SCCB_WR_Reg(0x61, 0xc0); break;case 4://偏綠SCCB_WR_Reg(0xa6, 0x1e);SCCB_WR_Reg(0x60, 0x60);SCCB_WR_Reg(0x61, 0x60); break;case 5://偏藍SCCB_WR_Reg(0xa6, 0x1e);SCCB_WR_Reg(0x60, 0xa0);SCCB_WR_Reg(0x61, 0x40); break;case 6://復古SCCB_WR_Reg(0xa6, 0x1e);SCCB_WR_Reg(0x60, 0x40);SCCB_WR_Reg(0x61, 0xa0);break; } }2.4 設置OV7725輸出窗口和輸出數據的格式(QVGA或VGA)
//設置圖像輸出窗口 //width:輸出圖像寬度,<=320 //height:輸出圖像高度,<=240 //mode:0,QVGA輸出模式;1,VGA輸出模式 //QVGA模式可視范圍廣但近物不是很清晰,VGA模式可視范圍小近物清晰 void OV7725_Window_Set(u16 width,u16 height,u8 mode) {u8 raw,temp;u16 sx,sy; if(mode){sx=(640-width)/2;sy=(480-height)/2;SCCB_WR_Reg(COM7,0x06); //設置為VGA模式SCCB_WR_Reg(HSTART,0x23); //水平起始位置SCCB_WR_Reg(HSIZE,0xA0); //水平尺寸SCCB_WR_Reg(VSTRT,0x07); //垂直起始位置SCCB_WR_Reg(VSIZE,0xF0); //垂直尺寸SCCB_WR_Reg(HREF,0x00);SCCB_WR_Reg(HOutSize,0xA0); //輸出尺寸SCCB_WR_Reg(VOutSize,0xF0); //輸出尺寸}else{sx=(320-width)/2;sy=(240-height)/2;SCCB_WR_Reg(COM7,0x46); //設置為QVGA模式SCCB_WR_Reg(HSTART,0x3f); //水平起始位置SCCB_WR_Reg(HSIZE, 0x50); //水平尺寸SCCB_WR_Reg(VSTRT, 0x03); //垂直起始位置SCCB_WR_Reg(VSIZE, 0x78); //垂直尺寸SCCB_WR_Reg(HREF, 0x00);SCCB_WR_Reg(HOutSize,0x50); //輸出尺寸SCCB_WR_Reg(VOutSize,0x78); //輸出尺寸}raw=SCCB_RD_Reg(HSTART);temp=raw+(sx>>2);//sx高8位存在HSTART,低2位存在HREF[5:4]SCCB_WR_Reg(HSTART,temp);SCCB_WR_Reg(HSIZE,width>>2);//width高8位存在HSIZE,低2位存在HREF[1:0]raw=SCCB_RD_Reg(VSTRT);temp=raw+(sy>>1);//sy高8位存在VSTRT,低1位存在HREF[6]SCCB_WR_Reg(VSTRT,temp);SCCB_WR_Reg(VSIZE,height>>1);//height高8位存在VSIZE,低1位存在HREF[2]raw=SCCB_RD_Reg(HREF);temp=((sy&0x01)<<6)|((sx&0x03)<<4)|((height&0x01)<<2)|(width&0x03)|raw;SCCB_WR_Reg(HREF,temp);SCCB_WR_Reg(HOutSize,width>>2);SCCB_WR_Reg(VOutSize,height>>1);SCCB_RD_Reg(EXHCH); temp = (raw|(width&0x03)|((height&0x01)<<2)); SCCB_WR_Reg(EXHCH,temp); }3. VSYNC中斷配置(幀中斷信號處理)
3.1 中斷GPIO口初始化
//外部中斷8初始化 void EXTI8_Init(void) { EXTI_InitTypeDef EXTI_InitStructure;NVIC_InitTypeDef NVIC_InitStructure; //選擇中斷信號源,開啟中斷線GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource8);//PA8對中斷線8EXTI_InitStructure.EXTI_Line=EXTI_Line8;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;;//下降沿觸發EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure); //根據EXTI_InitStruct中指定的參數初始化外設EXTI寄存器NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //使能按鍵所在的外部中斷通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //搶占優先級0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子優先級0 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中斷通道NVIC_Init(&NVIC_InitStructure); //根據NVIC_InitStruct中指定的參數初始化外設NVIC寄存器 }3.2 中斷服務程序
//外部中斷5~9服務程序,外部中斷5-9和中斷10-15向量存放在一起 void EXTI9_5_IRQHandler(void) {if(EXTI_GetITStatus(EXTI_Line8)==SET)//是8線的中斷{if(ov_sta<2){if(ov_sta==0){OV7725_WRST=0; //復位寫指針 OV7725_WRST=1; OV7725_WREN=1; //允許寫入FIFO}else {OV7725_WREN=0; //禁止寫入FIFO OV7725_WRST=0; //復位寫指針 OV7725_WRST=1; }ov_sta++;}}EXTI_ClearITPendingBit(EXTI_Line8); //清除EXTI8線路掛起位 } 4. 主函數#include "led.h" #include "delay.h" #include "key.h" #include "sys.h" #include "lcd.h" #include "usart.h" #include "string.h" #include "OV7725.h" #include "timer.h" #include "exti.h" #include "ff.h" #include "sdio.h"//const u8*LMODE_TBL[5]={"Auto","Sunny","Cloudy","Office","Home"}; //5種光照模式 //const u8*EFFECTS_TBL[7]={"Normal","Negative","B&W","Redish","Greenish","Bluish","Antique"}; //7種特效 extern u8 ov_sta; //在exit.c里面定義 extern u8 ov_frame; //在timer.c里面定義//由于OV7725傳感器安裝方式原因,OV7725_WINDOW_WIDTH相當于LCD的高度,OV7725_WINDOW_HEIGHT相當于LCD的寬度 //注意:此宏定義只對OV7725有效 #define OV7725_WINDOW_WIDTH 320 // <=320 #define OV7725_WINDOW_HEIGHT 240 // <=240//內存卡的讀寫狀態 SD_Error Status; FATFS fs; //FatFs文件系統對象 FIL fnew; //文件對象 FRESULT res_sd;//文件操作結果 UINT fnum; //文件成功讀寫數量//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 {u8 rgbBlue ; //指定藍色強度u8 rgbGreen ; //指定綠色強度 u8 rgbRed ; //指定紅色強度 u8 rgbReserved ;//保留,設置為0 }RGBQUAD ; //整體信息頭 typedef __packed struct { BITMAPFILEHEADER bmfHeader;BITMAPINFOHEADER bmiHeader; RGBQUAD RGB_MASK[3]; //調色板用于存放RGB掩碼. }BITMAPINFO; //更新LCD顯示 void camera_refresh(void) {u32 i,j;u16 color;BITMAPINFO bmp;//提前檢查是否需要保存圖片if(ov_sta && KEY_Scan(S1))//按鍵1按下{printf("開始保存圖片\r\n");//打開文件,若不存在就創建res_sd = f_open(&fnew, "0:test1.bmp", FA_OPEN_ALWAYS | FA_WRITE);//文件打開成功if(res_sd == FR_OK){//填寫文件信息頭信息 bmp.bmfHeader.bfType = 0x4D42; //bmp類型 bmp.bmfHeader.bfSize= 54 + 320*240*2; //文件大小(信息結構體+像素數據)bmp.bmfHeader.bfReserved1 = 0x0000; //保留,必須為0bmp.bmfHeader.bfReserved2 = 0x0000; bmp.bmfHeader.bfOffBits=54; //位圖信息結構體所占的字節數//填寫位圖信息頭信息 bmp.bmiHeader.biSize=40; //位圖信息頭的大小bmp.bmiHeader.biWidth=320; //位圖的寬度bmp.bmiHeader.biHeight=240; //圖像的高度bmp.bmiHeader.biPlanes=1; //目標設別的級別,必須是1bmp.bmiHeader.biBitCount=16; //每像素位數bmp.bmiHeader.biCompression=0; //RGB555格式bmp.bmiHeader.biSizeImage=320*240*2; //實際位圖所占用的字節數(僅考慮位圖像素數據)bmp.bmiHeader.biXPelsPerMeter=0; //水平分辨率bmp.bmiHeader.biYPelsPerMeter=0; //垂直分辨率bmp.bmiHeader.biClrImportant=0; //說明圖像顯示有重要影響的顏色索引數目,0代表所有的顏色一樣重要bmp.bmiHeader.biClrUsed=0; //位圖實際使用的彩色表中的顏色索引數,0表示使用所有的調色板項//RGB565格式掩碼bmp.RGB_MASK[0].rgbBlue = 0;bmp.RGB_MASK[0].rgbGreen = 0xF8;bmp.RGB_MASK[0].rgbRed = 0;bmp.RGB_MASK[0].rgbReserved = 0;bmp.RGB_MASK[1].rgbBlue = 0xE0;bmp.RGB_MASK[1].rgbGreen = 0x07;bmp.RGB_MASK[1].rgbRed = 0;bmp.RGB_MASK[1].rgbReserved = 0;bmp.RGB_MASK[2].rgbBlue = 0x1F;bmp.RGB_MASK[2].rgbGreen = 0;bmp.RGB_MASK[2].rgbRed = 0;bmp.RGB_MASK[2].rgbReserved = 0;//寫文件頭進文件 res_sd= f_write(&fnew, &bmp, sizeof(bmp), &fnum);}//讀指針復位OV7725_RRST=0; //開始復位讀指針OV7725_RCK_L;OV7725_RCK_H;OV7725_RCK_L;OV7725_RRST=1; //復位讀指針結束 OV7725_RCK_H; /*圖像花屏的原因在于讀取時的干擾和讀取時漏掉幾個像素*/for(i=0;i<240;i++){for(j=0;j<320;j++){OV7725_RCK_L;color=GPIOC->IDR&0XFF; //讀數據OV7725_RCK_H; color<<=8; OV7725_RCK_L;color|=GPIOC->IDR&0XFF; //讀數據OV7725_RCK_H; //寫位圖信息頭進內存卡f_write(&fnew, &color, sizeof(color), &fnum);}}//關閉文件f_close(&fnew);delay_ms(1000);return;}//不需要保存圖片,繼續刷新LCDif(ov_sta){LCD_Scan_Dir(U2D_L2R); //從上到下,從左到右 LCD_WriteRAM_Prepare(); //開始寫入GRAM //讀指針復位OV7725_RRST=0; //開始復位讀指針 OV7725_RCK_L;OV7725_RCK_H;OV7725_RCK_L;OV7725_RRST=1; //復位讀指針結束 OV7725_RCK_H; /*圖像花屏的原因在于讀取時的干擾和讀取時漏掉幾個像素*/for(i=0;i<240;i++){for(j=0;j<320;j++){OV7725_RCK_L;color=GPIOC->IDR&0XFF; //讀數據OV7725_RCK_H; color<<=8; OV7725_RCK_L;color|=GPIOC->IDR&0XFF; //讀數據OV7725_RCK_H; LCD->LCD_RAM=color; }}ov_sta=0; //開始下一次采集ov_frame++; LCD_Scan_Dir(DFT_SCAN_DIR); //恢復默認掃描方向 } }int main(void){u8 lightmode=0,saturation=2,brightness=2,contrast=2;u8 effect=0;u8 i=0;delay_init(); ????????????????//延時函數初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);?//設置中斷優先級分組為組2:2位搶占優先級,2位響應優先級uart_init(115200); ????????//串口初始化為 115200LED_Init(); //初始化與LED連接的硬件接口KEY_Init(); //初始化按鍵LCD_Init(); //初始化LCD //初始化SD卡if(SD_Init() == SD_OK){printf("SD卡初始化成功,即將掛載SD卡。\r\n");}//掛載SD卡res_sd = f_mount(&fs, "0:", 1);POINT_COLOR=RED;//設置字體為紅色 LCD_ShowString(60,50,200,16,16,"M3S STM32"); LCD_ShowString(60,70,200,16,16,"OV7725 TEST"); LCD_ShowString(60,90,200,16,16,"www.doflye.net");LCD_ShowString(60,110,200,16,16,"need a 7725 camera"); LCD_ShowString(60,130,200,16,16,"S1:Light Mode");LCD_ShowString(60,150,200,16,16,"S2:Saturation");LCD_ShowString(60,170,200,16,16,"S3:Brightness");LCD_ShowString(60,190,200,16,16,"S4:Contrast");LCD_ShowString(60,210,200,16,16,"OV7725 Init..."); while(1){//初始化ov7725if(OV7725_Init()==0){LCD_ShowString(60,210,200,16,16,"OV7725 Init OK ");OV7725_Light_Mode(lightmode);OV7725_Color_Saturation(saturation);OV7725_Brightness(brightness);OV7725_Contrast(contrast);OV7725_Special_Effects(effect);//設置輸出格式OV7725_Window_Set(OV7725_WINDOW_WIDTH,OV7725_WINDOW_HEIGHT,0);????//QVGA模式輸出//輸出使能OV7725_CS=0;break;}} EXTI8_Init(); //使能定時器捕獲 LCD_Clear(BLACK); //可以防止割屏while(1){camera_refresh();???????//更新顯示i++;if(i==15)???????????????//DS0閃爍.{i=0;LED0=!LED0;}} }
5. 實驗效果
按下按鈕S1,LCD圖像停止刷新一秒,然后再SD卡上生成一張test1.bmp文件,在電腦端查看如下所示
(數據有點問題,(:)
總結
以上是生活随笔為你收集整理的基于STM32的OV7725摄像头拍照实验的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NIST数字测试套件使用说明
- 下一篇: 梦幻西游网页版无法在虚拟机上运行【游戏】