STM32完全学习——0V5640的JPEG模式采集

发布于:2025-02-10 ⋅ 阅读:(14) ⋅ 点赞:(0)

一、写在前面

我参考的是买开发板的时候,普中送的资料里面的源码,他那个是用标准库写的,我将他的代码移植到了HAL库,有一些不一样的地方。由于标准库和HAL库的差别造成的。

二、编程思路

首先初始化OV5640模块,使用的是SCCB总线,和I2C很像,具体的就不说了,再就是将OV5640设置成JPEG输出模式,然后就是调整OV5640输出的图像的大小。下来就是开启DMA传输。然后每捕获一帧图像,DCMI会产生一个帧中断,然后在中断里面处理JPEG的数据,然后再回到主程序,然后将图像数据通过串口发送出去,至于初始化那些CubMAX这个工具会帮我们做。

三、相关函数HAL库实现

我们的主程序,主要用来开启DMA传输,并且将数据通过串口发送出去

//JPEG测试
//JPEG数据,通过串口1发送给电脑.
void jpeg_test(void)
{
	u32 i,jpgstart,jpglen; 
	u8 *p;
	u8 key,headok=0;
	u8 effect=0,contrast=2;
	u8 size = 2;			//默认是QVGA 640*480尺寸
	u8 msgbuf[15];		//消息缓存区 
	u8 res = 0;
 	//自动对焦初始化
	OV5640_Focus_Init(); 
	
 	OV5640_JPEG_Mode();		//JPEG模式
	
	OV5640_Light_Mode(0);	//自动模式
	OV5640_Color_Saturation(3);//色彩饱和度0
	OV5640_Brightness(4);	//亮度0
	OV5640_Contrast(3);		//对比度0
	OV5640_Sharpness(33);	//自动锐度
	OV5640_Focus_Constant();//启动持续对焦

	OV5640_OutSize_Set(4, 0, jpeg_img_size_tbl[size][0], jpeg_img_size_tbl[size][1]);//设置输出尺寸 
	DCMI_Start(); 		//启动传输
	
	while(1)
	{
		
		if(jpeg_data_ok==1)	//已经采集完一帧图像了
		{  
			p = (u8*)jpeg_buf;

			jpglen=0;	//设置jpg文件大小为0
			headok=0;	//清除jpg头标记
			for(i=0; i<jpeg_data_len*4; i++) //查找0XFF,0XD8和0XFF,0XD9,获取jpg文件大小
			{
				
				if((p[i]==0XFF) && (p[i+1]==0XD8))//找到FF D8
				{
//					printf("err3\n");
					jpgstart = i;
					headok = 1;	//标记找到jpg头(FF D8)
				}
				if((p[i]==0XFF) && (p[i+1]==0XD9) && headok)//找到头以后,再找FF D9
				{
					jpglen = i-jpgstart+2;
					break;
				}
			}
			
//			printf("err 89 7 6yu\n");
			if(jpglen)	//正常的jpeg数据 
			{
//				
				p += jpgstart;			//偏移到0XFF,0XD8处 
				for(i=0; i<jpglen; i++)	//发送整个jpg文件
				{
					while((USART1->SR&0X40)==0);	//循环发送,直到发送完毕   
					USART1->DR=p[i];   
				}

			}
			DCMI_Start();
			jpeg_data_ok = 0;	//标记jpeg数据处理完了,可以让DMA去采集下一帧了.
		}	
		HAL_GPIO_TogglePin(GPIOF, LED0_Pin);
	}     
} 

 由于我这里的目标很单纯,所以有些参数直接就是定死的,先实现功能花里胡哨的功能,后面在调。

void DCMI_Start(void)
{
	long tmp=0, num=0;
	u16 temp = 0;
	HAL_DCMI_Start_DMA(&hdcmi, DCMI_MODE_CONTINUOUS, (u32)&jpeg_buf, jpeg_buf_size);
	
}

 帧中断回调函数

void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
{
	jpeg_data_process(); 	//jpeg数据处理	
}

 这个函数我改过,和普中的标准库,很不一样。因为在标准库里面,DMA使能和DCMI捕获他们两个是分开的,因此可以那样操作,但是在HAL库里面就不行,因此就做了如下更改。


//处理JPEG数据
//当采集完一帧JPEG数据后,调用此函数,切换JPEG BUF.开始下一帧采集.
void jpeg_data_process(void)
{
	if(jpeg_data_ok == 0)	//jpeg数据还未采集完
	{	
		HAL_DCMI_Stop(&hdcmi);
		jpeg_data_len = jpeg_buf_size-__HAL_DMA_GET_COUNTER(&hdma_dcmi);
		jpeg_data_ok = 1; 				//标记JPEG数据采集完按成,等待其他函数处理
	}
}

有了上面这些你会发现还不能正常运行,那是因为HAL库里面的问题,我发现我的代码虽然中断啥的都好着呢,但是传输的数据里面没有JPEG相关的头标记,然乎通过看源码发现,它里面处理完之后直接将中断关闭了,但是呢没有清除中断的标记,我看其他的中断都将标记清楚了,然后就试着改了一下,发现果然可以正常,传输了。

 

 最终显示的图像

 虽然视频的刷新率很低很低,卡的要死,但是最起码可以显示,至于优化啥的那就自由发挥了。