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)
{
}
} 您好,我也是想用52单片机连接ov7670,我也是遇到了这个问题,现在开始怀疑是不是我的ov7670出了问题了…… 请问楼主您在读出ov7670视频数据后是让上位机显示还是显示器显示啊? 楼主,问题您解决了吗? 图像采集之后有用到压缩芯片吗 单片机做的话,是不是只能采集到一帧这样呢,我想直接用stm32来驱动,不外接fifo 楼主问题解决了吗 我也是遇到相同问题了用示波器看SCCB通信完全是没有应答 我都怀疑是不是芯片坏了 最近想搞摄像头,一直没头绪呢 夏日么么茶 发表于 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(;;);
}
hpdell 发表于 2013-9-1 08:58 static/image/common/back.gif
看看对你能否有用
多谢了,我先好好看看 夏日么么茶 发表于 2013-9-1 11:23 static/image/common/back.gif
多谢了,我先好好看看
单片机是stm32f407vgt6,时钟频率是168M
如果与你使用的不同,请修改延时即可
页:
[1]