将UI连接到系统

在大多数应用程序中,UI需要以某种方式连接到系统的其余部分,并发送和接收数据。这可以与硬件外围设备(传感器数据,A / D转换,串行通信等)接口,也可以与其他软件模块接口。

本文介绍了实现此连接的推荐解决方案。

第一种方法是“快速且肮脏的”方法,主要用于原型制作,而第二种方法是在架构上合理地将UI与现实应用程序中的其余组件连接的一种方法。

在本文的最后,我们链接到使用这两种方法的示例。

模型类

所有TouchGFX应用程序都有一个Model类,该类除了存储UI状态信息之外,还旨在充当您周围系统的接口。这样,我们既指硬件外围设备,也指系统中的其他OS任务。通常,访问各个View类中的其他软件模块或硬件不是一个好的设计。

Model类非常适合放置任何此类接口代码,因为:

  1. Model类具有tick()函数,该函数会在每帧中自动调用,并且可以实现为查找其他子模块中的事件并对事件做出反应。
  2. Model类具有指向您当前活动的Presenter的指针,以便能够将传入事件通知UI。

硬件接口

方法1:直接从GUI任务采样

与硬件接口的最佳方法取决于您需要采样的频率,采样的时间和时间的紧迫性。如果您在这些方面的要求比较宽松,那么最简单的方法就是直接在Model::tick功能中对硬件进行采样  。如果采样发生的频率低于帧速率(通常在60Hz左右),则可以添加一个计数器,并且仅在第N个时钟间隔进行一次采样。用这种方法完成后,您的采样操作必须快一些(通常为1ms或更短),否则您的帧速率将开始受到影响,因为采样是在GUI任务的上下文中完成的,并且会延迟绘制帧。

方法2:从辅助任务采样

或者,如果不希望将硬件交互直接放在GUITask的上下文中,则可以创建一个新的OS任务来执行采样。您可以配置此任务以在特定情况下所需的确切时间间隔上运行。另外,根据您的需要,此新任务的优先级可以比GUI任务低或高。如果它具有更高的优先级,那么可以保证它在指定的时间准确运行,而不管GUI任务在做什么。这样做的缺点是,如果这是占用CPU的进程,则可能会影响UI的帧速率。另一方面,如果采样不是时间紧迫的,则可以为任务分配比GUI任务更低的优先级,这样UI帧速率就不会受到硬件采样的影响。

如果您使用辅助任务方法,我们建议您利用RTOS提供的任务间消息传递系统。大多数(如果不是全部)RTOS具有队列/邮件机制,可让您将数据(通常是用户定义的C结构,字节数组或简单整数)从一个任务发送到另一个任务。为了将新数据传递到GUI任务,请为UI tast设置邮箱或消息队列,然后使用此消息传递系统将数据发送到GUI任务。然后,您可以Model::tick轮询GUI任务的邮箱,以检查是否有新数据到达。以防万一,读取数据并相应地更新UI。

将数据传播到UI

无论使用方法1还是方法2,该Model::tick功能都是GUITask知道要在UI中显示的新数据的地方。除了充当与周围系统的接口之外,还记得以前Model该类还负责保存状态数据,因此可能还需要更新一些状态变量。

让我们考虑一个简单的示例,其中将温度传感器连接到系统,并且当前温度将显示在UI中。在准备中,我们将扩展Model类以支持此操作:

Model.hpp:
class Model
{
public:
// Function that allow your presenters to read current temperature.
int getCurrentTemperature() const { return currentTemperature; }
// Called automatically by framework every tick.
void tick();
...
private:
// Variable storing last received temperature;
int currentTemperature;
...
};

通过上述操作,您Presenters 可以向模型询问当前温度,从而允许演示者在进入显示温度的屏幕时在UI(视图)中设置此值。我们现在需要做的是能够在收到新的温度信息时再次更新UI。为此,我们利用了模型具有指向您当前活动的演示者的指针这一事实。该指针的类型是接口(ModelListener),您可以对其进行修改以反映适当的应用程序特定事件:

ModelListener.hpp:
class ModelListener
{
public:
// Call this function to notify that temperature has changed.
// Per default, use an empty implementation so that only those
// Presenters interested in this specific event need to
// override this function.
virtual void notifyTemperatureChanged(int newTemperature) {}
};

现在我们已经连接了该接口,剩下的就是对传入的“新温度”事件进行实际采样了。 Model::tick

