当前位置:   article > 正文

基于STM32的OV7725摄像头拍照实验_stm32f103zet6 ov7725

stm32f103zet6 ov7725

平台:STM32ZET6(核心板)+ST-LINK/V2+SD卡+USB串口线+鹰眼OV7725摄像头(注意,为了减少摄像头连线的麻烦,建议初学者选取单片机时选用带有摄像头接口的板子)

工程介绍:需要移植FatFs文件系统,同时需要了解BMP位图的存储数据结构,从而实现将摄像头输出的RGB565像素数据直接输出到sd卡上,保存为*.bmp文件。

1. BMP位图的存储

1.1 数据结构介绍

  1. //BMP头文件
  2. typedef __packed struct
  3. {
  4. u16 bfType ; //文件标志.只对'BM',用来识别BMP位图类型
  5. u32 bfSize ; //文件大小,占四个字节
  6. u16 bfReserved1 ;//保留
  7. u16 bfReserved2 ;//保留
  8. u32 bfOffBits ; //从文件开始到位图数据(bitmap data)开始之间的的偏移量
  9. }BITMAPFILEHEADER ;
  10. //BMP信息头
  11. typedef __packed struct
  12. {
  13. u32 biSize ; //说明BITMAPINFOHEADER结构所需要的字数。
  14. long biWidth ; //说明图象的宽度,以象素为单位
  15. long biHeight ; //说明图象的高度,以象素为单位
  16. u16 biPlanes ; //为目标设备说明位面数,其值将总是被设为1
  17. u16 biBitCount ;         //说明比特数/象素,其值为1、4、8、16、24、或32
  18. /*说明图象数据压缩的类型。其值可以是下述值之一:
  19. BI_RGB:没有压缩;
  20. BI_RLE8:每个象素8比特的RLE压缩编码,压缩格式由2字节组成(重复象素计数和颜色索引);
  21. BI_RLE4:每个象素4比特的RLE压缩编码,压缩格式由2字节组成
  22. BI_BITFIELDS:每个象素的比特由指定的掩码决定。*/
  23. u32 biCompression ;
  24. u32 biSizeImage ; //说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0
  25. long biXPelsPerMeter ; //说明水平分辨率,用象素/米表示
  26. long biYPelsPerMeter ; //说明垂直分辨率,用象素/米表示
  27. u32 biClrUsed ; //说明位图实际使用的彩色表中的颜色索引数
  28. u32 biClrImportant ; //说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。
  29. }BITMAPINFOHEADER ;
  30. //彩色表
  31. typedef __packed struct
  32. {
  33. u8 rgbBlue ;     //指定蓝色强度
  34. u8 rgbGreen ; //指定绿色强度
  35. u8 rgbRed ; //指定红色强度
  36. u8 rgbReserved ;    //保留,设置为0
  37. }RGBQUAD ;
  38. //整体信息头(以上数据结构的组合)
  39. typedef __packed struct
  40. {
  41. BITMAPFILEHEADER bmfHeader;
  42. BITMAPINFOHEADER bmiHeader;
  43. RGBQUAD RGB_MASK[3]; //调色板用于存放RGB掩码.
  44. }BITMAPINFO;

1.2 设置方法

  1. //提前检查是否需要保存图片
  2. if(ov_sta && KEY_Scan(S1))//按键1按下(拍照)
  3. {
  4. printf("开始保存图片\r\n");
  5. //打开文件,若不存在就创建
  6. res_sd = f_open(&fnew, "0:test1.bmp", FA_OPEN_ALWAYS | FA_WRITE);
  7. //文件打开成功
  8. if(res_sd == FR_OK)
  9. {
  10. //填写文件信息头信息
  11. bmp.bmfHeader.bfType = 0x4D42; //bmp类型
  12. bmp.bmfHeader.bfSize= 54 + 320*240*2;         //文件大小(信息结构体+像素数据)
  13. bmp.bmfHeader.bfReserved1 = 0x0000; //保留,必须为0
  14. bmp.bmfHeader.bfReserved2 = 0x0000;
  15. bmp.bmfHeader.bfOffBits=54; //位图信息结构体所占的字节数
  16. //填写位图信息头信息
  17. bmp.bmiHeader.biSize=40;             //位图信息头的大小
  18. bmp.bmiHeader.biWidth=320;     //位图的宽度
  19. bmp.bmiHeader.biHeight=240; //图像的高度
  20. bmp.bmiHeader.biPlanes=1;             //目标设别的级别,必须是1
  21. bmp.bmiHeader.biBitCount=16;             //每像素位数
  22. bmp.bmiHeader.biCompression=0;      //RGB555格式
  23. bmp.bmiHeader.biSizeImage=320*240*2;              //实际位图所占用的字节数(仅考虑位图像素数据)
  24. bmp.bmiHeader.biXPelsPerMeter=0; //水平分辨率
  25. bmp.bmiHeader.biYPelsPerMeter=0; //垂直分辨率
  26. bmp.bmiHeader.biClrImportant=0;           //说明图像显示有重要影响的颜色索引数目,0代表所有的颜色一样重要
  27. bmp.bmiHeader.biClrUsed=0; //位图实际使用的彩色表中的颜色索引数,0表示使用所有的调色板项
  28. //RGB565格式掩码
  29. bmp.RGB_MASK[0].rgbBlue = 0;
  30. bmp.RGB_MASK[0].rgbGreen = 0xF8;
  31. bmp.RGB_MASK[0].rgbRed = 0;
  32. bmp.RGB_MASK[0].rgbReserved = 0;
  33. bmp.RGB_MASK[1].rgbBlue = 0xE0;
  34. bmp.RGB_MASK[1].rgbGreen = 0x07;
  35. bmp.RGB_MASK[1].rgbRed = 0;
  36. bmp.RGB_MASK[1].rgbReserved = 0;
  37. bmp.RGB_MASK[2].rgbBlue = 0x1F;
  38. bmp.RGB_MASK[2].rgbGreen = 0;
  39. bmp.RGB_MASK[2].rgbRed = 0;
  40. bmp.RGB_MASK[2].rgbReserved = 0;
  41. //写文件头进文件
  42. res_sd= f_write(&fnew, &bmp, sizeof(bmp), &fnum);
  43. }
  44. //读指针复位
  45. OV7725_RRST=0; //开始复位读指针
  46. OV7725_RCK_L;
  47. OV7725_RCK_H;
  48. OV7725_RCK_L;
  49. OV7725_RRST=1; //复位读指针结束
  50. OV7725_RCK_H;
  51. /*图像花屏的原因在于读取时的干扰和读取时漏掉几个像素*/
  52. for(i=0;i<240;i++)
  53. {
  54. for(j=0;j<320;j++)
  55. {
  56. OV7725_RCK_L;
  57. color=GPIOC->IDR&0XFF; //读数据
  58. OV7725_RCK_H;
  59. color<<=8;
  60. OV7725_RCK_L;
  61. color|=GPIOC->IDR&0XFF; //读数据
  62. OV7725_RCK_H;
  63. //写位图信息头进内存卡(FatFs中的方法)
  64. f_write(&fnew, &color, sizeof(color), &fnum);
  65. }
  66. }
  67. //关闭文件
  68. f_close(&fnew);
  69. delay_ms(1000);
  70. return;
  71. }

