将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. 使用STM32F103ZET霸道主板实现LCD显示屏显示

    简单了解液晶显示屏 液晶显示屏LCD是靠背光LED发光,然后经过横竖透光,每个点电压可以改变光线的方向,总之能改变透光度0-100%,最后就是每个像素点对应红绿蓝RGB,RGB各自的亮度不同,组成的颜 ...

  2. jenkins:多个job时怎么按照一定顺序执行构建

    一.安装Jenkins多项目构建插件(我已安装):Multijob 二.新建Multijob Project任务 三.配置

  3. .NET(C#):判断Type类的继承关系

    //Type类的函数 class Type bool IsInstanceOfType(object); //判断对象是否是指定类型 //类型可以是父类,接口 //用法:父类.IsInstanceOf ...

  4. Jmeter 逻辑控制器 之 ForEach 控制器

    一.认识 ForEach 控制器 如下,创建一个 ForEach 控制器 设置界面如下: 输入变量前缀:要进行循环读取的变量前缀 Start index for loop (exclusive):循环 ...

  5. [Tensorflow] 使用 tf.train.Checkpoint() 保存 / 加载 keras subclassed model

    在 subclassed_model.py 中,通过对 tf.keras.Model 进行子类化,设计了两个自定义模型. import tensorflow as tf tf.enable_eager ...

  6. Java基础——接口和抽象类

    接口(interface) 什么是接口? 接口时抽象方法的合集.接口不可以被直接被实例化. 为什么要使用接口? 为了扩展.Java不支持多继承,但是通过接口就可以实现“多继承” 制定规则.接口就是规则 ...

  7. 记录编译<Separable Subsurface Scattering demo>工程遇到的问题

    1. Separable Subsurface Scattering demo 可以从 https://github.com/iryoku/separable-sss 下载下来,但是默认的sln 是 ...

  8. 01.02 linux命令(1

    =================常用的Linux命令============================Ls 查看当前文件夹下或者其他文件夹的文件列表或者文件夹列表Ls  -l 详细信息的列表L ...

  9. ssh出现公钥错误问题的解决方法

      问题:主机app1推送公钥时,公钥判定错误   原因:之前推过公钥,用的是ip而不是主机名(即hosts文件中的对应关系不对),导致app1的~/.ssh/known_hosts中的公钥对不上. ...

  10. MapReduce 框架原理

    1. Hadoop 序列化 1.1 自定义Bean对象实现序列化接口 必须实现 Writable 接口: 反序列化时,需要反射调用空参构造函数,所以必须有空参构造: 重写序列化方法: 重写反序列化方法 ...