你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32F1的OV7725摄像头经验分享

[复制链接]
攻城狮Melo 发布时间:2023-5-15 21:05
最近做项目需要用到OV7725,于是花了些时间研究。由于OV7725对于工作频率的要求较高,因此使用带FIFO的摄像头模块。代码参考自正点原子官方。9 B2 @6 l! H$ X5 t' _; S& a
/ F8 @5 c( j! t3 G7 U8 |
! w6 e, a3 R8 ?  w
OV7725资源0 Z1 L& R6 j1 F+ Y9 Q5 S2 m
引脚说明
: y" W. k; k, T: i. S) w$ X+ B以下时关于十八个引脚的说明(来自正点原子的用户手册), W$ y/ ]- z, n0 [* f& B! g

" c" J0 B5 s7 X  b5 A4 m/ |  X3 @: e
20200323141056716.png 3 n% I. c9 g8 b& S5 y) p+ k

+ b" W& o/ ]" f/ t& F" ]+ H其中,OV_SCL和OV_SDA组成SCCB,即串行摄像头控制总线,它的通信机制类似于IIC,有使用过IIC总线的较容易理解。OV_VSYNC为帧同步信号,该引脚产生信号时,意味着一帧数据传输完成后,下一帧数据传输即将开始(这里,从OV7725传输至FIFO)。FIFO_D[7:0] 是FIFO的数据引脚,用于数据传输。当发生帧同步信号时,复位FIFO_WRST写指针信号,使能FIFO_WEN写使能信号,则OV7725开始往FIFO写数据,并置位帧中断标志位(该标志位在读数据完成后被清零),保证FIFO的数据被读取完成之前不会被覆盖,具体见下面的中断服务程序。帧中断标志位有效时,就复位RIFO_RRST读指针信号,然后在每个FIFO_RCLK读时钟信号,使用STM32去读取FIFO_D[7:0] 的数据。FIFO_OE片选信号在初始化之后就拉低,使之有效。5 C8 A4 S  b. c- [3 M% O

