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

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

[复制链接]
攻城狮Melo 发布时间:2023-5-15 21:05
最近做项目需要用到OV7725,于是花了些时间研究。由于OV7725对于工作频率的要求较高,因此使用带FIFO的摄像头模块。代码参考自正点原子官方。
- T6 m) s- J, o& m4 x1 J, K* ^: d# K* E3 B5 |+ L, S" C
% o( ]( F$ `1 u' j) S) U1 E  ?1 H
OV7725资源0 C; v' }3 [& [- s
引脚说明
- f/ s) B% E: H* J8 G以下时关于十八个引脚的说明(来自正点原子的用户手册)9 R  b% q$ l0 `4 v( x1 b* G/ d9 X
) n% \' s. h+ t4 X
20200323141056716.png
2 j  p  s+ I4 Y4 L: w

' j* K3 S9 Y* w" b1 q, \其中,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片选信号在初始化之后就拉低,使之有效。
$ A( k$ `; p  w6 X4 U5 T. l" f: y
- r/ R% J3 v1 b3 B1 o寄存器
# W9 F% m, m, B  W' D这是来自datasheet的寄存器描述,看手册,英文很重要:) N. v+ d5 y* f+ ]8 J
- t. q. w+ k8 n9 Z8 t
20200323135602683.png 6 x  v+ S. M0 N5 J5 O5 n0 w' s

1 W9 `, B% k, S2 ?6 U" A4 N这些寄存器在代码里表现为一堆宏定义
  1.   /*OV7725寄存器宏定义*/
    7 Z1 o8 e7 u/ p) M' P
  2. #define GAIN      0x00
    4 u/ ?4 ~( ]# D; W- I% u
  3. #define BLUE      0x018 O- `! w( b! x. R* g; s; L
  4. #define RED       0x02
    ) [3 J4 W  d. \* f; z
  5. #define GREEN     0x03( J! W1 j. e* f; }9 d; J/ e
  6. #define BAVG      0x058 R1 F/ C/ h/ Q: E0 X- U; i
  7. #define GAVG      0x06
    ( N* j4 i6 S1 i# g/ n# p; P
  8. …………
    ) V2 D8 y& r" k- G
复制代码

/ F: P0 s! m7 u& Q8 L模块初始化
( u. o* \/ z6 B% {引脚定义
2 s* W& c8 e& J6 Q8 {7 x. e
  1. //D0~D7:PA0~PA7       VSYNC:PA84 n5 O; p( c. r3 L/ _* X
  2. //WRST:PB13  RRST:PB14  OE:PB5  RCLK:PB6  WEN:PB7  SDA:PB8  SCL:PB9   
    " ~" a- V9 [4 u3 `7 p4 @0 t. l
  3. #define OV7725_VSYNC    PAin(8)                        $ e+ }( \$ f) n
  4. #define OV7725_WRST                PBout(13)               
    # Q5 G/ K: U% Z/ q" r
  5. #define OV7725_WREN                PBout(7)               
    2 ^. B& M+ H  X6 O' P* n8 j, T* b
  6. #define OV7725_RCK_H        GPIOB->BSRR=1<<6
    + g$ p6 w$ h2 b9 C/ P$ k( }
  7. #define OV7725_RCK_L        GPIOB->BRR=1<<61 T4 s7 Q' D# d0 d3 o: V# k' L5 `
  8. #define OV7725_RRST                PBout(14)         
    3 ?( m: N  k8 r0 S! G1 L
  9. #define OV7725_CS                PBout(5)  
    - ?; k; ^0 Z, T) X% O* Q4 J
复制代码
  1. #define SCCB_SCL                    PBout(9)                 //SCL
    9 ?4 g! Q8 B" X; Y+ _4 ?: A: j
  2. #define SCCB_SDA                    PBout(8)                 //SDA           [, b# H! H& f' y& I  X! u! H# [
  3. # }. g: q* |/ B. S  G( w2 m
  4. #define SCCB_READ_SDA            PBin(8)                  //ÊäÈëSDA   4 U+ i! p7 [5 S- G9 e0 i, Q
复制代码
( }/ I; ~" {! n) d" V5 a6 y, [

, n) G: `; l/ s* |# P$ L  b/ e我使用的是杜邦线连接如,IO口是自己重新定义的(全使用普通IO即可),STM32F1系列的PB3,PB4,PA13,PA14,PA15用于JTAG,如果有使用到其中的引脚,需要进行特殊配置,具体可参考网上更多教程。当时使用PB3,PB4作为SCCB的引脚,出现问题才发现这个原因。
. v- L' p7 ?* D( ^
! [' c% G5 b. j" \1 e# X
初始化" N0 X* V& z/ d: @. m5 i) O4 B4 W1 n
写寄存器的函数,寄存器的配置都是通过这个函数$ r* U- \0 N9 ^
  1. u8 SCCB_WR_Reg(u8 reg,u8 data)
    . d  h! t0 r: F; M8 S7 p
  2. {9 P1 ?) M- u, E3 G( b* V3 b
  3.         u8 res=0;
    , n& I( [+ f5 d5 C6 H  f4 {
  4.         SCCB_Start();                          //启动SCCB传输                 
    : C. D3 V% s+ i; a& e+ @
  5.         if(SCCB_WR_Byte(SCCB_ID))res=1;        //写器件ID,为0x42
    - D1 Q1 {: Q' t1 I6 i6 U
  6.         delay_us(100);
    ) h4 l& e+ e( C
  7.           if(SCCB_WR_Byte(reg))res=1;                //写寄存器地址,直接写对应的寄存器地址" @+ J% Y* ?& t' d  Z2 d  B
  8.         delay_us(100);% |1 M/ d. N. u& s9 k6 u/ ?+ p! Z
  9.           if(SCCB_WR_Byte(data))res=1;         //写数据,根据寄存器功能写对应数据: }+ l6 L$ r- t' o/ U# X
  10.           SCCB_Stop();          8 W( N$ a  ]) k8 H( ?) [7 j! A
  11.           return        res;& |9 Z& n& w! V! Z' g& \; d
  12. }                          & }) H# J! B, I+ L/ B# B& p; Z
复制代码

7 H; C/ ~/ b! ?, G. H将要配置的寄存器地址和对应的值,存在一个二维数组里边/ B" l  U! H1 h8 `7 h! H0 G
  1. //初始化寄存器系列及其对应的值
    2 X; \7 A3 `( P4 ?8 P! J
  2. const u8 ov7725_init_reg_tb1[][2]=
    % ~/ G, P" Q2 h) D1 v/ o* V: e
  3. {   
    + n3 `: F1 Z* x& o6 ?; ~5 ^- T/ a
  4.         /*输出窗口设置*/
    2 G6 Z7 A% ^5 c1 x$ U
  5.         {CLKRC,     0x00}, //clock config0 Q0 p$ H8 i* d) c* ^; q# _/ p
  6.         {COM7,      0x06}, //VGA RGB565
    & o+ @3 |' b2 O3 o) D
  7.         {HSTART,    0x3f}, //水平起始位置0 x7 ]. ^' U3 h. C1 \
  8.         {HSIZE,     0x50}, //水平尺寸4 t- a- t! T$ X3 }6 _& X7 P* U
  9.         {VSTRT,     0x03}, //垂直其实位置
    . Q- p* R& W8 X, a5 H
  10.         ......; ?9 U" g& J" M7 N
复制代码
2 `7 F7 D  {/ O- x
初始化时,在循环语句调用写寄存器的函数,依次写入寄存器的地址和对应的值,即可完成寄存器的配置
. R3 ]' n1 P0 \/ X& H2 r3 ]% |- u
  1.   //初始化OV7725,采用QVGA分辨率(320*240)  
      _6 [- S" a: l5 l) t  C3 Z  [; i
  2.         for(i=0;i<sizeof(ov7725_init_reg_tb1)/sizeof(ov7725_init_reg_tb1[0]);i++)" q* y1 e9 R( s6 K8 S" l
  3.         {                                                               
    , S  @) X- i/ D; f0 E; d: `2 @$ i
  4.                    SCCB_WR_Reg(ov7725_init_reg_tb1[i][0],ov7725_init_reg_tb1[i][1]);
    6 X' R1 e' ?$ g* y
  5.          }
    8 u0 Q% U# F8 S( F7 V2 i; A
复制代码

4 N, i( N& O9 a! x, k2 P) v; c帧中断和数据处理* F, i% W% k3 P/ y
发生帧中断时
- J# R# N& h" C8 i, I
  1. u8 ov_sta;        //帧中断标记2 }7 v" C4 k5 h" v5 I1 {
  2. //中断处理函数. q$ }5 u! t6 h5 I
  3. void EXTI9_5_IRQHandler(void)
    3 J& k- ^; `+ ^
  4. {                                 * V1 f" U" [% _/ X5 d3 S
  5.         if(EXTI_GetITStatus(EXTI_Line8)==SET)//是8线的中断
    / [: A9 D# S& L7 w* Q6 @
  6.         {      * i1 u' ~7 ^. A
  7.                 if(ov_sta==0)9 ^0 {* a: p# w5 ]/ h4 f) k
  8.                 {
    ! J( k( _. N% h  \5 I5 {8 q
  9.                         OV7725_WRST=0;        //复位写指针                 - d  Z3 r5 l& K% }% U! P' H: I/ {
  10.                         OV7725_WRST=1;       
    % }8 U' \( r- V# O! |
  11.                         OV7725_WREN=1;        //允许写入FIFO          
    ( X9 v9 p6 ]/ _9 q' ~9 ^
  12.                         ov_sta++;                //帧中断加1# q1 _; _! |+ o5 w
  13.                 }else OV7725_WREN=0;//禁止写入FIFO
    $ J) Q# Q2 [# B
  14.         }' o6 I; L8 M( L9 d9 l7 q
  15.         EXTI_ClearITPendingBit(EXTI_Line8);  //清除中断标志位                                          
    1 U0 l3 i+ ]/ d) n2 Q
  16. } # v# k) c4 F5 R: w2 p
复制代码
4 p+ X/ B% c) \/ ~
数据处理9 ~) l  r, [3 H( V. A, t
  1. if(ov_sta)//判断是否有帧中断发生$ g4 K0 `4 O: ?! v
  2. {! o1 K1 m% r- H
  3.         OV7725_RRST=0;                  //复. i& W! I- c* ~& S  Z; A
  4.         OV7725_RCK_L;         //位* g  W. j/ e7 Y3 Z) M
  5.         OV7725_RCK_H;         //读
    ' @. b- M+ k: T
  6.         OV7725_RCK_L;         //指( }5 V; a: `: B8 Q
  7.         OV7725_RRST=1;                  //针
    + @+ e9 c7 u) Z: ?1 h8 p4 {8 ^1 a
  8.         OV7725_RCK_H;
    ( X8 K6 y2 D9 s- N1 @, z, u
  9.         for(i=0;i<OV7725_WINDOW_HEIGHT;i++)//循环语句读取FIFO的数据( t5 x" }5 p. K" t, J
  10.         {3 I$ G& C3 S# U0 w1 u
  11.                 for(j=0;j<OV7725_WINDOW_WIDTH;j++)
    . _8 E) R; W* I3 V* O
  12.                 {
    & ~  `  c: C  C/ [* x
  13.                         //将数据填入相应缓冲区
    0 i& K. S& s+ {1 J/ |
  14.                         ......
    # b. a7 O3 _3 W- T3 j
  15.                 }. S/ v) p& Q1 L  _1 V3 L  D
  16.         }+ Q( y6 m$ Y5 f+ a# P" q
  17.         ov_sta=0;  //清零帧中断标志
    + S1 R- }: A4 `$ ~) ^+ h) Z' X
  18. }& D% N  u2 W% W3 K6 g/ |' h
复制代码

& h4 Q. l! L0 A, H, r) X7 t3 P以上是对于OV7725的初步理解,还有很多不懂的地方,后续有进一步研究再补充. d- W8 L! ~! y* }$ U1 P
————————————————
, p' k. j/ E# h8 V7 }; D4 K版权声明:hu_hong_hao
7 {9 L9 {# p# @( {如有侵权请联系删除
( [7 M" l0 ?+ U( o# d! \# J2 R# h& g  T5 Y! \/ Z9 L$ N
; l6 v( [8 v" w! ^5 h0 A

* @; B+ H/ B) u2 {* H1 ~
收藏 评论0 发布时间:2023-5-15 21:05

举报

0个回答

所属标签

相似分享

官网相关资源

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