本文主要是介绍【STM32H7】第29章 ThreadX GUIX的摄像头OV7670动态图像显示,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
最新教程下载:第3版emWin教程和ThreadX GUIX教程开工,双管齐下,GUIX更新至第29章,emWin更新至第56章(2022-01-10) - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz!
第29章 ThreadX GUIX的摄像头OV7670动态图像显示
本章节为大家讲解ThreadX GUIX中实现摄像头图像的动态展示。
目录
29.1 初学者重要提示
29.2 第1步,GUIX Studio创建空白窗口
29.3 第2步,GUIX Studio设置窗口回调
29.3.1 窗口事件回调设置
29.3.2 窗口绘制回调设置
29.4 第3步,开辟摄像头图像空间
29.5 第4步,摄像头DMA完整中断发消息
29.6 第5步,窗口回调函数里面设置局部Dirty
29.7 第6步,窗口绘制回调里面绘制图像并开启下一帧传输
29.8 实验例程
29.9 总结
29.1 初学者重要提示
- 务必看第16章局部刷新的实现。
- 本章配套了320*240和640*480两种分辨率图像显示案例。
- GUIX中实现摄像头动态图像展示的关键是开辟一个存储设备,每次摄像头采集的一帧数据通道DMA传输到缓冲里面后,将其通过存储设备绘制到GUIX里面。
29.2 第1步,GUIX Studio创建空白窗口
GUIX Studio的设置方法与第11章一样。创建的界面效果如下:
29.3 第2步,GUIX Studio设置窗口回调
29.3.1 窗口事件回调设置
下面我们为窗口控件设置一个Event Function,此功能是窗口的事件回调函数。在这个回调函数里面,大家可以处理各种事件。
这里为Event Function设置的回调函数名为_cbEventWindow0,然后就可以使用GUIX Studio生成新的代码。生成的代码移植到硬件平台的方法看第12章即可。
29.3.2 窗口绘制回调设置
下面我们为窗口设置一个Draw Function,此功能是窗口的绘制回调函数。在这个回调函数里面,大家可以实现各种2D绘制。
这里为Draw Function设置的回调函数名为_cbWindow0,然后就可以使用GUIX Studio生成新的代码。
29.4 第3步,开辟摄像头图像空间
将SDRAM后2MB的空间作为摄像头图像空间:
#define SDRAM_CAMERA (0xC0000000 + 30 * 1024 * 1024)
29.5 第4步,摄像头DMA完整中断发消息
一帧640*480图像传输完毕后,DMA中断实现代码如下:
/*
*********************************************************************************************************
* 函 数 名: CAM_Stop
* 功能说明: 停止DMA和DCMI
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
#include "gx_api.h"
GX_EVENT event;void CAM_Stop(void)
{HAL_DCMI_Stop(&hdcmi);
}void DMA1_Stream7_IRQHandler(void)
{HAL_DMA_IRQHandler(&hdma_dcmi);
}void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
{/* 关闭摄像 */CAM_Stop();event.gx_event_type = 0x40000000;gx_system_event_send(&event);g_tCam.CaptureOk = 1; /* 表示DMA传输结束 */
}
- 上面代码中红色代码是关键,这里是发送自定义消息给GUIX的窗口回调函数。
29.6 第5步,窗口回调函数里面设置局部Dirty
通过设置窗口局部Dirty可以触发重绘:
/* 摄像头图像绘制区 */
GX_RECTANGLE WinPartialDraw = {0, 0, 640, 480};/*
*********************************************************************************************************
* 函 数 名: _cbEventWindow
* 功能说明: 窗口window的事件回调函数
* 形 参: widget 窗口句柄
* event_ptr 事件指针
* 返 回 值: 返回0表示成功
*********************************************************************************************************
*/
UINT _cbEventWindow(GX_WINDOW *widget, GX_EVENT *event_ptr)
{switch (event_ptr->gx_event_type){/* 控件显示事件 */case GX_EVENT_SHOW:/* 默认事件处理 */gx_window_event_process(widget, event_ptr);break;/* 接收到摄像头图像数据 */case 0x40000000:/* 设置窗口dirty,这样会触发窗口更新 */gx_system_dirty_partial_add(widget, &WinPartialDraw);break;default:return gx_window_event_process(widget, event_ptr);}return 0;
}
窗口局部更新也比较容易实现,调用函数gx_system_dirty_partial_add来标记窗口为dirty,这样就会触发GUIX执行绘制回调函数。
#define gx_system_dirty_partial_add(a, b) _gxe_system_dirty_partial_add((GX_WIDGET *)a, b)
UINT _gxe_system_dirty_partial_add(GX_WIDGET *widget, GX_RECTANGLE *dirty_area)
与全局更新不同的是局部更新可以设置想更新的区域,这样可以有效降低CPU和DMA2D的利用率。
- 第1个参数是大家要更新的窗口句柄。
- 第2个参数是要更新的区域。更新区域是GX_RECTANGLE类型结构体,此结构体定义了矩形区域。
29.7 第6步,窗口绘制回调里面绘制图像并开启下一帧传输
实现代码如下:
/* 摄像头位图定义 */
GX_PIXELMAP CAMREA_pixelmap =
{0x00000001, /* major version */0x00000000, /* minor version */0, /* flags */GX_COLOR_FORMAT_565RGB, /* Format */(GX_UBYTE *) 0,640*480*2, /* the size of pixelmap_data*/NULL,0, /* auxiliary data size */0x00, /* used for transparent iamges */640, /* width in pixel */480 /* height in pixel */
};/*
*********************************************************************************************************
* 函 数 名: _cbWindow0
* 功能说明: 窗口window的绘制回调函数
* 形 参: widget 窗口句柄
* 返 回 值: 无
*********************************************************************************************************
*/
VOID _cbWindow0(GX_WINDOW *widget)
{GX_RECTANGLE drawto; GX_CANVAS *mycanvas; /* 默认的窗口绘制回调函数,即默认界面效果绘制 */gx_window_draw(widget);/* 定义一个矩形框,后续的2D绘制函数都是在这个矩形范围内绘制的 */gx_utility_rectangle_define(&drawto,WinPartialDraw.gx_rectangle_left, WinPartialDraw.gx_rectangle_top,WinPartialDraw.gx_rectangle_right, WinPartialDraw.gx_rectangle_bottom);/* 返回窗口对应的canvas画布 */gx_widget_canvas_get(widget, &mycanvas);/* 在指定的画布上启动绘图。此功能在内部被延迟绘图算法调用,GUIX在需要画布时自动执行更新。 但是允许应用程序绕过延期绘图算法并立即执行。首先调用gx_canvas_drawing_inititate在画布上绘画。然后调用所需的绘图函数,然后调用gx_canvas_drawing_complete即可。*/gx_canvas_drawing_initiate(mycanvas, widget, &drawto);gx_canvas_pixelmap_draw( WinPartialDraw.gx_rectangle_left, WinPartialDraw.gx_rectangle_top,&CAMREA_pixelmap);/* 用于强制立即绘制,注意,务必和gx_canvas_drawing_initiate成对调用 */gx_canvas_drawing_complete(mycanvas, GX_TRUE);/* 更新完毕开启下一帧 */CAM_Start1(SDRAM_CAMERA);
}
- 这段代码的关键是函数gx_canvas_pixelmap_draw,我们提前定义好位图大小CAMREA_pixelmap,然后更新设置的WinPartialDraw局部区域。
- 函数CAM_Start1用于启动下一帧。
29.8 实验例程
(注,如果是电阻屏,需要做触摸校准,校准方法看本教程附件章节A)
配套例子:
本章节配套了如下四个例子供大家移植参考:
- V7-2041_GUIX Camera 320x240
- V7-2042_GUIX Studio Camera 320x240
- V7-2043_GUIX Camera 640x480
- V7-2044_GUIX Studio Camera 640x480
实验目的:
1、本章主要学习GUIX的摄像头动态图像展示
实验内容:
1、共创建了如下几个任务,通过按下按键K1可以通过串口打印任务堆栈使用情况
App Task Start任务 :启动任务,这里用作BSP驱动包处理。
App Task MspPro任务 :消息处理,这里用作LED闪烁。
App Task UserIF任务 :按键消息处理。
App Task GUI任务 :GUI应用任务。
App Task STAT任务 :统计任务。
App Task IDLE任务 :空闲任务。
GUIX System Thread :GUI系统任务。
System Timer Thread任务:系统定时器任务。
实验效果:
串口打印任务执行情况:
IAR,MDK AC5和AC6工程可以串口打印任务执行情况:按开发板的按键K1可以打印,波特率 115200,数据位 8,奇偶校验位无,停止位 1:
29.9 总结
本章节主要为大家讲解了摄像头动态图像在GUIX中的显示方法,大家也可以尝试其它方式实现动态图像展示。
这篇关于【STM32H7】第29章 ThreadX GUIX的摄像头OV7670动态图像显示的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!