【STM32H7】第29章 ThreadX GUIX的摄像头OV7670动态图像显示

2023-12-17 00:18

本文主要是介绍【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 初学者重要提示

  1.   务必看第16章局部刷新的实现。
  2.   本章配套了320*240和640*480两种分辨率图像显示案例。
  3.   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动态图像显示的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/502418

相关文章

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

动态规划---打家劫舍

题目: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 思路: 动态规划五部曲: 1.确定dp数组及含义 dp数组是一维数组,dp[i]代表

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

代码随想录冲冲冲 Day39 动态规划Part7

198. 打家劫舍 dp数组的意义是在第i位的时候偷的最大钱数是多少 如果nums的size为0 总价值当然就是0 如果nums的size为1 总价值是nums[0] 遍历顺序就是从小到大遍历 之后是递推公式 对于dp[i]的最大价值来说有两种可能 1.偷第i个 那么最大价值就是dp[i-2]+nums[i] 2.不偷第i个 那么价值就是dp[i-1] 之后取这两个的最大值就是d

lvgl8.3.6 控件垂直布局 label控件在image控件的下方显示

在使用 LVGL 8.3.6 创建一个垂直布局,其中 label 控件位于 image 控件下方,你可以使用 lv_obj_set_flex_flow 来设置布局为垂直,并确保 label 控件在 image 控件后添加。这里是如何步骤性地实现它的一个基本示例: 创建父容器:首先创建一个容器对象,该对象将作为布局的基础。设置容器为垂直布局:使用 lv_obj_set_flex_flow 设置容器

C# dateTimePicker 显示年月日,时分秒

dateTimePicker默认只显示日期,如果需要显示年月日,时分秒,只需要以下两步: 1.dateTimePicker1.Format = DateTimePickerFormat.Time 2.dateTimePicker1.CustomFormat = yyyy-MM-dd HH:mm:ss Tips:  a. dateTimePicker1.ShowUpDown = t

Verybot之OpenCV应用一:安装与图像采集测试

在Verybot上安装OpenCV是很简单的,只需要执行:         sudo apt-get update         sudo apt-get install libopencv-dev         sudo apt-get install python-opencv         下面就对安装好的OpenCV进行一下测试,编写一个通过USB摄像头采

LeetCode:64. 最大正方形 动态规划 时间复杂度O(nm)

64. 最大正方形 题目链接 题目描述 给定一个由 0 和 1 组成的二维矩阵,找出只包含 1 的最大正方形,并返回其面积。 示例1: 输入: 1 0 1 0 01 0 1 1 11 1 1 1 11 0 0 1 0输出: 4 示例2: 输入: 0 1 1 0 01 1 1 1 11 1 1 1 11 1 1 1 1输出: 9 解题思路 这道题的思路是使用动态规划