wolwc3891 发表于 2011-11-8 15:51:04

OV7670 SCCB寄存器读写问题

这是我原来的帖子http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=5167779&bbs_page_no=1&search_mode=3&search_text=wolwc3891&bbs_id=9999
通过上面的贴子,我发现OV7670 的寄存器无法读写,于是我改用51单片机对OV7670的寄存器0X0a,0X0b进行读写,可是读出来的都是0XFF,单片机为AT89S52,晶振用的是11.0592MHz,
// OmniVision Serial Camera Control Bus (SCCB) Functional File.                                                                     
#include <Reg52.h>   
#include <Intrins.h>   
#include<stdio.h>   

sbit SIO_C=P0^0;   
sbit SIO_D=P0^1;

bit ack;
   
void serial_init(void)      //串口初始化!   
{   
          TMOD=0x20;
          TH1=0xFD;
          TL1=0xFD;
          SM0=0;
          SM1=1;
          ES=0;
          TR1=1;
   }
void tr(unsigned char i)   //串口传输OV7670寄存器的值
{
        ES=0;
        SBUF=i;
        while(!TI);
        TI=0;
        ES=1;                
}

void delay_100us(void) //100us
{
        unsigned int i,j,k;
        for(i=0;i<1;i++)
                {
                for(j=0;j<1;j++)
                        for(k=0;k<=7;k++);
                }
}

void delay_500us(void) //500us
{
        unsigned int i,j;
        for(i=0;i<2;i++)
                {
                        for(j=0;j<2;j++)
                        delay_100us();
                }
}   

void OV7670_SCCB_START(void)   
{   
   SIO_D=1;   
   delay_100us();   
   SIO_C=1;   
   delay_100us();   
   SIO_D=0;   
   delay_100us();   
   SIO_C=0;   
   delay_100us();      
   
}   
void OV7670_SCCB_END(void)   
{   
   SIO_D=0;   
   delay_100us();   
   SIO_C=1;   
   delay_100us();   
   SIO_D=1;
   delay_100us();   
   
}   
void noAck(void)   
{      
SIO_D=1;   
delay_100us();
SIO_C=1;   
delay_100us();   
SIO_C=0;               
delay_100us();
SIO_D=0;
delay_100us();   
}

void nAck(void)   
{      
SIO_D=0;   
delay_100us();
SIO_C=1;   
delay_100us();   
SIO_C=0;               
delay_100us();
SIO_D=0;
delay_100us();   
}   
      
unsigned charOV7670_SCCB_Writechar(unsigned char c)   
{   
unsigned char BitCnt;      
for(BitCnt=0;BitCnt<8;BitCnt++)/*要传送的数据长度为8位*/   ////////////
    {   
   if((c<<BitCnt)&0x80)SIO_D=1;   /*判断发送位*/   
       elseSIO_D=0;                  
       delay_100us();
   SIO_C=1;               /*置时钟线为高,通知被控器开始接收数据位*/   
       delay_100us();         
   SIO_C=0;
       delay_100us();
    }         
        delay_100us();      
    SIO_C=1;   
        delay_500us();
        delay_500us();
    if(SIO_D==1)ack=0;      
       else ack=1;      /*判断是否接收到应答信号*/ //正常SDA由接收端拉低//   
    SIO_C=0;   
    delay_100us();
        return (ack);      
}

voidOV7670_Write(unsigned char RegisterAddress, unsigned char Write_Data)   
{   
   
OV7670_SCCB_START();      //Start   
OV7670_SCCB_Writechar(0x42);
nAck();
delay_100us();   
OV7670_SCCB_Writechar(RegisterAddress);
nAck();
delay_100us();   
OV7670_SCCB_Writechar( Write_Data);
nAck();   
OV7670_SCCB_END();    //stop   

}

unsigned charV7670_SCCB_Readchar()   
{   
unsigned char retc;   
unsigned char BitCnt;   
   
retc=0x00;   
SIO_D=1;            // /*置数据线为输入方式/
delay_100us();
for(BitCnt=8;BitCnt>0;BitCnt--)   
      {   
      delay_100us();            
      SIO_C=1;   ///*置时钟线为高使数据线上数据有效/
        delay_100us();   
      retc=retc<<1;   
      if(SIO_D==1){retc=retc+1;} ///*读数据位,接收的数据位放入retc中 /   
                SIO_C=0;      
          delay_100us();
      }   
    return(retc);


}
   