2. OV7725驱动程序设计

2.1 OV7725寄存器设置

  1. #ifndef _OV7725CFG_H
  2. #define _OV7725CFG_H
  3. #include "ov7725.h"
  4. /* OV7725寄存器宏定义 */
  5. #define GAIN 0x00
  6. #define BLUE 0x01
  7. #define RED 0x02
  8. #define RED 0x02
  9. #define GREEN 0x03
  10. #define BAVG 0x05
  11. #define GAVG 0x06
  12. #define RAVG 0x07
  13. #define AECH 0x08
  14. #define COM2 0x09
  15. #define PID 0x0A
  16. #define VER 0x0B
  17. #define COM3 0x0C
  18. #define COM4 0x0D
  19. #define COM5 0x0E
  20. #define COM6 0x0F
  21. #define AEC 0x10
  22. #define CLKRC 0x11
  23. #define COM7 0x12
  24. #define COM8 0x13
  25. #define COM9 0x14
  26. #define COM10 0x15
  27. #define REG16 0x16
  28. #define HSTART 0x17
  29. #define HSIZE 0x18
  30. #define VSTRT 0x19
  31. #define VSIZE 0x1A
  32. #define PSHFT 0x1B
  33. #define MIDH 0x1C
  34. #define MIDL 0x1D
  35. #define LAEC 0x1F
  36. #define COM11 0x20
  37. #define BDBase 0x22
  38. #define BDMStep 0x23
  39. #define AEW 0x24
  40. #define AEB 0x25
  41. #define VPT 0x26
  42. #define REG28 0x28
  43. #define HOutSize 0x29
  44. #define EXHCH 0x2A
  45. #define EXHCL 0x2B
  46. #define VOutSize 0x2C
  47. #define ADVFL 0x2D
  48. #define ADVFH 0x2E
  49. #define YAVE 0x2F
  50. #define LumHTh 0x30
  51. #define LumLTh 0x31
  52. #define HREF 0x32
  53. #define DM_LNL 0x33
  54. #define DM_LNH 0x34
  55. #define ADoff_B 0x35
  56. #define ADoff_R 0x36
  57. #define ADoff_Gb 0x37
  58. #define ADoff_Gr 0x38
  59. #define Off_B 0x39
  60. #define Off_R 0x3A
  61. #define Off_Gb 0x3B
  62. #define Off_Gr 0x3C
  63. #define COM12 0x3D
  64. #define COM13 0x3E
  65. #define COM14 0x3F
  66. #define COM16 0x41
  67. #define TGT_B 0x42
  68. #define TGT_R 0x43
  69. #define TGT_Gb 0x44
  70. #define TGT_Gr 0x45
  71. #define LC_CTR 0x46
  72. #define LC_XC 0x47
  73. #define LC_YC 0x48
  74. #define LC_COEF 0x49
  75. #define LC_RADI 0x4A
  76. #define LC_COEFB 0x4B
  77. #define LC_COEFR 0x4C
  78. #define FixGain 0x4D
  79. #define AREF1 0x4F
  80. #define AREF6 0x54
  81. #define UFix 0x60
  82. #define VFix 0x61
  83. #define AWBb_blk 0x62
  84. #define AWB_Ctrl0 0x63
  85. #define DSP_Ctrl1 0x64
  86. #define DSP_Ctrl2 0x65
  87. #define DSP_Ctrl3 0x66
  88. #define DSP_Ctrl4 0x67
  89. #define AWB_bias 0x68
  90. #define AWBCtrl1 0x69
  91. #define AWBCtrl2 0x6A
  92. #define AWBCtrl3 0x6B
  93. #define AWBCtrl4 0x6C
  94. #define AWBCtrl5 0x6D
  95. #define AWBCtrl6 0x6E
  96. #define AWBCtrl7 0x6F
  97. #define AWBCtrl8 0x70
  98. #define AWBCtrl9 0x71
  99. #define AWBCtrl10 0x72
  100. #define AWBCtrl11 0x73
  101. #define AWBCtrl12 0x74
  102. #define AWBCtrl13 0x75
  103. #define AWBCtrl14 0x76
  104. #define AWBCtrl15 0x77
  105. #define AWBCtrl16 0x78
  106. #define AWBCtrl17 0x79
  107. #define AWBCtrl18 0x7A
  108. #define AWBCtrl19 0x7B
  109. #define AWBCtrl20 0x7C
  110. #define AWBCtrl21 0x7D
  111. #define GAM1 0x7E
  112. #define GAM2 0x7F
  113. #define GAM3 0x80
  114. #define GAM4 0x81
  115. #define GAM5 0x82
  116. #define GAM6 0x83
  117. #define GAM7 0x84
  118. #define GAM8 0x85
  119. #define GAM9 0x86
  120. #define GAM10 0x87
  121. #define GAM11 0x88
  122. #define GAM12 0x89
  123. #define GAM13 0x8A
  124. #define GAM14 0x8B
  125. #define GAM15 0x8C
  126. #define SLOP 0x8D
  127. #define DNSTh 0x8E
  128. #define EDGE0 0x8F
  129. #define EDGE1 0x90
  130. #define DNSOff 0x91
  131. #define EDGE2 0x92
  132. #define EDGE3 0x93
  133. #define MTX1 0x94
  134. #define MTX2 0x95
  135. #define MTX3 0x96
  136. #define MTX4 0x97
  137. #define MTX5 0x98
  138. #define MTX6 0x99
  139. #define MTX_Ctrl 0x9A
  140. #define BRIGHT 0x9B
  141. #define CNST 0x9C
  142. #define UVADJ0 0x9E
  143. #define UVADJ1 0x9F
  144. #define SCAL0 0xA0
  145. #define SCAL1 0xA1
  146. #define SCAL2 0xA2
  147. #define SDE 0xA6
  148. #define USAT 0xA7
  149. #define VSAT 0xA8
  150. #define HUECOS 0xA9
  151. #define HUESIN 0xAA
  152. #define SIGN 0xAB
  153. #define DSPAuto 0xAC
  154. //初始化寄存器序列及其对应的值
  155. const u8 ov7725_init_reg_tb1[][2]=
  156. {
  157. /*输出窗口设置*/
  158. {CLKRC, 0x00}, //clock config
  159. {COM7, 0x06}, //VGA RGB565
  160. {HSTART, 0x3f}, //水平起始位置
  161. {HSIZE, 0x50}, //水平尺寸
  162. {VSTRT, 0x03}, //垂直起始位置
  163. {VSIZE, 0x78}, //垂直尺寸
  164. {HREF, 0x00},
  165. {HOutSize, 0x50}, //输出尺寸
  166. {VOutSize, 0x78}, //输出尺寸
  167. /*DSP control*/
  168. {TGT_B, 0x7f},
  169. {FixGain, 0x09},
  170. {AWB_Ctrl0, 0xe0},
  171. {DSP_Ctrl1, 0xff},
  172. {DSP_Ctrl2, 0x00},
  173. {DSP_Ctrl3, 0x00},
  174. {DSP_Ctrl4, 0x00},
  175. /*AGC AEC AWB*/
  176. {COM8, 0xf0},
  177. {COM4, 0x81}, /*Pll AEC CONFIG*/
  178. {COM6, 0xc5},
  179. {COM9, 0x11},
  180. {BDBase, 0x7F},
  181. {BDMStep, 0x03},
  182. {AEW, 0x40},
  183. {AEB, 0x30},
  184. {VPT, 0xa1},
  185. {EXHCL, 0x9e},
  186. {AWBCtrl3, 0xaa},
  187. {COM8, 0xff},
  188. /*matrix shapness brightness contrast*/
  189. {EDGE1, 0x08},
  190. {DNSOff, 0x01},
  191. {EDGE2, 0x03},
  192. {EDGE3, 0x00},
  193. {MTX1, 0xb0},
  194. {MTX2, 0x9d},
  195. {MTX3, 0x13},
  196. {MTX4, 0x16},
  197. {MTX5, 0x7b},
  198. {MTX6, 0x91},
  199. {MTX_Ctrl, 0x1e},
  200. {BRIGHT, 0x08},
  201. {CNST, 0x20},
  202. {UVADJ0, 0x81},
  203. {SDE, 0X06},
  204. {USAT, 0x65},
  205. {VSAT, 0x65},
  206. {HUECOS, 0X80},
  207. {HUESIN, 0X80},
  208. /*GAMMA config*/
  209. {GAM1, 0x0c},
  210. {GAM2, 0x16},
  211. {GAM3, 0x2a},
  212. {GAM4, 0x4e},
  213. {GAM5, 0x61},
  214. {GAM6, 0x6f},
  215. {GAM7, 0x7b},
  216. {GAM8, 0x86},
  217. {GAM9, 0x8e},
  218. {GAM10, 0x97},
  219. {GAM11, 0xa4},
  220. {GAM12, 0xaf},
  221. {GAM13, 0xc5},
  222. {GAM14, 0xd7},
  223. {GAM15, 0xe8},
  224. {SLOP, 0x20},
  225. {COM3, 0x50},/*Horizontal mirror image*/
  226. //注:datasheet默认0x10,即改变YUV为UVY格式。但是摄像头不是芯片而是模组时,
  227. //要将0X10中的1变成0,即设置YUV格式。
  228. /*night mode auto frame rate control*/
  229. {COM5, 0xf5}, /*在夜视环境下,自动降低帧率,保证低照度画面质量*/
  230. //{COM5, 0x31}, /*夜视环境帧率不变*/
  231. };
  232. #endif

