【正点原子STM32连载】 第五十三章 照相机实验 摘自【正点原子】APM32F407最小系统板使用指南

1)实验平台:正点原子stm32f103战舰开发板V4

2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420

3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html##

第五十三章 照相机实验

本章将介绍使用APM32F407模拟照相机将摄像头采集到的图像数据以BMP或JPEG的文件格式保存至SD中,是前面章节中SD卡驱动、摄像头驱动、FATFS、字库管理库、图片编解码库等的综合应用。通过本章的学习,读者将学习到编码BMP文件以及保存摄像头采集到图像数据的保存。

本章分为如下几个小节:

53.1 硬件设计

53.2 程序设计

53.3 下载验证

53.1 硬件设计

53.1.1 例程功能

  1. 程序运行后会先检查SD卡,若检测不到SD卡则无法进行本实验,若SD无法访问则后续不能保存图片文件
  2. 初始化完成后,LCD实时显示摄像头采集到的数据
  3. 按下KEY0或KEY_UP按键,可分别进行拍摄并保存BMP或JPG格式的图片文件至SD卡
  4. LED1闪烁,提示DCI捕获到一帧数据
  5. LED0闪烁,指示程序正在运行
    53.1.2 硬件资源
  6. LED
    LED0 - PF9
    LED1 - PF10
  7. 按键
    KEY0 - PE4
    KEY_UP - PA0
  8. 正点原子 2.8/3.5/4.3/7/10寸TFTLCD模块(仅限MCU屏,16位8080并口驱动)
  9. ATK-MC2640摄像头模块
    OV_D0~D7 - PC6/PC7/PC8/PC9/PC11/PB6/PE5/PE6
    OV_SCL - PD6
    OV_SDA - PD7
    OV_VSYNC - PB7
    OV_HREF - PA4
    OV_PCLK - PA6
    OV_PWDN - PG9
    OV_RESET - PG15
    OV_XCLK - PA8
  10. SD卡(SDIO驱动)
  11. NOR Flash(SPI驱动)
    53.1.3 原理图
    本章实验涉及的SD卡、摄像头、LCD等的连接原理图,请读者自行查看前面对应章节中的连接原理图。
    53.2 程序设计
    53.2.1 实验应用代码
    本章实验的应用代码,如下所示:
