STM32+TFT+OV7670实现图片的显示

本文介绍了使用STM32F103ZET6单片机结合OV7670图像传感器和TFT显示屏,实现图片显示的项目。OV7670是一款CMOS VGA图像传感器,具备多种输出格式和自动控制功能。通过SCCB接口进行控制,完成图像数据的存储和读取,最终在TFT屏幕上显示。项目中涉及OV7670的初始化、数据传输以及与STM32的连接。
摘要由CSDN通过智能技术生成

最近在做一个项目,使用OV7670来采集图片将采集好的图片上传到云端,通过手机可以在云端中查看。这两天就先搞了通过TFT显示采集的图片,后面再通过esp8266上传到云端。

材料的准备

  1. STM32F103ZET6 ,主控芯片;

    在这里插入图片描述

  2. TFT显示屏(某宝上的图片)

在这里插入图片描述

  1. OV7670(带FIFO)

在这里插入图片描述

OV7670简介

(从这里开始就只介绍OV7670了 因为其他两个的资料都差不多)

OV7670 是 OV( OmniVision)公司生产的一颗 1/6 寸的 CMOS VGA 图像传感器。该传感器体积小、工作电压低,提供单片 VGA 摄像头和影像处理器的所有功能。通过 SCCB 总线控制,可以输出整帧、子采样、取窗口等方式的各种分辨率 8 位影像数据。该产品 VGA 图像最高达到 30 帧/秒。用户可以完全控制图像质量、数据格式和传输方式。所有图像处理功能过程包括伽玛曲线、白平衡、度、色度等都可以通过 SCCB 接口编程。 OmmiVision 图像传感器应用独有的传感器技术,通过减少或消除光学或电子缺陷如固定图案噪声、托尾、浮散等,提高图像质量,得到清晰的稳定的彩色图像。
OV7670 的特点有:
(1)高灵敏度、低电压适合嵌入式应用
(2)标准的 SCCB 接口,兼容 IIC 接口
(3)支持 RawRGB、RGB(GBR4:2:2,RGB565/RGB555/RGB444),YUV(4:2:2)
和 YCbCr( 4:2:2)输出格式
(4)支持 VGA、 CIF,和从 CIF 到 40*30 的各种尺寸输出
(5)支持自动曝光控制、自动增益控制、自动白平衡、自动消除灯光条纹、
自动黑电平校准等自动控制功能。同时支持色饱和度、色相、伽马、锐度等设置。
(6)支持闪光灯
(7)支持图像缩放
OV7670 的功能框图图如图所示:

在这里插入图片描述

原理图

OV7670
从上图可以看出, PZ-OV7670 摄像头模块自带了有源晶振 Y1,用于产生 12M时钟作为 OV7670 的 XCLK 输入。同时自带了稳压芯片,用于提供 OV7670 稳定的 2.8V 工作电压,并带有一个 FIFO 芯片(AL422B),该 FIFO 芯片的容量是384K 字节,足够存储 2 帧 QVGA 的图像数据。

管脚功能如图所示:
在这里插入图片描述

OV7670使用方法

1、存储图像数据。
OV7670 摄像头模块存储图像数据的过程为:等待 OV7670 同步信号→FIFO 写指针复位→FIFO 写使能→等待第二个 OV7670 同步信号→FIFO 写禁止。通过以上 5 个步骤,我们就完成了 1 帧图像数据的存储。

2、读取图像数据。
在存储完一帧图像以后,我们就可以开始读取图像数据了。读取过程为:
FIFO 读指针复位→给 FIFO 读时钟( FIFO_RCLK)→读取第一个像素高字节→给 FIFO 读时钟→读取第一个像素低字节→给 FIFO 读时钟→读取第二个像素高字节→循环读取剩余像素→结束。

从上诉可知,摄像头模块数据的读取也是十分简单,比如 QVGA 模式,RGB565 格式,我们总共循环读取 3202402 次,就可以读取 1 帧图像数据,把这些数据写入 TFT 模块,我们就可以看到摄像头捕捉到的画面了。

与STM32单片机的连接

//OV7670摄像头模块接线说明:

//D0-D7:PF0-PF7
//WEN:PB6
//RCLK:PB7
//VSYNC:PA7
//SDA:PC6
//SCL:PC4
//RRST:PC2
//OE:PC3
//WRST:PE6
//GND:GND
//3.3V:3.3V

