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);//退出应用程序
    }
}

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花开花落的个人博客

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值