OV7620摄像头使用

  • Post author:
  • Post category:其他



转载请注明出处:http://blog.csdn.net/lxk7280




有人会奇怪为什么使用OV系列的摄像头每次都要进行SCCB的操作呢?难道它自己不会保存上次的操作结果吗?




原因是:OV系列的摄像头的寄存器是EEPROM,不稳定,数据很容易丢失,因此程序每次初始化时我们都要重新写入寄存器设置。


PS:常见需要修改的寄存器有,PCLK速率,帧率、图像亮度、对比度、色饱和度、镜像等功能。








智能车摄像头组的初期学习中,虽然有不少摄像头优于OV7620,但是相信大部分的车友第一个接触的都是OV7620。下面从其特性和性能等角度,剖析摄像头的特点。




摄像头的输出格式有RGB565,YUY422等格式,我所接触的第一个摄像头

OV7620的输出格式是YUV422

。下面给大家介绍一下YUV422。


什么是YUV422?




人的眼睛对低频信号比对高频信号具有更高的敏感度,事实上,人的眼睛对明视度的改变比对色彩的改变要敏感的多。因此,人们将RGB三色信号改为YUV来表示,其中Y为灰度,UV为色差。如果是表示一副彩色图像,同样的道理,YUV444是无损的存储方式,但是需要3个字节,存储空间开销很大。由于Y分量比UV分量重要的多,因此人们用YUV422来表示。这样一来图像被压缩了很多,一个字节就可以表示其彩色的信息。




对于OV7620,它有2 组并行的数据口Y[7..0]和UV[7..0],其中对于数据口Y[7..0],输出的是灰度值Y,对于UV[7..0]输出的色度信号UV。下图给出了k 个像素(K 个字节)输出的格式。




OV762的控制采用SCCB(Serial Camera ControlBus)协议。SCCB的简化的I2C协议,SIO-I是串行时钟输入线,SIO-O是串行双向数据线,分别相当于I2C协议的SCL和SDA。SCCB的总线时序与I2C基本相同,他的响应信号ACK被陈伟一个传输单元的第9位,分别Do not care和NA.Do not care位由从机产生;NA位由主机产生,由于SCCB不支持多字节的读写,NA位必须为高电平。另外SCCB没有重复起始的概念,因此在SCCB的读周期中,当主机发送读命令时,从机将不能产生Do not care响应信号。



由于I2C和SCCB的一些细微差别,所以采用GPIO模拟SCCB总线的方式,SCL所连接的引脚始终设为输出方式,而SDA所连接的引脚在数据传输过程中,通过设置IODIR的值,动态改变引脚的输入/输出方式。SCCB的写周期直接使用I2C总线协议的写周期时序;而SC-CB的读周期,则增加一个总线停止条件。


OV7620的几个优点:



第一,OV7620的电平兼容3.3V和5V。目前智能车用户用到的处理器基本上可以分为XS128和K60和KL25三种控制器,而这三种控制器的工作电平分别是5V和3.3V和3.3V。OV7620可以完全适应这两种电平,XS128和K60和KL25可以随性切换,无需做电平匹配。

(要注意的是当OV7620接5v和3.3v的时候,输出的效果是不同的,建议在5v的电压下使用,因为在3.3v的电压下使用比较难调,输出的16进制数据清一色偏小。)











同样的情况下:


3.3V下:                                                                                                       5v下:








第二,OV7620的帧率是60帧/s。新手学习摄像头的时候,误以为摄像头帧率越快越好,其实不然。就拿OV7620来说,其PCLK(像素中断)的周期是73ns,该频率下的PCLK很容易被K60的IO捕捉,如果帧率更快的摄像头,其PCLK的周期就会更小,该频率下PCLK不易被K60的IO捕捉到。

(但是鹰眼摄像头不然,火哥的鹰眼摄像头理论上宣传的是150帧每秒,但是他并不是通过PCLK的周期减小从而获得效果的,鹰眼摄像头的高明之处在于它在硬件二值化之后,每一次PCLK中断对外输出了8个像素,而不是1个像素。鹰眼摄像头已经买来了,以后有机会会试试效果。)




