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

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

[复制链接]
攻城狮Melo 发布时间:2023-5-15 21:05
最近做项目需要用到OV7725,于是花了些时间研究。由于OV7725对于工作频率的要求较高,因此使用带FIFO的摄像头模块。代码参考自正点原子官方。
/ `% A8 }" {" A: C3 K9 K4 X
) o! \! b/ W' S6 w# S

; ^+ k* w9 |% w. M& UOV7725资源6 D8 q  W* o, S
引脚说明6 G3 J1 k0 e1 ?% j7 w/ D8 k/ b8 @
以下时关于十八个引脚的说明(来自正点原子的用户手册)7 [8 u5 d7 t. T3 @) d6 ?

8 i* Y" D4 B7 @* I! h
20200323141056716.png ( f1 o& K  D) K+ C) m, k

0 s( u. ?& {8 H9 o& H% ]/ j其中,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片选信号在初始化之后就拉低,使之有效。
) X( g3 Z+ O3 I  h' o6 T1 Y; x( m/ J: z* F+ \/ L
寄存器9 P2 V4 Z- H3 E0 ]0 _9 a
这是来自datasheet的寄存器描述,看手册,英文很重要:5 m5 V7 J9 H+ I, w* a% O
, o# r$ w  u5 Z0 A, ?* k
20200323135602683.png " Q9 \5 H6 o, w- E' {/ [5 |( C6 p
/ [' }0 a: D' O
这些寄存器在代码里表现为一堆宏定义
  1.   /*OV7725寄存器宏定义*/, E8 R- z* b$ |' n0 E) \5 B
  2. #define GAIN      0x00  ~. {8 k7 A; W: U: C; t2 x
  3. #define BLUE      0x01% _* @3 J9 i2 p5 }
  4. #define RED       0x025 g; P0 B3 f$ z/ U# S
  5. #define GREEN     0x033 ?9 }* W6 {5 v7 x
  6. #define BAVG      0x05
    : K" ?+ J% S) |5 t7 v
  7. #define GAVG      0x062 a: p2 ^, {2 Q+ `! I! U% c, u9 d
  8. …………; f4 f5 ~" j" P
复制代码
3 z7 |( E9 A1 L" p% r
模块初始化
4 }+ b# C2 P/ l5 [' t% W, c引脚定义