2.2 OV7725初始化

  1. #define OV7725_MID 0X7FA2
  2. #define OV7725_PID 0X7721
  3. #define OV7725_VSYNC PAin(8)         //同步信号检测IO
  4. #define OV7725_WRST PDout(6) //写指针复位
  5. #define OV7725_WREN PBout(3) //写入FIFO使能
  6. #define OV7725_RCK_H GPIOB->BSRR=1<<4                //设置读数据时钟高电平
  7. #define OV7725_RCK_L GPIOB->BRR=1<<4                 //设置读数据时钟低电平
  8. #define OV7725_RRST PGout(14) //读指针复位
  9. #define OV7725_CS PGout(15) //片选信号(OE)
  10. #define OV7725_DATA GPIO_ReadInputData(GPIOC,0x00FF) //数据输入端口
  1. #include "sys.h"
  2. #include "ov7725.h"
  3. #include "ov7725config.h"
  4. #include "delay.h"
  5. #include "usart.h"
  6. #include "sccb.h"
  7. //初始化OV7725
  8. //返回0:成功
  9. //返回其他值:错误代码
  10. u8 OV7725_Init(void)
  11. {
  12. u16 i=0;
  13. u16 reg=0;
  14. //设置IO
  15. GPIO_InitTypeDef GPIO_InitStructure;
  16. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOG|RCC_APB2Periph_AFIO, ENABLE);//使能相关端口时钟
  17. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //PA8 输入 上拉
  18. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  19. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  20. GPIO_Init(GPIOA, &GPIO_InitStructure);
  21. GPIO_SetBits(GPIOA,GPIO_Pin_8);
  22. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4; // 端口配置
  23. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
  24. GPIO_Init(GPIOB, &GPIO_InitStructure);
  25. GPIO_SetBits(GPIOB,GPIO_Pin_3|GPIO_Pin_4);
  26. GPIO_InitStructure.GPIO_Pin = 0xff; //PC0~7 输入 上拉
  27. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  28. GPIO_Init(GPIOC, &GPIO_InitStructure);
  29. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  30. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  31. GPIO_Init(GPIOD, &GPIO_InitStructure);
  32. GPIO_SetBits(GPIOD,GPIO_Pin_6);
  33. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14|GPIO_Pin_15;
  34. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  35. GPIO_Init(GPIOG, &GPIO_InitStructure);
  36. GPIO_SetBits(GPIOG,GPIO_Pin_14|GPIO_Pin_15);
  37. GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //SWD
  38. SCCB_Init(); //初始化SCCB 的IO口
  39. if(SCCB_WR_Reg(0x12,0x80))return 1; //软复位OV7725
  40. delay_ms(100);
  41. reg=SCCB_RD_Reg(0X1c); //读取厂家ID 高八位
  42. reg<<=8;
  43. reg|=SCCB_RD_Reg(0X1d); //读取厂家ID 低八位
  44. if(reg!=OV7725_MID)
  45. {
  46. printf("MID:%d\r\n",reg);
  47. return 1;
  48. }
  49. reg=SCCB_RD_Reg(0X0a); //读取厂家ID 高八位
  50. reg<<=8;
  51. reg|=SCCB_RD_Reg(0X0b); //读取厂家ID 低八位
  52. if(reg!=OV7725_PID)
  53. {
  54. printf("HID:%d\r\n",reg);
  55. return 2;
  56. }
  57. //初始化 OV7725,采用QVGA分辨率(320*240)
  58. for(i=0;i<sizeof(ov7725_init_reg_tb1)/sizeof(ov7725_init_reg_tb1[0]);i++)
  59. {
  60. SCCB_WR_Reg(ov7725_init_reg_tb1[i][0],ov7725_init_reg_tb1[i][1]);
  61. }
  62. printf("HID:%d\r\n",reg);
  63. return 0x00; //ok
  64. }