第三:OV7620的分辨率也是非常合适的,在第三篇也提到OV7620是隔行扫描,采集VSYN的话,其输出分辨率是640*240。如果改为QVGA格式,默认输出分辨率是320*120,该分辨率下非常适合采集赛道,数据容量有限又不会失真图像。

(OV7620的分辨率可以通过SCCB修改,有兴趣修改的可以去查看OV7620的寄存器配置,然后通过SCCB修改。)









只有掌握了OV7620的时序,才能灵活得使用OV7620。下面开始本篇的重点:OV7620时序分析。



对于OV7620,我们只关心场中断信号VSYN、行中断信号HREF、像素中断信号PCLK的波形。用示波器去监控这三个波形,可以看到一下关系




VSYN 的周期是16.64ms,高电平时间为换场时间,约80us;低电平时间内像素输出。我们在采集VSYN脉冲时,既可以采集上升沿,也可以采集下降沿,采集下降沿更准确些,这也是一场的开始。从VSYN的周期可以算出,1s/16.64ms=60帧,OV7620的帧率是60帧/s。

HREF的周期63.6us,高电平时间为像素输出时间,约47us;低电平时间为换行时间,因此采集HREF一定要采集其上升沿,下降沿后的数据是无效的。从HREF的周期可以算出,16.64ms/63.6us≈261,除去期间的间隙时间,可以算出每场图像有240行。


PCLK的周期是73ns,高电平输出像素,低电平像素无效。PCLK是一直输出的,因此一定要在触发VSYN并且触发HREF以后,再去捕捉PCLK才能捕捉到像素数据。从PCLK的周期可以算出,47us/73ns≈640,可以算出每行图像中有640个像素点。


介绍完基本知识之后,下面开始写程序了(Keil–K60–C语言):



在这我分成两部分着重介绍7620的时序程序和贴上SCCB的协议程序(其实原理和处理情况和I2C差不多):




First :


首先要对使用到的一些IO口进行初始化处理,四个部分的初始化,


A.像素中断PCLK


B.行中断HREF


C.场中断VSYNC


D.DMA


程序如下:



  1. //初始化OV7620模块





  2. void


    OV


    7


    6


    2


    0


    _Init()


  3. {


  4. //像素中断 PCLK




  5. GPIO_InitStruct

    1


    .GPIO_Pin


    = OV


    7


    6


    2


    0


    _PCLK_PIN;


  6. GPIO_InitStruct

    1


    .GPIO_InitState


    = Bit_SET;


  7. GPIO_InitStruct

    1


    .GPIO_IRQMode


    = GPIO_IT_DMA_RISING;


  8. GPIO_InitStruct

    1


    .GPIO_Mode


    = GPIO_Mode_IPD;


  9. GPIO_InitStruct

    1


    .GPIOx


    = OV


    7


    6


    2


    0


    _PCLK_PORT;


  10. GPIO_Init(&GPIO_InitStruct

    1


    );




  11. //行中断 HREF




  12. GPIO_InitStruct

    1


    .GPIO_Pin


    = OV


    7


    6


    2


    0


    _HREF_PIN;


  13. GPIO_InitStruct

    1


    .GPIO_InitState


    = Bit_SET;


  14. GPIO_InitStruct

    1


    .GPIO_IRQMode


    = GPIO_IT_RISING;


  15. GPIO_InitStruct

    1


    .GPIO_Mode


    = GPIO_Mode_IPD;


  16. GPIO_InitStruct

    1


    .GPIOx


    = OV


    7


    6


    2


    0


    _HREF_PORT;


  17. GPIO_Init(&GPIO_InitStruct

    1


    );




  18. // 场中断 VSYNC




  19. GPIO_InitStruct

    1


    .GPIO_Pin


    = OV


    7


    6


    2


    0


    _VSYNC_PIN;


  20. GPIO_InitStruct

    1


    .GPIO_InitState


    = Bit_SET;


  21. GPIO_InitStruct

    1


    .GPIO_IRQMode


    = GPIO_IT_RISING;


    //GPIO_IT_RISING




  22. GPIO_InitStruct

    1


    .GPIO_Mode


    = GPIO_Mode_IPD;


    //GPIO_Mode_IPD




  23. GPIO_InitStruct

    1


    .GPIOx


    = OV


    7


    6


    2


    0


    _VSYNC_PORT;


  24. GPIO_Init(&GPIO_InitStruct

    1


    );




  25. //配置DMA




  26. DMA_InitStruct

    1


    .Channelx


    = DMA_CH


    1


    ;


    //DMA 1通道




  27. DMA_InitStruct

    1


    .PeripheralDMAReq


    =PORTC_DMAREQ;


    //C端口(PCLK) 上升呀触发




  28. DMA_InitStruct

    1


    .MinorLoopLength


    =


    1


    7


    0


    ;


    //传输次数 超过摄像头每行像素数即可




  29. DMA_InitStruct

    1


    .TransferBytes


    =


    1


    ;


    //每次传输1个字节




  30. DMA_InitStruct

    1


    .DMAAutoClose


    = ENABLE;


    //连续采集




  31. DMA_InitStruct

    1


    .EnableState


    = ENABLE;


    //初始化后立即采集





  32. DMA_InitStruct

    1


    .SourceBaseAddr


    =(uint


    3


    2


    _t)&PTD->PDIR;


    //摄像头端口接D0-D7




  33. DMA_InitStruct

    1


    .SourceMajorInc


    =


    0


    ;


    //地址不增加




  34. DMA_InitStruct

    1


    .SourceDataSize


    = DMA_SRC_


    8


    BIT;


    //8BIT数据




  35. DMA_InitStruct

    1


    .SourceMinorInc


    =


    0


    ;




  36. DMA_InitStruct

    1


    .DestBaseAddr


    =(uint


    3


    2


    _t)DMABuffer;


    //DMA 内存  //uint8_t DMABuffer[400];




  37. DMA_InitStruct

    1


    .DestMajorInc


    =


    0


    ;


  38. DMA_InitStruct

    1


    .DestDataSize


    = DMA_DST_


    8


    BIT;


  39. DMA_InitStruct

    1


    .DestMinorInc


    =


    1


    ;


    //每次传输 +1个字节




  40. DMA_Init(&DMA_InitStruct

    1


    );


  41. }