Model.cpp
void Model::tick()
{
// Pseudo-code for Method 1 or Method 2. Depends on your concrete Operating System
if (OS_Poll(GuiTaskMBox))
{
// Here we assume that you have defined a "Message" struct containing type and data,
// along with some event definitions.
struct Message msg = OS_Read(GuiTaskMBox);
if (msg.eventType == EVT_TEMP_CHANGED)
{
// We received information that temperature has changed.
// First, update Model state variable
currentTemperature = msg.data; // Second, notify the currently active presenter that temperature has changed.
// The modelListener pointer points to the currently active presenter.
if (modelListener != 0)
{
modelListener->notifyTemperatureChanged(currentTemperature);
}
}
}
}

上面的方法可以确保两件事:

  1. currentTemperature变量始终是最新的,以便您的Presenter可以随时获取当前温度。
  2. 主持人会立即收到有关温度变化的通知,并可以采取适当的措施。

MVP模式的优点之一是,您可以根据当前所处的屏幕来单独处理通知。例如,假设在显示某种与当前温度无关的设置菜单(例如,MainMenuPresenter / MainMenuView处于活动状态)时发生了温度变化事件。

由于notifyTemperatureChanged函数具有默认的空实现,因此MainMenuPresenter完全忽略了此通知。另一方面,如果您有TemperatureControlPresenter,则可以在此演示者中重写notifyTemperatureChanged函数,并通知View它应显示更新的温度:

TemperatureControlPresenter.hpp:
class TemperatureControlPresenter : public ModelListener
{
public:
// override the empty function.
virtual void notifyTemperatureChanged(int newTemperature) {
view.setTemp(newTemperature);
}
};
当然,View类TemperatureControlView必须实现setTemp方法。 

将数据从UI传输到周围的系统

数据/事件从UI传输到周围系统的相反方向是通过Model进行的,方法大致相同。如果需要添加配置新设定点(目标温度)的功能,则从上一个示例继续进行,我们将在模型中添加以下内容:

Model.hpp:
void setNewTargetTemperature(int newTargetTemp)
{
// Pseudo-code for sending an event to a task responsible for controlling temperature.
struct Message msg;
msg.eventType = EVT_SET_TARGET_TEMP;
msg.data = newTargetTemp;
OS_Send(SystemTaskMBox, &msg);
}

如果用户在UI中设置新的目标温度,则视图可以通知Presenter,该Presenter拥有指向Model对象的指针,因此可以调用该  setNewTargetTemperature函数。

例子

方法1-从GUI任务

下载此链接可找到STM32F746的工作示例,该示例演示如何在Model类中对按钮进行采样并直接控制LED。该示例使用MVP体系结构在两个视图和Model类之间传递值和事件。Model类对按钮进行采样并更新LED以匹配应用程序的状态。

下载此链接可找到STM32F429的工作示例,其中显示了如何对Model类中的按钮进行采样。该示例使用MVP架构将按钮事件传输到视图。

方法2-从其他任务

下载此链接可找到STM32F469的工作示例,该示例显示如何在单独的线程中对模拟输入进行采样。该示例使用MVP架构将模拟值传输到View。
 
一个工作示例显示了任务间通信以及往返于UI的传播。以此为您自己设置的灵感。该示例在用C代码实现的后端系统和C ++ TouchGFX GUI之间进行通信。该示例在FreeRTOS之上的STM32F746G-DISCO板上运行。 

方法3-从多个任务(4.9.3)

该工作示例已在2018年5月28日举行的TouchGFX网络研讨会“与硬件集成”中进行了演示。

该应用程序是为STM32F769-DISCO板设计的,并与LED和用户按钮交互,以显示如何将C代码和硬件外围设备集成到您的TouchGFX应用程序中。

应用程序以GPIO模式配置按钮。行为是在btntask.c中采样按钮的状态,如果按下按钮,则将消息通过GUI消息队列传递。这使我们可以通过按住按钮来在应用程序中推进动画。

该应用程序使用三个FreeRTOS任务。一个用于GUI,每个用于外围设备(LED和用户按钮)。

方法4-从任务和外部中断线(4.9.3)

该工作示例已在2018年5月28日举行的TouchGFX网络研讨会“与硬件集成”中进行了演示。

该应用程序是为STM32F769-DISCO板设计的,并与LED和用户按钮交互,以显示如何将C代码和硬件外围设备集成到您的TouchGFX应用程序中。

该应用程序将按钮配置为EXTI模式(外部中断线0)。行为是在按下按钮后接收中断,然后清除中断。这不允许与GPIO中的行为相同,但是我们将单步执行动画,因为仅在接收到中断时才通过gui消息队列发送消息。

该应用程序使用两个FreeRTOS任务。一个用于GUI,一个用于LED。(方法3中的Button任务在此应用程序中保持活动状态,以说明外围设备交互代码已移至中断处理程序中)。

原文

