【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中的显示方法,大家也可以尝试其它方式实现动态图像展示。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
stm32h7板子支持100脚的stm32h743和h750这两款芯片,并且板子的IO口全部引出来。除了基本功能外,它还有SD卡接口、24pin的CMOS摄像头接口、RTC时钟、QSPI接口的W25Q64,还支持程序从外置SPI芯片启动,解决了stm32h750内存Flash小的问题。 在代码编写方面,如果要开启闹钟中断和唤醒定时器中断,可以使用以下代码: ``` RTC_TimeTypeDef time; RTC_DateTypeDef data; uint32_t wakeup_data; __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&hrtc, RTC_FLAG_WUTF); while (1) { HAL_RTC_GetTime(&hrtc, &time, RTC_FORMAT_BIN); HAL_RTC_GetDate(&hrtc, &data, RTC_FORMAT_BIN); wakeup_data = HAL_RTCEx_GetWakeUpTimer(&hrtc); printf("%d h %d min %d s\r\n", time.Hours, time.Minutes, time.Seconds); HAL_GPIO_TogglePin(LEDB_GPIO_Port, LEDB_Pin); HAL_Delay(1000); } void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc) { printf("%s\r\n", __FUNCTION__); } void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef * hrtc) { printf("%s\r\n", __FUNCTION__); } ``` 关于RTC的功能,它是stm32h7板子的核心功能之一,主要用于实现日历功能。RTC的时钟来源可以是外部参考时钟、LSE、分频HSE以及LSI,最终输入到RTC中。RTC的实时计数器是一个重要的计数器,但直接读取会出现数据不一致的问题,因此 stm32h7 内部还有一个影子寄存器,该寄存器会在时间变化时将实时计数器的数据复制过去。为了保证数据一致性,在读取影子寄存器时有硬件锁定机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值