. C' R0 v3 _( L$ Y6 Y0 Z寄存器6 n% j  Z5 e7 N0 ^
这是来自datasheet的寄存器描述,看手册,英文很重要:
% y- D0 {- ~. Q* J5 @  `' J5 M! F+ ~! _) T
20200323135602683.png - H+ h& N/ ]) ^. c# N

* ?% f* h! V  R  k- y这些寄存器在代码里表现为一堆宏定义
  1.   /*OV7725寄存器宏定义*/
    3 t6 x4 P5 s- m8 ?4 C7 _$ K. p; U
  2. #define GAIN      0x004 p# @1 Q. w3 x/ l( |) ^
  3. #define BLUE      0x01: E# c% f7 Y/ _& [5 ~; g$ v! [! o
  4. #define RED       0x02
    8 q6 l* w3 w2 k. l  i0 Y0 L1 q
  5. #define GREEN     0x030 T( c- ?0 l) m: X7 O
  6. #define BAVG      0x05
      f% [% `: f$ q" F( i) e
  7. #define GAVG      0x06
      K& t2 W5 J; x% x/ c. y" M% X
  8. …………! a& h  T- i! _6 K4 M
复制代码
1 S3 y1 \( {5 i% C* R2 {  e
模块初始化0 c/ I! \) M: m3 Z1 o  {
引脚定义

) W+ j" w  J5 [! C& y7 Z: p
  1. //D0~D7:PA0~PA7       VSYNC:PA8% s% ^5 X( U" H7 ^  w" u
  2. //WRST:PB13  RRST:PB14  OE:PB5  RCLK:PB6  WEN:PB7  SDA:PB8  SCL:PB9   
    # ?4 G* k- U' [5 t) ?* [! A
  3. #define OV7725_VSYNC    PAin(8)                        ' V  }9 G( W8 P3 z
  4. #define OV7725_WRST                PBout(13)                9 v( v0 k8 c- Q2 s- s
  5. #define OV7725_WREN                PBout(7)               
    - u* L, z6 S0 d  z( F
  6. #define OV7725_RCK_H        GPIOB->BSRR=1<<6
    2 g8 a- A0 c3 \
  7. #define OV7725_RCK_L        GPIOB->BRR=1<<6: g5 j  C, b0 R  L1 r
  8. #define OV7725_RRST                PBout(14)         
    ) J, l4 m9 u* U! G1 B
  9. #define OV7725_CS                PBout(5)  # T9 N: H9 m3 e0 ~' p
复制代码
  1. #define SCCB_SCL                    PBout(9)                 //SCL1 `, W+ F4 j2 A' v
  2. #define SCCB_SDA                    PBout(8)                 //SDA         
    $ P. P4 Q0 J1 i# A

  3. 3 T2 Q2 T# n. @5 S' ^7 A, X( H
  4. #define SCCB_READ_SDA            PBin(8)                  //ÊäÈëSDA   $ m0 g- D3 W7 x+ I, L0 M3 i
复制代码
  O  M) Y  L. `+ {! p' P+ C9 R, T2 ]

( k3 P! R) g5 |& {2 N我使用的是杜邦线连接如,IO口是自己重新定义的(全使用普通IO即可),STM32F1系列的PB3,PB4,PA13,PA14,PA15用于JTAG,如果有使用到其中的引脚,需要进行特殊配置,具体可参考网上更多教程。当时使用PB3,PB4作为SCCB的引脚,出现问题才发现这个原因。
0 p) f' `" N: W* W, T. v
7 m; f$ b( h( E6 c0 o$ `
初始化  b4 K4 u6 V4 @3 C( ?& K, n4 K
写寄存器的函数,寄存器的配置都是通过这个函数/ R% {7 B" q5 Q( J: d  V. y
  1. u8 SCCB_WR_Reg(u8 reg,u8 data)0 H5 d' L3 }  c2 b' [0 s9 T9 p
  2. {
    2 r! H& M1 }7 f* k3 ?
  3.         u8 res=0;. r- b4 D' o2 j- K- D- ~
  4.         SCCB_Start();                          //启动SCCB传输                 + p, ~5 @; W0 z1 p( C1 i
  5.         if(SCCB_WR_Byte(SCCB_ID))res=1;        //写器件ID,为0x42
    % `5 @+ ~8 c) @3 q& j, R1 l! s
  6.         delay_us(100);8 A7 T7 w3 F6 F/ R1 [6 S' O- m
  7.           if(SCCB_WR_Byte(reg))res=1;                //写寄存器地址,直接写对应的寄存器地址, o+ [* Z& ]6 @, `# E
  8.         delay_us(100);
    ' ~6 y& ~! H# N, N" d( a( R
  9.           if(SCCB_WR_Byte(data))res=1;         //写数据,根据寄存器功能写对应数据
    5 j6 W+ s7 ?5 ]
  10.           SCCB_Stop();         
    $ }/ g" X8 b; g8 m$ u0 n0 [
  11.           return        res;! H- m5 `) K( |! d  z/ R) u6 W
  12. }                          
    9 E7 C# U/ q# |9 R$ s$ W
复制代码

" z, X$ I; |5 A/ U将要配置的寄存器地址和对应的值,存在一个二维数组里边7 g. Z! M& X7 e) u7 k
  1. //初始化寄存器系列及其对应的值9 @* \2 C5 }2 l* \6 p' ]
  2. const u8 ov7725_init_reg_tb1[][2]=
    0 ~  ]5 u! _) P
  3. {   % a" j) P2 l" |, ~  F
  4.         /*输出窗口设置*/5 e( n% ^2 Y6 H; c5 i8 A) v( E5 |, R7 f
  5.         {CLKRC,     0x00}, //clock config
    " u% ?, E! U* C  ~
  6.         {COM7,      0x06}, //VGA RGB565  }/ c. v/ G$ W: V; n+ e
  7.         {HSTART,    0x3f}, //水平起始位置  ~) Y- e0 U% V/ S' x2 L+ ^4 U
  8.         {HSIZE,     0x50}, //水平尺寸
    % M3 x7 K/ V( y, P% J
  9.         {VSTRT,     0x03}, //垂直其实位置! Y8 C( |) c7 V( e6 b! r0 M
  10.         ......' s+ R7 S) z/ d# T  V
复制代码

# C5 e: t3 Z6 u. D# j( Z9 S初始化时,在循环语句调用写寄存器的函数,依次写入寄存器的地址和对应的值,即可完成寄存器的配置
; F& v" P7 c6 K+ z+ I, d
  1.   //初始化OV7725,采用QVGA分辨率(320*240)  
    . H3 E# N0 X" Q. q
  2.         for(i=0;i<sizeof(ov7725_init_reg_tb1)/sizeof(ov7725_init_reg_tb1[0]);i++)
    & b3 A8 F: n$ G9 @3 O% B: ]4 y' f
  3.         {                                                                " \9 x3 F2 ^3 J( b
  4.                    SCCB_WR_Reg(ov7725_init_reg_tb1[i][0],ov7725_init_reg_tb1[i][1]);
    6 |: {0 c9 @/ O' I, A% f7 q
  5.          } 7 c6 ~1 ~8 G# G" w- l; g
复制代码
( [6 u& E. B% t6 u: k/ f, V! \, V4 h
帧中断和数据处理* }+ |& B& d* k# m
发生帧中断时
+ c' M0 v  w* D0 B& F! n. t
  1. u8 ov_sta;        //帧中断标记
    1 z2 ~2 ~; \( N- A0 z7 G' g
  2. //中断处理函数
      ]" u4 N, f' U$ D
  3. void EXTI9_5_IRQHandler(void)2 T% K# Q4 _9 N4 I
  4. {                                
    ) o1 }1 H1 n5 x8 e
  5.         if(EXTI_GetITStatus(EXTI_Line8)==SET)//是8线的中断) `' Z. l; c1 o# F, ?
  6.         {      
    % t+ h  _2 P( ^6 J+ O
  7.                 if(ov_sta==0), s- X, v) N* B0 u6 N  _: k- f
  8.                 {$ V: \  @! p4 m
  9.                         OV7725_WRST=0;        //复位写指针                 
    ; W4 o+ y7 n6 s+ z) \- x' R
  10.                         OV7725_WRST=1;        / V0 g% K+ I- c0 J+ B
  11.                         OV7725_WREN=1;        //允许写入FIFO          $ U; O1 O& Y1 N6 d; q+ f
  12.                         ov_sta++;                //帧中断加1( i) i! C$ M. M1 N! f! j7 K
  13.                 }else OV7725_WREN=0;//禁止写入FIFO
    & S; v7 C! O1 }* K- e
  14.         }
    : _. d$ ?1 T4 H) Q: @
  15.         EXTI_ClearITPendingBit(EXTI_Line8);  //清除中断标志位                                            d: C+ w6 h7 v4 O1 d+ P
  16. } 6 W0 v! Y7 K- C# d+ m