2.3 OV7725其他功能设置

  1. //OV7725功能设置
  2. //白平衡设置
  3. //0:自动模式
  4. //1:晴天
  5. //2,多云
  6. //3,办公室
  7. //4,家里
  8. //5,夜晚
  9. void OV7725_Light_Mode(u8 mode)
  10. {
  11. switch(mode)
  12. {
  13. case 0: //Auto,自动模式
  14. SCCB_WR_Reg(0x13, 0xff); //AWB on
  15. SCCB_WR_Reg(0x0e, 0x65);
  16. SCCB_WR_Reg(0x2d, 0x00);
  17. SCCB_WR_Reg(0x2e, 0x00);
  18. break;
  19. case 1://sunny,晴天
  20. SCCB_WR_Reg(0x13, 0xfd); //AWB off
  21. SCCB_WR_Reg(0x01, 0x5a);
  22. SCCB_WR_Reg(0x02, 0x5c);
  23. SCCB_WR_Reg(0x0e, 0x65);
  24. SCCB_WR_Reg(0x2d, 0x00);
  25. SCCB_WR_Reg(0x2e, 0x00);
  26. break;
  27. case 2://cloudy,多云
  28. SCCB_WR_Reg(0x13, 0xfd); //AWB off
  29. SCCB_WR_Reg(0x01, 0x58);
  30. SCCB_WR_Reg(0x02, 0x60);
  31. SCCB_WR_Reg(0x0e, 0x65);
  32. SCCB_WR_Reg(0x2d, 0x00);
  33. SCCB_WR_Reg(0x2e, 0x00);
  34. break;
  35. case 3://office,办公室
  36. SCCB_WR_Reg(0x13, 0xfd); //AWB off
  37. SCCB_WR_Reg(0x01, 0x84);
  38. SCCB_WR_Reg(0x02, 0x4c);
  39. SCCB_WR_Reg(0x0e, 0x65);
  40. SCCB_WR_Reg(0x2d, 0x00);
  41. SCCB_WR_Reg(0x2e, 0x00);
  42. break;
  43. case 4://home,家里
  44. SCCB_WR_Reg(0x13, 0xfd); //AWB off
  45. SCCB_WR_Reg(0x01, 0x96);
  46. SCCB_WR_Reg(0x02, 0x40);
  47. SCCB_WR_Reg(0x0e, 0x65);
  48. SCCB_WR_Reg(0x2d, 0x00);
  49. SCCB_WR_Reg(0x2e, 0x00);
  50. break;
  51. case 5://night,夜晚
  52. SCCB_WR_Reg(0x13, 0xff); //AWB on
  53. SCCB_WR_Reg(0x0e, 0xe5);
  54. break;
  55. }
  56. }
  57. //色度设置
  58. //sat:-4~+4
  59. void OV7725_Color_Saturation(s8 sat)
  60. {
  61. if(sat>=-4 && sat<=4)
  62. {
  63. SCCB_WR_Reg(USAT,(sat+4)<<4);
  64. SCCB_WR_Reg(VSAT,(sat+4)<<4);
  65. }
  66. }
  67. //亮度设置
  68. //bright:-4~+4
  69. void OV7725_Brightness(s8 bright)
  70. {
  71. u8 bright_value,sign;
  72. switch(bright)
  73. {
  74. case 4:
  75. bright_value = 0x48;
  76. sign = 0x06;
  77. break;
  78. case 3:
  79. bright_value = 0x38;
  80. sign = 0x06;
  81. break;
  82. case 2:
  83. bright_value = 0x28;
  84. sign = 0x06;
  85. break;
  86. case 1:
  87. bright_value = 0x18;
  88. sign = 0x06;
  89. break;
  90. case 0:
  91. bright_value = 0x08;
  92. sign = 0x06;
  93. break;
  94. case -1:
  95. bright_value = 0x08;
  96. sign = 0x0e;
  97. break;
  98. case -2:
  99. bright_value = 0x18;
  100. sign = 0x0e;
  101. break;
  102. case -3:
  103. bright_value = 0x28;
  104. sign = 0x0e;
  105. break;
  106. case -4:
  107. bright_value = 0x38;
  108. sign = 0x0e;
  109. break;
  110. }
  111. SCCB_WR_Reg(BRIGHT, bright_value);
  112. SCCB_WR_Reg(SIGN, sign);
  113. }
  114. //对比度设置
  115. //contrast:-4~+4
  116. void OV7725_Contrast(s8 contrast)
  117. {
  118. if(contrast >= -4 && contrast <=4)
  119. {
  120. SCCB_WR_Reg(CNST,(0x30-(4-contrast)*4));
  121. }
  122. }
  123. //特效设置
  124. //0:普通模式
  125. //1,负片
  126. //2,黑白
  127. //3,偏红色
  128. //4,偏绿色
  129. //5,偏蓝色
  130. //6,复古
  131. void OV7725_Special_Effects(u8 eft)
  132. {
  133. switch(eft)
  134. {
  135. case 0://正常
  136. SCCB_WR_Reg(0xa6, 0x06);//TSLB设置
  137. SCCB_WR_Reg(0x60, 0x80);//MANV,手动V值
  138. SCCB_WR_Reg(0x61, 0x80);//MANU,手动U值
  139. break;
  140. case 1://负片
  141. SCCB_WR_Reg(0xa6, 0x46);
  142. break;
  143. case 2://黑白
  144. SCCB_WR_Reg(0xa6, 0x26);
  145. SCCB_WR_Reg(0x60, 0x80);
  146. SCCB_WR_Reg(0x61, 0x80);
  147. break;
  148. case 3://偏红
  149. SCCB_WR_Reg(0xa6, 0x1e);
  150. SCCB_WR_Reg(0x60, 0x80);
  151. SCCB_WR_Reg(0x61, 0xc0);
  152. break;
  153. case 4://偏绿
  154. SCCB_WR_Reg(0xa6, 0x1e);
  155. SCCB_WR_Reg(0x60, 0x60);
  156. SCCB_WR_Reg(0x61, 0x60);
  157. break;
  158. case 5://偏蓝
  159. SCCB_WR_Reg(0xa6, 0x1e);
  160. SCCB_WR_Reg(0x60, 0xa0);
  161. SCCB_WR_Reg(0x61, 0x40);
  162. break;
  163. case 6://复古
  164. SCCB_WR_Reg(0xa6, 0x1e);
  165. SCCB_WR_Reg(0x60, 0x40);
  166. SCCB_WR_Reg(0x61, 0xa0);
  167. break;
  168. }
  169. }

