|
发表于 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(;;);
}
|
|