STM32+TFT+OV7670实现图片的显示
作者:互联网
最近在做一个项目,使用OV7670来采集图片将采集好的图片上传到云端,通过手机可以在云端中查看。这两天就先搞了通过TFT显示采集的图片,后面再通过esp8266上传到云端。
材料的准备
STM32F103ZET6 ,主控芯片;
TFT显示屏(某宝上的图片) ;
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 的功能框图图如图所示:
原理图
从上图可以看出, 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
2
3
4
5
6
7
8
9
10
11
12
13
代码部分
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
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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;
}
//读寄存器
//返回值:读到的寄存器值
u8 SCCB_RD_Reg(u8 reg)
{
u8 val=0;
SCCB_Start(); //启动SCCB传输
SCCB_WR_Byte(SCCB_ID); //写器件ID
delay_us(100);
SCCB_WR_Byte(reg); //写寄存器地址
delay_us(100);
SCCB_Stop();
delay_us(100);
//设置寄存器地址后,才是读
SCCB_Start();
SCCB_WR_Byte(SCCB_ID|0X01); //发送读命令
delay_us(100);
val=SCCB_RD_Byte(); //读取数据
SCCB_No_Ack();
SCCB_Stop();
return val;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
2、OV7670驱动程序
2.1 ov7670.h
//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
//自己可以根据自己的需求改脚位
#ifndef __OV7670_H__
#define __OV7670_H__
#include "sys.h"
#include "sccb.h"
#define OV7670_VSYNC PAin(7) //同步信号检测IO
#define OV7670_WRST PEout(6) //写指针复位
#define OV7670_WREN PBout(6) //写入FIFO使能
#define OV7670_RCK_H GPIO_SetBits(GPIOB,GPIO_Pin_7)//GPIOB->BSRRH=1<<7设置读数据时钟高电平
#define OV7670_RCK_L GPIO_ResetBits(GPIOB,GPIO_Pin_7)//GPIOB->BSRRL=1<<7// //设置读数据时钟低电平
#define OV7670_RRST PCout(2) //读指针复位
#define OV7670_CS PCout(3) //片选信号(OE)
#define OV7670_DATA GPIOF->IDR&0x00FF //数据输入端口
/
u8 OV7670_Init(void);
void OV7670_Light_Mode(u8 mode);
void OV7670_Color_Saturation(u8 sat);
void OV7670_Brightness(u8 bright);
void OV7670_Contrast(u8 contrast);
void OV7670_Special_Effects(u8 eft);
void OV7670_Window_Set(u16 sx,u16 sy,u16 width,u16 height);
#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2.2 ov7670cfg.h
#ifndef _OV7670CFG_H
#define _OV7670CFG_H
#include "ov7670.h"
//初始化寄存器序列及其对应的值
const u8 ov7670_init_reg_tbl[][2]=
{
/*以下为OV7670 QVGA RGB565参数 */
{0x3a, 0x04},//dummy
{0x40, 0xd0},//565
{0x12, 0x14},//QVGA,RGB输出
//输出窗口设置
{0x32, 0x80},//HREF control bit[2:0] HREF start 3 LSB bit[5:3] HSTOP HREF end 3LSB
{0x17, 0x16},//HSTART start high 8-bit MSB
{0x18, 0x04},//5 HSTOP end high 8-bit
{0x19, 0x02},
{0x1a, 0x7b},//0x7a,
{0x03, 0x06},//0x0a,帧竖直方向控制
{0x0c, 0x00},
{0x15, 0x00},//0x00
{0x3e, 0x00},//10
{0x70, 0x3a},
{0x71, 0x35},
{0x72, 0x11},
{0x73, 0x00},//
{0xa2, 0x02},//15
{0x11, 0x81},//时钟分频设置,0,不分频.
{0x7a, 0x20},
{0x7b, 0x1c},
{0x7c, 0x28},
{0x7d, 0x3c},//20
{0x7e, 0x55},
{0x7f, 0x68},
{0x80, 0x76},
{0x81, 0x80},
{0x82, 0x88},
{0x83, 0x8f},
{0x84, 0x96},
{0x85, 0xa3},
{0x86, 0xaf},
{0x87, 0xc4},//30
{0x88, 0xd7},
{0x89, 0xe8},
{0x13, 0xe0},
{0x00, 0x00},//AGC
{0x10, 0x00},
{0x0d, 0x00},//全窗口, 位[5:4]: 01 半窗口,10 1/4窗口,11 1/4窗口
{0x14, 0x28},//0x38, limit the max gain
{0xa5, 0x05},
{0xab, 0x07},
{0x24, 0x75},//40
{0x25, 0x63},
{0x26, 0xA5},
{0x9f, 0x78},
{0xa0, 0x68},
{0xa1, 0x03},//0x0b,
{0xa6, 0xdf},//0xd8,
{0xa7, 0xdf},//0xd8,
{0xa8, 0xf0},
{0xa9, 0x90},
{0xaa, 0x94},//50
{0x13, 0xe5},
{0x0e, 0x61},
{0x0f, 0x4b},
{0x16, 0x02},
{0x1e, 0x27},//图像输出镜像控制.0x07
{0x21, 0x02},
{0x22, 0x91},
{0x29, 0x07},
{0x33, 0x0b},
{0x35, 0x0b},//60
{0x37, 0x1d},
{0x38, 0x71},
{0x39, 0x2a},
{0x3c, 0x78},
{0x4d, 0x40},
{0x4e, 0x20},
{0x69, 0x00},
{0x6b, 0x40},//PLL*4=48Mhz
{0x74, 0x19},
{0x8d, 0x4f},
{0x8e, 0x00},//70
{0x8f, 0x00},
{0x90, 0x00},
{0x91, 0x00},
{0x92, 0x00},//0x19,//0x66
{0x96, 0x00},
{0x9a, 0x80},
{0xb0, 0x84},
{0xb1, 0x0c},
{0xb2, 0x0e},
{0xb3, 0x82},//80
{0xb8, 0x0a},
{0x43, 0x14},
{0x44, 0xf0},
{0x45, 0x34},
{0x46, 0x58},
{0x47, 0x28},
{0x48, 0x3a},
{0x59, 0x88},
{0x5a, 0x88},
{0x5b, 0x44},//90
{0x5c, 0x67},
{0x5d, 0x49},
{0x5e, 0x0e},
{0x64, 0x04},
{0x65, 0x20},
{0x66, 0x05},
{0x94, 0x04},
{0x95, 0x08},
{0x6c, 0x0a},
{0x6d, 0x55},
{0x4f, 0x80},
{0x50, 0x80},
{0x51, 0x00},
{0x52, 0x22},
{0x53, 0x5e},
{0x54, 0x80},
//{0x54, 0x40},//110
{0x09, 0x03},//驱动能力最大
{0x6e, 0x11},//100
{0x6f, 0x9f},//0x9e for advance AWB
{0x55, 0x00},//亮度
{0x56, 0x40},//对比度 0x40
{0x57, 0x40},//0x40, change according to Jim's request
///
//以下部分代码由开源电子网网友:duanzhang512 提出
//添加此部分代码将可以获得更好的成像效果,但是最下面一行会有蓝色的抖动.
//如不想要,可以屏蔽此部分代码.然后将:OV7670_Window_Set(12,176,240,320);
//改为:OV7670_Window_Set(12,174,240,320);,即可去掉最下一行的蓝色抖动
{0x6a, 0x40},
{0x01, 0x40},
{0x02, 0x40},
{0x13, 0xe7},
{0x15, 0x00},
{0x58, 0x9e},
{0x41, 0x08},
{0x3f, 0x00},
{0x75, 0x05},
{0x76, 0xe1},
{0x4c, 0x00},
{0x77, 0x01},
{0x3d, 0xc2},
{0x4b, 0x09},
{0xc9, 0x60},
{0x41, 0x38},
{0x34, 0x11},
{0x3b, 0x02},
{0xa4, 0x89},
{0x96, 0x00},
{0x97, 0x30},
{0x98, 0x20},
{0x99, 0x30},
{0x9a, 0x84},
{0x9b, 0x29},
{0x9c, 0x03},
{0x9d, 0x4c},
{0x9e, 0x3f},
{0x78, 0x04},
{0x79, 0x01},
{0xc8, 0xf0},
{0x79, 0x0f},
{0xc8, 0x00},
{0x79, 0x10},
{0xc8, 0x7e},
{0x79, 0x0a},
{0xc8, 0x80},
{0x79, 0x0b},
{0xc8, 0x01},
{0x79, 0x0c},
{0xc8, 0x0f},
{0x79, 0x0d},
{0xc8, 0x20},
{0x79, 0x09},
{0xc8, 0x80},
{0x79, 0x02},
{0xc8, 0xc0},
{0x79, 0x03},
{0xc8, 0x40},
{0x79, 0x05},
{0xc8, 0x30},
{0x79, 0x26},
{0x09, 0x00},
///
};
#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
2.3 ov7670.c
#include "sys.h"
#include "ov7670.h"
#include "ov7670cfg.h"
#include "time.h"
#include "delay.h"
#include "usart.h"
#include "sccb.h"
#include "exti.h"
//初始化OV7670
//返回0:成功
//返回其他值:错误代码
u8 OV7670_Init(void)
{
u8 temp;
u16 i=0;
//设置IO
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOF|RCC_APB2Periph_GPIOE|RCC_APB2Periph_GPIOC,ENABLE);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //上拉模式
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//速度为50M
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=0xff;
GPIO_Init(GPIOF, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_SetBits(GPIOE,GPIO_Pin_6);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC,GPIO_Pin_2|GPIO_Pin_3);
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)/sizeof(ov7670_init_reg_tbl[0]);i++)
{
SCCB_WR_Reg(ov7670_init_reg_tbl[i][0],ov7670_init_reg_tbl[i][1]);
}
return 0x00; //ok
}
//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;
endx=sx+width*2; //V*2
endy=sy+height*2;
if(endy>784)endy-=784;
temp=SCCB_RD_Reg(0X03); //读取Vref之前的值
temp&=0XF0;
temp|=((endx&0X03)<<2)|(sx&0X03);
SCCB_WR_Reg(0X03,temp); //设置Vref的start和end的最低2位
SCCB_WR_Reg(0X19,sx>>2); //设置Vref的start高8位
SCCB_WR_Reg(0X1A,endx>>2); //设置Vref的end的高8位
temp=SCCB_RD_Reg(0X32); //读取Href之前的值
temp&=0XC0;
temp|=((endy&0X07)<<3)|(sy&0X07);
SCCB_WR_Reg(0X17,sy>>3); //设置Href的start高8位
SCCB_WR_Reg(0X18,endy>>3); //设置Href的end的高8位
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
3、main主函数
#include "delay.h"
#include "sys.h"
#include "lcd.h"
#include "touch.h"
#include "gui.h"
#include "test.h"
#include "ov7670.h"
#include "time.h"
#include "exti.h"
#include "led.h"
#include "key.h"
extern u8 ov_sta; //在exit.c里面定义
extern u8 ov_frame; //在time.c里面定义
//更新LCD显示
void camera_refresh(void)
{
u32 j;
// u16 i;
u16 color;
if(ov_sta)//有帧中断更新?
{
LCD_direction(1);
LCD_SetWindows(0,0,320-1,240-1);
OV7670_RRST=0; //开始复位读指针
OV7670_RCK_L;
OV7670_RCK_H;
OV7670_RCK_L;
OV7670_RRST=1; //复位读指针结束
OV7670_RCK_H;
// for(i=0;i<240;i++) //此种方式可以兼容任何彩屏,但是速度很慢
// {
// for(j=0;j<320;j++)
// {
// OV7670_RCK_L;
// color=GPIOF->IDR&0XFF; //读数据
// OV7670_RCK_H;
// color<<=8;
// OV7670_RCK_L;
// color|=GPIOF->IDR&0XFF; //读数据
// OV7670_RCK_H;
// LCD_DrawFRONT_COLOR(i,j,color);
// }
// }
for(j=0;j<76800;j++) //此种方式需清楚TFT内部显示方向控制寄存器值 速度较快
{
OV7670_RCK_L;
color=GPIOF->IDR&0XFF; //读数据
OV7670_RCK_H;
color<<=8;
OV7670_RCK_L;
color|=GPIOF->IDR&0XFF; //读数据
OV7670_RCK_H;
Lcd_WriteData_16Bit(color);
}
EXTI_ClearITPendingBit(EXTI_Line7);//清零帧中断标记
ov_sta=0; //下一次扫描
ov_frame++;
}
}
int main(void)
{
KEY_Init();
LED_Init();
SystemInit();//初始化RCC 设置系统主频为72MHZ
delay_init(72); //延时初始化
LCD_Init(); //液晶屏初始化
LCD_Clear(0xffff);
LCD_Clear(BLUE);
LCD_ShowString(8,8,16,"1234567",1);
while(OV7670_Init())//初始化OV7670
{
LCD_ShowString(100,20,16,"ERROR",1);
delay_ms(200);
LCD_Fill(0,80,239,206,BLACK);
delay_ms(200);
}
LCD_ShowString(200,200,16,"ok",1);
delay_ms(1500);
OV7670_Light_Mode(0);
OV7670_Color_Saturation(2);
OV7670_Brightness(2);
OV7670_Contrast(2);
OV7670_Special_Effects(0);
LCD_Clear(BLACK);
EXTI7_Init();
OV7670_CS=0;
LCD_Clear(BLACK);
while(1){
camera_refresh();//更新显示
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
最后连接好之后显示的图像
大概就是下面这样的(屏幕坏的 -_- )
写得太差了,希望大佬们不要吐槽
…
下面是源码下载链接
百度网盘链接
提取码:a61c
————————————————
版权声明:本文为CSDN博主「[有红包][QQ红包]恭喜发财」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_45134854/article/details/107833326
标签:SCCB,u8,OV7670,void,STM32,InitStructure,GPIO,TFT 来源: https://www.cnblogs.com/bruce1992/p/16660044.html