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

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

[复制链接]
攻城狮Melo 发布时间:2023-5-15 21:05
最近做项目需要用到OV7725,于是花了些时间研究。由于OV7725对于工作频率的要求较高,因此使用带FIFO的摄像头模块。代码参考自正点原子官方。
- k4 l( e8 O) f+ b8 I3 D( h" e* J2 o3 X- b2 L8 P

/ F  j/ v2 p, x1 e* l# E8 SOV7725资源3 d) C; _3 n0 `9 P& J+ o, z
引脚说明
: a# ~) \* C+ j8 ^/ R  B9 p5 N1 O以下时关于十八个引脚的说明(来自正点原子的用户手册); y9 u, T( O' A. v: k3 T5 L6 y
. o- l5 K: c# P9 S5 l
20200323141056716.png ) h; u* R# `5 `6 C
" z+ w& u+ c, E+ 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片选信号在初始化之后就拉低,使之有效。
' K, y: {1 z6 B9 S" y# B) V" _, _; |: x# Y3 b
寄存器
& r4 Y4 c: w5 [0 q. x这是来自datasheet的寄存器描述,看手册,英文很重要:% ?* y( z) U2 p# P
9 j# ^9 G$ q6 M! K% O1 h: A
20200323135602683.png   k1 U% w) f- P. ^  }3 L) e4 p) c3 f) m

* e$ i( C( s+ N7 J& F/ K3 R8 t这些寄存器在代码里表现为一堆宏定义
  1.   /*OV7725寄存器宏定义*/
    & ?3 m8 w& s" ~
  2. #define GAIN      0x00: y+ C3 u# c, Y7 s3 W3 P' a
  3. #define BLUE      0x01" D$ B/ ]/ S  W% d/ ~
  4. #define RED       0x02" \4 y5 v* J3 }0 a! F( ]
  5. #define GREEN     0x038 G/ M; t9 ~6 J& ?( X( ~, l6 ~
  6. #define BAVG      0x05
    : o  k: r$ M9 C% e0 C/ G+ b- \& W
  7. #define GAVG      0x068 J1 t6 v5 u0 X" d1 L
  8. …………) x0 t( r/ c, O7 n
复制代码

9 B# g  I; B0 ~) m模块初始化
! y! r6 [2 ?' B引脚定义

/ Q. v. Z3 u4 A2 v- y
  1. //D0~D7:PA0~PA7       VSYNC:PA85 p+ n2 l" O& z
  2. //WRST:PB13  RRST:PB14  OE:PB5  RCLK:PB6  WEN:PB7  SDA:PB8  SCL:PB9    & P* V% _/ G: o4 s
  3. #define OV7725_VSYNC    PAin(8)                        
    ( t: \& L  j/ ?
  4. #define OV7725_WRST                PBout(13)                . s* R5 h% ~/ C- m# `6 ?! }
  5. #define OV7725_WREN                PBout(7)               
    ! x+ L2 |1 L7 e
  6. #define OV7725_RCK_H        GPIOB->BSRR=1<<63 j5 X5 [/ i  Y$ F
  7. #define OV7725_RCK_L        GPIOB->BRR=1<<6
    . O3 X* E7 N1 d) p) ]- d- D
  8. #define OV7725_RRST                PBout(14)         
    : K. E4 G+ g8 v% a" h
  9. #define OV7725_CS                PBout(5)  
    ! \) n1 m7 {+ F
复制代码
  1. #define SCCB_SCL                    PBout(9)                 //SCL) L# ]5 _. o! y$ C! n% Z( A5 a
  2. #define SCCB_SDA                    PBout(8)                 //SDA         
    ) L) M2 ]; `0 _
  3. . X  ?  t& L! U9 w6 N
  4. #define SCCB_READ_SDA            PBin(8)                  //ÊäÈëSDA   5 y7 p3 q6 l8 f
复制代码
3 {- z# d3 ^+ T/ E5 ]" ]4 r

% M$ U# S! I' V0 J( v我使用的是杜邦线连接如,IO口是自己重新定义的(全使用普通IO即可),STM32F1系列的PB3,PB4,PA13,PA14,PA15用于JTAG,如果有使用到其中的引脚,需要进行特殊配置,具体可参考网上更多教程。当时使用PB3,PB4作为SCCB的引脚,出现问题才发现这个原因。* V+ ?, _. c" ^/ g0 a1 ~: e' `; D- p$ V( T

7 R4 f3 b+ M: i7 u* _初始化
0 [  S9 {+ H" ?+ T' O1 P; E写寄存器的函数,寄存器的配置都是通过这个函数
; V4 C; h; m7 S) d& R
  1. u8 SCCB_WR_Reg(u8 reg,u8 data)
    3 m$ l* k9 Y* C+ r5 C
  2. {
    ) K4 b+ A" T7 ~
  3.         u8 res=0;  T- l5 V) Z: F1 a% t
  4.         SCCB_Start();                          //启动SCCB传输                 * J. S) e7 e, F7 e/ j. h
  5.         if(SCCB_WR_Byte(SCCB_ID))res=1;        //写器件ID,为0x42
    ; o( p  h' L: ]( F# ?. U
  6.         delay_us(100);
      j: A: s5 K5 G
  7.           if(SCCB_WR_Byte(reg))res=1;                //写寄存器地址,直接写对应的寄存器地址; g9 o. |( w0 w; r# U" ~  C
  8.         delay_us(100);
    9 m, M. R) v1 g2 c4 }) \- G
  9.           if(SCCB_WR_Byte(data))res=1;         //写数据,根据寄存器功能写对应数据
    ; G/ B5 b' g3 P6 Y: P8 C
  10.           SCCB_Stop();          ) U9 L! o) n/ b7 d* y' \- u* U3 F
  11.           return        res;
    ' u* X0 Z5 P, o
  12. }                          
    # t3 e$ o6 |/ ?0 s8 k
