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

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

[复制链接]
攻城狮Melo 发布时间:2023-5-15 21:05
最近做项目需要用到OV7725,于是花了些时间研究。由于OV7725对于工作频率的要求较高,因此使用带FIFO的摄像头模块。代码参考自正点原子官方。0 [- p* J0 S" t: e7 O2 Y) t( i
! J/ h! U, h, j5 M. v( y

- V- }' f; [- E. C7 ^; a, dOV7725资源
" `5 c9 o) w( z- u2 q# H引脚说明
% _/ B9 s! Q$ T3 }5 \* Z$ t3 P; G以下时关于十八个引脚的说明(来自正点原子的用户手册)
- v2 K/ n# t  q9 W4 B6 A' A+ D; Q- x" u: T' Y% R) G) U) n. @) l
20200323141056716.png 8 ^6 e' V5 V1 Q5 w/ i! i
3 c9 }6 ]+ B. K* v
其中,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片选信号在初始化之后就拉低,使之有效。0 b  u8 K, I% \& N
0 U% u  ^' r' f" M' ^
寄存器
# z' z# K& q# _" I" A* v( M$ Y这是来自datasheet的寄存器描述,看手册,英文很重要:
9 E. F% e; `8 V  @
5 A: A# V, G5 `2 O/ ~* P. c
20200323135602683.png
6 W; I2 F5 M$ F4 E6 Y3 L1 ]

4 B2 b. t; H& J. t; K/ [这些寄存器在代码里表现为一堆宏定义
  1.   /*OV7725寄存器宏定义*/
    ! m) p5 |: P' a) H4 N/ m
  2. #define GAIN      0x003 c& H$ y9 \5 E6 b, z
  3. #define BLUE      0x01
    $ B& h  b, R8 L# _' w
  4. #define RED       0x02
    ; h; g3 x: X- u
  5. #define GREEN     0x03
    4 Z9 }9 Z% L1 T- ^5 E  N" s7 Y
  6. #define BAVG      0x05
    , o% q3 [5 U, g* l5 V, l
  7. #define GAVG      0x06
    4 \) C" V- G4 c/ Z
  8. …………
    ' m+ A" _- M) G) [, @8 k# D, k$ Z
复制代码

