搜索
bottom↓
回复: 11

OV7670 SCCB寄存器读写问题

[复制链接]

出0入0汤圆

发表于 2011-11-8 15:51:04 | 显示全部楼层 |阅读模式
这是我原来的帖子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 char  OV7670_SCCB_Writechar(unsigned char c)   
{   
unsigned char BitCnt;      
for(BitCnt=0;BitCnt<8;BitCnt++)  /*要传送的数据长度为8位*/   ////////////
    {   
     if((c<<BitCnt)&0x80)SIO_D=1;   /*判断发送位*/   
       else  SIO_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);      
}

void  OV7670_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 char  V7670_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 char  val=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 char  temp;
unsigned char  temp_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)
                {

                }
}

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2011-11-15 10:01:33 | 显示全部楼层
您好,我也是想用52单片机连接ov7670,我也是遇到了这个问题,现在开始怀疑是不是我的ov7670出了问题了……

出0入0汤圆

发表于 2011-11-15 10:05:54 | 显示全部楼层
请问楼主您在读出ov7670视频数据后是让上位机显示还是显示器显示啊?

出0入0汤圆

发表于 2011-11-16 10:24:37 | 显示全部楼层
楼主,问题您解决了吗?

出0入0汤圆

发表于 2011-12-2 18:31:20 | 显示全部楼层
图像采集之后有用到压缩芯片吗

出0入0汤圆

发表于 2012-1-1 23:30:23 | 显示全部楼层
单片机做的话,是不是只能采集到一帧这样呢,我想直接用stm32来驱动,不外接fifo

出0入0汤圆

发表于 2012-9-24 15:16:20 | 显示全部楼层
楼主问题解决了吗

出0入0汤圆

发表于 2013-3-9 18:45:05 | 显示全部楼层
我也是遇到相同问题了  用示波器看  SCCB通信完全是没有应答 我都怀疑是不是芯片坏了  

出0入0汤圆

发表于 2013-8-7 01:02:53 | 显示全部楼层
最近想搞摄像头,一直没头绪呢

出0入0汤圆

发表于 2013-9-1 08:58:30 | 显示全部楼层
夏日么么茶 发表于 2013-8-7 01:02
最近想搞摄像头,一直没头绪呢



看看对你能否有用


#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_SCL  GPIOEout(2)        // 定义 I2C-SCL 为 GPIOE_Pin_2
//#define SCCB_SDA  GPIOEout(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;                //SCCB  SCL->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[0])/2; i++)
        {
                        SCCB_WR_Reg(SCCB_ID, ov7670_init_reg_tbl[0],ov7670_init_reg_tbl[1]);
                        delay_ms(2);
        }

  for(;;);

}





出0入0汤圆

发表于 2013-9-1 11:23:51 | 显示全部楼层
hpdell 发表于 2013-9-1 08:58
看看对你能否有用

多谢了,我先好好看看

出0入0汤圆

发表于 2013-9-2 12:16:58 | 显示全部楼层
夏日么么茶 发表于 2013-9-1 11:23
多谢了,我先好好看看

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

如果与你使用的不同,请修改延时即可
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-25 19:26

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表