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

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

[复制链接]
攻城狮Melo 发布时间:2023-5-15 21:05
最近做项目需要用到OV7725,于是花了些时间研究。由于OV7725对于工作频率的要求较高,因此使用带FIFO的摄像头模块。代码参考自正点原子官方。
/ f+ [+ ]+ T0 e, }% [  h
" l+ t  U6 C1 O9 t9 N+ o3 Y% O+ `
' @8 I+ u0 z% Z0 q
OV7725资源
5 D0 G  Z& u9 o8 C4 O' J( d$ |2 `8 {引脚说明' n* w* A, B6 D0 H( I0 t; Z
以下时关于十八个引脚的说明(来自正点原子的用户手册)9 M$ r  P2 x- n  |
* Q$ _, w' E$ x% j
20200323141056716.png 8 R$ r6 `" |) w. @

; }* P' J) Y0 C' g7 l* `其中,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' z9 s5 |" B: r$ e6 \

* Z/ O4 `$ s) ]3 x6 E  N寄存器
6 c* k" I. {0 L: T0 {这是来自datasheet的寄存器描述,看手册,英文很重要:" c0 u! \6 |# l9 s1 K$ S( j
9 |* r! U4 o9 d8 J7 V$ U7 \8 z$ I
20200323135602683.png 1 u; h" ^9 u* ~' [& O" H0 e, R0 J8 v

# F0 B4 l1 s/ k/ L; C' }. D# a这些寄存器在代码里表现为一堆宏定义
  1.   /*OV7725寄存器宏定义*/
    6 L& @' j; A9 o( U, o% @
  2. #define GAIN      0x00% t, n+ I: a! C8 G9 X
  3. #define BLUE      0x01+ C# H% z7 O: R9 p1 ^; |, u8 W4 S5 j5 }
  4. #define RED       0x027 k% i% t8 b2 z: v" }
  5. #define GREEN     0x03
    2 V! m. S9 ^. i" j6 N. P: Z
  6. #define BAVG      0x05
    & _" r8 E1 Q8 `+ P+ b- U- I
  7. #define GAVG      0x06
    1 r2 L0 B9 a- h- G" V3 f8 O4 [" p
  8. …………4 ]$ ^! |9 n0 B# K/ I% m  y
复制代码
6 y: v4 z4 m% r5 V2 B
模块初始化
0 d3 V$ h' B9 Z5 D$ N% i引脚定义
* k& B+ c" M! x- W8 H/ Q7 ^
  1. //D0~D7:PA0~PA7       VSYNC:PA84 h9 B/ |5 x/ l$ i, z/ _
  2. //WRST:PB13  RRST:PB14  OE:PB5  RCLK:PB6  WEN:PB7  SDA:PB8  SCL:PB9   
    ) L) S/ h1 e+ ]/ b, q0 }3 \
  3. #define OV7725_VSYNC    PAin(8)                        2 }5 _6 w7 a4 @  Y/ c
  4. #define OV7725_WRST                PBout(13)               
    ! c( l( @2 k  q+ D) ^! a6 }2 M8 w
  5. #define OV7725_WREN                PBout(7)                + C; a- ~* l. X7 b. a
  6. #define OV7725_RCK_H        GPIOB->BSRR=1<<6
    ! F4 L- E" w1 l/ E& z  l- G
  7. #define OV7725_RCK_L        GPIOB->BRR=1<<6
    7 Q, }1 r7 p, ?6 e
  8. #define OV7725_RRST                PBout(14)          6 x: p0 G+ K; e; w. {* M
  9. #define OV7725_CS                PBout(5)  , c! R" N3 K9 U& e1 P# P  W
复制代码
  1. #define SCCB_SCL                    PBout(9)                 //SCL9 I* l' W' t- Y8 ~+ @
  2. #define SCCB_SDA                    PBout(8)                 //SDA         
    / C7 p) J6 m" x. X

  3. % R) h8 x: b0 y+ f
  4. #define SCCB_READ_SDA            PBin(8)                  //ÊäÈëSDA   2 X+ i, c/ O$ `. m
复制代码