3 j7 ^: H0 J3 H模块初始化( F. n1 o) q/ [1 n9 e# a
引脚定义

( m: h8 f8 a, U" ~* U- S# C
  1. //D0~D7:PA0~PA7       VSYNC:PA8
    & ^2 @% ?' i$ ]# O% e4 U, d
  2. //WRST:PB13  RRST:PB14  OE:PB5  RCLK:PB6  WEN:PB7  SDA:PB8  SCL:PB9   
    ; z# t2 N9 ^. R4 D& f: ?
  3. #define OV7725_VSYNC    PAin(8)                        
    9 o/ R& i6 ~# L( _! W
  4. #define OV7725_WRST                PBout(13)                ( ~3 B& h( Q- {. S
  5. #define OV7725_WREN                PBout(7)                0 k8 |4 M% Z1 s9 v8 l
  6. #define OV7725_RCK_H        GPIOB->BSRR=1<<6
    ! |! D/ {5 J( Y7 S; r
  7. #define OV7725_RCK_L        GPIOB->BRR=1<<63 S) Z) e* h7 m- [
  8. #define OV7725_RRST                PBout(14)         
    8 l4 x+ f* E" R
  9. #define OV7725_CS                PBout(5)  
    , u0 D, I. j0 H3 B8 Q( h1 b0 `
复制代码
  1. #define SCCB_SCL                    PBout(9)                 //SCL  b" x# l9 p5 w: F& V& G5 ?9 E, p
  2. #define SCCB_SDA                    PBout(8)                 //SDA         ; d3 w1 y6 L! u; d1 U: O/ f

  3. 0 h$ Z* x# I2 t' Y& k5 a; F
  4. #define SCCB_READ_SDA            PBin(8)                  //ÊäÈëSDA   8 E% [9 o# \% `7 j% c, Y" G& s
复制代码
" |, W# r4 W8 v
  [% S1 l2 b+ o' K
我使用的是杜邦线连接如,IO口是自己重新定义的(全使用普通IO即可),STM32F1系列的PB3,PB4,PA13,PA14,PA15用于JTAG,如果有使用到其中的引脚,需要进行特殊配置,具体可参考网上更多教程。当时使用PB3,PB4作为SCCB的引脚,出现问题才发现这个原因。4 x7 d( Y- M$ Q' `8 |- k9 A
/ E+ ^0 }7 f/ g) Z8 P
初始化
$ f* J; U, W, H  H6 w5 T& N写寄存器的函数,寄存器的配置都是通过这个函数
! w( t' L4 m7 X' m/ J
  1. u8 SCCB_WR_Reg(u8 reg,u8 data)
    1 G. J% }6 Q0 q) M- q5 O
  2. {
    / q: P4 T/ e0 g9 a/ K# W
  3.         u8 res=0;
    8 O/ j& X7 w: S. v/ k
  4.         SCCB_Start();                          //启动SCCB传输                 5 g/ V$ |/ j! p2 }
  5.         if(SCCB_WR_Byte(SCCB_ID))res=1;        //写器件ID,为0x42
    - a. Z1 v9 ]$ |% u9 u: E2 n
  6.         delay_us(100);
    4 y# }: k* V6 t7 a: N" M& \4 q
  7.           if(SCCB_WR_Byte(reg))res=1;                //写寄存器地址,直接写对应的寄存器地址5 E; B- R3 v3 s1 B" b$ C
  8.         delay_us(100);4 ]7 x9 R- g, C
  9.           if(SCCB_WR_Byte(data))res=1;         //写数据,根据寄存器功能写对应数据
    4 U2 G" \  s5 T6 i  f7 Q; n
  10.           SCCB_Stop();          4 o" p& e: ]/ t3 V0 t
  11.           return        res;
    6 |7 n( p( v0 z/ \2 H7 M
  12. }                          
    9 T5 W- _5 f/ H3 d8 i) Z
复制代码
% K4 ~! z" U( F2 V) o+ z
将要配置的寄存器地址和对应的值,存在一个二维数组里边1 K2 C* H+ \/ N. L* G
  1. //初始化寄存器系列及其对应的值$ F: U( a, p$ |  ?% U% S3 g
  2. const u8 ov7725_init_reg_tb1[][2]=
    ) N+ [6 N, K, O9 F$ |
  3. {   
    0 M! P! x: O) g" U
  4.         /*输出窗口设置*/' p, F0 Y) O* q; |- o' ]
  5.         {CLKRC,     0x00}, //clock config
      ~2 a8 j1 _# y/ L3 n
  6.         {COM7,      0x06}, //VGA RGB565% i+ e0 g! [9 x2 i7 M- l4 }& w5 y
  7.         {HSTART,    0x3f}, //水平起始位置- o3 o4 f+ ]# |) {
  8.         {HSIZE,     0x50}, //水平尺寸
      s& p7 G  w# y+ z+ S
  9.         {VSTRT,     0x03}, //垂直其实位置
    ) |8 h3 n" H% i. s+ N
  10.         ......) a" f9 e3 G# n+ @- p$ s
复制代码

, M. I# E% G0 \- X& p8 d初始化时,在循环语句调用写寄存器的函数,依次写入寄存器的地址和对应的值,即可完成寄存器的配置; f- b3 q; N' N
  1.   //初始化OV7725,采用QVGA分辨率(320*240)  6 K  }- r* {/ x
  2.         for(i=0;i<sizeof(ov7725_init_reg_tb1)/sizeof(ov7725_init_reg_tb1[0]);i++)
    7 M) f) H. Z6 y+ f6 |$ G
  3.         {                                                               
    # b8 i( v8 q9 a! c8 m
  4.                    SCCB_WR_Reg(ov7725_init_reg_tb1[i][0],ov7725_init_reg_tb1[i][1]);
    $ D6 m4 R9 y' I# ^. }& D: p
  5.          } . r' m5 j$ O* I" J9 W1 Y2 q1 s
