SCCB协议是OV公司公布的摄像头用的串行总线协议,相当于一个简易的I2C协议。本文写作意图在于记录使用软件SCCB驱动OV7670模块的配置方法。
这是官方历程中给出的SCCB时序图,虽然是三线的但是我们也可以用来学习二线的时序。
任意挑选两个IO口作为时钟线和数据线,将时钟线设置为推挽输出模式,数据线在输出时为推挽输出模式;在输入时是上拉输入模式。
1.协议开始,2.发送设备ID编号,等待,3. 发送要存入的寄存器号,等待,4.发送要写入的数据,5.协议结束。
#include "sccb.h" #include "./iodefine.h"
void sub_SDA_DirectSet( unsigned char u8_Tmp ) { DDR_EESDA = u8_Tmp; }
void sub_SCL_DirectSet( unsigned char u8_Tmp ) { DDR_EESCL = u8_Tmp; }
void sub_SDA_Set( unsigned char u8_Tmp ) { IO_EESDAO = u8_Tmp; }
void sub_SCL_Set( unsigned char u8_Tmp ) { IO_EESCL = u8_Tmp; }
unsigned char sub_SDA_Read( void ) { unsigned char u8_Tmp;
u8_Tmp = IO_EESDAI;
return u8_Tmp; }
//初始化SCCB接口 //CHECK OK void SCCB_Init(void) { sub_SDA_DirectSet( _OUTPUT ); sub_SCL_DirectSet( _OUTPUT ); sub_SCL_Set( _HIGH ); I2C_Flash(); sub_SDA_Set( _HIGH ); I2C_Flash(); }
void I2C_Flash( void ) { unsigned char i,j;
for( i=0; i<20; i++ ) { for(j=0;j<20;j++){
} } }
//SCCB起始信号 //当时钟为高的时候,数据线的高到低,为SCCB起始信号 //在激活状态下,SDA和SCL均为低电平 void SCCB_Start(void) {
sub_SDA_Set( _HIGH ); sub_SCL_Set( _HIGH ); I2C_Flash(); sub_SDA_Set( _LOW ); I2C_Flash(); sub_SCL_Set( _LOW ); }
//SCCB停止信号 //当时钟为高的时候,数据线的低到高,为SCCB停止信号 //空闲状况下,SDA,SCL均为高电平 void SCCB_Stop(void) { sub_SDA_Set( _LOW ); I2C_Flash(); sub_SCL_Set( _HIGH ); I2C_Flash(); sub_SDA_Set( _HIGH ); I2C_Flash(); } //产生NA信号 void SCCB_No_Ack(void) { I2C_Flash(); sub_SDA_Set( _HIGH ); sub_SCL_Set( _HIGH ); I2C_Flash(); sub_SCL_Set( _LOW ); I2C_Flash(); sub_SDA_Set( _LOW ); I2C_Flash(); }
//SCCB,写入一个字节 //返回值:0,成功;1,失败. unsigned char SCCB_WR_Byte(unsigned char dat) { unsigned char j,res; for(j=0;j<8;j++) //循环8次发送数据 { if(dat&0x80)sub_SDA_Set( _HIGH ); else sub_SDA_Set( _LOW ); dat<<=1; I2C_Flash(); sub_SCL_Set( _HIGH ); I2C_Flash(); sub_SCL_Set( _LOW ); } sub_SDA_DirectSet( _INPUT ); //设置SDA为输入 I2C_Flash(); sub_SCL_Set( _HIGH ); //接收第九位,以判断是否发送成功 I2C_Flash(); if(sub_SDA_Read())res=1; //SDA=1发送失败,返回1 else res=0; //SDA=0发送成功,返回0 sub_SCL_Set( _LOW ); sub_SDA_DirectSet( _OUTPUT ); //设置SDA为输出 return res; } //SCCB 读取一个字节 //在SCL的上升沿,数据锁存 //返回值:读到的数据 unsigned char SCCB_RD_Byte(void) { unsigned char temp=0,j; sub_SDA_DirectSet( _INPUT ); //设置SDA为输入 for(j=8;j>0;j--) //循环8次接收数据 { I2C_Flash(); sub_SCL_Set( _HIGH ); temp=temp<<1; if(sub_SDA_Read())temp++; I2C_Flash(); sub_SCL_Set( _LOW ); } sub_SDA_DirectSet( _OUTPUT ); //设置SDA为输出 return temp; } //写寄存器 //返回值:0,成功;1,失败. unsigned char SCCB_WR_Reg(unsigned char reg,unsigned char data) { unsigned char res=0; SCCB_Start(); //启动SCCB传输 if(SCCB_WR_Byte(SCCB_ID))res=1; //写器件ID I2C_Flash(); I2C_Flash(); if(SCCB_WR_Byte(reg))res=1; //写寄存器地址 I2C_Flash(); I2C_Flash(); if(SCCB_WR_Byte(data))res=1; //写数据 SCCB_Stop(); return res; } //读寄存器 //返回值:读到的寄存器值 unsigned char SCCB_RD_Reg(unsigned char reg) { unsigned char val=0; SCCB_Start(); //启动SCCB传输 SCCB_WR_Byte(SCCB_ID); //写器件ID I2C_Flash(); I2C_Flash(); SCCB_WR_Byte(reg); //写寄存器地址 I2C_Flash(); I2C_Flash(); SCCB_Stop(); I2C_Flash(); I2C_Flash(); //设置寄存器地址后,才是读 SCCB_Start(); SCCB_WR_Byte(SCCB_ID|0X01); //发送读命令 I2C_Flash(); I2C_Flash(); val=SCCB_RD_Byte(); //读取数据 SCCB_No_Ack(); SCCB_Stop(); return val; }
备注:本文图片截取于OV颁布的SCCB协议手册