本文将介绍ov7670摄像头模组与 STONE 显示模块。 通过串行显示模块显示摄像机图像。 本文介绍的方法和代码仅供个人开发者测试使用,不能保证商业稳定性。
ov7670摄像头模块与 STONE 显示模块,主要功能
- 显示屏实时显示摄像头采集的图片
- 单击按钮拍摄图像并保存到 TF 卡
- 切换颜色和灰度
- 分辨率可切换(240*320、240*240、160*160、80*80)
- 可以切换到查看图片模式
- 你可以浏览最后一张图片
- 您可以浏览下一张图片
在继续这个项目之前,让我们来看看需要哪些硬件模块。
- STONE 7寸800*480分辨率串口显示模块
- STM32F103ZE 开发板
- OV7670 摄像头模组
- 少量相关线材
STM32F103ZE开发板
该开发板具有多项集成功能
- Cortex-m3核心芯片,STM32F103ZET6,
- 144P针
- 外接晶振8M,时钟晶振32768Hz
- 标准20P插座,JTAG接口,用于下载Jlink、Ulink、st-link等调试程序
- 标准4P插针,SWD接口,使用2线通讯调试下载程序
- 所有 I/O 端口均用于插入针头,方便实验扩展
- USB-TTL串口转换电路,实现USB接口的串口通讯
- 自动下载适配器电路,使用串口下载无需频繁切换,一键下载
- MAX232转换电路,适合外接串口线
- 集成红外接收器,用户远程红外接收功能
- DS18B20插座,直接插入芯片实现数字测温功能
- 带时钟备用电池,保持时钟和重要信息不掉电
- EEPROM芯片24c02存储常用用户信息,使用IIC进行通信
- FLASH芯片W25Q64,8,XNUMXM内存,可存储图片、系统数据等信息
- SPI模式 SD卡座、TF卡、PI通讯
- SDIO模式 SD卡座,TF卡,专用SDIO接口,高速,稳定。
- RF24L01 用于测试无线通信的插座(至少需要2台机器)
- 3路普通按键输入功能,人机界面
- 1路唤醒按钮,用于从低功耗或待机模式唤醒
- 2路用户LED灯,制作基本状态及操作说明
- 1个USB设备接口,用于调试USB设备功能,如读卡器、USB串口功能
- TFT彩屏液晶接口,包括触摸屏接口,可直接插入配套屏幕
- 摄像头预留接口,支持摄像头模组实现视频演示功能
- 1号蜂鸣器
- 1个触摸按键功能
- 自恢复保险丝,保护计算机免受损坏
- 复位按钮
- 电源指示灯
- 选择插入引脚
- 选择具有 VREF 参考电压的引脚
- CAN、USB开关针
- 3.3v外置电源插针
- 5V外扩电源引脚插入
但实际上我们只用了他的相机接口和串口,还有TF卡接口
STONE TFT-LCD显示模块
STONE STVC070WT-01是一款7英寸显示模组,分辨率为800*480。 这个显示模块可以从 STONE的官网或来自 STONE的网购平台链接。
的通讯方式 STONE stvc070wt-01是uart-rs232和uart-ttl。在这个项目中,我使用了uart-TTL通信方式。
显示模块开发方式简单,MCU只需通过UART发送指令到 STONE,显示模块的内容,控制就ok了,用户触摸的时候原理一样 STONE 显示屏、显示模块及相关指令通过UART发送给MCU,然后MCU控制相应的设备(如电机转动、灯开关等)。
7英寸 STONE STVC070WT-01
厂家提供的材料如下:
主要装箱单
- 传输连接和连接
- USB-TTL转接板
- U盘(含开发资料)
- 微型USB数据线
- USB转接板
- STONE STVC070WT-01显示模块
- 12V电源适配器
STONE 显示模块简介
STVC070WT-01 是一款 TFT 显示和触摸控制器。 它包括处理器、控制程序、驱动器、闪光灯、RS232/RS485/TTL端口、触摸屏、电源等,是一个功能强大的显示系统
操作系统简单,可任意单片机控制。STVC070WT-01可用于执行所有基本功能,如文字显示、图像显示、曲线显示、触摸功能、视音频功能等。
- 内置 Cortex CPU 和驱动程序
- 可由任何单片机控制
- 显示图片/文字/曲线
- 65536彩色TFT显示屏
- - 可以触摸
- RS232/ RS485/ TTL UART接口和USB接口
- 宽电压范围
STVC070WT-01显示模块控制原理
TFT-LCD 模组通过指令(十六进制)与 MCU 进行通讯,MCU 会根据收到的指令进行工作。
完成固件开发需要三个步骤 STONE 显示模块
运用 STONE的TFT-LCD模组只需要3个步骤:
- 设计一组人机画面(UI)。
- UART-TTL 直接连接到客户的 MCU。
- 编写一个简单的程序,由单片机通过命令控制TFT-LCD模块。 (十六进制代码)。
TFT LCD 模块的串行命令帧由五个数据块组成,全部以十六进制格式表示。 数据传输到 MSB 的方式。例如,对于 0x1234,先发送 0x12,然后发送 0x34。
UI图片设计
用户使用 Photoshop 或其他软件设计 UI
我设计的界面如下:
第一张是主屏画面,第二张是按键按下时的效果。
使用TOOL2019软件套装生成LCD模块配置文件
点击箭头按钮生成配置文件,然后将配置文件下载到显示模块,即可显示我们设计的UI界面。
这部分内容和教程我就不赘述了,大家可以去 STONE 网站下载非常详细的教程。
此外,我们还需要设计一个与按钮按下时的效果一模一样的图片。 我们只需要将按钮位置的颜色更改为下表。
STM32 MCU和VO7670接线和焊接
在之前的内容中,我介绍了相关的开发操作 STONE STVC070WT-01。 在接下来的内容中,我将重点介绍STM32 MCU和VO7670摄像头。 在我们这样做之前,让我们看一下项目的硬件部分是如何连接的。
一个完整的接线图 STONE 项目
OV7670模块——STM32开发板:
OV_D0 ~ D7 — — — — — — — — — — — PC0 ~ 7
OV_SCL — — — — — — — — — — — — PD3
OV_SDA — — — — — — — — — — — — PG13
OV_VSYNC — — — — — — — — — — — — PA8
FIFO_RRST — — — — — — — — — — — PG14
FIFO_OE — — — — — — — — — — — PG15
FIFO_WRST — — — — — — — — — — — — PD6
FIFO_WEN — — — — — — — — — — — — PB3
FIFO_RCLK — — — — — — — — — — — — PB4
电源适配器为12V,需要给电源供电 STONE stvc070wt-01显示模块并通过dc-dc降压至7670伏为MCU模块和OV5供电。
项目中使用的配件
主要配件有:
- STM32F103ZE开发板
- DC-DC降压模块
- UART切换
由于默认的通信模式 STONE STVC070WT-01为uart-TTL,我们不需要RS232接口进行切换连接,去掉RS232接口:
焊接
通过将这些部件焊接在一起,效果如下:
当这部分准备好后,您就可以为 MCU 编写程序了。
OV7670 摄像头模组
OV7670功能框图
OV7670是一种图像传感器,工作温度-30℃-70℃,模拟电压2.5-3.0v,感光阵列640*480,功耗60mW/15fps。休眠时小于20uA .
体积小,工作电压低,提供单个 VGA 摄像头和图像处理器的所有功能。 通过SCCB总线控制,可以输入各种分辨率8位图像数据的整帧、子采样、窗口等多种方式。 该产品的VGA图像最高可达每秒30帧。 用户可以完全控制图像质量、数据格式和传输。 所有图像处理功能,包括伽马曲线、白平衡、饱和度、色度等,都可以通过 SCCB 接口进行编程。 通过减少或消除固定图案噪声、尾托、浮动等光学或电子缺陷,提高图像质量,获得清晰稳定的彩色图像。
OV7670 是 OV(OmniVision)生产的 1/6 英寸 CMOS VGA 图像传感器。
该器件体积小,工作电压低,提供单个VGA摄像头和图像处理器的所有功能。 通过SCCB总线控制,可以输出整帧、子采样、窗口等各种分辨率的8位图像数据。 该产品的 VGA 图像最高可达每秒 30 帧。 用户可以完全控制图像质量、数据格式和传输。 包括伽马曲线、白平衡、度数、颜色等在内的所有图像处理过程都可以通过 SCCB 接口进行编程。OmniVision 图像传感器采用独特的传感器技术,通过减少或消除固定图案噪声等光学或电子缺陷来提高图像质量、尾托、浮动等,获得清晰稳定的彩色图像。
OV7670 的特点包括:
- 适用于嵌入式应用的高灵敏度、低电压
- 标准SCCB接口,兼容IIC接口
- 支持 RawRGB、RGB(gbr4:2:2、RGB565/RGB555/RGB444)、YUV(4:2:2) 和 YCbCr
- 支持 VGA、CIF 以及从 CIF 到 40*30 的所有尺寸
- 支持自动曝光控制、自动增益控制、自动白平衡和自动消除光纹
- 自动黑电平校准和其他自动控制功能。 同时支持色彩饱和度、色调、伽玛、锐度等设置。
- 支持Flash
- 支持图像缩放
OV7670 传感器包括以下功能模块。
1. 图像阵列
OV7670共有656*488像素,其中640*480有效(即有效像素为30W)。
2. 视频定时发生器
序列发生器具有以下功能:全序列控制和帧率生成(7种不同格式输出),内部信号发生器535和分配,帧率定时,自动曝光控制,以及外部定时输出(VSYNC,HREF/HSYNC,和 PCLK)。
3.模拟信号处理
模拟信号处理所有模拟功能,包括自动增益 (AGC) 和自动白平衡 (AWB)。
4、A/D转换(A/D)
原始信号经过模拟处理器模块后,通过G、BR通道进入A 10位A/D转换器。
A/D转换器以12M的A频率工作,与像素频率完全同步(转换频率与帧率有关)。
A/D 范围产品和 A/D 范围控制共同设置 A/D 范围和最大值,允许用户根据应用调整图像的亮度。
接下来介绍一下OV7670的图像数据输出格式。 首先,让我们简单介绍一些定义:
VGA,即分辨率为640*480的输出模式;
QVGA,分辨率为320*240的输出格式,就是我们本章需要的格式。
QQVGA,即分辨率为160*120的输出格式;
PCLK,或像素时钟,一个PCLK时钟,输出一个像素(或半个像素)。
VSYNC,帧同步信号。HREF /HSYNC,行同步信号。
OV7670 的图像数据输出(通过 D[7:0])由 PCLK、VSYNC 和 HREF/HSYNC 控制
以下。 首先看一下行输出的时序,如图:
从上图可以看出,当HREF为高电平时输出图像数据,而当每个PCLK时HREF为高电平时输出图像数据
时钟,输出一个字节的数据。 比如我们使用VGA时序,RGB565格式输出,每2个字节构成一个像素颜色(高字节前,低字节后)这样每行输出总共有640*2个PCLK周期,输出640* 2 个字节。
帧时序(VGA 模式):
上图清晰的显示了OV7670在VGA模式下的数据输出。 注意图中的HSYNC和HREF
它实际上是来自同一个引脚的信号,但是在不同的情况下以不同的方式,我们在本章中使用 HREF。
由于OV7670的像素时钟(PCLK)最高可以达到24Mhz,所以我们使用STM32F103ZET6的IO口直接抓取,难度很大,占用CPU很多(IO口可以通过降低PCLK的输出频率来抓取,但不推荐)。
在这个项目中,我使用的是RGB565模式,采集到的图像数据是RGB的原始数据,然后传输到 STONE 通过UART显示模块。
OV7670摄像头模块的驱动代码
u8 OV7670_Init(void)
{
u8 temp;
u16 i=0;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOG, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_3|GPIO_Pin_4);
GPIO_InitStructure.GPIO_Pin = 0xff;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_SetBits(GPIOD,GPIO_Pin_6);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14|GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOG, &GPIO_InitStructure);
GPIO_SetBits(GPIOG,GPIO_Pin_14|GPIO_Pin_15);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //SWD
SCCB_Init(); //³õʼ»¯SCCB µÄIO¿Ú
if(SCCB_WR_Reg(0x12,0x80))return 1; //¸´Î»SCCB
delay_ms(50);
temp=SCCB_RD_Reg(0x0b);
if(temp!=0x73)return 2;
temp=SCCB_RD_Reg(0x0a);
if(temp!=0x76)return 2;
//³õʼ»¯ÐòÁÐ
for(i=0;i<sizeof(ov7670_init_reg_tbl_rgb565) sizeof=""></sizeof(ov7670_init_reg_tbl_rgb565)>
{
SCCB_WR_Reg(ov7670_init_reg_tbl_RGB565[i][0],ov7670_init_reg_tbl_RGB565[i][1]);
delay_ms(2);
}
return 0x00; //ok
}
OV7670_CONFIG ov7670_config;
//ÅäÖÃOV7670µÄÊä³ö
void config_ov7670_OutPut(u16 xsta,u16 ysta,u16 width,u16 height,u8 ouput_mode){
int i=0;
ov7670_config.xsta = xsta;
ov7670_config.ysta = ysta;
ov7670_config.width = width;
ov7670_config.height = height;
ov7670_config.mode = ouput_mode;
if(ouput_mode){ //²ÊÉ«Êä³ö
for(i=0;i<sizeof(ov7670_init_reg_tbl_yuv) sizeof=""></sizeof(ov7670_init_reg_tbl_yuv)>
{
SCCB_WR_Reg(ov7670_init_reg_tbl_YUV[i][0],ov7670_init_reg_tbl_YUV[i][1]);
delay_ms(2);
}
}else{ //ºÚ°×Êä³ö
for(i=0;i<sizeof(ov7670_init_reg_tbl_rgb565) sizeof=""></sizeof(ov7670_init_reg_tbl_rgb565)>
{
SCCB_WR_Reg(ov7670_init_reg_tbl_RGB565[i][0],ov7670_init_reg_tbl_RGB565[i][1]);
delay_ms(2);
}
}
OV7670_Window_Set(176,10,width,height); //ÉèÖô°¿Ú
LCD_Clear(WHITE);
}
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);
SCCB_WR_Reg(0X01,reg01val);
SCCB_WR_Reg(0X02,reg02val);
}
void OV7670_Color_Saturation(u8 sat)
{
u8 reg4f5054val=0X80;
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);
SCCB_WR_Reg(0X50,reg4f5054val);
SCCB_WR_Reg(0X51,0X00);
SCCB_WR_Reg(0X52,reg52val);
SCCB_WR_Reg(0X53,reg53val);
SCCB_WR_Reg(0X54,reg4f5054val);
SCCB_WR_Reg(0X58,0X9E);
}
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);
}
void OV7670_Contrast(u8 contrast)
{
u8 reg56val=0X40;
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);
}
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);
SCCB_WR_Reg(0X68,reg67val);
SCCB_WR_Reg(0X67,reg68val);
}
void OV7670_Window_Set(u16 sx,u16 sy,u16 width,u16 height)
{
u16 endx;
u16 endy;
u8 temp;
endx=(sx+width*2)%784; // sx:HSTART endx:HSTOP
endy=sy+height*2; // sy:VSTRT endy:VSTOP
//ÉèÖÃHREF
temp=SCCB_RD_Reg(0X32);
temp&=0XC0;
temp|=((endx&0X07)<<3)|(sx&0X07);
SCCB_WR_Reg(0X032,temp);
SCCB_WR_Reg(0X17,sx>>3);
SCCB_WR_Reg(0X18,endx>>3);
//ÉèÖÃVREF
temp=SCCB_RD_Reg(0X03);
temp&=0XF0;
temp|=((endy&0X03)<<2)|(sy&0X03);
SCCB_WR_Reg(0X03,temp);
SCCB_WR_Reg(0X19,sy>>2);
SCCB_WR_Reg(0X1A,endy>>2);
}
TF卡驱动
该项目还需要一个 TF 卡来存储拍摄的图像。 因为TF卡驱动太长,这里就不贴了。 您可以在网络上搜索相关代码来使用。
STM32F103ZE
网络上有很多关于这款芯片的资料和开发文档,这里简单介绍一下这款芯片。
这个芯片我就不多说了。 芯片下载代码使用j-link,如下图所示:
这是一个简单版的j-link,只支持SWD调试和下载,不支持JTAG。 但是对于STM32芯片的开发,SWD调试就足够了。
下载代码到STM32芯片
确保j-link和STM32F103ZE的连接正确,然后在KEIL开发环境中就可以识别芯片了:
点击下载按钮,将代码下载到芯片:
STM32控制代码
数据接收 STONE 显示模块一次只能接收255个字节,而单个RGB565数据的图像大小为240*320*2=153600Byte=153.6kb,所以需要分分发。
另外,由于串口通信速率的限制,图片实时刷新的效果不是很好。 串口波特率配置为 921600,这也是串口的最高通信波特率 STONE 串行显示模块。
显示屏中的按钮和文本具有相应的地址。 本项目中显示组件的地址如下:
拍照按钮:0X002A
彩色和灰色按钮:0X002B
更改比例按钮:0X002C
上一个图片按钮:0X002D
下一张图片按钮:0X002E
浏览按钮:0X002F
主要功能代码如下:
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"
#include "string.h"
#include "ov7670.h"
#include "tpad.h"
#include "timer.h"
#include "exti.h"
#include "usmart.h"
#include "dma.h"
#include "sdio_sdcard.h"
extern u8 ov_sta;
extern u8 img_dis_cnt;
extern u8 data_ready;
extern u8 USART_RX_END;
u16 user_width=240;
u16 user_heigh=240;
#define PIC_TOTAL 20
u8 sd_select=1;
u16 color_r;
u16 color_g;
u16 color_b;
void UART1_Send_Array(u8 send_array[],u16 num)
{
u16 i=0;
while(i<num)< span=""></num)<>
{
USART_SendData(USART1,send_array[i]);
while( USART_GetFlagStatus(USART1,USART_FLAG_TC)!= SET);
i++;
}
}
void ov7670_clock_set(u8 PLL)
{
u8 temp=0;
RCC->CFGR&=0XFFFFFFFC;
RCC->CR&=~0x01000000;
RCC->CFGR&=~(0XF<<18);
PLL-=2;//µÖÏû2¸öµ¥Î»
RCC->CFGR|=PLL<<18;
RCC->CFGR|=1<<16; //PLLSRC ON
FLASH->ACR|=0x12;
RCC->CR|=0x01000000; //PLLON
while(!(RCC->CR>>25));
RCC->CFGR|=0x02;
while(temp!=0x02)
{
temp=RCC->CFGR>>2;
temp&=0x03;
}
}
#define SEND_BUF_SIZE 169
#define LCD_X_H 5
#define LCD_X_L 6
#define LCD_Y_H 7
#define LCD_Y_L 8
u8 lcd_send_buf[SEND_BUF_SIZE]={0xa5,0x5a,0xa6,0x85,0x00,0x00,0x00,0x00,0x00};
u8 lcd_send_buf1[512]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
u8 upda_flag=1;
u16 dis_fixel=0;
void camera_refresh()
{
u16 i=0,j=0,k=0;
u8 color;
u8 cnt=9;
u16 user_x_cnt=0,user_x_start=0,lcd_send_times=0;
u16 user_width1=user_width;
u16 user_heigh1=user_heigh;
if(user_width1==240)
{
user_x_cnt=2;
user_x_start=450;
}
else if(user_width1==320)
{
user_x_cnt=3;
user_x_start=410;
}
else if(user_width1==160)
{
user_x_cnt=1;
user_x_start=490;
}
else if(user_width1==80)
{
user_x_cnt=0;
user_x_start=530;
}
if(ov_sta==2)
{
OV7670_RRST=0;
OV7670_RCK_L;
OV7670_RCK_H;
OV7670_RCK_L;
OV7670_RRST=1;
OV7670_RCK_H;
upda_flag=0;
for(i=0;i<user_heigh1;i++)< span=""></user_heigh1;i++)<>
{
k=i+150;
lcd_send_buf[LCD_Y_L] = (u8)(k & 0x00ff);
lcd_send_buf[LCD_Y_H] = (u8)(k >> 8);
cnt=9;
lcd_send_times=0;
for(j=0;j<user_width1*2;j++)></user_width1*2;j++)>
{
OV7670_RCK_L;
color=(u8)GPIOC->IDR&0XFF;
OV7670_RCK_H;
lcd_send_buf[cnt++]=color;
if(cnt > 168)
{
if(lcd_send_times==0)
{
dis_fixel=user_x_start;
lcd_send_buf[LCD_X_H] =(u8)(dis_fixel >> 8);
lcd_send_buf[LCD_X_L] = (u8)(dis_fixel & 0x00ff);
}
else if(lcd_send_times==1)
{
dis_fixel+=80;
lcd_send_buf[LCD_X_H] =(u8)(dis_fixel >> 8);
lcd_send_buf[LCD_X_L] = (u8)(dis_fixel & 0x00ff);
}
else if(lcd_send_times==2)
{
dis_fixel+=80;
lcd_send_buf[LCD_X_H] =(u8)(dis_fixel >> 8);
lcd_send_buf[LCD_X_L] = (u8)(dis_fixel & 0x00ff);
}
else if(lcd_send_times==3)
{
dis_fixel+=80;
lcd_send_buf[LCD_X_H] =(u8)(dis_fixel >> 8);
lcd_send_buf[LCD_X_L] = (u8)(dis_fixel & 0x00ff);
}
if(USART_RX_END==1)
{
EXTI_ClearITPendingBit(EXTI_Line8);
ov_sta=0;
upda_flag=1;
return;
}
else
{
UART1_Send_Array(lcd_send_buf,169);
}
lcd_send_times++;
if(lcd_send_times>user_x_cnt)
lcd_send_times=0;
cnt=9;
}
}
}
EXTI_ClearITPendingBit(EXTI_Line8);
ov_sta=0;
upda_flag=1;
}
}
void clear_display()
{
u16 i=0,j=0,k=0;
u8 cnt=9,lcd_send_times=0;
u8 color;
u16 user_x_cnt=0,user_x_start=0;
u16 user_width1=user_width;
u16 user_heigh1=user_heigh;
if(user_width1==240)
{
user_x_cnt=2;
user_x_start=450;
}
else if(user_width1==320)
{
user_x_cnt=3;
user_x_start=410;
}
else if(user_width1==160)
{
user_x_cnt=1;
user_x_start=490;
}
else if(user_width1==80)
{
user_x_cnt=0;
user_x_start=530;
}
upda_flag=0;
for(i=0;i<user_heigh1;i++)< span=""></user_heigh1;i++)<>
{
k=i+150;
lcd_send_buf[LCD_Y_L] = (u8)(k & 0x00ff);
lcd_send_buf[LCD_Y_H] = (u8)(k >> 8);
cnt=9;
lcd_send_times=0;
for(j=0;j<user_width1*2;j++)></user_width1*2;j++)>
{
OV7670_RCK_L;
color=(u8)GPIOC->IDR&0XFF;
OV7670_RCK_H;
lcd_send_buf[cnt++]=0xff;
if(cnt > 168)
{
if(lcd_send_times==0)
{
dis_fixel=user_x_start;
lcd_send_buf[LCD_X_H] =(u8)(dis_fixel >> 8);
lcd_send_buf[LCD_X_L] = (u8)(dis_fixel & 0x00ff);
}
else if(lcd_send_times==1)
{
dis_fixel+=80;
lcd_send_buf[LCD_X_H] =(u8)(dis_fixel >> 8);
lcd_send_buf[LCD_X_L] = (u8)(dis_fixel & 0x00ff);
}
else if(lcd_send_times==2)
{
dis_fixel+=80;
lcd_send_buf[LCD_X_H] =(u8)(dis_fixel >> 8);
lcd_send_buf[LCD_X_L] = (u8)(dis_fixel & 0x00ff);
}
else if(lcd_send_times==3)
{
dis_fixel+=80;
lcd_send_buf[LCD_X_H] =(u8)(dis_fixel >> 8);
lcd_send_buf[LCD_X_L] = (u8)(dis_fixel & 0x00ff);
}
UART1_Send_Array(lcd_send_buf,169);
lcd_send_times++;
if(lcd_send_times>user_x_cnt)
lcd_send_times=0;
cnt=9;
}
}
}
EXTI_ClearITPendingBit(EXTI_Line8);
ov_sta=0;
upda_flag=1;
}
void user_save_image()
{
u16 i=0,j=0,k=0;
u8 color;
u8 cnt=9,m_cnt=0;
u16 user_x_cnt=0,user_x_start=0,lcd_send_times=0;
u16 user_width1=user_width;
if(user_width1==240)
{
user_x_cnt=2;
user_x_start=450;
}
else
{
return;
}
while(ov_sta!=2);
if(ov_sta==2)
{
OV7670_RRST=0;
OV7670_RCK_L;
OV7670_RCK_H;
OV7670_RCK_L;
OV7670_RRST=1;
OV7670_RCK_H;
upda_flag=0;
for(i=0;i<240;i++)
{
k=i+150;
lcd_send_buf[LCD_Y_L] = (u8)(k & 0x00ff);
lcd_send_buf[LCD_Y_H] = (u8)(k >> 8);
cnt=9;
lcd_send_times=0;
for(j=0;j<240*2;j++)
{
OV7670_RCK_L;
color=(u8)GPIOC->IDR&0XFF;
OV7670_RCK_H;
lcd_send_buf[cnt++]=color;
if(cnt > 168)
{
m_cnt=0;
if(lcd_send_times==0)
{
dis_fixel=user_x_start;
lcd_send_buf[LCD_X_H] =(u8)(dis_fixel >> 8);
lcd_send_buf[LCD_X_L] = (u8)(dis_fixel & 0x00ff);
for(m_cnt=0;m_cnt<169;m_cnt++)
{
lcd_send_buf1[m_cnt]=lcd_send_buf[m_cnt];
}
}
else if(lcd_send_times==1)
{
dis_fixel+=80;
lcd_send_buf[LCD_X_H] =(u8)(dis_fixel >> 8);
lcd_send_buf[LCD_X_L] = (u8)(dis_fixel & 0x00ff);
for(m_cnt=0;m_cnt<169;m_cnt++)
{
lcd_send_buf1[m_cnt+169]=lcd_send_buf[m_cnt];
}
}
else if(lcd_send_times==2)
{
dis_fixel+=80;
lcd_send_buf[LCD_X_H] =(u8)(dis_fixel >> 8);
lcd_send_buf[LCD_X_L] = (u8)(dis_fixel & 0x00ff);
for(m_cnt=0;m_cnt<169;m_cnt++)
{
lcd_send_buf1[m_cnt+169*2]=lcd_send_buf[m_cnt];
}
}
UART1_Send_Array(lcd_send_buf,169);
lcd_send_times++;
if(lcd_send_times>user_x_cnt)
{
SD_WriteDisk(lcd_send_buf1,i+240*sd_select,1);
lcd_send_times=0;
}
cnt=9;
}
}
}
}
EXTI_ClearITPendingBit(EXTI_Line8);
ov_sta=0;
upda_flag=1;
}
void read_image()
{
u8 i=0;
for(i=0;i<240;i++)
{
if(SD_ReadDisk(lcd_send_buf1,i+240*sd_select,1)==0)
{
UART1_Send_Array(lcd_send_buf1,507);
}
}
}
int main(void)
{
u8 pixel_ch_flag=0,user_effect_flag=0;
delay_init();
NVIC_Configuration();
uart_init(921600);
LED_Init();
LCD_Init();
delay_ms(1000);
delay_ms(1000);
while(OV7670_Init())//³õʼ»¯OV7670
{
delay_ms(200);
}
while(SD_Init())
{
delay_ms(500);
LED0=!LED0;
}
if(SD_ReadDisk(lcd_send_buf1,240*(PIC_TOTAL+10),1)==0)
{
sd_select=lcd_send_buf1[0];
if(sd_select>=PIC_TOTAL )
{
lcd_send_buf1[0]=0x00;
SD_WriteDisk(lcd_send_buf1,240*(PIC_TOTAL+10),1);
sd_select=0;
}
}
//show_sdcard_info();
EXTI8_Init();
OV7670_CS=0;
config_ov7670_OutPut(20,60,user_width,user_heigh,0);
while(1)
{
if(USART_RX_END==1)
{
switch(USART_RX_BUF[5])
{
case 0x2c:
clear_display();
pixel_ch_flag+=1;//!pixel_ch_flag;
if(pixel_ch_flag>3)
pixel_ch_flag=0;
if(pixel_ch_flag==1)
{
user_width=160;
user_heigh=160;
}
else if(pixel_ch_flag==2)
{
user_width=80;
user_heigh=80;
}
else if(pixel_ch_flag==3)
{
user_width=320;
user_heigh=240;
}
else
{
user_width=240;
user_heigh=240;
}
config_ov7670_OutPut(20,60,user_width,user_heigh,0);
if(user_effect_flag)
OV7670_Special_Effects(1);
else
OV7670_Special_Effects(0);
break;
case 0x2b:
user_effect_flag=!user_effect_flag;
if(user_effect_flag)
OV7670_Special_Effects(1);
else
OV7670_Special_Effects(0);
break;
case 0x2a:
if(user_width!=240)break;
if(img_dis_cnt==0)
{
img_dis_cnt=1;
}
else
{
if(SD_ReadDisk(lcd_send_buf1,240*(PIC_TOTAL+10),1)==0)
{
if(lcd_send_buf1[0]>=PIC_TOTAL)
{
lcd_send_buf1[0]=PIC_TOTAL;
sd_select=1;
}
else
{
sd_select=lcd_send_buf1[0]+1;
lcd_send_buf1[0]=sd_select;
}
SD_WriteDisk(lcd_send_buf1,240*(PIC_TOTAL+10),1);
user_save_image();
//sd_select=lcd_send_buf1[0];
}
}
break;
case 0x2d:
if(SD_ReadDisk(lcd_send_buf1,240*(PIC_TOTAL+10),1)==0)
{
if(lcd_send_buf1[0]==0)
break;
else
{
sd_select-=1;
if(sd_select==0)sd_select=lcd_send_buf1[0];
}
if(sd_select>lcd_send_buf1[0])
sd_select=1;
}
if(user_width==320)
clear_display();
read_image();
img_dis_cnt=0;
break;
case 0x2e:
if(SD_ReadDisk(lcd_send_buf1,240*(PIC_TOTAL+10),1)==0)
{
if(lcd_send_buf1[0]==0)
break;
if(sd_select>=lcd_send_buf1[0])
{
sd_select=1;
}
else
{
sd_select+=1;
}
}
if(user_width==320)
clear_display();
read_image();
img_dis_cnt=0;
break;
case 0x2f:
img_dis_cnt=0;
break;
default:
break;
}
USART_RX_END=0;
USART_RX_STA=0;
}
else
{
// USART_RX_END=0;
// USART_RX_STA=0;
if(img_dis_cnt==1)
camera_refresh();
}
}
}
最后把代码下载到STM32芯片上,然后把完成的电路板接到显示屏上,保证供电稳定。 可以通过VO7670看到的图片 STONE 显示模块。
ov7670摄像头模块连接 STONE 显示模块项目结束。