然后开始编写场中断函数,编写之前我们需要在心里理一下思绪,在场中断函数里我们要

按照顺序

,做以下几件事情:



A.确认是否是场中断,确认之后进入处理。


B.清除标志位Flag。

(Flag是用来观察是否处理完一场图像的标志)


C.清除中断标志。


D.计数全部清零。(因为新的一场已经开始)


E.打开行中断,关闭场中断。



  1. void


    PORTB_IRQHandler(


    void


    )


    //功  能:PORTB 外部中断服务 //V




  2. {

  3. u

    8


    i=


    9


    ;



  4. if


    ((PORTB->ISFR>>i)==


    1


    )


  5. {

  6. Flag =

    0


    ;


  7. PORTB->ISFR|=(

    1


    <<


    9


    );


  8. Row =

    0


    ;


  9. Row_Num =

    0


    ;


  10. NVIC_EnableIRQ(PORTA_IRQn);

    //行




  11. NVIC_DisableIRQ(PORTB_IRQn);

    //场




  12. }




接着编写行中断函数,在行中断中,我们要做以下几件事情:



A.确认是否是行中断。


B.关闭DMA中断,防止提前进入PCLK的采集。


C.跳过消隐区。

(消隐区:消隐区的出现,在电视机原理上,是因为电子束结束一行扫描,从一行尾换到另一行头,期间的空闲期,这叫做行消隐信号;同理,从一场尾换到另一场尾,期间也会有空闲期,这叫做场消隐信号。)


D.进入行采集处理。


E.配置DMA,并且打开DMA中断。


F.行计数加1,表示已经采集完了一行。(因为PCLK的中断周期远远小于HREF的中断周期,所以不需要杞人忧天,担心中断搞得混乱。)


G.当采集完了自己的目标行数之后,标志位Flag修改。并关闭行中断,打开场中断,等待下一次的场中断。



  1. void


    PORTA_IRQHandler(


    void


    )


    //功  能:PORTA 外部中断服务//Herf




  2. {

  3. u

    8


    i=


    1


    4


    ;


  4. DMA_SetEnableReq(DMA_CH

    1


    ,DISABLE);


    //close DMA ISr





  5. if


    ((PORTA->ISFR>>i)==


    1


    );


  6. {

  7. PORTA->ISFR|=(

    1


    <<


    1


    4


    );



  8. if


    (Row_Num++ >


    1


    5


    )


    //消隐区啦




  9. {


  10. if


    (Row_Num%


    5


    )


    //进入行采集




  11. {


  12. //配置DMA




  13. DMA_InitStruct

    1


    .Channelx


    = DMA_CH


    1


    ;


    //DMA 1通道




  14. DMA_InitStruct

    1


    .PeripheralDMAReq


    =PORTC_DMAREQ;


    //C端口(PCLK) 上升呀触发




  15. DMA_InitStruct

    1


    .MinorLoopLength


    =


    1


    7


    0


    ;


    //传输次数 超过摄像头每行像素数即可




  16. DMA_InitStruct

    1


    .TransferBytes


    =


    1


    ;


    //每次传输1个字节




  17. DMA_InitStruct

    1


    .DMAAutoClose


    = ENABLE;


    //连续采集




  18. DMA_InitStruct

    1


    .EnableState


    = ENABLE;


    //初始化后立即采集





  19. DMA_InitStruct

    1


    .SourceBaseAddr


    =(uint


    3


    2


    _t)&PTD->PDIR;


    //摄像头端口接D0-D7




  20. DMA_InitStruct

    1


    .SourceMajorInc


    =


    0


    ;


    //地址不增加




  21. DMA_InitStruct

    1


    .SourceDataSize


    = DMA_SRC_


    8


    BIT;


    //8BIT数据




  22. DMA_InitStruct

    1


    .SourceMinorInc


    =


    0


    ;



  23. DMA_InitStruct

    1


    .DestBaseAddr


    =(uint


    3


    2


    _t)Image[Row];


    //DMA 内存  //uint8_t DMABuffer[400];




  24. DMA_InitStruct

    1


    .DestMajorInc


    =


    0


    ;


  25. DMA_InitStruct

    1


    .DestDataSize


    = DMA_DST_


    8


    BIT;


  26. DMA_InitStruct

    1


    .DestMinorInc


    =


    1


    ;


    //每次传输 +1个字节




  27. DMA_Init(&DMA_InitStruct

    1


    );



  28. ///




  29. Row ++;


  30. if


    (Row==MAX_ROW)


  31. {

  32. Flag =

    1


    ;


  33. NVIC_DisableIRQ(PORTA_IRQn);

    //行




  34. NVIC_EnableIRQ(PORTB_IRQn);

    //场




  35. }

  36. }

  37. }

  38. }

  39. }



最后给大家看一下,DMA的初始化函数,这个函数是超核的库里面的,不是我写的,但是上面的解释很详细了,相信都能看懂。




  1. void


    DMA_Init(


    DMA_InitTypeDef


    *DMA_InitStruct)


  2. {


  3. //参数检查




  4. assert_param(IS_DMA_REQ(DMA_InitStruct->PeripheralDMAReq));

  5. assert_param(IS_DMA_ATTR_SSIZE(DMA_InitStruct->SourceDataSize));

  6. assert_param(IS_DMA_ATTR_DSIZE(DMA_InitStruct->DestDataSize));

  7. assert_param(IS_DMA_CH(DMA_InitStruct->Channelx));

  8. assert_param(IS_DMA_MINOR_LOOP(DMA_InitStruct->MinorLoopLength));



  9. //打开DMA0和DMAMUX时钟源




  10. SIM->SCGC

    6


    |= SIM_SCGC


    6


    _DMAMUX_MASK;


  11. SIM->SCGC

    7


    |= SIM_SCGC


    7


    _DMA_MASK;



  12. //配置DMA触发源




  13. DMAMUX->CHCFG[DMA_InitStruct->Channelx] = DMAMUX_CHCFG_SOURCE(DMA_InitStruct->PeripheralDMAReq);


  14. //设置源地址信息




  15. DMA

    0


    ->TCD[DMA_InitStruct->Channelx]


    .SADDR


    = DMA_InitStruct->SourceBaseAddr;



  16. //执行完源地址操作后,是否在源地址基础上累加




  17. DMA

    0


    ->TCD[DMA_InitStruct->Channelx]


    .SOFF


    = DMA_SOFF_SOFF(DMA_InitStruct->SourceMinorInc);



  18. //设置源地址传输宽度




  19. DMA

    0


    ->TCD[DMA_InitStruct->Channelx]


    .ATTR


    =


    0


    ;


  20. DMA

    0


    ->TCD[DMA_InitStruct->Channelx]


    .ATTR


    |= DMA_ATTR_SSIZE(DMA_InitStruct->SourceDataSize);



  21. //主循环进行完后 是否更改源地址




  22. DMA

    0


    ->TCD[DMA_InitStruct->Channelx]


    .SLAST


    = DMA_InitStruct->SourceMajorInc;




  23. //设置目的地址信息




  24. DMA

    0


    ->TCD[DMA_InitStruct->Channelx]


    .DADDR


    = DMA_InitStruct->DestBaseAddr;



  25. //执行完源地址操作后,是否在源地址基础上累加




  26. DMA

    0


    ->TCD[DMA_InitStruct->Channelx]


    .DOFF


    = DMA_DOFF_DOFF(DMA_InitStruct->DestMinorInc);



  27. //设置目的地址传输宽度




  28. DMA

    0


    ->TCD[DMA_InitStruct->Channelx]


    .ATTR


    |= DMA_ATTR_DSIZE(DMA_InitStruct->DestDataSize);



  29. //主循环进行完后 是否更改源地址




  30. DMA

    0


    ->TCD[DMA_InitStruct->Channelx]


    .DLAST_SGA


    = DMA_InitStruct->DestMajorInc;




  31. //设置计数器长度 循环次数





  32. //设置数据长度 长度每次递减 也被称作当前主循环计数 current major loop count




  33. DMA

    0


    ->TCD[DMA_InitStruct->Channelx]


    .CITER_ELINKNO


    = DMA_CITER_ELINKNO_CITER(DMA_InitStruct->MinorLoopLength );



  34. //起始循环计数器 当主循环计数器为0 时候 将装载起始循环计数器的值




  35. DMA

    0


    ->TCD[DMA_InitStruct->Channelx]


    .BITER_ELINKNO


    = DMA_BITER_ELINKNO_BITER(DMA_InitStruct->MinorLoopLength);



  36. //设置每一次传输字节的个数  个数到达上限时 DMA便将数据存入RAM




  37. DMA

    0


    ->TCD[DMA_InitStruct->Channelx]


    .NBYTES_MLNO


    = DMA_NBYTES_MLNO_NBYTES(DMA_InitStruct->TransferBytes);



  38. //设置DMA TCD控制寄存器




  39. DMA

    0


    ->TCD[DMA_InitStruct->Channelx]


    .CSR


    =


    0


    ;



  40. if


    (DMA_InitStruct->DMAAutoClose == ENABLE)


  41. {

  42. DMA

    0


    ->TCD[DMA_InitStruct->Channelx]


    .CSR


    |=DMA_CSR_DREQ_MASK;


  43. }


  44. else




  45. {

  46. DMA

    0


    ->TCD[DMA_InitStruct->Channelx]


    .CSR


    &=(~DMA_CSR_DREQ_MASK);


  47. }


  48. //使能此寄存器DMA开始工作




  49. DMA_SetEnableReq(DMA_InitStruct->Channelx,DMA_InitStruct->EnableState);


  50. //DMA 通道使能




  51. DMAMUX->CHCFG[DMA_InitStruct->Channelx] |= DMAMUX_CHCFG_ENBL_MASK;

  52. }








Second:


讲完OV7620的一些中断处理函数之后,我们来看看SCCB的库程序,这个库可以通用,需要的车友可以直接添加,只需要对照自己使用的库,在IO口初始化里面做出相应的修改即可。



  1. #ifndef __SCCB_H





  2. #define __SCCB_H







  3. #define SCL_HIGH         PEout(1) = 1    //设置为输出后输出1





  4. #define SCL_LOW         PEout(1) = 0    //设置为输出后输出0





  5. #define SCL_OUT     PTE->PDDR|=(1<<1)   //设置为输出





  6. //#define   SCL_DDR_IN()      PTE->PDDR&=~(1<<1)//输入






  7. #define SDA_HIGH         PEout(0)= 1    //设置为输出后输出1





  8. #define SDA_LOW         PEout(0)= 0    //设置为输出后输出0





  9. #define SDA_DATA        PEin(0)





  10. #define SDA_OUT   PTE->PDDR|=(1<<0)  //设置为输出





  11. #define SDA_IN    PTE->PDDR&=~(1<<0) //设置为输入





  12. #define u8 unsigned char





  13. #define u16 unsigned short






  14. //#define ADDR_OV7725   0x42






  15. void


    sccb_init(


    void


    );


    //初始化SCCB端口为GPIO





  16. void


    sccb_wait(


    void


    );


    //SCCB时序延时





  17. void


    sccb_start(


    void


    );


    //起始标志





  18. void


    sccb_stop(


    void


    );


    //停止标志




  19. u

    8


    sccb_sendByte(u


    8


    data);



  20. void


    sccb_regWrite(u


    8


    device,u


    8


    address,u


    8


    data);



  21. #endif





  22. #include “sys.h”





  23. #include “gpio.h”





  24. #include “sccb.h”





  25. #include “delay.h”





  26. #include “stdio.h”






  27. /*************************************************************************



  28. *  函数名称:sccb_init



  29. *  功能说明:初始化SCCB  其中SCL接PE1 SDA接PTE0



  30. *************************************************************************/





  31. void


    sccb_init(


    void


    )


  32. {


  33. int


    i ;


  34. GPIO_InitTypeDef GPIO_InitStruct

    1


    ;



  35. for


    (i=


    0


    ;i<


    8


    ;i++)


  36. {

  37. GPIO_InitStruct

    1


    .GPIO_Pin


    = i;


  38. GPIO_InitStruct

    1


    .GPIO_InitState


    = Bit_RESET;


    //change as Bit_Set , it will shut.




  39. GPIO_InitStruct

    1


    .GPIO_IRQMode


    = GPIO_IT_DISABLE;


  40. GPIO_InitStruct

    1


    .GPIO_Mode


    = GPIO_Mode_IN_FLOATING;


  41. GPIO_InitStruct

    1


    .GPIOx


    = PTD;


  42. GPIO_Init(&GPIO_InitStruct

    1


    );


  43. }


  44. GPIO_InitStruct

    1


    .GPIO_Pin


    =


    0


    ;


  45. GPIO_InitStruct

    1


    .GPIO_InitState


    = Bit_RESET;


  46. GPIO_InitStruct

    1


    .GPIO_IRQMode


    = GPIO_IT_DISABLE;


  47. GPIO_InitStruct

    1


    .GPIO_Mode


    = GPIO_Mode_OPP;


  48. GPIO_InitStruct

    1


    .GPIOx


    = PTE;


  49. GPIO_Init(&GPIO_InitStruct

    1


    );



  50. GPIO_InitStruct

    1


    .GPIO_Pin


    =


    1


    ;


  51. GPIO_InitStruct

    1


    .GPIO_InitState


    = Bit_RESET;


  52. GPIO_InitStruct

    1


    .GPIO_IRQMode


    = GPIO_IT_DISABLE;


  53. GPIO_InitStruct

    1


    .GPIO_Mode


    = GPIO_Mode_OPP;


  54. GPIO_InitStruct

    1


    .GPIOx


    = PTE;


  55. GPIO_Init(&GPIO_InitStruct

    1


    );


  56. }


  57. /************************************************************************



  58. *  函数名称:sccb_wait



  59. *  功能说明:SCCB延时,不应太小



  60. *************************************************************************/





  61. void


    sccb_wait(


    void


    )


  62. {

  63. u

    8


    i;


  64. u

    1


    6


    j;



  65. for


    ( i=


    0


    ; i<


    1


    0


    0


    ; i++)


  66. {

  67. j++;

  68. }

  69. }


  70. /************************************************************************



  71. *  函数名称:sccb_start



  72. *  功能说明:SCCB启动位



  73. *************************************************************************/





  74. void


    sccb_start(


    void


    )


  75. {

  76. SCL_OUT;

  77. SDA_OUT;


  78. SDA_HIGH;


  79. //sccb_wait();




  80. SCL_HIGH;

  81. sccb_wait();

  82. SDA_LOW;

  83. sccb_wait();

  84. SCL_LOW;

  85. }



  86. /************************************************************************



  87. *  函数名称:sccb_stop



  88. *  功能说明:SCCB停止位



  89. *************************************************************************/





  90. void


    sccb_stop(


    void


    )


  91. {

  92. SCL_OUT;

  93. SDA_OUT;


  94. SDA_LOW;

  95. sccb_wait();

  96. SCL_HIGH;

  97. sccb_wait();

  98. SDA_HIGH;

  99. sccb_wait();

  100. }



  101. /************************************************************************



  102. *  函数名称:sccb_sendByte



  103. *  功能说明:在SCCB总线上发送一个字节



  104. *  参数说明:data 要发送的字节内容



  105. *************************************************************************/




  106. u

    8


    sccb_sendByte(u


    8


    data)


  107. {

  108. u

    8


    i;


  109. u

    8


    ack;


  110. SDA_OUT;


  111. for


    ( i=


    0


    ; i<


    8


    ; i++)


  112. {


  113. if


    (data &


    0


    x


    8


    0


    )


  114. SDA_HIGH;


  115. else




  116. SDA_LOW;

  117. data <<=

    1


    ;


  118. sccb_wait();

  119. SCL_HIGH;

  120. sccb_wait();

  121. SCL_LOW;

  122. sccb_wait();

  123. }

  124. SDA_HIGH;

  125. SDA_IN;

  126. sccb_wait();

  127. SCL_HIGH;

  128. sccb_wait();

  129. ack = SDA_DATA;

  130. SCL_LOW;

  131. sccb_wait();


  132. return


    ack;


  133. }




  134. /************************************************************************



  135. *  函数名称:sccb_regWrite



  136. *  功能说明:通过SCCB总线向指定设备的指定地址发送指定内容



  137. *  参数说明:device—设备号  读写有区别  42是写,43是写



  138. *            address—写数据的寄存器



  139. *            data—写的内容



  140. *  函数返回:ack=1未收到应答(失败)    ack=0收到应答(成功)



  141. *************************************************************************/





  142. void


    sccb_regWrite(u


    8


    device,u


    8


    address,u


    8


    data)


  143. {


  144. // u8 i;




  145. u

    8


    ack;



  146. //  for( i=0; i<20; i++)





  147. //  {





  148. sccb_start();

  149. ack = sccb_sendByte(device);


  150. while


    ( ack )


  151. {

  152. ack = sccb_sendByte(device);


  153. //      printf(“device\n\r”);




  154. }

  155. ack = sccb_sendByte(address);


  156. while


    ( ack )


  157. {

  158. ack = sccb_sendByte(address);;


  159. //    printf(“address\n\r”);




  160. }

  161. ack = sccb_sendByte(data);


  162. while


    ( ack  )


  163. {

  164. ack = sccb_sendByte(data);


  165. //    printf(“data\n\r”);




  166. }

  167. sccb_stop();


  168. //    if( ack == 0 ) break;





  169. //  }




  170. }




贴上使用的SCCB的库之后,给大家看一下对SCCB的一段实例操作程序。程序上有详细的解释,我就不赘述了。




  1. sccb_init();


  2. sccb_regWrite(

    0


    x


    4


    2


    ,


    0


    x


    1


    1


    ,


    0


    x


    0


    1


    );


    //地址0X11-中断四分频(1280*480)           PCLK:166ns   HREF:254.6us   VSYN:133.6ms




  3. sccb_regWrite(

    0


    x


    4


    2


    ,


    0


    x


    1


    4


    ,


    0


    x


    2


    4


    );


    //地址0X14-QVGA(320*240)                  PCLK:332ns   HREF:509.6us   VSYN:133.6ms




  4. sccb_regWrite(

    0


    x


    4


    2


    ,


    0


    x


    2


    8


    ,


    0


    x


    4


    0


    );


    //地址0X28-黑白模式(320*240               PCLK:332ns   HREF:127us   VSYN:33.6ms




  5. sccb_wait();








以上就是关于OV7620的使用了,看完之后大家是不是会使用了呢。关于后期图像的处理和调试,我目前正在使用一款智能车调试助手,感觉非常好用,完全免费,并且可以配合Visual Studio,在Visual Studio里面用C#编写一些图像处理的算法,生成dll文件,然后在调试助手的界面里面直接观察。非常好非常好。给大家看看图。




如果有需要关于OV7620资料或者调试软件或者有什么赐教,请留言共同探讨。.




End。2014、03、26