touchgfx -- Integration的更多相关文章

  1. 在 Laravel 中使用图片处理库 Integration/Image

    系统需求 PHP >= 5.3 Fileinfo Extension GD Library (>=2.0) … or … Imagick PHP extension (>=6.5.7 ...

  2. 按照Enterprise Integration Pattern搭建服务系统

    在前一篇文章中,我们已经对Enterprise Integration Pattern中所包含的各个组成进行了简单地介绍.限于篇幅(20页Word以内),我并没有深入地讨论各个组成.但是如果要真正地按 ...

  3. Enterprise Integration Pattern - 组成简介

    近些年来,越来越多的Web应用正在逐渐向大型化的方向发展.它们通常都会包含一系列相互协作的子服务.在开发过程中,如何让这些子服务协同工作常常是软件开发人员所最为头疼的问题,如各个子服务之间的数据表示不 ...

  4. Spring 4 + Quartz 2.2.1 Scheduler Integration Example

    In this post we will see how to schedule Jobs using Quartz Scheduler with Spring. Spring provides co ...

  5. OpenCASCADE Gauss Integration

    OpenCASCADE Gauss Integration eryar@163.com Abstract. Numerical integration is the approximate compu ...

  6. MAGENTO - APACHE SOLR INTEGRATION - PART II (SETUP)

    MAGENTO - APACHE SOLR INTEGRATION - PART II (SETUP) Tue, 03/01/2011 - 18:30 Tweet Development E-Comm ...

  7. POSTMAN as debugger for integration APPs

    Chrome Menu: Window > Extensions > Postman - REST Client 0.8.4.10 起个标题,有空总结一下一个经验,关于Netsuite i ...

  8. [转](六)unity4.6Ugui中文教程文档-------概要-UGUI Animation Integration

    5.Animation Integration(动画集成) 动画允许控件的所有状态之间相互转换,充分使用unity的动画系统.这是最强大的的转换模式的在处理很多属性的同时可以进行动画. 要使用动画转换 ...

  9. Informatica相同环境与不同环境的导入导出( Repository Name,Integration Service Name,Folder Name是否相同):

    Informatica相同环境与不同环境的导入导出( Repository Name,Integration Service Name,Folder Name是否相同): 1.repository N ...

随机推荐

  1. Sql 中常用日期转换Convert(Datetime) convert datetime

    Convert(data_type,expression[,style]) Convert(varchar(10),字段名,转换格式) 说明:此样式一般在时间类型(datetime,smalldate ...

  2. 详解Arduino Uno开发板的引脚分配图及定义(重要且基础)

    首先开发板实物图如下: 在本篇文章中,我们将详细介绍Arduino开发板的硬件电路部分,具体来说,就是介绍Arduino Uno开发板的引脚分配图及定义.Arduino Uno微控制器采用的是Atme ...

  3. 生成SSH秘钥连接github(详细教程)

    第一步.首先,检查下自己之前有没有已经生成: 在开始菜单中打开git下的git bash(当然,在其他目录下打开git bash也是一样的): 然后执行 cd ~/.ssh 第二步.如果能进入到.ss ...

  4. 【转帖】Samba AD DC(域控制器)的配置

    Samba AD DC(域控制器)的配置 http://lihaitao.cn/?p=299 山东前辈写的blog 挺好的.. 改天做实验. 发表于2017年3月7日由李海涛 ■Samba AD DC ...

  5. (十五)springMvc 拦截器

    文章目录 定义拦截器 接口中三个方法 配置拦截器 多个拦截器的规则 定义拦截器 springMvc 中定义拦截器只需要实现一个接口 org.springframework.web.servlet.Ha ...

  6. (一)springMvc 底层运作流程

    目录 什么是 springMvc SpringMVC的底层运作流程 什么是 springMvc springMvc 是spring 框架的一个模块,这也就意味着二者不需要通过整合层(整合包)进行整合 ...

  7. 2019HDU暑期多校训练-1004equation-方程求解

    Description You are given two integers N,C and two integer sequences a and b of length N. The sequen ...

  8. opencv实现人脸识别(二) 人脸图像采集模块

    这一步我们开始搭建第一个模块,用来检测到图像中的人脸位置,并将它拍下来保存在指定路径 流程图: 代码实现: import cv2 def pic(cam): # 调用笔记本内置摄像头,所以参数为0,如 ...

  9. global和nonlocal的区别

    global可以在任何地方修饰变量,而且被global修饰的变量直接被标识为全局变量,对该变量修改会影响全局变量的值,但不影响函数中未被global修饰的同名变量(依然是局部变量),nonlocal只 ...

  10. 通过ImageReader进行图像裁剪时出现NoSuchElementException异常

    首先放上最初的Image工具类 package util; import java.awt.Rectangle; import java.awt.image.BufferedImage; import ...