复制代码
4 h, `$ T2 m3 i4 O3 K5 m
帧中断和数据处理- Y* L0 n  u; Y& u- \3 A
发生帧中断时
: O/ t. y  C/ u: q! w: k$ N
  1. u8 ov_sta;        //帧中断标记
    2 {* H5 H( B4 {* y; Q
  2. //中断处理函数5 M8 P0 e/ f" r
  3. void EXTI9_5_IRQHandler(void)
    / n* w" T$ m- W. T' k6 o
  4. {                                
    ! D2 Y/ P' T0 V4 j
  5.         if(EXTI_GetITStatus(EXTI_Line8)==SET)//是8线的中断5 W! `  N9 Q5 ], w2 \$ H
  6.         {      
    % z/ N: B6 \' t% R# x! G
  7.                 if(ov_sta==0)
    ( E" R* n$ n+ {" _4 `$ `6 C
  8.                 {1 R& z# H, m4 D6 D$ L& u' x- w
  9.                         OV7725_WRST=0;        //复位写指针                 
    7 |, {; M$ L+ f7 x
  10.                         OV7725_WRST=1;        7 {5 Q+ M( [$ W$ {( _0 T$ s
  11.                         OV7725_WREN=1;        //允许写入FIFO          " [' @( p$ ?0 `0 x  P# X4 B
  12.                         ov_sta++;                //帧中断加1
    6 _$ v+ i4 ^% s  Z
  13.                 }else OV7725_WREN=0;//禁止写入FIFO
    : b5 v" B4 U* [/ C3 X. S+ e
  14.         }
    + Y0 I5 p/ o$ l* X9 H$ l& ~/ \
  15.         EXTI_ClearITPendingBit(EXTI_Line8);  //清除中断标志位                                          ! E0 r0 A9 H2 `! H' ~4 H
  16. }
    : T3 i5 b' n7 N5 }8 I/ U0 [
复制代码

8 c1 ]: P& M: X8 I& l2 p/ q数据处理. n, f8 V. S9 T" N5 _9 `( U
  1. if(ov_sta)//判断是否有帧中断发生
    + C9 k1 \) W5 E. i3 l5 V
  2. {
    ; R9 h  r; X! i: S7 n
  3.         OV7725_RRST=0;                  //复
    . R) L9 [! I4 Z8 P" W% z$ y% P
  4.         OV7725_RCK_L;         //位
    / C3 \* R% z4 w; W* u# k* X$ f
  5.         OV7725_RCK_H;         //读1 p% w" {8 t% K2 j
  6.         OV7725_RCK_L;         //指
    ' _4 w% z* X- A' R
  7.         OV7725_RRST=1;                  //针
    $ _  T) Q) N+ ?( {) o
  8.         OV7725_RCK_H;
    / m0 [4 q$ A: G5 N/ J8 f
  9.         for(i=0;i<OV7725_WINDOW_HEIGHT;i++)//循环语句读取FIFO的数据
    # d: y6 I0 \+ P7 Q
  10.         {
    7 R' K3 C1 u6 D' s, R4 i
  11.                 for(j=0;j<OV7725_WINDOW_WIDTH;j++)& p& a' t& x9 c1 k6 `$ u
  12.                 {
    ! T1 \; A9 u% L4 k: l
  13.                         //将数据填入相应缓冲区7 H4 z& L. Y+ w  O
  14.                         ......  P( X7 w' U9 k) k6 }
  15.                 }
    3 |( E3 L: x% Z1 s/ @/ y3 ~% z
  16.         }3 l3 y1 X8 i0 Y% }( V
  17.         ov_sta=0;  //清零帧中断标志
    5 J8 t' }" E8 V6 }6 y/ Z( l
  18. }0 U) `  ~7 |; m7 I0 U  W9 S
复制代码

0 F  r" i' a# P* U7 N3 D# v7 i9 i以上是对于OV7725的初步理解,还有很多不懂的地方,后续有进一步研究再补充  @% m5 M) \3 y6 M
————————————————
7 S: g$ |4 H. j& ?7 ?版权声明:hu_hong_hao% W; P& ~: ], T5 T0 `( P* a9 B
如有侵权请联系删除6 _- `0 H% k( r. n6 E( r3 e
3 ~% M: S. s  X0 _
7 e% H2 j2 g3 ^8 U; @9 f+ \

. \) |" ^: Q+ u1 ~
赞 收藏 评论0 发布时间:2023-5-15 21:05

举报

0个回答

所属标签

相似技术帖

官网相关资源

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