• 基于zynq7100的OV5640摄像头照相机实验,提供工程源码和技术支持


    1.设计架构

    设计框图如下:
    在这里插入图片描述
    采用Xilinx官方推荐的VDMA架构实现图像缓存和显示,除OV5640摄像头采集和HDMI输出外,其他ip均采用Xilinx官方IP实现。
    这里说明一下:
    OV5640摄像头图像数据经VDMA三帧缓存后有2路输出
    1路输出HDMI显示器显示;
    1路通过FATFS文件系统写入sd卡中存放,存放的数据格式位bmp图片;

    2.工程简介

    开发板的zynq主控是zynq7100,工程实现功能如下:
    1.实现OV5640摄像头HDMI输出;
    2.实现sd卡FATFS文件系统简单读写测试;
    3.实现OV5640摄像头循环拍照,3秒拍摄一张图片;
    4.实现OV5640摄像头按键拍照,板载PS侧按键按一下拍照;
    工程BD部分如下:
    在这里插入图片描述
    工程代码架构如下:
    在这里插入图片描述
    工程SDK代码架构如下:
    在这里插入图片描述
    SDK代码说明:
    设置了2个宏定义:

    //#define FATFS_TEST
    //#define KEY_CAMERA
    
    • 1
    • 2

    #define FATFS_TEST:FATFS文件系统测试:
    默认为注释掉,程序执行摄像头循环拍照功能;
    取消注释则程序执行FATFS文件系统读写测试;
    #define KEY_CAMERA:摄像头按键拍照功能;
    默认为注释掉,程序执行摄像头循环拍照功能;
    取消注释则程序执行摄像头按键拍照功能;

    3.zynq配置

    zynq配置这里主要是要使能i2c外设和sd卡外设,i2c外设使能是为了配置OV5640摄像头,sd卡外设使能则是为了存放拍摄的照片,除此之外,还要使能一个mio,因为mio连接了一个PS侧的按键,后面要依靠此按键来触发拍照;
    在这里插入图片描述
    在这里插入图片描述

    4.sd卡文件系统FATFS配置

    在嵌入式领域,sd卡可以跑FATFS文件系统,Xilinx的SDK开发环境已经集成了FATFS库,所以我们只需在使用前配置一下就可以了,非常方便,设置方法如下:
    1.vivado导出比特流并启动sdk;
    2.sdk新建一个工程;
    3.接下来添加 FATFS 库。需要注意的是,先关闭 system.mss 的界面,再添加 FATFS库,否则有可能导致 FATFS 库添加失败。
    在这里插入图片描述
    system.mss 界面关闭后,右击 micro_sd_rw_bsp,选择“Board Support Package Setting”。
    在这里插入图片描述
    在弹出的界面中勾选“xilffs”,xilffs 即为 FATFS 库
    在这里插入图片描述
    勾选后,会在左侧 Overview 的 standalone 一栏出现 xilffs,点击 xilffs。可以看到 use_lfn 的默认设置为
    false,即不使能。use_lfn 用于设置是否使能长文件名以及文件名的小写字母,这里将 use_lfn 设置为 true,
    点击“OK”按钮完成设置。
    在这里插入图片描述
    设置完成后,在 sd_rw_txt_bsp→ps_cortexa9_0→libsrc 一栏下,会多出 FATFS 的库函数。
    在这里插入图片描述

    5.sd卡文件系统FATFS读写测试

    在摄像头拍照实验之前,需要先对FATFS文件系统进行测试,看是否在sd卡上能跑通;
    测是方法如下:
    第一步:在sd卡中新建一个txt文件;
    第二步:新建的txt文件中写入一段测试字符串;
    第三步:读出txt文件中上一步写入的测试字符串;
    第四步:比较读写字符串内容是否完全一致;也可以拔出sd卡在电脑中查看内容;
    在SDK中建立了sd读写的头文件和源文件,在源文件中含有读写测试的功能函数;
    在进行sd卡文件系统FATFS读写测试之前,应在主函数中取消#define FATFS_TEST的注释:

    #define FATFS_TEST
    //#define KEY_CAMERA
    
    • 1
    • 2

    写数据如下:

    const char src_str[100] = "I love Xilinx FPGAs ~~~~~~~~~~~~"; //定义文本内容
    
    • 1

    下面给出读写测试函数源码;

    int helai_sd_test(){
        int len;
        int i;
        char dest_str[100] = "";
        sd_mount();           //挂载SD卡
        len = strlen(src_str);         //计算字符串长度
        sd_write_data(FILE_NAME,(u32)src_str,len);	//SD卡写数据
        sd_read_data(FILE_NAME,(u32)dest_str,len);	//SD卡读数据
        //比较写入的字符串和读出的字符串是否相等
       //for(i=0;i
       // 	xil_printf("read data =%c\r\n",dest_str[i]);
       // }
        if (strcmp(src_str, dest_str) == 0) xil_printf("src_str is equal to dest_str,SD card test success!\n");
        else xil_printf("src_str is not equal to dest_str,SD card test failed!\n");
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    测试结果:
    串口观测读写内容的对比结果为正确:
    在这里插入图片描述
    拔出SD卡用读卡器到电脑端直接查看内容:
    在这里插入图片描述
    在这里插入图片描述

    6.OV5640摄像头显示测试

    为了保证拍照的正确性,调试拍照之前,必须保证图像数据采集的正确,所以直接接上显示器输出,分辨率位720P,这部分由VDMA配置;

    7.OV5640摄像头循环拍照测试

    这部分功能为实现OV5640摄像头循环拍照,3秒拍摄一张图片;
    bmp图片有固定的数据头,所以直接在程序中定义该部分,如下:

    //BMP图片文件头
    u8 bmp_head[54] = {
         0x42,0x4d,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x36,0x0,0x0,0x0,0x28,0x0,
    	 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x18,0x0,0x0,0x0,
    	 0x0,0x0,0x0,0x0,0x0,0x0,0xc4,0xe,0x0,0x0,0xc4,0x0e,0x0,0x0,0x0,0x0,
    	 0x0,0x0,0x0,0x0,0x0,0x0 };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    随后就是将图像的rgb数据部分和数据头部分一起写入sd卡中形成bmp图片;
    直接给出主函数代码:

    void main(){
    	XGpioPs_Config_key=XGpioPs_LookupConfig(GPIO_KEY);
    	XGpioPs_CfgInitialize(&XgpioPS_key, XGpioPs_Config_key, XGpioPs_Config_key->BaseAddr);
    	XGpioPs_SetDirectionPin(&XgpioPS_key, 51, 0);
    	// Initialize OV5640 regesiter
    	int  rd_index;				//VDMA读通道操作的帧缓存编号
    	unsigned int rd_fram_addr;	//VDMA读通道操作的帧缓存地址
    	I2C_config_init();
    	helai_vdma();
    #ifdef FATFS_TEST
    	helai_sd_test();
    	while(1);
    #else
    	//最后一个参数表示清零的字节数,由于RGB888数据格式占用3个字节,因此最后乘以3
    	memset(0x01000000,0,1280*720*3*3);
    	Xil_DCacheFlush();
    	//根据VDMA显存大小给BMP文件头赋值
    	*bmp_width  = 1280;
    	*bmp_height = 720;
    	*bmp_size   = 1280*720*3;
    	*bf_size    = *bmp_size + 54;
    	f_mount(&fatfs,"",1);	//挂载文件系统
    	while (1){
    		#ifdef KEY_CAMERA
    		int key;
    		key=XGpioPs_ReadPin(&XgpioPS_key, 51);
    		if(key==0){
    			usleep(20000);
    			if(key==0){
    				printf("capture picture\n");
    				rd_index = XAxiVdma_CurrFrameStore(&vdma, XAXIVDMA_READ);	//获取当前读通道操作的帧缓存编号
    				printf("current read frame is %d\n",rd_index);
    				XAxiVdma_StartParking(&vdma, rd_index, XAXIVDMA_READ);	//读通道驻停在当前帧
    				rd_fram_addr = 0x01000000 + 1280*720*3*rd_index;	//并获取当前帧的起始地址
    				memcpy((void *)bmp_addr,(void *)rd_fram_addr,1280*720*3);	//将当前帧的图像拷贝到抓拍图片缓存区域
    				XAxiVdma_StopParking(&vdma, XAXIVDMA_READ);	//结束读通道驻停过程,继续在多帧之间进行切换
    				write_sd_bmp((u8 *)bmp_addr);	//将抓拍图片缓存区域中的图像以BMP格式写入SD卡
    				pic_cnt++;	//BMP图片编号累加
    			}
    		}
    		#else
    		printf("capture picture\n");
    		rd_index = XAxiVdma_CurrFrameStore(&vdma, XAXIVDMA_READ);	//获取当前读通道操作的帧缓存编号
    		printf("current read frame is %d\n",rd_index);
    		XAxiVdma_StartParking(&vdma, rd_index, XAXIVDMA_READ);	//读通道驻停在当前帧
    		rd_fram_addr = 0x01000000 + 1280*720*3*rd_index;	//并获取当前帧的起始地址
    		memcpy((void *)bmp_addr,(void *)rd_fram_addr,1280*720*3);	//将当前帧的图像拷贝到抓拍图片缓存区域
    		XAxiVdma_StopParking(&vdma, XAXIVDMA_READ);	//结束读通道驻停过程,继续在多帧之间进行切换
    		write_sd_bmp((u8 *)bmp_addr);	//将抓拍图片缓存区域中的图像以BMP格式写入SD卡
    		pic_cnt++;	//BMP图片编号累加
    		sleep(3);
    		#endif
    	}
    #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

    测试完成后,拔出SD卡用读卡器到电脑端直接查看内容:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    8.OV5640摄像头按键拍照测试

    这部分功能为实现OV5640摄像头按键拍照,板载PS侧按键按一下拍照;
    在使用之前,应在主函数中取消#define KEY_CAMERA的注释:

    //#define FATFS_TEST
    #define KEY_CAMERA
    
    • 1
    • 2

    9.上板调试

    开发板:zynq7100开发板;
    开发环境:vivado2019.1;
    输入:OV5640摄像头,720P,RGB888格式;
    输出:HDMI输出,SD卡bmp图片;
    如下:
    在这里插入图片描述

    10.福利领取

    福利:工程代码的获取
    代码太大,无法邮箱发送,以某度网盘链接方式发送,
    资料获取方式:私,或者文章末尾的V名片。
    网盘资料如下:
    在这里插入图片描述

  • 相关阅读:
    用20行python写一个最简单的网站
    webpack优化系列五:vue项目配置 webpack-obfuscator 进行代码加密混淆
    在Linux中进行Prometheus部署
    阿里云购买磁盘,挂载到/root/XXXX 详细的步骤
    【广州华锐互动】屠宰场生猪检疫VR模拟演练系统
    C++ mutex 与 condition_variable
    Nginx -Web服务器/反向代理/负载均衡
    【JVM】JVM的垃圾回收机制
    Java项目:ssm大学生兼职论坛
    SQL面试题(2)
  • 原文地址:https://blog.csdn.net/qq_41667729/article/details/127865247