复制代码
! i3 Q7 I- O+ h
将要配置的寄存器地址和对应的值,存在一个二维数组里边0 w; o% N2 Q: V4 b
  1. //初始化寄存器系列及其对应的值
    , R& g# W& W$ e. c
  2. const u8 ov7725_init_reg_tb1[][2]=
    & V) E' ~3 E% u
  3. {   
    3 E0 ~0 A7 k' Y1 T# y9 f" `
  4.         /*输出窗口设置*/
    . D/ o! |6 A2 m9 S1 j1 V# }
  5.         {CLKRC,     0x00}, //clock config
    " \6 @" z0 C! P: ]. z' r9 w
  6.         {COM7,      0x06}, //VGA RGB5657 d6 G% a  r# d/ }# M
  7.         {HSTART,    0x3f}, //水平起始位置4 G- N8 J& X2 W
  8.         {HSIZE,     0x50}, //水平尺寸* O; A6 d0 K* ?: U% o/ x% X4 ^
  9.         {VSTRT,     0x03}, //垂直其实位置
    % `) b$ y" d% P8 V. c3 _
  10.         ......) m  ^3 M0 b8 @
复制代码
0 ]9 r* w  }, I+ |2 k
初始化时,在循环语句调用写寄存器的函数,依次写入寄存器的地址和对应的值,即可完成寄存器的配置
, I0 Q# J- ~3 S
  1.   //初始化OV7725,采用QVGA分辨率(320*240)  
    ) E' D: w3 ^$ V9 y/ h# U# c0 |
  2.         for(i=0;i<sizeof(ov7725_init_reg_tb1)/sizeof(ov7725_init_reg_tb1[0]);i++)
    ! I0 f) {, n. V3 @9 ?7 @
  3.         {                                                                . \) a+ P* m. i6 A+ `# j3 K
  4.                    SCCB_WR_Reg(ov7725_init_reg_tb1[i][0],ov7725_init_reg_tb1[i][1]);7 d. [1 O+ p( {9 V) M
  5.          } ) O' y9 C8 ?( ?  o* S% Q8 _