c 复制代码
int main(void)
{
    uint8_t t = 0;
    uint8_t key;
    uint8_t res;
    uint8_t sd_ok = 1;
    uint8_t *pname;
    
    NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_3);	/* 设置中断优先级分组为组3 */
    sys_apm32_clock_init(336, 8, 2, 7);					/* 配置系统时钟 */
    delay_init(168);										/* 初始化延时功能 */
    usart_init(115200);									/* 初始化串口 */
    led_init();											/* 初始化LED */
    key_init();											/* 初始化按键 */
    lcd_init();											/* 初始化LCD */
    piclib_init();										/* 初始化画图 */
    sram_init();											/* 初始化外部SRAM */
    my_mem_init(SRAMIN);								/* 初始化内部SRAM内存池 */
    my_mem_init(SRAMCCM);								/* 初始化CCM内存池 */
    my_mem_init(SRAMEX);								/* 初始化外部SRAM内存池 */
    exfuns_init();										/* 为exfuns申请内存 */
    f_mount(fs[0], "0:", 1);							/* 挂载SD卡 */
    f_mount(fs[1], "1:", 1);							/* 挂载NOR Flash */
    
    while (ov2640_init() != 0)							/* 初始化OV2640 */
    {
    		/* 摄像头错误,代码省略 */
    }
    
    sw_sdcard_mode();
    while (sd_init() != SD_OK)							/* 初始化SD卡 */
    {
    		/* SD卡错误,代码省略 */
    }
    
    while (fonts_init() != 0)							/* 检查字库 */
    {
    		/* 字库错误,代码省略 */
    }
    
    text_show_string(30, 50, 200, 16, "正点原子APM32开发板", 16, 0, RED);
    text_show_string(30, 70, 200, 16, "照相机实验", 16, 0, RED);
    text_show_string(30, 90, 200, 16, "KEY0:拍照(bmp格式)", 16, 0, RED);
    text_show_string(30, 110, 200, 16, "KEY_UP:拍照(jpg格式)", 16, 0, RED);
    
    /* 创建PHOTO文件夹 */
    res = (uint8_t)f_mkdir("0:/PHOTO");
    if ((res != (uint8_t)FR_EXIST) && (res != 0))
    {
    		/* SD卡错误,代码省略 */
    }
    
    /* 申请内存 */
    g_dci_line_buf[0] = (uint32_t *)mymalloc(SRAMIN,
    											JPEG_LINE_SIZE * sizeof(uint32_t));
    g_dci_line_buf[1] = (uint32_t *)mymalloc(SRAMIN,
    											JPEG_LINE_SIZE * sizeof(uint32_t));
    g_jpeg_data_buf = (uint32_t *)mymalloc(SRAMEX, JPEG_BUF_SIZE);
    pname = (uint8_t *)mymalloc(SRAMIN, 30);
    while (	(g_dci_line_buf[0] == NULL) ||
    			(g_dci_line_buf[1] == NULL) ||
    			(g_jpeg_data_buf == NULL) ||
    (pname == NULL))
    {
    		/* 内存分配错误,代码省略 */
    }
    
    sw_ov2640_mode();
    ov2640_rgb565_mode();							/* 配置OV2640为RGB565模式 */
    dci_init();											/* 初始化DCI */
    dci_dma_init(	(uint32_t)&(LCD->LCD_RAM),			/* 配置DCI DMA */
    					0,
    					1,
    					DMA_MEMORY_DATA_SIZE_HALFWORD,
    					DMA_MEMORY_INC_DISABLE);
    ov2640_outsize_set(lcddev.width, lcddev.height);	/* 全屏缩放 */
    dci_start();											/* 启动DCI传输 */
    ov2640_flash_intctrl();								/* 内部控制闪光灯 */
    
    while (1)
    {
    		t++;
    		key = key_scan(0);
    		
    		if (key != 0)									/* 有按键按下 */
    		{
    			dci_stop();									/* 先禁止DCI传输 */
    			if (sd_ok == 1)								/* SD卡正常 */
    			{
    				sw_sdcard_mode();						/* 切换为SD卡模式 */
    				switch (key)
    				{
    					case KEY0_PRES:
    					{
    						/* 得到BMP格式文件名 */
    						camera_new_pathname(pname, 0);
    						/* 编码并保存BMP文件 */
    						res = bmp_encode(	pname,
    											0,
    											0,
    											lcddev.width,
    											lcddev.height,
    											0);
    						break;
    					}
    					case WKUP_PRES:
    					{
    						/* 得到JPG格式文件名 */
    						camera_new_pathname(pname, 1);
    						/* 保存OV2640输出的JPEG数据到JPG文件 */
    						res = ov2640_jpg_photo(pname);
    						ov2640_outsize_set(lcddev.width, lcddev.height);
    						break;
    					}
    					default:
    					{
    						break;
    					}
    				}
    				sw_ov2640_mode();						/* 切换为OV2640模式 */
    				if (res != 0)
    				{
    					text_show_string(30, 130, 240, 16,
    									"写入文件错误!", 16, 0, RED);
    				}
    				else
    				{
    					text_show_string(10, 130, 240, 16, "拍照成功!", 16, 0, RED);
    					text_show_string(10, 150, 240, 16, "保存为:", 16, 0, RED);
    					text_show_string(10 + 56, 150, 240, 16,
    									(char*)pname, 16, 0, RED);
    				}
    				
    				delay_ms(1000);
    			}
    			else/* SD卡不可用 */
    			{
    				text_show_string(30, 130, 240, 16, "SD卡错误!", 16, 0, RED);
    				text_show_string(30, 150, 240, 16, "拍照功能不可用!", 16, 0, RED);
    			}
    			delay_ms(2000);
    			dci_start();								/* 恢复DCI传输 */
    		}
    		
    		if (t == 20)
    		{
    			LED0_TOGGLE();
    			t = 0;
    		}
    		
    		delay_ms(10);
    }
}

