亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

使用有限状态机在 Arduino 上的数字手表

组件和用品

Arduino UNO
您可以使用所有与 LCD Shield 兼容的 Arduino。我用过 Arduino Mega。
× 1
LCD 键盘屏蔽
× 1

应用和在线服务

YAKINDU 状态图工具
非商业用途免费。
用于 Arduino 的 Eclipse C++ IDE

关于这个项目

你好,

我将向您展示如何使用 YAKINDU Statechart Tools 创建数字手表并在使用 LCD Keypad Shield 的 Arduino 上运行。

数字手表的原始模型取自大卫·哈雷尔 (David Harel)。他发表了一篇关于“状态机和状态图的传统形式主义的广泛扩展”的论文。

在这篇论文中,他以数字手表为例进行了研究。我以它为灵感,用 YAKINDU 状态图工具(一种用于创建状态机图形模型并用它生成 C/C++ 代码的工具)重建了手表,并在 Arduino 上让它恢复生机。

数字手表的工作原理

让我们首先定义数字手表应该如何工作。你还记得这些......让我们说......每个人在 90 年代都拥有的“超酷”数字手表?一个集成的秒表、不同的闹钟和它每整整一小时发出的恼人的哔哔声。如果没有,看看:90年代的数字手表。

所以基本上它是一个具有不同模式的可配置手表。主要是显示当前时间,但还有一些其他功能。作为输入,您有一个开/关 , 模式 和一个集合 按钮。此外,您可以打开和关闭灯。

使用模式 按钮,您可以区分模式并激活/禁用时钟功能:

  • 显示时间(时钟)
  • 显示日期(Date)
  • 设置闹钟(闹钟 1、闹钟 2)
  • 启用/禁用提示音(设置提示音)
  • 使用秒表(Stop Watch)

在菜单中,您可以使用开/关 按钮来配置模式。 集合 按钮允许您设置时间 - 例如用于时钟或闹钟。秒表可以控制 - 启动和停止 - 通过使用开灯和关灯按钮。您也可以使用集成的计圈器。

此外,还有一个钟声响起,并集成了可控背光。第一步我没有将它们连接到 Arduino。

状态机

我不想详细解释这个例子。不是因为它太复杂,它只是有点太大了。我将尝试解释它如何工作的基本思想。通过查看模型或下载并模拟它,执行应该是不言自明的。状态机的某些部分在子区域中汇总,例如设置时间 地区。这样就可以保证状态机的可读性。

该模型分为两部分 - 图形和文本。在文本部分,将定义事件、变量等。在图形部分 - 状态图 - 指定了模型的逻辑执行。要创建满足指定行为的状态机,需要一些输入事件,可以在模型中使用:onoff , 设置 , 模式 , , 和 light_r. 在定义部分中使用了一个内部事件,它每 100 毫秒增加一次时间值:

每100毫秒/次+=1 

基于 100 毫秒的步长,当前时间将在 HH:MM:SS 中计算 格式:

display.first =(time / 36000) % 24;
display.second =(time / 600) % 60;
display.third =(time / 10) % 60;

这些值将通过操作 updateLCD 连接到 LCD 显示器 每次调用状态机时:

display.updateLCD(display.first, display.second, display.third, display.text) 

状态机的基本执行已在数字手表的工作原理部分定义 .在该工具中,我使用了一些“特殊”建模元素,例如 CompositeState , 历史 , 子图 , ExitNodes, 等。详细说明可以在用户指南中找到。

LCD键盘屏蔽

LCD Keypad Shield 对于简单的项目来说非常酷,这些项目需要一个用于可视化的屏幕和一些按钮作为输入 - 一个典型的简单 HMI(人机界面)。 LCD Keypad Shield 包含五个用户按钮和另一个用于重置。五个按钮一起连接到 Arduino 的 A0 引脚。它们中的每一个都连接到一个分压器,可以区分按钮。

您可以使用analogRead(0) 来查找特定值,这当然会因制造商而异。这个简单的项目在 LCD 上显示当前值:

#include 
#include

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

void setup() {
lcd.begin(16, 2);
lcd.setCursor(0,0);
lcd.write("测量值");
}

void loop() {
lcd.setCursor(0,1);
lcd.print(" ");
lcd. setCursor(0,1);
lcd.print(analogRead(0));
delay(200);
}

