显示效果图
OV7670模块
我用的OV7670是在某宝上买的花几块钱买的,如下图所示:
OV7670的接线
ov7670的接线是按照STM32F407VG开发板上预留的DMCI接口来接的,具体可以参照开发板的资料原理图说明,也可以直接按照下面的接线把ov7670接上STM32.
关于STM32驱动OV7670模块网上的教程有很多,这里我用的是普中科技的STM32F407VG,屏幕用的是它自带的ILI9481,屏幕的驱动代码我是直接使用普中科技官方的,具体的代码大家可以自己去找,下面我主要讲解一下我的代码构成:
DCMI驱动代码
DCMI是一种数字摄像头接口,是一个并行接口,能够接收外部8为、10位、12位或者14位CMOS摄像头模块发出的高速数据流。
#include "system.h"
#include "dcmi.h"
#include "uart.h"
extern u8 ov_frame; //帧率
u32 datanum=0;
u32 HSYNC=0;
u32 VSYNC=0;
u8 ov_rev_ok = 0;
extern void jpeg_data_process(void); //JPEG数据处理函数
DCMI_InitTypeDef DCMI_InitStructure;
void DMA2_Stream1_IRQHandler(void)
{
if(DMA_GetFlagStatus(DMA2_Stream1,DMA_FLAG_TCIF1)==SET)//DMA2_Steam1,传输完成标志
{
DMA_Cmd(DMA2_Stream1, DISABLE);
DMA_ClearFlag(DMA2_Stream1,DMA_FLAG_TCIF1);//清除传输完成中断
ov_rev_ok= 1; //数据获取完毕标志位位
}
}
void DCMI_DMA_Init(u32 DMA_Memory0BaseAddr,u16 DMA_BufferSize,u32 DMA_MemoryDataSize,u32 DMA_MemoryInc)
{
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能
DMA_DeInit(DMA2_Stream1);
while (DMA_GetCmdStatus(DMA2_Stream1) != DISABLE){}//等待DMA2_Stream1可配置
/* 配置 DMA Stream */
DMA_InitStructure.DMA_Channel = DMA_Channel_1; //通道1 DCMI通道
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&DCMI->DR; ;//外设地址为:DCMI->DR
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)DMA_Memory0BaseAddr;//DMA 存储器0地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//外设到存储器模式
DMA_InitStructure.DMA_BufferSize = DMA_BufferSize;//数据传输量
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc;//存储器增量模式
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//外设数据长度:32位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize;//存储器数据长度
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;// 使用循环模式 DMA_Mode_Normal
DMA_InitStructure.DMA_Priority = DMA_Priority_High;//高优先级
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; //FIFO模式
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;//使用全FIFO
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//外设突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//存储器突发单次传输
DMA_Init(DMA2_Stream1, &DMA_InitStructure);//初始化DMA Stream
DMA_ITConfig(DMA2_Stream1,DMA_IT_TC,ENABLE);
NVIC_InitStructure.NVIC_IRQChannel= DMA2_Stream1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
}
//DCMI初始化
void My_DCMI_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOE, ENABLE);
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_DCMI,ENABLE);//使能DCMI时钟
//PA4/6初始化设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_6;//PA4/6 复用功能输出 HSYNC PIXCLK
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能输出
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_6;// PB6/7 复用功能输出 VSYNC D5
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_11;//PC6/7/8/9 复用功能输出 D0 D1 D2 D3
GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_5|GPIO_Pin_6;//PE4/5/6 复用功能输出 D4 D6 D7
GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化
GPIO_PinAFConfig(GPIOA,GPIO_PinSource4,GPIO_AF_DCMI); //PA4,AF13 DCMI_HSYNC
GPIO_PinAFConfig(GPIOA,GPIO_PinSource6,GPIO_AF_DCMI); //PA6,AF13 DCMI_PCLK
GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_DCMI); //PB7,AF13 DCMI_VSYNC
GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_DCMI); //PC6,AF13 DCMI_D0
GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_DCMI); //PC7,AF13 DCMI_D1
GPIO_PinAFConfig(GPIOC,GPIO_PinSource8,GPIO_AF_DCMI); //PC8,AF13 DCMI_D2
GPIO_PinAFConfig(GPIOC,GPIO_PinSource9,GPIO_AF_DCMI); //PC9,AF13 DCMI_D3
GPIO_PinAFConfig(GPIOC,GPIO_PinSource11,GPIO_AF_DCMI); //PC11,AF13 DCMI_D4
GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_DCMI); //PB6,AF13 DCMI_D5
GPIO_PinAFConfig(GPIOE,GPIO_PinSource5,GPIO_AF_DCMI); //PE5,AF13 DCMI_D6
GPIO_PinAFConfig(GPIOE,GPIO_PinSource6,GPIO_AF_DCMI); //PE6,AF13 DCMI_D7
DCMI_DeInit();//清除原来的设置
DCMI_InitStructure.DCMI_CaptureMode=DCMI_CaptureMode_SnapShot;//快照模式 DCMI_CaptureMode_SnapShot
DCMI_InitStructure.DCMI_CaptureRate=DCMI_CaptureRate_All_Frame;//全帧捕获
DCMI_InitStructure.DCMI_ExtendedDataMode= DCMI_ExtendedDataMode_8b;//8位数据格式
DCMI_InitStructure.DCMI_HSPolarity = DCMI_HSPolarity_Low;//DCMI_HSPolarity_High;//HSYNC 低电平有效
DCMI_InitStructure.DCMI_PCKPolarity= DCMI_PCKPolarity_Falling;//PCLK 下升沿有效
DCMI_InitStructure.DCMI_SynchroMode= DCMI_SynchroMode_Hardware;//硬件同步HSYNC,VSYNC
DCMI_InitStructure.DCMI_VSPolarity=DCMI_VSPolarity_High;//VSYNC 低电平有效
DCMI_Init(&DCMI_InitStructure);
DCMI_ITConfig(DCMI_IT_FRAME,ENABLE);//开启帧中断
DCMI_ITConfig(DCMI_IT_LINE,ENABLE); //开启行中断
DCMI_ClearITPendingBit(DCMI_IT_VSYNC);
DCMI_ITConfig(DCMI_IT_VSYNC,ENABLE); //开启场中断
DCMI_Cmd(ENABLE); //DCMI使能
NVIC_InitStructure.NVIC_IRQChannel = DCMI_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3; //抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority =2; //子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化NVIC寄存器、
}
//DCMI,启动传输
void DCMI_Start(void)
{
DMA_Cmd(DMA2_Stream1, ENABLE);//开启DMA2,Stream1
DCMI_CaptureCmd(ENABLE);//DCMI捕获使能
}
//DCMI,关闭传输
void DCMI_Stop(void)
{
DCMI_CaptureCmd(DISABLE);//DCMI捕获使关闭
while(DCMI->CR&0X01); //等待传输结束
DMA_Cmd(DMA2_Stream1,DISABLE);//关闭DMA2,Stream1
}
//DCMI中断服务函数
void DCMI_IRQHandler(void)
{
if(DCMI_GetITStatus(DCMI_IT_LINE)==SET)//捕获到行
{
DCMI_ClearITPendingBit(DCMI_IT_LINE);//清除中断
ov_frame++;
}
if(DCMI_GetITStatus(DCMI_IT_FRAME)==SET)//捕获到帧
{
DCMI_ClearITPendingBit(DCMI_IT_FRAME);//清除中断
}
if(DCMI_GetITStatus(DCMI_IT_VSYNC)==SET)//捕获到场
{
DCMI_ClearITPendingBit(DCMI_IT_VSYNC);//清除中断
}
}
//DCMI设置显示窗口
//sx,sy;LCD的起始坐标
//width,height:LCD显示范围.
void DCMI_Set_Window(u16 sx,u16 sy,u16 width,u16 height)
{
DCMI_Stop();
DMA_Cmd(DMA2_Stream1,ENABLE); //开启DMA2,Stream1
DCMI_CaptureCmd(ENABLE);//DCMI捕获使能
}
SCCB通信协议
SCCB协议是主要用于OV系列图像传感器,它是简化版的I2C协议,专为图像传感器设计。
#include "sccb.h"
#include "delay.h"
#include "uart.h"
#include "tftlcd.h"
/*
*无FIFO的ov7670需要输入时钟
*时钟为84MHz
*分频为4MHz
*PB5
*/
void ov7670_MCLK_Init(void)
{
//1.配置GPIO
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//2.配置GPIO的复用
GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_TIM3);
//3.配置定时器
TIM_TimeBaseInitTypeDef TIM_TimeInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
TIM_TimeInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeInitStructure.TIM_Period=12-1;
TIM_TimeInitStructure.TIM_Prescaler=1-1;
TIM_TimeBaseInit(TIM3,&TIM_TimeInitStructure);
//4.配置PWM
TIM_OCInitTypeDef TIM_OCInitStucture;
TIM_OCInitStucture.TIM_OCMode=TIM_OCMode_PWM1; //PWM1模式
TIM_OCInitStucture.TIM_OCPolarity=TIM_OCPolarity_Low; //极性
TIM_OCInitStucture.TIM_OutputState=TIM_OutputState_Enable;
TIM_OC2Init(TIM3,&TIM_OCInitStucture); //初始化通道2
//5.使能预装载
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
//6.允许PWM输出
TIM_CtrlPWMOutputs(TIM3,ENABLE);
TIM_ARRPreloadConfig(TIM3,ENABLE);//使能预装载寄存器
//7.允许定时器计时
TIM_Cmd(TIM3,ENABLE);
//8.设置占空比
TIM_SetCompare2(TIM3,10);
}
/*******************************
SCCB总线
时钟线PD6,数据线PD7
******************************/
//初始化SCCB接口
void SCCB_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// RCC_AHB1PeriphClockCmd(OV7670_SCCB_RCC, ENABLE);
// RCC_AHB1PeriphClockCmd(OV7670_XCLK_RCC, ENABLE);
ov7670_MCLK_Init(); //初始化输入时钟
//STM32F4时钟输出XCLK
// GPIO_InitStructure.GPIO_Pin = OV7670_XCLK_Pin;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
// GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//50MHz
// GPIO_Init(OV7670_XCLK_GPIO, &GPIO_InitStructure);
// RCC_MCO1Config(RCC_MCO1Source_HSI,STM32_MCO1_DIV);
//GPIOF9,F10初始化设置
GPIO_InitStructure.GPIO_Pin = OV7670_SCCB_Pin;//PD6,7 推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //PD6,7 推挽输出
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(OV7670_SCCB_GPIO, &GPIO_InitStructure);//初始化
GPIO_SetBits(OV7670_SCCB_GPIO,OV7670_SCCB_Pin);
SCCB_SDA_OUT();
}
//SCCB起始信号
//当时钟为高的时候,数据线的高到低,为SCCB起始信号
//在激活状态下,SDA和SCL均为低电平
void SCCB_Start(void)
{
SCCB_SDA=1; //数据线高电平
delay_us(500);
SCCB_SCL=1; //在时钟线高的时候数据线由高至低
delay_us(500);
SCCB_SDA=0;
delay_us(500);
SCCB_SCL=0; //数据线恢复低电平,单操作函数必要
delay_us(500);
}
//SCCB停止信号
//当时钟为高的时候,数据线的低到高,为SCCB停止信号
//空闲状况下,SDA,SCL均为高电平
void SCCB_Stop(void)
{
SCCB_SDA=0;
delay_us(500);
SCCB_SCL=1;
delay_us(500);
SCCB_SDA=1;
delay_us(500);
}
//产生NA信号
void SCCB_No_Ack(void)
{
delay_us(500);
SCCB_SDA=1;
delay_us(500);
SCCB_SCL=1;
delay_us(500);
SCCB_SCL=0;
delay_us(500);
SCCB_SDA=0;
delay_us(500);
}
//SCCB,写入一个字节
//返回值:0,成功;1,失败.
u8 SCCB_WR_Byte(u8 dat)
{
u8 j,res;
for(j=0;j<8;j++) //循环8次发送数据
{
if(dat&0x80)SCCB_SDA=1;
else SCCB_SDA=0;
dat<<=1;
delay_us(500);
SCCB_SCL=1;
delay_us(500);
SCCB_SCL=0;
}
SCCB_SDA_IN(); //设置SDA为输入
delay_us(500);
SCCB_SCL=1; //接收第九位,以判断是否发送成功
delay_us(500);
if(SCCB_READ_SDA)res=1; //SDA=1发送失败,返回1
else res=0; //SDA=0发送成功,返回0
SCCB_SCL=0;
//printf("res=%d\r\n",res);
SCCB_SDA_OUT(); //设置SDA为输出
return res;
}
//SCCB 读取一个字节
//在SCL的上升沿,数据锁存
//返回值:读到的数据
u8 SCCB_RD_Byte(void)
{
u8 temp=0,j;
SCCB_SDA_IN(); //设置SDA为输入
for(j=8;j>0;j--) //循环8次接收数据
{
delay_us(500);
SCCB_SCL=1;
temp=temp<<1;
if(SCCB_READ_SDA)temp++;
delay_us(500);
SCCB_SCL=0;
}
SCCB_SDA_OUT(); //设置SDA为输出
return temp;
}
//写寄存器
//返回值:0,成功;1,失败.
u8 SCCB_WR_Reg(u8 reg,u8 data)
{
u8 res=0;
SCCB_Start(); //启动SCCB传输
if(SCCB_WR_Byte(SCCB_ID))res=1; //写器件ID
delay_us(100);
if(SCCB_WR_Byte(reg))res=1; //写寄存器地址
delay_us(100);
if(SCCB_WR_Byte(data))res=1; //写数据
SCCB_Stop();
return res;
}
//读寄存器
//返回值:读到的寄存器值
u8 SCCB_RD_Reg(u8 reg)
{
u8 val=0;
SCCB_Start(); //启动SCCB传输
if(0==SCCB_WR_Byte(0x42))
{
SCCB_Stop();
delay_us(500);
}
if(0==SCCB_WR_Byte(reg))
{
SCCB_Stop();
delay_us(500);
}
SCCB_Stop();
delay_us(100);
//设置寄存器地址后,才是读
SCCB_Start();
if(0==SCCB_WR_Byte(SCCB_ID|0X01)) //发送读命令
{
SCCB_Stop();
delay_us(100);
}
val=SCCB_RD_Byte(); //读取数据
delay_us(500);
SCCB_No_Ack();
delay_us(500);
SCCB_Stop();
return val;
}
OV7670的一些配置
包括初始化、白平衡设置、色度设置、亮度设置、对比度设置等。
#include "ov7670.h"
#include "ov7670config.h"
#include "delay.h"
#include "uart.h"
#include "sccb.h"
#include "led.h"
#include "tftlcd.h"
#include "dcmi.h"
uint16_t camera_buffer[PIC_WIDTH*PIC_HEIGHT]={0};
//初始化OV7670
//返回0:成功
//返回其他值:错误代码
u8 OV7670_Init(void)
{
u16 i=0;
u16 reg=0;
//设置IO
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
//GPIOG9,15初始化设置pow和reset
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_15;//PG9,8推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //推挽输出
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化
OV7670_PWDN=0; //POWER ON
delay_ms(100);
OV7670_RST=0; //复位OV7670
delay_ms(100);
OV7670_RST=1; //结束复位
SCCB_Init(); //初始化SCCB 的IO口
SCCB_WR_Reg(0X12, 0x80); //软复位OV7670
delay_ms(50);
//初始化配置 OV7670寄存器,采用QVGA分辨率(320*240)
for(i=0;i<sizeof(ov7670_init_reg_tbl)/sizeof(ov7670_init_reg_tbl[0]);i++)
{
SCCB_WR_Reg(ov7670_init_reg_tbl[i][0],ov7670_init_reg_tbl[i][1]);
}
//裁剪摄像头照片尺寸,参数:起始坐标x、y;长度、高度;裁剪长高不可大于上面设置的分辨率
OV7670_Window_Set(PIC_START_X,PIC_START_Y,PIC_WIDTH,PIC_HEIGHT);
/* 白平衡设置,默认值0 */
OV7670_Light_Mode(0);
/* 色度设置,默认值2 */
OV7670_Color_Saturation(2);
/* 亮度设置,默认值2 */
OV7670_Brightness(2);
/* 对比度设置,默认值2 */
OV7670_Contrast(2);
My_DCMI_Init();
/* DCMI DMA设置,数据指向照片数组camera_buffer */
DCMI_DMA_Init((uint32_t)&camera_buffer,sizeof(camera_buffer)/4,DMA_MemoryDataSize_HalfWord,DMA_MemoryInc_Enable);//DCMI DMA
return 0x00; //返回0初始化成功
}
//OV7670功能设置
//白平衡设置
//0:自动
//1:太阳sunny
//2,阴天cloudy
//3,办公室office
//4,家里home
void OV7670_Light_Mode(u8 mode)
{
u8 reg13val=0XE7;//默认就是设置为自动白平衡
u8 reg01val=0;
u8 reg02val=0;
switch(mode)
{
case 1://sunny
reg13val=0XE5;
reg01val=0X5A;
reg02val=0X5C;
break;
case 2://cloudy
reg13val=0XE5;
reg01val=0X58;
reg02val=0X60;
break;
case 3://office
reg13val=0XE5;
reg01val=0X84;
reg02val=0X4c;
break;
case 4://home
reg13val=0XE5;
reg01val=0X96;
reg02val=0X40;
break;
}
SCCB_WR_Reg(0X13,reg13val);//COM8设置
SCCB_WR_Reg(0X01,reg01val);//AWB蓝色通道增益
SCCB_WR_Reg(0X02,reg02val);//AWB红色通道增益
}
//色度设置
//0:-2
//1:-1
//2,0
//3,1
//4,2
void OV7670_Color_Saturation(u8 sat)
{
u8 reg4f5054val=0X80;//默认就是sat=2,即不调节色度的设置
u8 reg52val=0X22;
u8 reg53val=0X5E;
switch(sat)
{
case 0://-2
reg4f5054val=0X40;
reg52val=0X11;
reg53val=0X2F;
break;
case 1://-1
reg4f5054val=0X66;
reg52val=0X1B;
reg53val=0X4B;
break;
case 3://1
reg4f5054val=0X99;
reg52val=0X28;
reg53val=0X71;
break;
case 4://2
reg4f5054val=0XC0;
reg52val=0X33;
reg53val=0X8D;
break;
}
SCCB_WR_Reg(0X4F,reg4f5054val); //色彩矩阵系数1
SCCB_WR_Reg(0X50,reg4f5054val); //色彩矩阵系数2
SCCB_WR_Reg(0X51,0X00); //色彩矩阵系数3
SCCB_WR_Reg(0X52,reg52val); //色彩矩阵系数4
SCCB_WR_Reg(0X53,reg53val); //色彩矩阵系数5
SCCB_WR_Reg(0X54,reg4f5054val); //色彩矩阵系数6
SCCB_WR_Reg(0X58,0X9E); //MTXS
}
//亮度设置
//0:-2
//1:-1
//2,0
//3,1
//4,2
void OV7670_Brightness(u8 bright)
{
u8 reg55val=0X00;//默认就是bright=2
switch(bright)
{
case 0://-2
reg55val=0XB0;
break;
case 1://-1
reg55val=0X98;
break;
case 3://1
reg55val=0X18;
break;
case 4://2
reg55val=0X30;
break;
}
SCCB_WR_Reg(0X55,reg55val); //亮度调节
}
//对比度设置
//0:-2
//1:-1
//2,0
//3,1
//4,2
void OV7670_Contrast(u8 contrast)
{
u8 reg56val=0X40;//默认就是contrast=2
switch(contrast)
{
case 0://-2
reg56val=0X30;
break;
case 1://-1
reg56val=0X38;
break;
case 3://1
reg56val=0X50;
break;
case 4://2
reg56val=0X60;
break;
}
SCCB_WR_Reg(0X56,reg56val); //对比度调节
}
//特效设置
//0:普通模式
//1,负片
//2,黑白
//3,偏红色
//4,偏绿色
//5,偏蓝色
//6,复古
void OV7670_Special_Effects(u8 eft)
{
u8 reg3aval=0X04;//默认为普通模式
u8 reg67val=0XC0;
u8 reg68val=0X80;
switch(eft)
{
case 1://负片
reg3aval=0X24;
reg67val=0X80;
reg68val=0X80;
break;
case 2://黑白
reg3aval=0X14;
reg67val=0X80;
reg68val=0X80;
break;
case 3://偏红色
reg3aval=0X14;
reg67val=0Xc0;
reg68val=0X80;
break;
case 4://偏绿色
reg3aval=0X14;
reg67val=0X40;
reg68val=0X40;
break;
case 5://偏蓝色
reg3aval=0X14;
reg67val=0X80;
reg68val=0XC0;
break;
case 6://复古
reg3aval=0X14;
reg67val=0XA0;
reg68val=0X40;
break;
}
SCCB_WR_Reg(0X3A,reg3aval);//TSLB设置
SCCB_WR_Reg(0X68,reg67val);//MANU,手动U值
SCCB_WR_Reg(0X67,reg68val);//MANV,手动V值
}
//设置图像输出窗口
//对QVGA设置。
void OV7670_Window_Set(u16 sx,u16 sy,u16 width,u16 height)
{
u16 endx;
u16 endy;
u8 temp;
if ((sx+width) > 320)
{
width = 320 - sx;
}
if ((sy+height) > 240)
{
height = 240 - sy;
}
sx += 176;
sy += 12;
endx=sx+width*2; //HREF
endy=sy+height*2; //VREF
if(endx>784)
{
endx-=784;
}
temp=SCCB_RD_Reg(0X32); //读取Href之前的值
temp&=0XC0;
temp|=((endx&0X07)<<3)|(sx&0X07);
SCCB_WR_Reg(0X32,temp);
SCCB_WR_Reg(0X17,sx>>3); //设置Href的start高8位
SCCB_WR_Reg(0X18,endx>>3); //设置Href的end的高8位
temp=SCCB_RD_Reg(0X03); //读取Vref之前的值
temp&=0XF0;
temp|=((endy&0X03)<<2)|(sy&0X03);
SCCB_WR_Reg(0X03,temp); //设置Vref的start和end的最低2位
SCCB_WR_Reg(0X19,sy>>2); //设置Vref的start高8位
SCCB_WR_Reg(0X1A,endy>>2); //设置Vref的end的高8位
}
主函数(main)设置
主函数的设置包括显示图像的函数即txxs函数。
void txxs(uint16_t *camera_buf, uint16_t length_w, uint16_t length_h) {
uint16_t y, x;
uint16_t color;
for (y = 0; y < length_h; y++) {
for (x = 0; x < length_w; x++) {
color = camera_buf[y * length_w + x]; //直接从camera_buf中读取当前像素的颜色值
LCD_Fill(x, y, x + 1, y + 1, color); //LCD_Fill接受 RGB565格式的颜色值
}
}
int main()
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
delay_init(168);
UART1_init(115200);
LED_init();
KEY_Init(); //按键初始化
My_EXTI_Init();
TFTLCD_Init();
FRONT_COLOR=RED;
while(OV7670_Init())//OV7725初始化成功
{
LCD_ShowString(30,30,200,16,16,"error");
}
{
if (ov_rev_ok)
{
txxs(camera_buffer, PIC_WIDTH, PIC_HEIGHT);
ov_rev_ok = 0;
}
else
{
DCMI_Start();
}
}
}
希望这篇文章可以帮助到正在学习O7670的同学!当然完成这个显示大家也可以进行颜色的识别,大家可以在网上寻找教程,我这个就不多说了。