我用的mini板+第三方的摄像头,想先试试SCCB有没有写对,ov7670只接了VCC、GND、SIO_C、SIO_D(SCL和SDA都接了4.7k上拉电阻),把RESET接3.3V(我看文档是低电平复位)。
程序是在别人写的基础上修改了一些。
SIOC接PB2,SIOD接PB3
[mw_shl_code=c,true]void SCCB_Init(void);
void 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);
#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 PBout(2) //SCL
#define SCCB_SDA PBout(3) //SDA
//SDA方向设置
#define SCCB_SID_IN() {GPIOB->CRL&=0XFFFF0FFF;GPIOB->CRL|=4<<12;}
#define SCCB_SID_OUT() {GPIOB->CRL&=0XFFFF0FFF;GPIOB->CRL|=3<<12;}//0011
//IO操作函数
#define SCCB_SDA_READ PBin(3) //输入SDA
int main(void)
{
NVIC_Configuration();
delay_init();
uart_init(9600); //串口初始化为9600
LED_Init(); //初始化与LED连接的硬件接口
SCCB_Init();
SCCB_WR_Reg(SCCB_ID,0x12,0x80); //软复位OV7670
delay_ms(50);
while(1)
{
printf( "Product ID Number MSB (Read only) %x Default=0x76\r\n",(int)SCCB_RD_Reg(SCCB_ID, 0x0a));
delay_ms(3);
printf(" Product ID Number LSB (Read only) %x Default=0x60\r\n",(int)SCCB_RD_Reg(SCCB_ID, 0x0b));
delay_ms(3000);
LED0=!LED0;
}
}
void SCCB_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
//GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;//SCCB,SCL->  B2, SDA->  B3
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_10;//SCCB,SCL->  B2, SDA->  B3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
SCCB_SCL=1;
delay_us(20);
SCCB_SDA=1;
delay_us(20);
}
/**********************************************************
启动子程序
在 SCL 高电平期间 SDA 发生负跳变【从高到低】
**********************************************************/
void SCCB_Start(void)
{
SCCB_SDA=1;
delay_us(200);
SCCB_SCL=1;
delay_us(200);
SCCB_SDA=0;
delay_us(200);
SCCB_SCL=0;
delay_us(200);
}
/**********************************************************
停止子函数
在 SCL 高电平期间 SDA 发生正跳变 【从低到高】
**********************************************************/
void SCCB_Stop(void)
{
SCCB_SDA=0;
delay_us(200);
SCCB_SCL=1;
delay_us(200);
SCCB_SDA=1;
delay_us(200);
}
//SCCB非应答信号
void noAck(void)
{
SCCB_SDA=1;
delay_us(200);
SCCB_SCL=1;
delay_us(200);
SCCB_SCL=0;
delay_us(200);
SCCB_SDA=0;
delay_us(200);
}
/**********************************************************
//读一字节 ack: SCCB_SEND_ACK 时应答,SCCB_SEND_NACK 时不应答
**********************************************************/
u8 SCCB_ReadByte(void)
{
u8 i = 0;
u8 Read_Data=0;
SCCB_SID_IN();//设置SDA为输入
delay_us(200);
for(i=0;i<8;i++) // 循环移入8个位
{
delay_us(200);//此处延时很关键,否则读取数据失败
SCCB_SCL=1;
delay_us(200);//此处延时很关键,否则读取数据失败
Read_Data <<= 1;
delay_us(2);
if(SCCB_SDA_READ) //读SDA
{
Read_Data++;
}
SCCB_SCL=0;
delay_us(200);//此处延时很关键,否则读取数据失败
}
SCCB_SID_OUT();//设置SDA为输出
delay_us(200);
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=1;
else
SCCB_SDA=0;
delay_us(200);
SCCB_SCL=1; //置时钟线为高,通知被控器开始接收数据位
delay_us(200);
SCCB_SCL=0;
delay_us(200);
}
delay_us(10);
SCCB_SID_IN(); //设置SDA为输入
delay_us(200);
SCCB_SCL=1;
delay_ms(3);
i=0;
while((SCCB_SDA_READ == 1) && (i<250))//如果SCCB_SDA=1,表示被控器无应答或损坏
{
i++; //计时开始,
if(i==249) //如果计时到了249,器件还没有应答则自动退出
{
SCCB_SCL=0;
delay_us(200);
SCCB_SID_OUT();//设置SDA为输出
return (SCCB_STATE_NACK);
}
}
SCCB_SCL=0;
delay_us(200);
SCCB_SID_OUT();//设置SDA为输出
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;
}
delay_us(100);
//res=SCCB_WriteByte(reg);
if(SCCB_STATE_NACK == SCCB_WriteByte(reg))
{
SCCB_Stop();
return SCCB_STATE_NACK;
}
delay_us(100);
//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;
}
delay_us(100);
if(SCCB_STATE_NACK == SCCB_WriteByte(reg))
{
SCCB_Stop();
return SCCB_STATE_NACK;
}
SCCB_Stop();
delay_us(100);
//设置寄存器地址后,才是读
SCCB_Start();
if(SCCB_STATE_NACK == SCCB_WriteByte(SlaveAddr | 0x01)) //发送读命令
{
SCCB_Stop();
return SCCB_STATE_NACK;
}
delay_us(100);
val = SCCB_ReadByte(); //读取数据
noAck();//发送NACK命令
SCCB_Stop();
return val;
}
[/mw_shl_code]
按照文档读0x0a应该返回0x76读0x0b返回0x60,可是我得到的不是0x00就是0x32,应该是没读成功。
然后我烧了原子哥的摄像头例程,(因为没有fifo,所以接法同上)显示init_error消息
我的程序或者接线方法有什么问题吗?或者有什么办法可以测试摄像头是否好用?
|