复制代码
0 `& B. W, n* [# J, M3 w
帧中断和数据处理
6 ~* j9 b/ G0 {. p发生帧中断时
9 W; R( E- b/ j7 {- y& H" P
  1. u8 ov_sta;        //帧中断标记
    . r7 _  p, n$ u
  2. //中断处理函数7 B) v8 ^) ?4 G9 H) O" ?
  3. void EXTI9_5_IRQHandler(void)$ h. }. y. B( a) V$ r
  4. {                                
    ; V# e/ u( p6 @! T' R( D9 z. V3 z/ y
  5.         if(EXTI_GetITStatus(EXTI_Line8)==SET)//是8线的中断7 j+ j7 x* u+ I5 @$ c$ l" Y0 R
  6.         {      4 e+ i4 L) a  c! E6 Q& G
  7.                 if(ov_sta==0)1 Q1 c7 H; \+ \5 n
  8.                 {- n7 y7 G: M* v! Z! F$ P
  9.                         OV7725_WRST=0;        //复位写指针                 
    - c+ o2 \% }* B1 C; {' X6 G
  10.                         OV7725_WRST=1;       
    , ?7 M( e6 Y) E# a2 x  |
  11.                         OV7725_WREN=1;        //允许写入FIFO          * t& o8 K1 o, K6 P; q6 `. w
  12.                         ov_sta++;                //帧中断加1
    9 {1 c# K( g1 V' c' J$ o2 d
  13.                 }else OV7725_WREN=0;//禁止写入FIFO  _/ `7 s0 X- ?! Q
  14.         }! b( j/ H  v; T
  15.         EXTI_ClearITPendingBit(EXTI_Line8);  //清除中断标志位                                          
    2 z, r0 m& F. @, W) K( N/ \
  16. } ' R- i- x' Z  w3 E7 k+ h+ F2 q8 q, u. V
复制代码

+ @1 f4 E1 z/ X) v# V/ N数据处理
! D) H4 M; A- I1 b7 ?4 C- X' V
  1. if(ov_sta)//判断是否有帧中断发生
    ! R1 _" l. u! Z# U: i8 J/ n
  2. {0 C' n, Z5 d, h  o. [0 g3 ?
  3.         OV7725_RRST=0;                  //复  j3 N% M- ]5 s6 N. f" c
  4.         OV7725_RCK_L;         //位1 J# O. R$ A3 ?; X
  5.         OV7725_RCK_H;         //读) ~' Q- S1 c# b/ l' ?, H
  6.         OV7725_RCK_L;         //指5 g4 T/ X4 K/ Z0 i4 y7 i7 t, t& Y( D) A
  7.         OV7725_RRST=1;                  //针: U( A" \0 q4 s8 w/ N
  8.         OV7725_RCK_H;
    4 G. U8 N4 V& X; N7 J8 x
  9.         for(i=0;i<OV7725_WINDOW_HEIGHT;i++)//循环语句读取FIFO的数据) n" z. E- @) M) t7 I" s
  10.         {
    8 |9 Z( b. e" ~6 m3 s: h
  11.                 for(j=0;j<OV7725_WINDOW_WIDTH;j++)! ?6 q7 i+ U( s2 J" A3 u" z
  12.                 {6 ~( Q3 Z9 e  H8 R! @
  13.                         //将数据填入相应缓冲区
      A# o4 N# c, G( B
  14.                         ......
    : c& x) i. h& @. F0 P+ U
  15.                 }
    , x6 O* s, z4 i: M+ Q% S" k8 O
  16.         }. d' |4 Q8 \! D% }$ I& E/ z" P% V
  17.         ov_sta=0;  //清零帧中断标志) U" U+ w: _) }$ o$ |$ x$ H
  18. }
    ' C0 N/ D; F8 T+ |
复制代码

' Q3 |, ^+ V2 F4 Z% i" w8 H以上是对于OV7725的初步理解,还有很多不懂的地方,后续有进一步研究再补充
& T1 g* q  R1 [  \7 o————————————————+ |6 C% J# E! E* R1 R
版权声明:hu_hong_hao
2 l! s, Q1 S) Y如有侵权请联系删除
" k$ C: ^& r  A4 {; Q! y/ [( W  e
- _2 V9 s/ a# o$ X9 [6 N! n# W$ [8 N+ H5 N) x7 _+ Y/ ~

/ P2 p& P5 w3 C5 Y
收藏 评论0 发布时间:2023-5-15 21:05

举报

0个回答

所属标签

相似技术帖

官网相关资源

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