2.4 设置OV7725输出窗口和输出数据的格式(QVGA或VGA)

  1. //设置图像输出窗口
  2. //width:输出图像宽度,<=320
  3. //height:输出图像高度,<=240
  4. //mode:0,QVGA输出模式;1,VGA输出模式
  5. //QVGA模式可视范围广但近物不是很清晰,VGA模式可视范围小近物清晰
  6. void OV7725_Window_Set(u16 width,u16 height,u8 mode)
  7. {
  8. u8 raw,temp;
  9. u16 sx,sy;
  10. if(mode)
  11. {
  12. sx=(640-width)/2;
  13. sy=(480-height)/2;
  14. SCCB_WR_Reg(COM7,0x06); //设置为VGA模式
  15. SCCB_WR_Reg(HSTART,0x23); //水平起始位置
  16. SCCB_WR_Reg(HSIZE,0xA0); //水平尺寸
  17. SCCB_WR_Reg(VSTRT,0x07); //垂直起始位置
  18. SCCB_WR_Reg(VSIZE,0xF0); //垂直尺寸
  19. SCCB_WR_Reg(HREF,0x00);
  20. SCCB_WR_Reg(HOutSize,0xA0); //输出尺寸
  21. SCCB_WR_Reg(VOutSize,0xF0); //输出尺寸
  22. }
  23. else
  24. {
  25. sx=(320-width)/2;
  26. sy=(240-height)/2;
  27. SCCB_WR_Reg(COM7,0x46); //设置为QVGA模式
  28. SCCB_WR_Reg(HSTART,0x3f); //水平起始位置
  29. SCCB_WR_Reg(HSIZE, 0x50); //水平尺寸
  30. SCCB_WR_Reg(VSTRT, 0x03); //垂直起始位置
  31. SCCB_WR_Reg(VSIZE, 0x78); //垂直尺寸
  32. SCCB_WR_Reg(HREF, 0x00);
  33. SCCB_WR_Reg(HOutSize,0x50); //输出尺寸
  34. SCCB_WR_Reg(VOutSize,0x78); //输出尺寸
  35. }
  36. raw=SCCB_RD_Reg(HSTART);
  37. temp=raw+(sx>>2);//sx高8位存在HSTART,低2位存在HREF[5:4]
  38. SCCB_WR_Reg(HSTART,temp);
  39. SCCB_WR_Reg(HSIZE,width>>2);//width高8位存在HSIZE,低2位存在HREF[1:0]
  40. raw=SCCB_RD_Reg(VSTRT);
  41. temp=raw+(sy>>1);//sy高8位存在VSTRT,低1位存在HREF[6]
  42. SCCB_WR_Reg(VSTRT,temp);
  43. SCCB_WR_Reg(VSIZE,height>>1);//height高8位存在VSIZE,低1位存在HREF[2]
  44. raw=SCCB_RD_Reg(HREF);
  45. temp=((sy&0x01)<<6)|((sx&0x03)<<4)|((height&0x01)<<2)|(width&0x03)|raw;
  46. SCCB_WR_Reg(HREF,temp);
  47. SCCB_WR_Reg(HOutSize,width>>2);
  48. SCCB_WR_Reg(VOutSize,height>>1);
  49. SCCB_RD_Reg(EXHCH);
  50. temp = (raw|(width&0x03)|((height&0x01)<<2));
  51. SCCB_WR_Reg(EXHCH,temp);
  52. }