unsigned char OV7670_Read(unsigned char RegisterAddress,unsigned char *regDat)   
{   
      
//unsigned charval=0;   
OV7670_SCCB_START();      //Start   
OV7670_SCCB_Writechar(0x42);
nAck();      
delay_100us();
OV7670_SCCB_Writechar(RegisterAddress);
nAck();   
OV7670_SCCB_END();    //stop   
delay_100us();

OV7670_SCCB_START();      //Start   
OV7670_SCCB_Writechar(0x43);
nAck();   
delay_100us();
SIO_C=0;
*regDat=V7670_SCCB_Readchar();   
noAck();
OV7670_SCCB_END();    //stop   
// return val;
return (1);
}   
   
   

void main()   
{   
unsigned chartemp;
unsigned chartemp_reg;
unsigned int i;
serial_init();
        for(i=0;i<10;i++)
        {
        delay_500us();
        }
    temp=0x80;
        tr(temp);
        OV7670_Write(0x12,temp);
        for(i=0;i<10;i++)
        {
        delay_500us();
        }
    temp=OV7670_Read(0x11, &temp_reg);
        tr(temp_reg);          
        OV7670_Write(0x11,0x05);                             
    temp=OV7670_Read(0x0a, &temp_reg);
        tr(temp_reg);
    temp=OV7670_Read(0x0b, &temp_reg);
        tr(temp_reg);      
while(1)
                {

                }
}

litianyi 发表于 2011-11-15 10:01:33

您好,我也是想用52单片机连接ov7670,我也是遇到了这个问题,现在开始怀疑是不是我的ov7670出了问题了……

litianyi 发表于 2011-11-15 10:05:54

请问楼主您在读出ov7670视频数据后是让上位机显示还是显示器显示啊?

litianyi 发表于 2011-11-16 10:24:37

楼主,问题您解决了吗?

sjy417810969 发表于 2011-12-2 18:31:20

图像采集之后有用到压缩芯片吗

fly_idea 发表于 2012-1-1 23:30:23

单片机做的话,是不是只能采集到一帧这样呢,我想直接用stm32来驱动,不外接fifo

nthaxw 发表于 2012-9-24 15:16:20

楼主问题解决了吗

xiakeyanghua 发表于 2013-3-9 18:45:05

我也是遇到相同问题了用示波器看SCCB通信完全是没有应答 我都怀疑是不是芯片坏了

夏日么么茶 发表于 2013-8-7 01:02:53

最近想搞摄像头,一直没头绪呢

hpdell 发表于 2013-9-1 08:58:30

夏日么么茶 发表于 2013-8-7 01:02 static/image/common/back.gif
最近想搞摄像头,一直没头绪呢



看看对你能否有用


#ifndef __SCCB_OV7670_H
#define __SCCB_OV7670_H


#include "stm32f4xx_conf.h"
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <gpio.h>


#define SCCB_ID                           0X42                                                //OV7670的ID

#define SCCB_SEND_ACK        (0x10)
#define SCCB_SEND_NACK        (0x11)

#define SCCB_STATE_NACK        (0x20)
#define SCCB_STATE_ACK          (0x21)


//#define SCCB_SCLGPIOEout(2)      // 定义 I2C-SCL 为 GPIOE_Pin_2
//#define SCCB_SDAGPIOEout(3)      // 定义 I2C-SDA 为 GPIOE_Pin_3

#define SCCB_SCL_L   (GPIOE->BSRRH = GPIO_Pin_2)   
#define SCCB_SCL_H   (GPIOE->BSRRL = GPIO_Pin_2)   

#define SCCB_SDA_L   (GPIOE->BSRRH = GPIO_Pin_3)   
#define SCCB_SDA_H   (GPIOE->BSRRL = GPIO_Pin_3)   
   

//RM0090   P.198
#define SCCB_SID_IN(){GPIOE->MODER&= 0XFFFFFF3F; /*GPIOE->MODER |= 0X00000000;*/}                        //PE3
#define SCCB_SID_OUT() {GPIOE->MODER&= 0XFFFFFF3F; GPIOE->MODER |= 0X00000040;}       
       

#define SCCB_SDA_READ      ((GPIOE->IDR)& GPIO_Pin_3)
                                                                                       
void SCCB_Delay(u16 i);
void SCCB_Init(void);
u8 SCCB_Start(void);
void SCCB_Stop(void);
u8 SCCB_ReadByte(void);
unsigned char SCCB_WriteByte(unsigned char write_data);

u8 SCCB_WR_Reg(u8 SlaveAddr, u8 reg, u8 data);
u8 SCCB_RD_Reg(u8 SlaveAddr, u8 reg);


#endif



#include "sccb_ov7670.h"
#include "usart.h"