& h! X8 d6 M9 ]1 }! R) h7 e9 N
  1. //D0~D7:PA0~PA7       VSYNC:PA8
    * B/ d, o5 s2 J) k
  2. //WRST:PB13  RRST:PB14  OE:PB5  RCLK:PB6  WEN:PB7  SDA:PB8  SCL:PB9   
    ( L, e2 X5 g, x) ~, T6 F
  3. #define OV7725_VSYNC    PAin(8)                        
    , ?& x8 q7 K5 u! s4 G6 h  D
  4. #define OV7725_WRST                PBout(13)                & e1 Q; J# _: u# a
  5. #define OV7725_WREN                PBout(7)                ' N7 u% Z, i. J' ^0 T
  6. #define OV7725_RCK_H        GPIOB->BSRR=1<<6
    - e& J% c6 I$ R/ ]) D: }
  7. #define OV7725_RCK_L        GPIOB->BRR=1<<6
    " u  n4 G# [2 S0 _% Q% j
  8. #define OV7725_RRST                PBout(14)          6 f9 u  U5 V8 P# F1 W: X6 B! b
  9. #define OV7725_CS                PBout(5)  
    ( J; P6 U8 {6 b) j7 D
复制代码
  1. #define SCCB_SCL                    PBout(9)                 //SCL# P- `6 K" R- j- b
  2. #define SCCB_SDA                    PBout(8)                 //SDA         
    7 M" K, X; d. P: f$ n: x

  3. " q9 B8 b- T! k. W% U& w& r
  4. #define SCCB_READ_SDA            PBin(8)                  //ÊäÈëSDA   
    6 E- t4 W8 @( k& v' Z5 J: g
复制代码
( x  S6 x0 R0 E, b0 V
0 O( K# l  x: c1 y, T- ~% k
我使用的是杜邦线连接如,IO口是自己重新定义的(全使用普通IO即可),STM32F1系列的PB3,PB4,PA13,PA14,PA15用于JTAG,如果有使用到其中的引脚,需要进行特殊配置,具体可参考网上更多教程。当时使用PB3,PB4作为SCCB的引脚,出现问题才发现这个原因。3 E% f; @. M) m4 ?
' X8 }/ I6 E$ U" g  D; g  {: g
初始化
3 W- W( ]2 M  ]2 w写寄存器的函数,寄存器的配置都是通过这个函数/ p6 _: j8 O# m) {! D% ~, q
  1. u8 SCCB_WR_Reg(u8 reg,u8 data)+ Q; H4 Y7 j9 d+ h5 I2 ~+ m
  2. {
    . `# D- N, p! J# W6 j1 Q
  3.         u8 res=0;5 N2 F) c( I* P3 |6 S/ x
  4.         SCCB_Start();                          //启动SCCB传输                 
    ( S9 I0 P1 W! C6 Y( I+ y( z
  5.         if(SCCB_WR_Byte(SCCB_ID))res=1;        //写器件ID,为0x42
    & e! y4 w7 ^+ k
  6.         delay_us(100);
    8 ~  X( k/ S% }5 P# P  x. w. Z8 A
  7.           if(SCCB_WR_Byte(reg))res=1;                //写寄存器地址,直接写对应的寄存器地址% `1 O3 v/ j" c) U) u' k' B
  8.         delay_us(100);* N8 _8 t7 g9 k9 j, v2 D; }
  9.           if(SCCB_WR_Byte(data))res=1;         //写数据,根据寄存器功能写对应数据8 N9 D! v: ?, j
  10.           SCCB_Stop();          % p. ]4 G$ y' F( M/ q% s- I* [' \
  11.           return        res;- @# X7 J1 t% P& |# E9 i
  12. }                          
    8 b( z( n. e4 g
复制代码

6 V. }6 `; v* O) S5 B. l将要配置的寄存器地址和对应的值,存在一个二维数组里边; Y) y, ^2 M/ Q* \9 n
  1. //初始化寄存器系列及其对应的值/ o, Y  n4 z& _# p8 f7 {
  2. const u8 ov7725_init_reg_tb1[][2]= . E. k4 A( Q, N. s
  3. {   3 O4 W% u" I( W7 W: A1 ^/ b. v
  4.         /*输出窗口设置*/
    ! m7 N6 e. ^/ g" ~9 I& P* S  ]  v8 p
  5.         {CLKRC,     0x00}, //clock config
    # C. ~8 s' n0 _( K( {
  6.         {COM7,      0x06}, //VGA RGB565+ o7 c! L# G8 I( }
  7.         {HSTART,    0x3f}, //水平起始位置; m* T" Z% B. M% ?1 Z
  8.         {HSIZE,     0x50}, //水平尺寸
    * Y: g. Q2 \6 z7 }3 b& ]
  9.         {VSTRT,     0x03}, //垂直其实位置
    0 r1 G9 F+ N8 L+ I! K
  10.         ......
    + K9 y' I. d8 e- f
复制代码
2 w* }9 c0 t; {
初始化时,在循环语句调用写寄存器的函数,依次写入寄存器的地址和对应的值,即可完成寄存器的配置
) O. c5 ?$ B# C/ t6 b) h9 J6 ^
  1.   //初始化OV7725,采用QVGA分辨率(320*240)  
    : r! C8 ~. i" R% w3 t# N+ @1 K% w
  2.         for(i=0;i<sizeof(ov7725_init_reg_tb1)/sizeof(ov7725_init_reg_tb1[0]);i++)
    ! }. B. G0 q( \) ]) Z; t# Z
  3.         {                                                               
    . a4 `2 e3 |2 d. {5 ^- h
  4.                    SCCB_WR_Reg(ov7725_init_reg_tb1[i][0],ov7725_init_reg_tb1[i][1]);
    3 L5 i* n5 M/ U
  5.          } ' W7 O6 J" ~, E; Z' U9 L
复制代码

9 X) L, f. _0 [9 y2 w6 ?) |( ?! ^帧中断和数据处理" @9 s9 H0 F( v
发生帧中断时3 ?1 V6 G, _& X0 {+ I, K4 p. [
  1. u8 ov_sta;        //帧中断标记
    - a3 T. }5 J- S# v# ?8 Y
  2. //中断处理函数" O, j' y4 v1 E+ G1 o
  3. void EXTI9_5_IRQHandler(void)
    5 q, Y9 `* {8 k1 B" }
  4. {                                 ) T4 x9 e  m$ q& b3 D0 U
  5.         if(EXTI_GetITStatus(EXTI_Line8)==SET)//是8线的中断
    / D$ a# J; F6 A+ S+ q
  6.         {      ; w. S* \$ n: R" n, J- d1 R
  7.                 if(ov_sta==0)
    . a" v' o( w2 w6 V) U
  8.                 {
    4 X0 N3 \2 D. e8 d* t# s
  9.                         OV7725_WRST=0;        //复位写指针                 ( O- \( R5 M; J0 h
  10.                         OV7725_WRST=1;        , T" C' y" T' z: N" V. s, |( y
  11.                         OV7725_WREN=1;        //允许写入FIFO          
    " i4 g+ T. s7 a- w# S0 ?7 `7 f
  12.                         ov_sta++;                //帧中断加1
    6 ?9 W% M* P& ?, P) ~
  13.                 }else OV7725_WREN=0;//禁止写入FIFO
    3 e8 V, @3 \, P. ^" |3 ^# M& v" n
  14.         }& W5 C* C3 m8 e% O; T2 U
  15.         EXTI_ClearITPendingBit(EXTI_Line8);  //清除中断标志位                                          , I* J# }1 A+ s2 ^
  16. }
    : J6 |- V7 I$ h7 B
