w806开发板驱动ov2640读取jpeg图片1600x1200分辨率,以及花屏原因及解决办法
Posted 花开花落的个人博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了w806开发板驱动ov2640读取jpeg图片1600x1200分辨率,以及花屏原因及解决办法相关的知识,希望对你有一定的参考价值。
主频需要160MHz以上,80MHz主频读取会丢数据,读取过程中要关闭所有中断否则会出现丢数据花屏现象,还有一个重要的地方需要注意,PCLK速度过慢同时照片信息量多时,jpeg文件过大也会花一部分,像如这样
这样
出现部分花屏原因是因为ov2640发现以当前PCLK的速度已经无法在一帧照片的时间内将jpeg文件发送完,索性直接就停止发送了,在单片机允许的速度下适当的调整PCLK的速度可以发送更大的jpeg图片,调整的方法就是设置0xD3寄存器
SCCB_WR_Reg(0XD3,0X14);//0X30:48MHz/48 = 1MHz;0X18:48MHz/24 = 2MHz;0X14:48MHz/20 = 2.4MHz;0X0F:48MHz/16 = 3MHz;0X0C:48MHz/12 = 4MHz
手册
废话不多说上样张102 KB (104,520 字节)
下位机程序
main.c
#include <stdio.h>
#include "wm_hal.h"
#include "ov2640.h"
#include "general.h"
void Error_Handler(void);
static void GPIO_Init(void);
static void GPIO_Init(void)
GPIO_InitTypeDef GPIO_InitStruct = 0;
__HAL_RCC_GPIO_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = GPIO_PIN_8| GPIO_PIN_12| GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8| GPIO_PIN_12| GPIO_PIN_14, GPIO_PIN_RESET);
//
//设置摄像头数据接口
GPIO_InitStruct.Pin = GPIO_PIN_9| GPIO_PIN_11| GPIO_PIN_13| GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
//设置摄像头数据接口
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5| GPIO_PIN_6 | GPIO_PIN_7 ;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_NVIC_SetPriority(GPIOB_IRQn, 0);
HAL_NVIC_EnableIRQ(GPIOB_IRQn);
int main(void)
SystemClock_Config(CPU_CLK_160M);
printf("enter main\\r\\n");
HAL_Init();
GPIO_Init();
HAL_Delay(5000);
printf("ov2640_init\\r\\n");
ov2640_init();
while (1)
HAL_Delay(5000);
return 0;
void Error_Handler(void)
while (1)
void assert_failed(uint8_t *file, uint32_t line)
printf("Wrong parameters value: file %s on line %d\\r\\n", file, line);
ov2640.c
#include "ov2640.h"
#include "ov2640cfg.h"
#include "wm_hal.h"
#include "general.h"
#define OV2640_VSYNC HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_9)
#define OV2640_PWDN_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_14, GPIO_PIN_SET) //POWER DOWN控制信号
#define OV2640_PWDN_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_14, GPIO_PIN_RESET) //POWER DOWN控制信号
#define OV2640_RST_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_SET) //复位控制信号
#define OV2640_RST_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET) //复位控制信号
#define OV2640_HREF HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) //HREF信号
#define OV2640_PCLK HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_13) //PCLK信号
//#define OV2640_SCL HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8) //读SCL信号
#define OV2640_SCL_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET) //写SCL高
#define OV2640_SCL_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET) //写SCL低
#define OV2640_SDA HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_10) //读SDA信号
#define OV2640_SDA_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET) //写SDA信号
#define OV2640_SDA_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_RESET) //读SDA信号
#define OV2640_JPEG_WIDTH 1600 //320//1600 //JPEG拍照的宽度
#define OV2640_JPEG_HEIGHT 1200 //240//1200 //JPEG拍照的高度
#define SCCB_ID 0X60 //OV2640的ID
uint8_t buffer[200*1024];
static void gpio_sda_output()
GPIO_InitTypeDef GPIO_InitStruct = 0;
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
static void gpio_sda_input()
GPIO_InitTypeDef GPIO_InitStruct = 0;
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
unsigned char ov2640_read_data(GPIO_TypeDef *GPIOx)
unsigned char data = GPIOx->DATA&0x00FF;//数据输入端口
return data;
//SCCB起始信号
//当时钟为高的时候,数据线的高到低,为SCCB起始信号
//在激活状态下,SDA和SCL均为低电平
void SCCB_Start(void)
OV2640_SDA_H; //数据线高电平
OV2640_SCL_H; //在时钟线高的时候数据线由高至低
delay_us(50);
OV2640_SDA_L;
delay_us(50);
OV2640_SCL_L; //数据线恢复低电平,单操作函数必要
//SCCB停止信号
//当时钟为高的时候,数据线的低到高,为SCCB停止信号
//空闲状况下,SDA,SCL均为高电平
void SCCB_Stop(void)
OV2640_SDA_L;
delay_us(50);
OV2640_SCL_H;
delay_us(50);
OV2640_SDA_H;
delay_us(50);
//产生NA信号
void SCCB_No_Ack(void)
delay_us(50);
OV2640_SDA_H;
OV2640_SCL_H;
delay_us(50);
OV2640_SCL_L;
delay_us(50);
OV2640_SDA_L;
delay_us(50);
//SCCB,写入一个字节
//返回值:0,成功;1,失败.
uint8_t SCCB_WR_Byte(uint8_t dat)
uint8_t j,res;
for(j=0;j<8;j++) //循环8次发送数据
if(dat&0x80)
OV2640_SDA_H;
else
OV2640_SDA_L;
dat<<=1;
delay_us(50);
OV2640_SCL_H;
delay_us(50);
OV2640_SCL_L;
gpio_sda_input(); //设置SDA为输入
delay_us(50);
OV2640_SCL_H; //接收第九位,以判断是否发送成功
delay_us(50);
if(OV2640_SDA == GPIO_PIN_SET)
res=1; //SDA=1发送失败,返回1
//printf("SDA=1发送失败,返回1\\r\\n");
else
res=0; //SDA=0发送成功,返回0
//printf("SDA=0发送成功,返回0\\r\\n");
OV2640_SCL_L;
gpio_sda_output(); //设置SDA为输出
return res;
//SCCB 读取一个字节
//在SCL的上升沿,数据锁存
//返回值:读到的数据
uint8_t SCCB_RD_Byte(void)
uint8_t temp=0,j;
gpio_sda_input(); //设置SDA为输入
for(j=8;j>0;j--) //循环8次接收数据
delay_us(50);
OV2640_SCL_H;
temp=temp<<1;
if(OV2640_SDA == GPIO_PIN_SET)
temp++;
delay_us(50);
OV2640_SCL_L;
gpio_sda_output(); //设置SDA为输出
return temp;
//写寄存器
//返回值:0,成功;1,失败.
uint8_t SCCB_WR_Reg(uint8_t reg,uint8_t data)
uint8_t 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;
//读寄存器
//返回值:读到的寄存器值
uint8_t SCCB_RD_Reg(uint8_t reg)
uint8_t 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;
uint8_t ov2640_start()
uint16_t i;
uint16_t reg;
gpio_sda_output();
OV2640_RST_H; //结束复位
OV2640_PWDN_H; //POWER OFF
HAL_Delay(1000);
OV2640_PWDN_L; //POWER ON
HAL_Delay(100);
OV2640_RST_L; //复位OV2640
HAL_Delay(100);
OV2640_RST_H; //结束复位
SCCB_WR_Reg(OV2640_DSP_RA_DLMT, 0x01); //操作sensor寄存器
SCCB_WR_Reg(OV2640_SENSOR_COM7, 0x80); //软复位OV2640
HAL_Delay(50);
reg=SCCB_RD_Reg(OV2640_SENSOR_MIDH); //读取厂家ID 高八位
reg<<=8;
reg|=SCCB_RD_Reg(OV2640_SENSOR_MIDL); //读取厂家ID 低八位
if(reg!=OV2640_MID)
printf("MID:%d\\r\\n",reg);
return 1;
reg=SCCB_RD_Reg(OV2640_SENSOR_PIDH); //读取厂家ID 高八位
reg<<=8;
reg|=SCCB_RD_Reg(OV2640_SENSOR_PIDL); //读取厂家ID 低八位
if(reg!=OV2640_PID)
printf("HID:%d\\r\\n",reg);
//return 2;
//初始化 OV2640,采用SXGA分辨率(1600*1200)
for(i=0;i<sizeof(ov2640_uxga_init_reg_tbl)/2;i++)
SCCB_WR_Reg(ov2640_uxga_init_reg_tbl[i][0],ov2640_uxga_init_reg_tbl[i][1]);
return 0x00; //ok
//OV2640切换为JPEG模式
void OV2640_JPEG_Mode(void)
uint16_t i=0;
//设置:YUV422格式
for(i=0;i<(sizeof(ov2640_yuv422_reg_tbl)/2);i++)
SCCB_WR_Reg(ov2640_yuv422_reg_tbl[i][0],ov2640_yuv422_reg_tbl[i][1]);
//设置:输出JPEG数据
for(i=0;i<(sizeof(ov2640_jpeg_reg_tbl)/2);i++)
SCCB_WR_Reg(ov2640_jpeg_reg_tbl[i][0],ov2640_jpeg_reg_tbl[i][1]);
//OV2640切换为RGB565模式
void OV2640_RGB565_Mode(void)
uint16_t i=0;
//设置:RGB565输出
for(i=0;i<(sizeof(ov2640_rgb565_reg_tbl)/2);i++)
SCCB_WR_Reg(ov2640_rgb565_reg_tbl[i][0],ov2640_rgb565_reg_tbl[i][1]);
//设置图像输出大小
//OV2640输出图像的大小(分辨率),完全由该函数确定
//width,height:宽度(对应:horizontal)和高度(对应:vertical),width和height必须是4的倍数
//返回值:0,设置成功
// 其他,设置失败
uint8_t OV2640_OutSize_Set(uint16_t width,uint16_t height)
uint16_t outh;
uint16_t outw;
uint8_t temp;
if(width%4)return 1;
if(height%4)return 2;
outw=width/4;
outh=height/4;
SCCB_WR_Reg(0XFF,0X00);
SCCB_WR_Reg(0XE0,0X04);
SCCB_WR_Reg(0X5A,outw&0XFF); //设置OUTW的低八位
SCCB_WR_Reg(0X5B,outh&0XFF); //设置OUTH的低八位
temp=(outw>>8)&0X03;
temp|=(outh>>6)&0X04;
SCCB_WR_Reg(0X5C,temp); //设置OUTH/OUTW的高位
SCCB_WR_Reg(0XE0,0X00);
return 0;
//OV2640拍照jpg图片
//返回值:0,成功
// 其他,错误代码
uint16_t ov2640_jpg_photo()
uint8_t res=0;
uint32_t bwr;
uint32_t i=0;
uint32_t jpeglen=0;
// uint8_t isJpeg = 0;
OV2640_JPEG_Mode(); //切换为JPEG模式
OV2640_OutSize_Set(OV2640_JPEG_WIDTH,OV2640_JPEG_HEIGHT);
SCCB_WR_Reg(0XFF,0X00);
SCCB_WR_Reg(0XD3,30);
SCCB_WR_Reg(0XFF,0X01);
SCCB_WR_Reg(0X11,0X1);
HAL_NVIC_DisableIRQ(SYS_TICK_IRQn);
for(i=0;i<10;i++) //丢弃20帧,等待OV2640自动调节好(曝光白平衡之类的)
while(OV2640_VSYNC == GPIO_PIN_SET);
while(OV2640_VSYNC == GPIO_PIN_RESET);
while(OV2640_VSYNC == GPIO_PIN_SET) //开始采集jpeg数据
while(OV2640_HREF)
while(OV2640_PCLK == GPIO_PIN_RESET);
buffer[jpeglen]=ov2640_read_data(GPIOA);
while(OV2640_PCLK == GPIO_PIN_SET);
jpeglen++;
printf("jpeg data size:%d\\r\\n",jpeglen); //串口打印JPEG文件大小
HAL_NVIC_EnableIRQ(SYS_TICK_IRQn);
HAL_Delay(1000);
for(i = 0;i < jpeglen;i++)
printf("%c",buffer[i]);
return res;
void ov2640_init()
while(ov2640_start()) //初始化OV2640
HAL_Delay(1000);
printf("ov2640_init_ok\\r\\n");
while(1)
ov2640_jpg_photo();
HAL_Delay(2000);
ov2640.h
#ifndef __OV2640_H__
#define __OV2640_H__
//
#define OV2640_MID 0X7FA2
#define OV2640_PID 0X2642
//当选择DSP地址(0XFF=0X00)时,OV2640的DSP寄存器地址映射表
#define OV2640_DSP_R_BYPASS 0x05
#define OV2640_DSP_Qs 0x44
#define OV2640_DSP_CTRL 0x50
#define OV2640_DSP_HSIZE1 0x51
#define OV2640_DSP_VSIZE1 0x52
#define OV2640_DSP_XOFFL 0x53
#define OV2640_DSP_YOFFL 0x54
#define OV2640_DSP_VHYX 0x55
#define OV2640_DSP_DPRP 0x56
#define OV2640_DSP_TEST 0x57
#define OV2640_DSP_ZMOW 0x5A
#define OV2640_DSP_ZMOH 0x5B
#define OV2640_DSP_ZMHH 0x5C
#define OV2640_DSP_BPADDR 0x7C
#define OV2640_DSP_BPDATA 0x7D
#define OV2640_DSP_CTRL2 0x86
#define OV2640_DSP_CTRL3 0x87
#define OV2640_DSP_SIZEL 0x8C
#define OV2640_DSP_HSIZE2 0xC0
#define OV2640_DSP_VSIZE2 0xC1
#define OV2640_DSP_CTRL0 0xC2
#define OV2640_DSP_CTRL1 0xC3
#define OV2640_DSP_R_DVP_SP 0xD3
#define OV2640_DSP_IMAGE_MODE 0xDA
#define OV2640_DSP_RESET 0xE0
#define OV2640_DSP_MS_SP 0xF0
#define OV2640_DSP_SS_ID 0x7F
#define OV2640_DSP_SS_CTRL 0xF8
#define OV2640_DSP_MC_BIST 0xF9
#define OV2640_DSP_MC_AL 0xFA
#define OV2640_DSP_MC_AH 0xFB
#define OV2640_DSP_MC_D 0xFC
#define OV2640_DSP_P_STATUS 0xFE
#define OV2640_DSP_RA_DLMT 0xFF
//当选择传感器地址(0XFF=0X01)时,OV2640的DSP寄存器地址映射表
#define OV2640_SENSOR_GAIN 0x00
#define OV2640_SENSOR_COM1 0x03
#define OV2640_SENSOR_REG04 0x04
#define OV2640_SENSOR_REG08 0x08
#define OV2640_SENSOR_COM2 0x09
#define OV2640_SENSOR_PIDH 0x0A
#define OV2640_SENSOR_PIDL 0x0B
#define OV2640_SENSOR_COM3 0x0C
#define OV2640_SENSOR_COM4 0x0D
#define OV2640_SENSOR_AEC 0x10
#define OV2640_SENSOR_CLKRC 0x11
#define OV2640_SENSOR_COM7 0x12
#define OV2640_SENSOR_COM8 0x13
#define OV2640_SENSOR_COM9 0x14
#define OV2640_SENSOR_COM10 0x15
#define OV2640_SENSOR_HREFST 0x17
#define OV2640_SENSOR_HREFEND 0x18
#define OV2640_SENSOR_VSTART 0x19
#define OV2640_SENSOR_VEND 0x1A
#define OV2640_SENSOR_MIDH 0x1C
#define OV2640_SENSOR_MIDL 0x1D
#define OV2640_SENSOR_AEW 0x24
#define OV2640_SENSOR_AEB 0x25
#define OV2640_SENSOR_W 0x26
#define OV2640_SENSOR_REG2A 0x2A
#define OV2640_SENSOR_FRARL 0x2B
#define OV2640_SENSOR_ADDVSL 0x2D
#define OV2640_SENSOR_ADDVHS 0x2E
#define OV2640_SENSOR_YAVG 0x2F
#define OV2640_SENSOR_REG32 0x32
#define OV2640_SENSOR_ARCOM2 0x34
#define OV2640_SENSOR_REG45 0x45
#define OV2640_SENSOR_FLL 0x46
#define OV2640_SENSOR_FLH 0x47
#define OV2640_SENSOR_COM19 0x48
#define OV2640_SENSOR_ZOOMS 0x49
#define OV2640_SENSOR_COM22 0x4B
#define OV2640_SENSOR_COM25 0x4E
#define OV2640_SENSOR_BD50 0x4F
#define OV2640_SENSOR_BD60 0x50
#define OV2640_SENSOR_REG5D 0x5D
#define OV2640_SENSOR_REG5E 0x5E
#define OV2640_SENSOR_REG5F 0x5F
#define OV2640_SENSOR_REG60 0x60
#define OV2640_SENSOR_HISTO_LOW 0x61
#define OV2640_SENSOR_HISTO_HIGH 0x62
void ov2640_init();
#endif
ov2640cfg.h
#ifndef __OV2640_CFG_H__
#define __OV2640_CFG_H__
//OV2640 UXGA初始化寄存器序列表
//此模式下帧率为15帧
//UXGA(1600*1200)
const unsigned char ov2640_uxga_init_reg_tbl[][2]=
0xff, 0x00,
0x2c, 0xff,
0x2e, 0xdf,
0xff, 0x01,
0x3c, 0x32,
//
0x11, 0x01,
0x09, 0x02,
0x04, 0xD8,//水平镜像,垂直翻转
0x13, 0xe5,
0x14, 0x48,
0x2c, 0x0c,
0x33, 0x78,
0x3a, 0x33,
0x3b, 0xfB,
//
0x3e, 0x00,
0x43, 0x11,
0x16, 0x10,
//
0x39, 0x92,
//
0x35, 0xda,
0x22, 0x1a,
0x37, 0xc3,
0x23, 0x00,
0x34, 0xc0,
0x36, 0x1a,
0x06, 0x88,
0x07, 0xc0,
0x0d, 0x87,
0x0e, 0x41,
0x4c, 0x00,
0x48, 0x00,
0x5B, 0x00,
0x42, 0x03,
//
0x4a, 0x81,
0x21, 0x99,
//
0x24, 0x40,
0x25, 0x38,
0x26, 0x82,
0x5c, 0x00,
0x63, 0x00,
0x46, 0x00,
0x0c, 0x3c,
//
0x61, 0x70,
0x62, 0x80,
0x7c, 0x05,
//
0x20, 0x80,
0x28, 0x30,
0x6c, 0x00,
0x6d, 0x80,
0x6e, 0x00,
0x70, 0x02,
0x71, 0x94,
0x73, 0xc1,
0x3d, 0x34,
0x5a, 0x57,
//
0x12, 0x00,//UXGA 1600*1200
0x17, 0x11,
0x18, 0x75,
0x19, 0x01,
0x1a, 0x97,
0x32, 0x36,
0x03, 0x0f,
0x37, 0x40,
//
0x4f, 0xca,
0x50, 0xa8,
0x5a, 0x23,
0x6d, 0x00,
0x6d, 0x38,
//
0xff, 0x00,
0xe5, 0x7f,
0xf9, 0xc0,
0x41, 0x24,
0xe0, 0x14,
0x76, 0xff,
0x33, 0xa0,
0x42, 0x20,
0x43, 0x18,
0x4c, 0x00,
0x87, 0xd5,
0x88, 0x3f,
0xd7, 0x03,
0xd9, 0x10,
0xd3, 0x82,
//
0xc8, 0x08,
0xc9, 0x80,
//
0x7c, 0x00,
0x7d, 0x00,
0x7c, 0x03,
0x7d, 0x48,
0x7d, 0x48,
0x7c, 0x08,
0x7d, 0x20,
0x7d, 0x10,
0x7d, 0x0e,
//
0x90, 0x00,
0x91, 0x0e,
0x91, 0x1a,
0x91, 0x31,
0x91, 0x5a,
0x91, 0x69,
0x91, 0x75,
0x91, 0x7e,
0x91, 0x88,
0x91, 0x8f,
0x91, 0x96,
0x91, 0xa3,
0x91, 0xaf,
0x91, 0xc4,
0x91, 0xd7,
0x91, 0xe8,
0x91, 0x20,
//
0x92, 0x00,
0x93, 0x06,
0x93, 0xe3,
0x93, 0x05,
0x93, 0x05,
0x93, 0x00,
0x93, 0x04,
0x93, 0x00,
0x93, 0x00,
0x93, 0x00,
0x93, 0x00,
0x93, 0x00,
0x93, 0x00,
0x93, 0x00,
//
0x96, 0x00,
0x97, 0x08,
0x97, 0x19,
0x97, 0x02,
0x97, 0x0c,
0x97, 0x24,
0x97, 0x30,
0x97, 0x28,
0x97, 0x26,
0x97, 0x02,
0x97, 0x98,
0x97, 0x80,
0x97, 0x00,
0x97, 0x00,
//
0xc3, 0xef,
0xa4, 0x00,
0xa8, 0x00,
0xc5, 0x11,
0xc6, 0x51,
0xbf, 0x80,
0xc7, 0x10,
0xb6, 0x66,
0xb8, 0xA5,
0xb7, 0x64,
0xb9, 0x7C,
0xb3, 0xaf,
0xb4, 0x97,
0xb5, 0xFF,
0xb0, 0xC5,
0xb1, 0x94,
0xb2, 0x0f,
0xc4, 0x5c,
//
0xc0, 0xc8,
0xc1, 0x96,
0x8c, 0x00,
0x86, 0x3d,
0x50, 0x00,
0x51, 0x90,
0x52, 0x2c,
0x53, 0x00,
0x54, 0x00,
0x55, 0x88,
0x5a, 0x90,
0x5b, 0x2C,
0x5c, 0x05,
0xd3, 0x82,//auto设置要小心
//
0xc3, 0xed,
0x7f, 0x00,
0xda, 0x09,
0xe5, 0x1f,
0xe1, 0x67,
0xe0, 0x00,
0xdd, 0x7f,
0x05, 0x00,
;
//OV2640 SVGA初始化寄存器序列表
//此模式下,帧率可以达到30帧
//SVGA 800*600
const unsigned char ov2640_svga_init_reg_tbl[][2]=
0xff, 0x00,
0x2c, 0xff,
0x2e, 0xdf,
0xff, 0x01,
0x3c, 0x32,
//
0x11, 0x01,
0x09, 0x02,
0x04, 0xD8,//水平镜像,垂直翻转
0x13, 0xe5,
0x14, 0x48,
0x2c, 0x0c,
0x33, 0x78,
0x3a, 0x33,
0x3b, 0xfB,
//
0x3e, 0x00,
0x43, 0x11,
0x16, 0x10,
//
0x39, 0x92,
//
0x35, 0xda,
0x22, 0x1a,
0x37, 0xc3,
0x23, 0x00,
0x34, 0xc0,
0x36, 0x1a,
0x06, 0x88,
0x07, 0xc0,
0x0d, 0x87,
0x0e, 0x41,
0x4c, 0x00,
0x48, 0x00,
0x5B, 0x00,
0x42, 0x03,
//
0x4a, 0x81,
0x21, 0x99,
//
0x24, 0x40,
0x25, 0x38,
0x26, 0x82,
0x5c, 0x00,
0x63, 0x00,
0x46, 0x22,
0x0c, 0x3c,
//
0x61, 0x70,
0x62, 0x80,
0x7c, 0x05,
//
0x20, 0x80,
0x28, 0x30,
0x6c, 0x00,
0x6d, 0x80,
0x6e, 0x00,
0x70, 0x02,
0x71, 0x94,
0x73, 0xc1,
0x3d, 0x34,
0x5a, 0x57,
//根据分辨率不同而设置
0x12, 0x40,//SVGA 800*600
0x17, 0x11,
0x18, 0x43,
0x19, 0x00,
0x1a, 0x4b,
0x32, 0x09,
0x37, 0xc0,
//
0x4f, 0xca,
0x50, 0xa8,
0x5a, 0x23,
0x6d, 0x00,
0x3d, 0x38,
//
0xff, 0x00,
0xe5, 0x7f,
0xf9, 0xc0,
0x41, 0x24,
0xe0, 0x14,
0x76, 0xff,
0x33, 0xa0,
0x42, 0x20,
0x43, 0x18,
0x4c, 0x00,
0x87, 0xd5,
0x88, 0x3f,
0xd7, 0x03,
0xd9, 0x10,
0xd3, 0x82,
//
0xc8, 0x08,
0xc9, 0x80,
//
0x7c, 0x00,
0x7d, 0x00,
0x7c, 0x03,
0x7d, 0x48,
0x7d, 0x48,
0x7c, 0x08,
0x7d, 0x20,
0x7d, 0x10,
0x7d, 0x0e,
//
0x90, 0x00,
0x91, 0x0e,
0x91, 0x1a,
0x91, 0x31,
0x91, 0x5a,
0x91, 0x69,
0x91, 0x75,
0x91, 0x7e,
0x91, 0x88,
0x91, 0x8f,
0x91, 0x96,
0x91, 0xa3,
0x91, 0xaf,
0x91, 0xc4,
0x91, 0xd7,
0x91, 0xe8,
0x91, 0x20,
//
0x92, 0x00,
0x93, 0x06,
0x93, 0xe3,
0x93, 0x05,
0x93, 0x05,
0x93, 0x00,
0x93, 0x04,
0x93, 0x00,
0x93, 0x00,
0x93, 0x00,
0x93, 0x00,
0x93, 0x00,
0x93, 0x00,
0x93, 0x00,
//
0x96, 0x00,
0x97, 0x08,
0x97, 0x19,
0x97, 0x02,
0x97, 0x0c,
0x97, 0x24,
0x97, 0x30,
0x97, 0x28,
0x97, 0x26,
0x97, 0x02,
0x97, 0x98,
0x97, 0x80,
0x97, 0x00,
0x97, 0x00,
//
0xc3, 0xed,
0xa4, 0x00,
0xa8, 0x00,
0xc5, 0x11,
0xc6, 0x51,
0xbf, 0x80,
0xc7, 0x10,
0xb6, 0x66,
0xb8, 0xA5,
0xb7, 0x64,
0xb9, 0x7C,
0xb3, 0xaf,
0xb4, 0x97,
0xb5, 0xFF,
0xb0, 0xC5,
0xb1, 0x94,
0xb2, 0x0f,
0xc4, 0x5c,
//根据分辨率不同而设置
0xc0, 0x64,
0xc1, 0x4B,
0x8c, 0x00,
0x86, 0x3D,
0x50, 0x00,
0x51, 0xC8,
0x52, 0x96,
0x53, 0x00,
0x54, 0x00,
0x55, 0x00,
0x5a, 0xC8,
0x5b, 0x96,
0x5c, 0x00,
0xd3, 0x82,//auto设置要小心
//
0xc3, 0xed,
0x7f, 0x00,
0xda, 0x09,
0xe5, 0x1f,
0xe1, 0x67,
0xe0, 0x00,
0xdd, 0x7f,
0x05, 0x00,
;
const unsigned char ov2640_yuv422_reg_tbl[][2]=
0xFF, 0x00,
0xDA, 0x10,
0xD7, 0x03,
0xDF, 0x00,
0x33, 0x80,
0x3C, 0x40,
0xe1, 0x77,
0x00, 0x00,
;
const unsigned char ov2640_jpeg_reg_tbl[][2]=
0xff, 0x01,
0xe0, 0x14,
0xe1, 0x77,
0xe5, 0x1f,
0xd7, 0x03,
0xda, 0x10,
0xe0, 0x00,
;
const unsigned char ov2640_rgb565_reg_tbl[][2]=
0xFF, 0x00,
0xDA, 0x09,
0xD7, 0x03,
0xDF, 0x02,
0x33, 0xa0,
0x3C, 0x00,
0xe1, 0x67,
0xff, 0x01,
0xe0, 0x00,
0xe1, 0x00,
0xe5, 0x00,
0xd7, 0x00,
0xda, 0x00,
0xe0, 0x00,
;
#endif
上位机程序.net开发,协议很简单,先发一行特定字符,包含图片大小,然后直接发送图片数据
程序
private byte[] buffer = new byte[200 * 1024];
private int offset = 0;
private int length = 0;
private bool isData = false;
public void DataCallBack(Object sender, SerialDataReceivedEventArgs e)
try
if (isData==false)
var data = _serialPort.ReadLine();
if (!string.IsNullOrEmpty(data) && data.Length > 4)
if(data.IndexOf("jpeg data size:")>=0)
var lengthStr = data.Split(':');
if(lengthStr != null && lengthStr.Length>1)
length = int.Parse(lengthStr[1]);
isData = true;
Console.WriteLine(data);
else
int thisLength = _serialPort.Read(buffer, offset, length - offset);
offset = offset + thisLength;
if(offset >= length)
Console.WriteLine($"接收完一张图片,offset:offset,length:length");
string path = Directory.GetCurrentDirectory();
DirectoryCheak(path + "\\\\out\\\\");
bool ispictrue = false;
List<byte> data = new List<byte>();
for(int i = 1;i< length;i++)
//Console.WriteLine($"i:i,length:length");
if (ispictrue == true)
data.Add(buffer[i]);
if((buffer[i - 1] == 0xFF)&& (buffer[i] == 0xd8))
ispictrue = true;
data.Add(buffer[i - 1]);
data.Add(buffer[i]);
if((buffer[i - 1] == 0xFF) && (buffer[i] == 0xd9))
data.Add(buffer[i - 1]);
data.Add(buffer[i]);
ispictrue = false;
break;
WriteFileUsingBinaryWriter(path + "\\\\out\\\\",DateTime.Now.ToString("yyyyMMdd-HHmmss.fff") + ".jpg", data.ToArray(), data.Count());
offset = 0;
length = 0;
isData = false;
catch (Exception ex)
Console.WriteLine("串口解析出错" + ex.ToString());
public void WriteFileUsingBinaryWriter(string path,string fileName,byte[] data,int length)
var outputStream = File.Create(path + fileName);
using (var writer = new BinaryWriter(outputStream))
writer.Write(data, 0, length);
/// <summary>
/// 效验文件夹,没有就创建
/// </summary>
private void DirectoryCheak(string path)
if (false == System.IO.Directory.Exists(path))
System.IO.Directory.CreateDirectory(path);
private void OpenSerialPort_Click(object sender, RoutedEventArgs e)
_serialPort = new SerialPort();
_serialPort.PortName = SerialPort.Text;
_serialPort.BaudRate = 115200;
_serialPort.Parity = Parity.None;
_serialPort.DataBits = 8;
_serialPort.StopBits = StopBits.One;
_serialPort.ReadTimeout = 10000;//单位毫秒
_serialPort.WriteTimeout = 10000;//单位毫秒
//设置串口字节接收缓冲值,通常为1
//获得接收后,触发事件处理
_serialPort.ReceivedBytesThreshold = 1;
_serialPort.DataReceived += new SerialDataReceivedEventHandler(DataCallBack);
try
_serialPort.Open();//Console.WriteLine(serialPort.IsOpen.ToString());
OpenSerialPort.IsEnabled = false;
CloseSerialPort.IsEnabled = true;
catch (Exception ex)
MessageBox.Show("串口打开失败" + ex.ToString());
System.Environment.Exit(0);//退出应用程序
private void CloseSerialPort_Click(object sender, RoutedEventArgs e)
try
if (_serialPort.IsOpen == true)
_serialPort.Close();
OpenSerialPort.IsEnabled = true;
CloseSerialPort.IsEnabled = false;
catch (Exception ex)
MessageBox.Show("串口关闭失败" + ex.ToString());
System.Environment.Exit(0);//退出应用程序
以上是关于w806开发板驱动ov2640读取jpeg图片1600x1200分辨率,以及花屏原因及解决办法的主要内容,如果未能解决你的问题,请参考以下文章
单片机开发OV2640在没有DCMI接口的情况下的STM32驱动
单片机开发OV2640在没有DCMI接口的情况下的STM32驱动