void SCCB_Delay(u16 i)
{      
   while(i--);
}

#define SCCB_Delay_20us   SCCB_Delay(40)
#define SCCB_Delay_10us   SCCB_Delay(20)                //仿真结果是10.8uS
#define SCCB_Delay_5us   SCCB_Delay(8)
#define SCCB_Delay_3us   SCCB_Delay(6)
#define SCCB_Delay_2us   SCCB_Delay(4)
#define SCCB_Delay_1us   SCCB_Delay(2)


void SCCB_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
       
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
       
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;                //SCCBSCL->PE2, SDA->PE3
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
        GPIO_Init(GPIOE, &GPIO_InitStructure);

        SCCB_SCL_H;
        SCCB_Delay_1us;
        SCCB_SDA_H;
        SCCB_Delay_1us;   
   
}


/**********************************************************
启动子程序
在 SCL 高电平期间 SDA 发生负跳变【从高到低】
scl为高电平期间,sda产生一个下降沿
**********************************************************/
u8 SCCB_Start(void)
{
u8 i;
        SCCB_SDA_H;
        SCCB_Delay_10us;
SCCB_SCL_H;
        SCCB_Delay_10us;

       
        i=0;
        while((SCCB_SDA_READ == 1) && (i<250))        //如果SCCB_SDA=1,表示被控器无应答或损坏
        {
                i++;                                                                                                                //计时开始,
                if(i==249)                                                                                        //如果计时到了249,器件还没有应答则自动退出
                        return (SCCB_STATE_NACK);
        }      

        SCCB_SDA_L;
        SCCB_Delay_10us;
       
       
        i=0;
        while((SCCB_SDA_READ == 1) && (i<250))        //如果SCCB_SDA=1,表示被控器无应答或损坏
        {
                i++;                                                                                                                //计时开始,
                if(i==249)                                                                                        //如果计时到了249,器件还没有应答则自动退出
                        return (SCCB_STATE_NACK);
        }          

SCCB_SCL_L;                                //数据线恢复低电平,单操作函数必要
        SCCB_Delay_10us;

return SCCB_STATE_ACK;                //SUCCESS;
}


/**********************************************************
停止子函数
在 SCL 高电平期间 SDA 发生正跳变 【从低到高】
scl高电平期间,sda产生一上升沿
**********************************************************/
void SCCB_Stop(void)
{
SCCB_SDA_L;
SCCB_Delay_10us;
        SCCB_SCL_H;
        SCCB_Delay_10us;
        SCCB_SDA_H;
SCCB_Delay_10us;
}


//SCCB非应答信号
void noAck(void)
{       
        SCCB_SDA_H;
        SCCB_Delay_10us;
        SCCB_SCL_H;       
        SCCB_Delay_10us;
        SCCB_SCL_L;
        SCCB_Delay_10us;
        SCCB_SDA_L;
        SCCB_Delay_10us;
}



/**********************************************************
//读一字节 ack: SCCB_SEND_ACK 时应答,SCCB_SEND_NACK 时不应答
**********************************************************/
u8 SCCB_ReadByte(void)                //【非常好】
{
        u8 i = 0,Read_Data=0;       

SCCB_SID_IN();                //设置SDA为输入
        SCCB_Delay_1us;        
        for(i=0;i<8;i++)          // 循环移入8个位
        {
                SCCB_Delay_10us;          //此处延时很关键,否则读取数据失败
    SCCB_SCL_H;
    SCCB_Delay_10us;                                        //此处延时很关键,否则读取数据失败
    Read_Data <<= 1;
                SCCB_Delay_1us;
   
                if(SCCB_SDA_READ)              //读SDA
                {
      Read_Data++;
                }

                SCCB_SCL_L;
                SCCB_Delay_5us;                              //此处延时很关键,否则读取数据失败
        }

SCCB_SID_OUT();                //设置SDA为输出   
        SCCB_Delay_1us;      //5us
        return (Read_Data);
}               