3. VSYNC中断配置(帧中断信号处理)

3.1 中断GPIO口初始化

  1. //外部中断8初始化
  2. void EXTI8_Init(void)
  3. {
  4. EXTI_InitTypeDef EXTI_InitStructure;
  5. NVIC_InitTypeDef NVIC_InitStructure;
  6. //选择中断信号源,开启中断线
  7. GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource8);//PA8对中断线8
  8. EXTI_InitStructure.EXTI_Line=EXTI_Line8;
  9. EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  10. EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;;//下降沿触发
  11. EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  12. EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
  13. NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //使能按键所在的外部中断通道
  14. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级0
  15. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级0
  16. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
  17. NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
  18. }

3.2 中断服务程序

  1. //外部中断5~9服务程序,外部中断5-9和中断10-15向量存放在一起
  2. void EXTI9_5_IRQHandler(void)
  3. {
  4. if(EXTI_GetITStatus(EXTI_Line8)==SET)//是8线的中断
  5. {
  6. if(ov_sta<2)
  7. {
  8. if(ov_sta==0)
  9. {
  10. OV7725_WRST=0; //复位写指针
  11. OV7725_WRST=1;
  12. OV7725_WREN=1; //允许写入FIFO
  13. }else
  14. {
  15. OV7725_WREN=0; //禁止写入FIFO
  16. OV7725_WRST=0; //复位写指针
  17. OV7725_WRST=1;
  18. }
  19. ov_sta++;
  20. }
  21. }
  22. EXTI_ClearITPendingBit(EXTI_Line8); //清除EXTI8线路挂起位
  23. }