这些是我的测量结果:

  • 无:1023
  • 选择:640
  • 左:411
  • 向下:257
  • 向上:100
  • 右:0

有了这些阈值,就可以读取按钮了:

#define NONE 0
#define SELECT 1
#define LEFT 2
#define DOWN 3
#define UP 4
#define RIGHT 5

static int readButton() {
int result =0;
result =analogRead(0);
if (result <50) {
return RIGHT;
}
if (result <150) {
return UP;
}
if (result <300) {
return DOWN;
}
if (result <550) {
return LEFT;
}
if (result <850) {
return SELECT;
}
return NONE;
}

连接状态机

状态机生成的C++代码提供了接口,必须实现这些接口才能控制状态机。第一步是将 in 事件与 Keypad Shield 的键连接起来。我已经展示了如何读取按钮,但是为了将它们连接到状态机,需要对按钮进行去抖动 - 否则事件将被多次引发,从而导致不可预测的行为。软件去抖动的概念并不新鲜。你可以看看Arduino文档。

在我的实现中,我检测到下降沿(释放按钮)。我读取按钮的值,等待 80 毫秒(使用 80 而不是 50 获得更好的结果),保存结果并读取新值。如果 oldResult 不是NONE (未按下),新结果为 NONE ,我知道,该按钮之前已按下,现在已释放。然后,我引发状态机的相应输入事件。

int oldState =NONE;
static void raiseEvents() {
int buttonPressed =readButton();
delay(80);
oldState =buttonPressed;
if (oldState !=NONE &&readButton() ==NONE) {
switch (oldState) {
case SELECT:{
stateMachine->getSCI_Button()->raise_mode();
break;
}
case LEFT:{
stateMachine->getSCI_Button()->raise_set();
break;
}
case DOWN:{
stateMachine->getSCI_Button()->raise_light();
break;
}
case UP:{
stateMachine->getSCI_Button() ->raise_light_r();
break;
}
case RIGHT:{
stateMachine->getSCI_Button()->raise_onoff();
break;
}
默认:{
break;
}
}
}
}

将事物连接在一起

主程序使用三部分:

  • 状态机
  • 计时器
  • 显示处理程序(典型的 lcd.print(...))
DigitalWatch* stateMachine =new DigitalWatch();
CPPTimerInterface* timer_sct =new CPPTimerInterface();
DisplayHandler* displayHandler =new DisplayHandler();

状态机使用一个显示处理程序并获得一个计时器,该计时器将被更新以控制定时事件。之后,状态机被初始化并进入。

void setup() {
stateMachine->setSCI_Display_OCB(displayHandler);
stateMachine->setTimer(timer_sct);
stateMachine->init();
stateMachine->enter();
}

循环做了三件事:

  • 引发输入事件
  • 计算经过的时间并更新计时器
  • 调用状态机
long current_time =0;
long last_cycle_time =0;
void loop() {
raiseEvents();
last_cycle_time =current_time;
current_time =millis();
timer_sct->updateActiveTimer(stateMachine,
current_time - last_cycle_time);
stateMachine->runCycle();
}

获取示例

而已。可能我没有提到实现的每一个细节,但你可以看看例子或发表评论。

将示例添加到正在运行的 IDE 中:

文件 -> 新建 -> 示例 -> YAKINDU 状态图示例 -> 下一步 -> Arduino - 数字手表 (C++)

>> 您可以在此处下载 IDE <<

您可以先试用 30 天。之后,您必须获得许可证,该许可证非商业用途免费


制造工艺

  1. 有限状态机
  2. 使用 Arduino 制作流光溢彩监视器
  3. Arduino 数字骰子
  4. 使用 ARDUINO 的超声波悬浮机器
  5. 使用 Arduino 和智能手机的 DIY 电压表
  6. 使用物联网的心率监测器
  7. WebServerBlink 使用 Arduino Uno WiFi
  8. Arduino Tamagotchi Clone - Digital Pet
  9. Arduino Apple Watch
  10. 使用 arduino 的自动化恐龙游戏
  11. 使用 Arduino 和 RDA8057M 的 FM 收音机
  12. BLUE_P:无线 Arduino 编程扩展板