/**********************************************************
//向总线写一字节,并返回有无应答
**********************************************************/
unsigned char SCCB_WriteByte(unsigned char write_data)                       
{
unsigned char i;
for(i=0;i<8;i++)
{
    if((write_data<<i) & 0x80)
   SCCB_SDA_H;
    else
   SCCB_SDA_L;
   
    SCCB_Delay_20us;
    SCCB_SCL_H;   //置时钟线为高,通知被控器开始接收数据位
    SCCB_Delay_20us;
    SCCB_SCL_L;
    SCCB_Delay_20us;
   
}
        SCCB_Delay_10us;
        SCCB_SID_IN();                //设置SDA为输入
SCCB_Delay_5us;
        SCCB_SCL_H;
SCCB_Delay_10us;

        i=0;
        while((SCCB_SDA_READ == 1) && (i<250))        //如果SCCB_SDA=1,表示被控器无应答或损坏
        {
                i++;                                                                                                                //计时开始,
                if(i==249)                                                                                        //如果计时到了249,器件还没有应答则自动退出
                        return (SCCB_STATE_NACK);
        }

        SCCB_SCL_L;
        SCCB_Delay_5us;
        SCCB_SID_OUT();                //设置SDA为输出
        SCCB_Delay_2us;
        return (SCCB_STATE_ACK);
}       


//写寄存器
//返回值:SCCB_STATE_ACK->成功; SCCB_STATE_NACK->失败.
u8 SCCB_WR_Reg(u8 SlaveAddr, u8 reg, u8 data)
{
        SCCB_Start();                                         //启动SCCB传输
       
        //res=SCCB_WriteByte(SCCB_ID);                //写器件ID 0x42       
        if(SCCB_STATE_NACK == SCCB_WriteByte(SlaveAddr))
        {
                SCCB_Stop();
                return SCCB_STATE_NACK;       
        }
       
        //res=SCCB_WriteByte(reg);
        if(SCCB_STATE_NACK == SCCB_WriteByte(reg))
        {
                SCCB_Stop();
                return SCCB_STATE_NACK;       
        }
       
//res=SCCB_WriteByte(data);       
        if(SCCB_STATE_NACK == SCCB_WriteByte(data))
        {
                SCCB_Stop();
                return SCCB_STATE_NACK;       
        }
       
        SCCB_Stop();          
return SCCB_STATE_ACK;
}       



//读寄存器
//返回值:读到的寄存器值
u8 SCCB_RD_Reg(u8 SlaveAddr, u8 reg)
{
        u8 val=0;
        SCCB_Start();                                 //启动SCCB传输
       
        if(SCCB_STATE_NACK == SCCB_WriteByte(SlaveAddr))
        {
                SCCB_Stop();
                return SCCB_STATE_NACK;       
        }

        if(SCCB_STATE_NACK == SCCB_WriteByte(reg))
        {
                SCCB_Stop();
                return SCCB_STATE_NACK;       
        }   

        SCCB_Stop();   
        SCCB_Delay_20us;



        //设置寄存器地址后,才是读
        SCCB_Start();
        if(SCCB_STATE_NACK == SCCB_WriteByte(SlaveAddr | 0x01))                //发送读命令          
        {
                SCCB_Stop();
                return SCCB_STATE_NACK;       
        }
        SCCB_Delay_20us;
val = SCCB_ReadByte();                       //读取数据
        noAck();//发送NACK命令
       
SCCB_Stop();
                               
return val;
}



void main()

{
        SCCB_Init();                      //初始化SCCB 的IO口          
       
        temp = SCCB_WR_Reg(SCCB_ID, 0x12, 0x80);                //软复位OV7670
       
        if(SCCB_STATE_NACK == temp)
                return 1;                  
        delay_ms(50);
       
        //读取产品型号
        temp = SCCB_RD_Reg(SCCB_ID, 0x0b);   //Product ID Number LSB (Read only)
        printexp(USART1, "DCMI_0X0B Product ID Number LSB",temp,16)        ;
        if(temp != 0x73)
                return 2;
       
        temp = SCCB_RD_Reg(SCCB_ID, 0x0a);   //Product ID Number MSB (Read only)
        printexp(USART1, "DCMI_0X0a Product ID Number MSB",temp,16)        ;
       
        if(temp != 0x76)
                return 2;
               
        //初始化序列          
        for(i=0; i<sizeof(ov7670_init_reg_tbl)/sizeof(ov7670_init_reg_tbl)/2; i++)
        {
                        SCCB_WR_Reg(SCCB_ID, ov7670_init_reg_tbl,ov7670_init_reg_tbl);
                        delay_ms(2);
        }

for(;;);

}





夏日么么茶 发表于 2013-9-1 11:23:51

hpdell 发表于 2013-9-1 08:58 static/image/common/back.gif
看看对你能否有用




多谢了,我先好好看看

hpdell 发表于 2013-9-2 12:16:58

夏日么么茶 发表于 2013-9-1 11:23 static/image/common/back.gif
多谢了,我先好好看看

单片机是stm32f407vgt6,时钟频率是168M

如果与你使用的不同,请修改延时即可
页: [1]
查看完整版本: OV7670 SCCB寄存器读写问题