為 16x2 LCD Keypad Shield 使用 YAKINDU 狀態(tài)圖工具創(chuàng)建數(shù)字手表。
我將向您展示如何使用YAKINDU Statechart Tools創(chuàng)建數(shù)字手表并在使用 LCD Keypad Shield 的 Arduino 上運(yùn)行。
數(shù)字手表的原始模型取自大衛(wèi)哈雷爾。他之前發(fā)表過(guò)一篇關(guān)于“狀態(tài)機(jī)和狀態(tài)圖的傳統(tǒng)形式的廣泛擴(kuò)展”的論文。在論文中,他以數(shù)字手表為例進(jìn)行了研究。我以此為靈感,使用YAKINDU Statechart Tools (一種用于創(chuàng)建狀態(tài)機(jī)圖形模型并使用它生成 C/C++ 代碼的工具)重建了手表,并在 Arduino 上讓它重新煥發(fā)生機(jī)。
數(shù)字手表的工作原理
讓我們從定義數(shù)字手表應(yīng)該如何工作開(kāi)始。
基本上,它是一個(gè)具有不同模式的可配置手表。主要是顯示當(dāng)前時(shí)間,但還有一些其他功能。作為輸入,您有一個(gè)開(kāi)/關(guān)、一個(gè)模式和一個(gè)設(shè)置按鈕。此外,還可以打開(kāi)和關(guān)閉燈。
使用模式按鈕,您可以區(qū)分模式并激活/禁用時(shí)鐘功能:
顯示時(shí)間(時(shí)鐘)
顯示日期(日期)
設(shè)置鬧鐘(鬧鐘 1、鬧鐘 2)
啟用/禁用鈴聲(設(shè)置鈴聲)
使用秒表(秒表)
在菜單中,您可以使用開(kāi)/關(guān)按鈕來(lái)配置模式。設(shè)置按鈕允許您設(shè)置時(shí)間 - 例如時(shí)鐘或鬧鐘。秒表可以通過(guò)使用開(kāi)燈和關(guān)燈按鈕來(lái)控制 - 啟動(dòng)和停止。您還可以使用集成的計(jì)圈器。
此外,還有一個(gè)鐘聲,每時(shí)每刻都在響起,并且集成了一個(gè)可控的背光。不過(guò)在第一步,我沒(méi)有將它們連接到 Arduino。
狀態(tài)機(jī)
我不想詳細(xì)解釋這個(gè)例子。這不是因?yàn)樗珡?fù)雜,它只是有點(diǎn)太大了。不過(guò)我會(huì)嘗試解釋它具體如何工作的基本思想。通過(guò)查看模型或下載并模擬它。狀態(tài)機(jī)的某些部分在子區(qū)域中匯總,例如設(shè)置的時(shí)間區(qū)域。這樣就可以確保狀態(tài)機(jī)的可讀性。
該模型共分為兩部分 - 圖形和文本。
在文本部分,將定義事件、變量等。
在圖形部分 - 狀態(tài)圖 - 指定了模型的邏輯執(zhí)行。
要?jiǎng)?chuàng)建滿足指定行為的狀態(tài)機(jī),需要一些輸入事件,這些事件可以在模型中使用:onoff 、set 、mode 、light和light_r。在定義部分中使用了一個(gè)內(nèi)部事件,它每 100 毫秒遞增一次時(shí)間值:
every 100 ms / time += 1
基于 100 毫秒步長(zhǎng),當(dāng)前時(shí)間將以HH:MM:SS格式計(jì)算:
display.first = (time / 36000) % 24;
display.second = (time / 600) % 60;
display.third = (time / 10) % 60;
每次調(diào)用狀態(tài)機(jī)時(shí),這些值將通過(guò)使用updateLCD操作連接到 LCD 顯示器:
display.updateLCD(display.first, display.second, display.third, display.text)
狀態(tài)機(jī)的基本執(zhí)行已在“數(shù)字手表的工作原理”部分中定義。在該工具中,我使用了一些“特殊”建模元素,如CompositeState 、History 、Sub-Diagrams 、ExitNodes等。
LCD 鍵盤(pán)屏蔽
LCD Keypad Shield 對(duì)于需要一個(gè)可視化屏幕和一些按鈕作為輸入的簡(jiǎn)單項(xiàng)目來(lái)說(shuō)非常酷 - 一個(gè)典型的簡(jiǎn)單 HMI(人機(jī)界面)。LCD Keypad Shield 包含五個(gè)用戶按鈕和一個(gè)用于重置的按鈕。五個(gè)按鈕一起連接到 Arduino 的 A0 引腳。它們中的每一個(gè)都連接到一個(gè)分壓器,可以區(qū)分按鈕。
您可以使用analogRead(0) 來(lái)查找特定值,這當(dāng)然可能因制造商而異。這個(gè)簡(jiǎn)單的項(xiàng)目在 LCD 上顯示當(dāng)前值:
#include
#include
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
void setup() {
lcd.begin(16, 2);
lcd.setCursor(0,0);
lcd.write("Measured Value");
}
void loop() {
lcd.setCursor(0,1);
lcd.print(" ");
lcd.setCursor(0,1);
lcd.print(analogRead(0));
delay(200);
}
這些是我的測(cè)量結(jié)果:
無(wú):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;
}
連接狀態(tài)機(jī)
狀態(tài)機(jī)生成的 C++ 代碼提供了接口,必須實(shí)現(xiàn)這些接口才能控制狀態(tài)機(jī)。第一步是將 in 事件與 Keypad Shield 的鍵連接起來(lái)。我已經(jīng)展示了如何讀取按鈕,但是為了將它們連接到狀態(tài)機(jī),需要對(duì)按鈕進(jìn)行去抖動(dòng)。否則事件將被多次引發(fā),從而導(dǎo)致不可預(yù)測(cè)的行為。軟件去抖動(dòng)的概念并不新鮮。
在我的實(shí)現(xiàn)中,我檢測(cè)到下降沿(釋放按鈕)。我讀取按鈕的值,等待 80 毫秒,保存結(jié)果并讀取新值。如果oldResult不是NONE (未按下)并且新結(jié)果是NONE ,那我就能知道該按鈕之前已被按下,現(xiàn)在已被釋放。之后,就可以提出狀態(tài)機(jī)的相應(yīng)輸入事件。
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;
}
default: {
break;
}
}
}
}
連接
主程序使用三個(gè)部分:
狀態(tài)機(jī)
計(jì)時(shí)器
顯示處理程序(典型的 lcd.print(...))
DigitalWatch* stateMachine = new DigitalWatch();
CPPTimerInterface* timer_sct = new CPPTimerInterface();
DisplayHandler* displayHandler = new DisplayHandler();
狀態(tài)機(jī)使用顯示處理程序并獲得一個(gè)計(jì)時(shí)器,該計(jì)時(shí)器將被更新以控制定時(shí)事件。之后,狀態(tài)機(jī)被初始化并進(jìn)入。
void setup() {
stateMachine->setSCI_Display_OCB(displayHandler);
stateMachine->setTimer(timer_sct);
stateMachine->init();
stateMachine->enter();
}
循環(huán)做了三件事:
引發(fā)輸入事件
計(jì)算經(jīng)過(guò)時(shí)間并更新計(jì)時(shí)器
調(diào)用狀態(tài)機(jī)
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();
}
添加示例
將示例添加到正在運(yùn)行的 IDE 中:
文件 -》 新建 -》 示例 -》 YAKINDU 狀態(tài)圖示例 -》 下一步 -》 Arduino - 數(shù)字手表 (C++)
-
lcd
+關(guān)注
關(guān)注
34文章
4439瀏覽量
168515 -
手表
+關(guān)注
關(guān)注
1文章
141瀏覽量
24819 -
Arduino
+關(guān)注
關(guān)注
188文章
6477瀏覽量
187993
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
ImageCraft MSP430 ANSI C Tools
Motorola Phone Tools快速入門(mén)
什么是Data Mining Tools
Express-tools使用詳解
LabVIEW網(wǎng)絡(luò)講壇第三季:介紹Statechart狀態(tài)圖的特點(diǎn)與原理(1)
![LabVIEW網(wǎng)絡(luò)講壇第三季:介紹<b class='flag-5'>Statechart</b>狀態(tài)圖的特點(diǎn)與原理(1)](https://file.elecfans.com/web1/M00/53/24/pIYBAFseDLaAWOUaAAAs-q5-h6w837.jpg)
介紹 LabVIEW 狀態(tài)圖及Statechart與狀態(tài)機(jī)的區(qū)別的區(qū)別
![介紹 LabVIEW 狀態(tài)圖及<b class='flag-5'>Statechart</b>與狀態(tài)機(jī)的區(qū)別的區(qū)別](https://file.elecfans.com/web1/M00/53/0E/o4YBAFseFCyAEYqEAAAoH7ftUO4135.jpg)
PCB技術(shù):異形敷銅的創(chuàng)建
![PCB技術(shù):異形敷銅的<b class='flag-5'>創(chuàng)建</b>](https://file.elecfans.com/web1/M00/C9/8E/o4YBAF-Ds-qAJbwOAAJTXOt_-aM482.png)
評(píng)論