5 x* Z# o5 I; f* V) s4 T7 o: P& d" l6 y
我使用的是杜邦线连接如,IO口是自己重新定义的(全使用普通IO即可),STM32F1系列的PB3,PB4,PA13,PA14,PA15用于JTAG,如果有使用到其中的引脚,需要进行特殊配置,具体可参考网上更多教程。当时使用PB3,PB4作为SCCB的引脚,出现问题才发现这个原因。
8 [: ^. u. M$ d  y- a

. g$ v3 s8 K$ Z4 @: e: I$ k初始化5 _, w$ y2 K2 s1 m$ r* X: ?
写寄存器的函数,寄存器的配置都是通过这个函数7 s. i7 k2 C' z' |; V: B+ u
  1. u8 SCCB_WR_Reg(u8 reg,u8 data)( y% a( r- }8 e' h/ ]  ^
  2. {1 o, p3 a1 S' L% d$ a9 I
  3.         u8 res=0;% |2 ?: L6 A! C; r
  4.         SCCB_Start();                          //启动SCCB传输                 6 B7 H4 H: U9 l
  5.         if(SCCB_WR_Byte(SCCB_ID))res=1;        //写器件ID,为0x42
    0 j, s& E; X* o5 {
  6.         delay_us(100);5 P, l+ T4 k# P" m+ W+ P8 ^
  7.           if(SCCB_WR_Byte(reg))res=1;                //写寄存器地址,直接写对应的寄存器地址+ K0 U' k9 C$ i) r( Y
  8.         delay_us(100);6 A' z7 Y; O/ {# l& _. Y
  9.           if(SCCB_WR_Byte(data))res=1;         //写数据,根据寄存器功能写对应数据9 V6 O6 |9 A+ g  m8 L3 j
  10.           SCCB_Stop();          ( ?& F( S/ R' ~1 \
  11.           return        res;
    2 A: y1 L% @0 W; z  w1 E
  12. }                          
    5 l0 l+ O( c0 G& I% f# z4 b
复制代码
: @8 k1 }6 F4 p  z: i
将要配置的寄存器地址和对应的值,存在一个二维数组里边0 L8 q+ ^# N* O9 h0 i) H* J
  1. //初始化寄存器系列及其对应的值
    ; H7 M- L" G( y. H  Z
  2. const u8 ov7725_init_reg_tb1[][2]=
      b. V# q5 |  Z
  3. {   
    + }, z5 F/ _# c* w) N
  4.         /*输出窗口设置*/
    ! a5 d2 {8 q9 F8 L# r6 c; T6 x
  5.         {CLKRC,     0x00}, //clock config
    ) ~3 ]" y0 o9 C" a$ ]
  6.         {COM7,      0x06}, //VGA RGB5652 {) E! f+ }5 ~
  7.         {HSTART,    0x3f}, //水平起始位置
    # w6 J4 V8 D  d! z
  8.         {HSIZE,     0x50}, //水平尺寸
    8 x$ x, n4 X8 |1 g
  9.         {VSTRT,     0x03}, //垂直其实位置
    % h* I1 b- |& V
  10.         ......9 p* H% ]+ J& A2 g% @: `
复制代码
4 X/ o# ^! ?; g) r, X2 a: d
初始化时,在循环语句调用写寄存器的函数,依次写入寄存器的地址和对应的值,即可完成寄存器的配置
; B; u1 P) g, U$ y  i4 x
  1.   //初始化OV7725,采用QVGA分辨率(320*240)    a- J0 h% v( p: Z+ S- E' s
  2.         for(i=0;i<sizeof(ov7725_init_reg_tb1)/sizeof(ov7725_init_reg_tb1[0]);i++)
    4 T& [5 c+ h' Z
  3.         {                                                                + J3 j7 s1 ^' F+ d
  4.                    SCCB_WR_Reg(ov7725_init_reg_tb1[i][0],ov7725_init_reg_tb1[i][1]);2 J8 J9 |* X* y9 H% S
  5.          }
    7 N3 N3 p$ H! I5 Y/ w: N" M
复制代码
' Z. W3 v. C( B/ c2 R
帧中断和数据处理
7 w/ q: G" |) {5 }2 \发生帧中断时8 T* u9 O! Y9 ?# i
  1. u8 ov_sta;        //帧中断标记
    4 h7 J6 S) p8 B- B. [; X
  2. //中断处理函数- p8 M" ~4 {, t2 ]
  3. void EXTI9_5_IRQHandler(void): K9 K* E0 q: |( w8 F
  4. {                                 " G0 T: g: [& H5 B, ~
  5.         if(EXTI_GetITStatus(EXTI_Line8)==SET)//是8线的中断
    + ~0 ~) [. }& p" |
  6.         {      
    % L* N  H; X$ p0 ^' z! b7 j' Z0 K: W
  7.                 if(ov_sta==0)
    ; L* g4 t7 Q% U2 A- {
  8.                 {# w8 v2 k; k: \' z. q
  9.                         OV7725_WRST=0;        //复位写指针                 
    - }5 h) Z" M" Z  F) R7 a+ p% c& C4 v. [4 r( S
  10.                         OV7725_WRST=1;        2 q2 F# g  U$ L' ~& Y4 d
  11.                         OV7725_WREN=1;        //允许写入FIFO          
    0 o( @* a& m+ o- R$ U' Q
  12.                         ov_sta++;                //帧中断加1  z5 k. u% O) z8 T
  13.                 }else OV7725_WREN=0;//禁止写入FIFO
    8 a- B- u; q  T: f: G4 M# p/ K
  14.         }
    - X  _$ m( w. [) t8 _
  15.         EXTI_ClearITPendingBit(EXTI_Line8);  //清除中断标志位                                          
    & P( u; e- O4 v2 l7 R9 t/ d
  16. }
    8 n8 e% L4 ~3 x/ X4 D
复制代码

' B* c2 ^' l; d0 ~4 S数据处理
7 i4 K( k7 b  W4 q4 ~/ a, U
  1. if(ov_sta)//判断是否有帧中断发生7 n: C+ S" l# u) c( Q1 R
  2. {% e( h9 }/ g9 |+ \2 g
  3.         OV7725_RRST=0;                  //复7 A7 C& V' _9 i7 E$ l. g
  4.         OV7725_RCK_L;         //位) ]4 K$ C# S6 p) H7 J& _
  5.         OV7725_RCK_H;         //读
      I* e0 E3 a, {3 T8 @
  6.         OV7725_RCK_L;         //指
    7 g7 E& M/ A  ^8 X
  7.         OV7725_RRST=1;                  //针
    , h5 |: T* G1 c3 s6 Q% [
  8.         OV7725_RCK_H; ! M; G' X" y7 ]5 J) S% V
  9.         for(i=0;i<OV7725_WINDOW_HEIGHT;i++)//循环语句读取FIFO的数据
    6 J8 k5 k. {% S- T2 O5 y
  10.         {
    8 @* u3 P1 g8 ?- @5 @( u/ L- P
  11.                 for(j=0;j<OV7725_WINDOW_WIDTH;j++)
    + Q0 p2 \$ o/ }3 j8 b) q( c
  12.                 {
    0 j1 T. j$ A0 D+ D
  13.                         //将数据填入相应缓冲区! h4 z7 d* r6 Q
  14.                         ......
    $ D5 a  L1 o7 i/ w$ x
  15.                 }
    9 n; }. D  u# b; ^- G
  16.         }
    ! _% j9 N+ ^$ o5 b- Q2 [
  17.         ov_sta=0;  //清零帧中断标志
    ; M: j/ ]/ r$ L- d
  18. }- R5 w& O& ?/ K+ ^, ~
复制代码

7 d9 K/ m0 T" l( y7 Q以上是对于OV7725的初步理解,还有很多不懂的地方,后续有进一步研究再补充
) d' K3 W3 L( G/ E  \. b$ P# z1 t/ g6 m————————————————
% p, {) i  V2 |# n: j  W# z版权声明:hu_hong_hao% {0 @4 P6 P  h1 q9 z. J6 [: m! \8 s
如有侵权请联系删除
% |; r  n2 l# M
4 w$ f4 @; b* j1 p% {3 T+ x, c6 R8 A* I

2 x1 Q; B  E1 N9 w
赞 收藏 评论0 发布时间:2023-5-15 21:05

举报

0个回答

所属标签

相似技术帖

官网相关资源

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