可以看到,本章实验实际上是前面章节中SD卡驱动、摄像头驱动、FATFS、字库管理库、图片编解码库等的综合应用,并没有涉及新的内容。要注意的是,对于正点原子APM32F407最小系统板,其SD卡和摄像头是无法同时工作的,因为它们使用到了部分共同的GPIO引脚,因此在本章实验中,需要对GPIO引脚的复用模式进行切换,以正常使用SD卡或摄像头,用于切换GPIO引脚复用模式的函数,如下所示:

c 复制代码
/**
 * @bref	切换为OV2640模式
 * @note	切换PC8/PC9/PC11为DCI复用功能(AF13)
 * @param	无
 * @retval	无
 */
static void sw_ov2640_mode(void)
{
    OV2640_PWDN(0);
    GPIO_ConfigPinAF(GPIOC, GPIO_PIN_SOURCE_8, GPIO_AF_DCMI);
    GPIO_ConfigPinAF(GPIOC, GPIO_PIN_SOURCE_9, GPIO_AF_DCMI);
    GPIO_ConfigPinAF(GPIOC, GPIO_PIN_SOURCE_11, GPIO_AF_DCMI);
}

/**
 * @bref	切换为SD卡模式
 * @note	切换PC8/PC9/PC11为SDIO复用功能(AF12)
 * @param	无
 * @retval	无
 */
static void sw_sdcard_mode(void)
{
    OV2640_PWDN(1);
    GPIO_ConfigPinAF(GPIOC, GPIO_PIN_SOURCE_8, GPIO_AF_SDIO);
    GPIO_ConfigPinAF(GPIOC, GPIO_PIN_SOURCE_9, GPIO_AF_SDIO);
    GPIO_ConfigPinAF(GPIOC, GPIO_PIN_SOURCE_11, GPIO_AF_SDIO);
}

从应用代码的初始化函数中可以看到,在初始化过程中,配置了DCI和DMA将摄像头返回的图像数据传输至LCD上进行显示,初始化完成后,便检测按键输入,若无按键输入,则一直在LCD上显示摄像头采集到的图像数据,若检测到KEY0按键被按下,则调用函数bmp_encode()读取LCD上整个屏幕显示的数据并编码保存到SD卡上,若检测到KEY_UP按键,则调用函数ov2640_jpg_photo()将摄像头配置为JPEG格式输出图像数据,然后获取摄像头输出的一帧JPEG数据,并将JPEG数据通过FATFS写入SD的指定文件中。

53.3 下载验证

在完成编译和烧录操作后,可以看到LCD上实时显示这摄像头采集到的图像数据,此时若按下KEY0按键,可以看到LCD上显示了拍照成功和BMP图片保存路径的提示信息,若按下KEY_UP按键,可以看到LCD上显示了拍照成功和JPEG图片保存路径的提示信息。拍照完成后,可通过PC或图片显示实验例程(需修改获取图片的文件夹路径为"0:PHOTO")查看所拍摄的BMP或JPEG格式的照片。

相关推荐
yutian06061 小时前
Keil MDK下载程序后MCU自动重启设置
单片机·嵌入式硬件·keil
析木不会编程4 小时前
【小白51单片机专用教程】protues仿真独立按键控制LED
单片机·嵌入式硬件·51单片机
枯无穷肉8 小时前
stm32制作CAN适配器4--WinUsb的使用
stm32·单片机·嵌入式硬件
不过四级不改名6778 小时前
基于HAL库的stm32的can收发实验
stm32·单片机·嵌入式硬件
嵌入式科普9 小时前
十一、从0开始卷出一个新项目之瑞萨RA6M5串口DTC接收不定长
c语言·stm32·cubeide·e2studio·ra6m5·dma接收不定长
嵌入式大圣9 小时前
单片机UDP数据透传
单片机·嵌入式硬件·udp
云山工作室9 小时前
基于单片机的视力保护及身姿矫正器设计(论文+源码)
stm32·单片机·嵌入式硬件·毕业设计·毕设
嵌入式-老费9 小时前
基于海思soc的智能产品开发(mcu读保护的设置)
单片机·嵌入式硬件
qq_3975623111 小时前
MPU6050 , 设置内部低通滤波器,对于输出数据的影响。(简单实验)
单片机
liyinuo201711 小时前
嵌入式(单片机方向)面试题总结
嵌入式硬件·设计模式·面试·设计规范