复制代码
8 |2 h  c$ ]9 \, Q9 }: G4 o, z
数据处理
/ J! x3 s6 M9 a  z0 E
  1. if(ov_sta)//判断是否有帧中断发生6 V: |6 H2 n* \3 {
  2. {
    ; p6 T/ d( V. P+ c
  3.         OV7725_RRST=0;                  //复  {$ |7 U# ~# g5 P0 V0 X; `
  4.         OV7725_RCK_L;         //位+ b% W: `* x+ a0 ]4 _
  5.         OV7725_RCK_H;         //读4 N9 I* C* |" t8 a* h
  6.         OV7725_RCK_L;         //指
      `+ |8 V, p( W2 T* W
  7.         OV7725_RRST=1;                  //针' X4 B6 i6 c" x5 i" I/ Z1 I% _
  8.         OV7725_RCK_H; + ~% H0 @' _0 x( x  s& x( H- x$ t
  9.         for(i=0;i<OV7725_WINDOW_HEIGHT;i++)//循环语句读取FIFO的数据3 \8 b% t+ D( r  Z
  10.         {
    # @1 x2 p: Y) S% h
  11.                 for(j=0;j<OV7725_WINDOW_WIDTH;j++)( \5 D' V; K9 l+ E7 }
  12.                 {) d4 [& u! v# r: I% r" i
  13.                         //将数据填入相应缓冲区
    9 I, j6 p$ N% ?) H: Z8 F
  14.                         ......  \0 z7 f' w5 R7 x- U0 u1 o& @
  15.                 }2 ]7 J2 a1 t3 l9 ~3 c$ a' {& Y; W
  16.         }
    2 v$ P6 w2 N' U5 H' Y
  17.         ov_sta=0;  //清零帧中断标志5 W6 R+ C3 l. I5 C
  18. }
    ) w0 d% a. j1 Y& w! Z" W- F1 K
复制代码

) D9 o( O6 K  O8 p9 {3 K; T以上是对于OV7725的初步理解,还有很多不懂的地方,后续有进一步研究再补充
1 x  B0 X- D$ m4 Q  e4 b————————————————
) B! R. C' @4 H/ f) U$ q: `版权声明:hu_hong_hao
9 X3 N# P/ a6 y0 Q# Z如有侵权请联系删除8 e- R# ?3 c2 w  E0 s: ^$ m

* W( ?. G& f' }8 W- z; m  H: d  q- ?" N5 c) j$ C# ^4 [
! q9 ]5 v. _; ]
赞 收藏 评论0 发布时间:2023-5-15 21:05

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版