复制代码
! w8 T# Z4 C7 x
数据处理) m. x2 Z% y5 b; t8 C
  1. if(ov_sta)//判断是否有帧中断发生7 b3 p% i. |& O' _4 C; ]& o
  2. {
    8 t5 |( `0 \( A7 ^5 m2 ~$ `
  3.         OV7725_RRST=0;                  //复; j% B0 ]' R2 u: x, @, z, u7 Y
  4.         OV7725_RCK_L;         //位
      z' `/ V! ?2 n! V) J, r
  5.         OV7725_RCK_H;         //读
    0 \& t7 t+ z0 I/ }* f/ I
  6.         OV7725_RCK_L;         //指
    9 J  R6 [$ s7 u  P- x7 f
  7.         OV7725_RRST=1;                  //针$ k! |7 y% `8 \/ i1 J; w% M( L
  8.         OV7725_RCK_H; 7 t. H) r) w; A$ A' y4 I
  9.         for(i=0;i<OV7725_WINDOW_HEIGHT;i++)//循环语句读取FIFO的数据
    0 C; ^. E+ L+ {" {; j4 S1 q4 k. ~
  10.         {
    5 ]; m1 @8 @. q& ~
  11.                 for(j=0;j<OV7725_WINDOW_WIDTH;j++)9 Z! A7 P% ?# I' s2 {' f
  12.                 {
    3 D7 d$ W1 L5 O! J5 l4 b( v
  13.                         //将数据填入相应缓冲区# s# s! r4 ?. `; ^/ c- _
  14.                         ......: }& G0 O) b5 a% x
  15.                 }* V% |+ ~- T/ B! Z. I
  16.         }' O& N5 @# ]9 ~1 u  y) ^
  17.         ov_sta=0;  //清零帧中断标志
    9 |2 `# f$ k& z0 b
  18. }
    ' C% U( z7 {9 m0 V, f; g8 n" g
复制代码
( H* D, g" x7 O; u% C- n! Q8 W
以上是对于OV7725的初步理解,还有很多不懂的地方,后续有进一步研究再补充& O. |8 c% t$ K) _& A
————————————————' M! Y% u# R/ Y" Q
版权声明:hu_hong_hao' H) Z3 E8 x+ e, V6 d" A: p) n
如有侵权请联系删除
, ~) }& e7 a9 ^0 C& Z6 o, U3 o# t' Y+ H+ q- K) \4 t, f/ t
$ `2 @0 o! n. ~( j; g$ ]. v# a, x
$ P  k- \; x) i; U4 E+ H
收藏 评论0 发布时间:2023-5-15 21:05

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版