4. 主函数
  1. #include "led.h"
  2. #include "delay.h"
  3. #include "key.h"
  4. #include "sys.h"
  5. #include "lcd.h"
  6. #include "usart.h"
  7. #include "string.h"
  8. #include "OV7725.h"
  9. #include "timer.h"
  10. #include "exti.h"
  11. #include "ff.h"
  12. #include "sdio.h"
  13. //const u8*LMODE_TBL[5]={"Auto","Sunny","Cloudy","Office","Home"}; //5种光照模式
  14. //const u8*EFFECTS_TBL[7]={"Normal","Negative","B&W","Redish","Greenish","Bluish","Antique"}; //7种特效
  15. extern u8 ov_sta; //在exit.c里面定义
  16. extern u8 ov_frame; //在timer.c里面定义
  17. //由于OV7725传感器安装方式原因,OV7725_WINDOW_WIDTH相当于LCD的高度,OV7725_WINDOW_HEIGHT相当于LCD的宽度
  18. //注意:此宏定义只对OV7725有效
  19. #define OV7725_WINDOW_WIDTH 320 // <=320
  20. #define OV7725_WINDOW_HEIGHT 240 // <=240
  21. //内存卡的读写状态
  22. SD_Error Status;
  23. FATFS fs; //FatFs文件系统对象
  24. FIL fnew; //文件对象
  25. FRESULT res_sd;//文件操作结果
  26. UINT fnum; //文件成功读写数量
  27. //BMP头文件
  28. typedef __packed struct
  29. {
  30. u16 bfType ; //文件标志.只对'BM',用来识别BMP位图类型
  31. u32 bfSize ; //文件大小,占四个字节
  32. u16 bfReserved1 ;//保留
  33. u16 bfReserved2 ;//保留
  34. u32 bfOffBits ; //从文件开始到位图数据(bitmap data)开始之间的的偏移量
  35. }BITMAPFILEHEADER ;
  36. //BMP信息头
  37. typedef __packed struct
  38. {
  39. u32 biSize ; //说明BITMAPINFOHEADER结构所需要的字数。
  40. long biWidth ; //说明图象的宽度,以象素为单位
  41. long biHeight ; //说明图象的高度,以象素为单位
  42. u16 biPlanes ; //为目标设备说明位面数,其值将总是被设为1
  43. u16 biBitCount ; //说明比特数/象素,其值为1、4、8、16、24、或32
  44. /*说明图象数据压缩的类型。其值可以是下述值之一:
  45. BI_RGB:没有压缩;
  46. BI_RLE8:每个象素8比特的RLE压缩编码,压缩格式由2字节组成(重复象素计数和颜色索引);
  47. BI_RLE4:每个象素4比特的RLE压缩编码,压缩格式由2字节组成
  48. BI_BITFIELDS:每个象素的比特由指定的掩码决定。*/
  49. u32 biCompression ;
  50. u32 biSizeImage ; //说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0
  51. long biXPelsPerMeter ; //说明水平分辨率,用象素/米表示
  52. long biYPelsPerMeter ; //说明垂直分辨率,用象素/米表示
  53. u32 biClrUsed ; //说明位图实际使用的彩色表中的颜色索引数
  54. u32 biClrImportant ; //说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。
  55. }BITMAPINFOHEADER ;
  56. //彩色表
  57. typedef __packed struct
  58. {
  59. u8 rgbBlue ; //指定蓝色强度
  60. u8 rgbGreen ; //指定绿色强度
  61. u8 rgbRed ; //指定红色强度
  62. u8 rgbReserved ;//保留,设置为0
  63. }RGBQUAD ;
  64. //整体信息头
  65. typedef __packed struct
  66. {
  67. BITMAPFILEHEADER bmfHeader;
  68. BITMAPINFOHEADER bmiHeader;
  69. RGBQUAD RGB_MASK[3]; //调色板用于存放RGB掩码.
  70. }BITMAPINFO;
  71. //更新LCD显示
  72. void camera_refresh(void)
  73. {
  74. u32 i,j;
  75. u16 color;
  76. BITMAPINFO bmp;
  77. //提前检查是否需要保存图片
  78. if(ov_sta && KEY_Scan(S1))//按键1按下
  79. {
  80. printf("开始保存图片\r\n");
  81. //打开文件,若不存在就创建
  82. res_sd = f_open(&fnew, "0:test1.bmp", FA_OPEN_ALWAYS | FA_WRITE);
  83. //文件打开成功
  84. if(res_sd == FR_OK)
  85. {
  86. //填写文件信息头信息
  87. bmp.bmfHeader.bfType = 0x4D42; //bmp类型
  88. bmp.bmfHeader.bfSize= 54 + 320*240*2; //文件大小(信息结构体+像素数据)
  89. bmp.bmfHeader.bfReserved1 = 0x0000; //保留,必须为0
  90. bmp.bmfHeader.bfReserved2 = 0x0000;
  91. bmp.bmfHeader.bfOffBits=54; //位图信息结构体所占的字节数
  92. //填写位图信息头信息
  93. bmp.bmiHeader.biSize=40; //位图信息头的大小
  94. bmp.bmiHeader.biWidth=320; //位图的宽度
  95. bmp.bmiHeader.biHeight=240; //图像的高度
  96. bmp.bmiHeader.biPlanes=1; //目标设别的级别,必须是1
  97. bmp.bmiHeader.biBitCount=16; //每像素位数
  98. bmp.bmiHeader.biCompression=0; //RGB555格式
  99. bmp.bmiHeader.biSizeImage=320*240*2; //实际位图所占用的字节数(仅考虑位图像素数据)
  100. bmp.bmiHeader.biXPelsPerMeter=0; //水平分辨率
  101. bmp.bmiHeader.biYPelsPerMeter=0; //垂直分辨率
  102. bmp.bmiHeader.biClrImportant=0; //说明图像显示有重要影响的颜色索引数目,0代表所有的颜色一样重要
  103. bmp.bmiHeader.biClrUsed=0; //位图实际使用的彩色表中的颜色索引数,0表示使用所有的调色板项
  104. //RGB565格式掩码
  105. bmp.RGB_MASK[0].rgbBlue = 0;
  106. bmp.RGB_MASK[0].rgbGreen = 0xF8;
  107. bmp.RGB_MASK[0].rgbRed = 0;
  108. bmp.RGB_MASK[0].rgbReserved = 0;
  109. bmp.RGB_MASK[1].rgbBlue = 0xE0;
  110. bmp.RGB_MASK[1].rgbGreen = 0x07;
  111. bmp.RGB_MASK[1].rgbRed = 0;
  112. bmp.RGB_MASK[1].rgbReserved = 0;
  113. bmp.RGB_MASK[2].rgbBlue = 0x1F;
  114. bmp.RGB_MASK[2].rgbGreen = 0;
  115. bmp.RGB_MASK[2].rgbRed = 0;
  116. bmp.RGB_MASK[2].rgbReserved = 0;
  117. //写文件头进文件
  118. res_sd= f_write(&fnew, &bmp, sizeof(bmp), &fnum);
  119. }
  120. //读指针复位
  121. OV7725_RRST=0; //开始复位读指针
  122. OV7725_RCK_L;
  123. OV7725_RCK_H;
  124. OV7725_RCK_L;
  125. OV7725_RRST=1; //复位读指针结束
  126. OV7725_RCK_H;
  127. /*图像花屏的原因在于读取时的干扰和读取时漏掉几个像素*/
  128. for(i=0;i<240;i++)
  129. {
  130. for(j=0;j<320;j++)
  131. {
  132. OV7725_RCK_L;
  133. color=GPIOC->IDR&0XFF; //读数据
  134. OV7725_RCK_H;
  135. color<<=8;
  136. OV7725_RCK_L;
  137. color|=GPIOC->IDR&0XFF; //读数据
  138. OV7725_RCK_H;
  139. //写位图信息头进内存卡
  140. f_write(&fnew, &color, sizeof(color), &fnum);
  141. }
  142. }
  143. //关闭文件
  144. f_close(&fnew);
  145. delay_ms(1000);
  146. return;
  147. }
  148. //不需要保存图片,继续刷新LCD
  149. if(ov_sta)
  150. {
  151. LCD_Scan_Dir(U2D_L2R); //从上到下,从左到右
  152. LCD_WriteRAM_Prepare(); //开始写入GRAM
  153. //读指针复位
  154. OV7725_RRST=0; //开始复位读指针
  155. OV7725_RCK_L;
  156. OV7725_RCK_H;
  157. OV7725_RCK_L;
  158. OV7725_RRST=1; //复位读指针结束
  159. OV7725_RCK_H;
  160. /*图像花屏的原因在于读取时的干扰和读取时漏掉几个像素*/
  161. for(i=0;i<240;i++)
  162. {
  163. for(j=0;j<320;j++)
  164. {
  165. OV7725_RCK_L;
  166. color=GPIOC->IDR&0XFF; //读数据
  167. OV7725_RCK_H;
  168. color<<=8;
  169. OV7725_RCK_L;
  170. color|=GPIOC->IDR&0XFF; //读数据
  171. OV7725_RCK_H;
  172. LCD->LCD_RAM=color;
  173. }
  174. }
  175. ov_sta=0; //开始下一次采集
  176. ov_frame++;
  177. LCD_Scan_Dir(DFT_SCAN_DIR); //恢复默认扫描方向
  178. }
  179. }
  180. int main(void)
  181. {
  182. u8 lightmode=0,saturation=2,brightness=2,contrast=2;
  183. u8 effect=0;
  184. u8 i=0;
  185. delay_init();                 //延时函数初始化
  186. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
  187. uart_init(115200);         //串口初始化为 115200
  188. LED_Init(); //初始化与LED连接的硬件接口
  189. KEY_Init(); //初始化按键
  190. LCD_Init(); //初始化LCD
  191. //初始化SD卡
  192. if(SD_Init() == SD_OK)
  193. {
  194. printf("SD卡初始化成功,即将挂载SD卡。\r\n");
  195. }
  196. //挂载SD卡
  197. res_sd = f_mount(&fs, "0:", 1);
  198. POINT_COLOR=RED;//设置字体为红色
  199. LCD_ShowString(60,50,200,16,16,"M3S STM32");
  200. LCD_ShowString(60,70,200,16,16,"OV7725 TEST");
  201. LCD_ShowString(60,90,200,16,16,"www.doflye.net");
  202. LCD_ShowString(60,110,200,16,16,"need a 7725 camera");
  203. LCD_ShowString(60,130,200,16,16,"S1:Light Mode");
  204. LCD_ShowString(60,150,200,16,16,"S2:Saturation");
  205. LCD_ShowString(60,170,200,16,16,"S3:Brightness");
  206. LCD_ShowString(60,190,200,16,16,"S4:Contrast");
  207. LCD_ShowString(60,210,200,16,16,"OV7725 Init...");
  208. while(1)
  209. {
  210. //初始化ov7725
  211. if(OV7725_Init()==0)
  212. {
  213. LCD_ShowString(60,210,200,16,16,"OV7725 Init OK ");
  214.                   OV7725_Light_Mode(lightmode);
  215. OV7725_Color_Saturation(saturation);
  216. OV7725_Brightness(brightness);
  217. OV7725_Contrast(contrast);
  218. OV7725_Special_Effects(effect);
  219. //设置输出格式
  220. OV7725_Window_Set(OV7725_WINDOW_WIDTH,OV7725_WINDOW_HEIGHT,0);    //QVGA模式输出
  221. //输出使能
  222. OV7725_CS=0;
  223. break;
  224. }
  225. }
  226. EXTI8_Init(); //使能定时器捕获
  227. LCD_Clear(BLACK); //可以防止割屏
  228. while(1)
  229. {
  230. camera_refresh();       //更新显示
  231. i++;
  232. if(i==15)               //DS0闪烁.
  233. {
  234. i=0;
  235. LED0=!LED0;
  236. }
  237. }
  238. }

5. 实验效果

按下按钮S1,LCD图像停止刷新一秒,然后再SD卡上生成一张test1.bmp文件,在电脑端查看如下所示

(数据有点问题,(:)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/526410
推荐阅读
相关标签
  

闽ICP备14008679号