将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. 如何调试JS查看异常信息

    如果页面上有错误,html页面的控制台会报错,可以查看报错信息,找到对应的行,找到出错的位置.也可以通过editplus运行调试,editplus会以弹框的形式出现提示,哪行的什么位置什么错误,需要记 ...

  2. ubuntu16.04 下通过rc.d(rc.local)实现开机启动(未登录)anydesk

    先编辑anydesk-X.X.X/init/anydesk文件,将"DAEMON=//usr/bin$NAME"改成"DAEMON=/XXX/anydesk-5.1.1/ ...

  3. 欢迎访问我的csdn博客

    csdn博客:https://blog.csdn.net/qq_27307175 这个里面有:许许多多的专业文章. 本人主要研究:网络工程,VMware虚拟化,docker容器,以及Linux等技术, ...

  4. 【编程开发】非对称加密过程详解(基于RSA非对称加密算法实现)

    1.非对称加密过程:         假如现实世界中存在A和B进行通讯,为了实现在非安全的通讯通道上实现信息的保密性.完整性.可用性(即信息安全的三个性质),A和B约定使用非对称加密通道进行通讯,具体 ...

  5. openssl交叉编译

    目录 openssl交叉编译 title: openssl交叉编译 date: 2019/12/18 21:09:33 toc: true --- openssl交叉编译 tar xvf openss ...

  6. Collection集合常用的功能

    package demo06; import java.util.ArrayList;import java.util.Collection; /** java.util接口 Collection&l ...

  7. C语言--分支结构

    一.PTA实验作业 题目1:7-1 计算分段函数[2] 1.实验代码 float x, y; printf("Enter x:\n"); scanf("%f", ...

  8. 《你必须知道的495个C语言问题》读书笔记之第4-7章:指针

    1. Q:为什么我不能对void *指针进行算术运算? A:因为编译器不知道所值对象的大小,而指针的算法运算总是基于所指对象的大小的. 2. Q:C语言可以“按引用传参”吗? A:不可以.严格来说,C ...

  9. poj3347(扩大数据,避免小数)

    题目链接:https://vjudge.net/problem/POJ-3347 题意:摆放n个正方形,问俯视视角来看时哪些正方形可见. 思路:在刷计算几何专题时刷到这题,但不需要用计算几何的知识.我 ...

  10. 什么是Java多线程?

    第五阶段 多线程 前言: 一个场景:周末,带着并不存在的女票去看电影,无论是现场买票也好,又或是手机买票也好,上一秒还有位置,迟钝了一下以后,就显示该座位已经无法选中,一不留神就没有座位了,影院的票是 ...