代码部分

1、SCCB总线
1.1 sccb.h

#ifndef __SCCB_H__
#define __SCCB_H__
#include "sys.h"

  
//#define SCCB_SDA_IN()  {GPIOG->CRH&=0XFF0FFFFF;GPIOG->CRH|=0X00800000;}
//#define SCCB_SDA_OUT() {GPIOG->CRH&=0XFF0FFFFF;GPIOG->CRH|=0X00300000;}

//IO操作函数	 
#define SCCB_SCL    		PCout(4)//PBout(12)	 	//SCL
#define SCCB_SDA    		PCout(6)//PBout(13) 		//SDA	 

#define SCCB_READ_SDA    	PCin(6)  		//输入SDA    
#define SCCB_ID   			0X42  			//OV7670的ID

///
void SCCB_Init(void);
void SCCB_Start(void);
void SCCB_Stop(void);
void SCCB_No_Ack(void);
u8 SCCB_WR_Byte(u8 dat);
u8 SCCB_RD_Byte(void);
u8 SCCB_WR_Reg(u8 reg,u8 data);
u8 SCCB_RD_Reg(u8 reg);
#endif

1.2 sccb.c

#include "sys.h"
#include "sccb.h"
#include "delay.h"


void SCCB_SDA_OUT(void)
{
   
	GPIO_InitTypeDef  GPIO_InitStructure;
	
 	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;				 // 端口配置
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOC, &GPIO_InitStructure);
}

void SCCB_SDA_IN(void)
{
   
	GPIO_InitTypeDef  GPIO_InitStructure;
	
 	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;				 // 端口配置
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 		 //输入
 	GPIO_Init(GPIOC, &GPIO_InitStructure);
}
 
//初始化SCCB接口
//CHECK OK
void SCCB_Init(void)
{
   			
 	GPIO_InitTypeDef  GPIO_InitStructure;
 	
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;				 // 端口配置
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 		 //上拉输入
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOC, &GPIO_InitStructure);
 	GPIO_SetBits(GPIOC,GPIO_Pin_6);						 // 输出高

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;				 // 端口配置
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 	GPIO_Init(GPIOC, &GPIO_InitStructure);
 	GPIO_SetBits(GPIOC,GPIO_Pin_4);						 // 输出高
 
	SCCB_SDA_OUT();	   
}			 

//SCCB起始信号
//当时钟为高的时候,数据线的高到低,为SCCB起始信号
//在激活状态下,SDA和SCL均为低电平
void SCCB_Start(void)
{
   
    SCCB_SDA=1;     //数据线高电平	   
    SCCB_SCL=1;	    //在时钟线高的时候数据线由高至低
    delay_us(50);  
    SCCB_SDA=0;
    delay_us(50);	 
    SCCB_SCL=0;	    //数据线恢复低电平,单操作函数必要	  
}

//SCCB停止信号
//当时钟为高的时候,数据线的低到高,为SCCB停止信号
//空闲状况下,SDA,SCL均为高电平
void SCCB_Stop(void)
{
   
    SCCB_SDA=0;
    delay_us(50);	 
    SCCB_SCL=1;	
    delay_us(50); 
    SCCB_SDA=1;	
    delay_us(50);
}  
//产生NA信号
void SCCB_No_Ack(void)
{
   
	delay_us(50);
	SCCB_SDA=1;	
	SCCB_SCL=1;	
	delay_us(50);
	SCCB_SCL=0;	
	delay_us(50);
	SCCB_SDA=0;	
	delay_us(50);
}
//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(50);
		SCCB_SCL=1;	
		delay_us(50);
		SCCB_SCL=0;		   
	}			 
	SCCB_SDA_IN();		//设置SDA为输入 
	delay_us(50);
	SCCB_SCL=1;			//接收第九位,以判断是否发送成功
	delay_us(50);
	if(SCCB_READ_SDA)res=1;  //SDA=1发送失败,返回1
	else res=0;         //SDA=0发送成功,返回0
	SCCB_SCL=0;		 
	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(50);
		SCCB_SCL=1;
		temp=temp<<1;
		if(SCCB_READ_SDA)temp++;   
		delay_us(50);
		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
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值