0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何在Arduino上實(shí)現(xiàn)有限狀態(tài)機(jī)

454398 ? 來(lái)源:wv ? 2019-09-23 11:17 ? 次閱讀

步驟1:什么是有限狀態(tài)機(jī)?

如何在Arduino上實(shí)現(xiàn)有限狀態(tài)機(jī)

一個(gè)有限狀態(tài)機(jī)(簡(jiǎn)稱FSM)是一臺(tái)機(jī)器(以抽象的方式)具有定義的有限數(shù)量的可能狀態(tài),一次只能激活一個(gè)狀態(tài)。狀態(tài)通過(guò)轉(zhuǎn)換連接。這些過(guò)渡有一個(gè)確定的方向,只能朝這個(gè)方向通過(guò)-可以將其視為一條單向街道。此外,過(guò)渡具有某些輸入和輸出。您可以將其視為要使用單向街道之前必須滿足的條件,并且在使用單向街道時(shí)會(huì)向外界發(fā)出信號(hào)–例如,您必須先付費(fèi)才能使用使用街道,然后計(jì)算您的汽車。

在許多房屋中都發(fā)現(xiàn)了一個(gè)非?;镜腇SM示例:按一下按鈕即可激活樓梯間的燈。一定時(shí)間后,指示燈會(huì)自動(dòng)關(guān)閉。您可以將此模型建模為具有兩種狀態(tài)的FSM:“亮”和“滅”。從一種狀態(tài)過(guò)渡到另一種狀態(tài),反之亦然,條件是在一個(gè)方向上按下按鈕,而在另一方向上經(jīng)過(guò)了一定的時(shí)間。我們可以在圖表(即狀態(tài)圖)中對(duì)此行為進(jìn)行建模??匆幌聢D片1。

黑色實(shí)心圓圈標(biāo)記著狀態(tài)機(jī)的入口點(diǎn)(一切都必須從某處開(kāi)始)。因此,如果我們的機(jī)器開(kāi)始運(yùn)行,則指示燈熄滅。一直這樣,直到我們使用電燈開(kāi)關(guān)–燈才亮起,并在30秒后熄滅。當(dāng)指示燈已亮起時(shí)按按鈕不起作用,并且30秒鐘后指示燈熄滅。該FSM沒(méi)有任何輸出。從傳統(tǒng)的數(shù)學(xué)角度來(lái)看,“點(diǎn)亮”狀態(tài)與“打開(kāi)”狀態(tài)等效,但是當(dāng)我們真正開(kāi)始對(duì)系統(tǒng)進(jìn)行編程時(shí),我們當(dāng)然需要添加某種實(shí)際上可以完成某些工作的輸出,例如打開(kāi)

此狀態(tài)機(jī)有效,但這是一個(gè)好的系統(tǒng)嗎? 30秒足夠長(zhǎng)嗎?對(duì)于大多數(shù)人來(lái)說(shuō),可能是的,但是位于10樓的人們可能不喜歡我們的系統(tǒng)。他們可能需要30秒以上的時(shí)間,比方說(shuō)他們需要40秒。但是他們需要等待30秒鐘過(guò)去,然后關(guān)閉燈以再次激活燈,然后他們可能在樓梯中間。因此,我們需要做的是允許在燈亮并且再次按下按鈕時(shí)重置計(jì)時(shí)器。為此,我們將需要對(duì)系統(tǒng)進(jìn)行重新建模,將計(jì)時(shí)器的開(kāi)始建模為轉(zhuǎn)換的輸出,并添加另一個(gè)轉(zhuǎn)換,如圖2所示。

在這里,您可以看到兩件事:

過(guò)渡完全可以進(jìn)入到它來(lái)自的狀態(tài)

過(guò)渡可以有一個(gè)事件作為發(fā)生過(guò)渡的條件,例如以及分配的輸出。斜線左邊的信息是事件,右邊的信息是輸出。事件也被視為機(jī)器的輸入,這被稱為輸入-輸出-自動(dòng)機(jī)。

步驟2:在Arduino上手動(dòng)實(shí)現(xiàn)FSM

當(dāng)我們想在Arduino上實(shí)現(xiàn)此行為時(shí),代碼可能類似于以下要點(diǎn)。代碼沒(méi)有什么特別的,switch-case語(yǔ)句僅針對(duì)每種可能的狀態(tài)包含一個(gè)case,并在其中檢查是否滿足轉(zhuǎn)換條件。如果是這樣,狀態(tài)就會(huì)更改。

如您所見(jiàn),代碼非常簡(jiǎn)單。但是您能想象如果沒(méi)有2個(gè)州,而是10個(gè)或100個(gè)州,會(huì)發(fā)生什么情況?對(duì)于現(xiàn)實(shí)世界的FSM來(lái)說(shuō),這并不罕見(jiàn)。該代碼變得不可讀,并且可以達(dá)到數(shù)千行的長(zhǎng)度。同樣,通常,我們希望以圖形方式計(jì)劃FSM,因?yàn)槲覀冃枰軌虮M快查看其實(shí)際功能。然后,我們?nèi)匀恍枰獙?duì)實(shí)際的狀態(tài)機(jī)進(jìn)行編碼,并且需要確保圖形設(shè)計(jì)和手寫代碼實(shí)際上可以完成相同的工作。這可能是一個(gè)巨大的問(wèn)題。

考慮一下:對(duì)于我們的FSM所具有的每個(gè)狀態(tài),我們的代碼都需要一個(gè)“ case”語(yǔ)句,對(duì)于向其他狀態(tài)的每個(gè)轉(zhuǎn)換,我們都需要在其中包含一個(gè)if或case語(yǔ)句。如果我們有一個(gè)狀態(tài)機(jī),每個(gè)狀態(tài)都可以到達(dá)其他每個(gè)狀態(tài)(最極端的情況),我們的代碼將以 n平方增長(zhǎng),其中 n 是狀態(tài)。因此,對(duì)于3個(gè)狀態(tài),我們將有3種情況,內(nèi)部有3個(gè)ifs,因此代碼長(zhǎng)度將與9成正比。當(dāng)我們有10個(gè)狀態(tài)(不是很多)時(shí),代碼長(zhǎng)度將與100成正比,并且在20個(gè)州中,代碼已長(zhǎng)四倍。該FSM的圖形表示將更容易掌握,并且如果我們不必處理所有這些switch case語(yǔ)句,那將很好。如果您熟悉描述模擬器原理圖的網(wǎng)表–我們也不想使用網(wǎng)表設(shè)計(jì)原理圖。那么,我們?cè)撛趺醋瞿兀?/p>

步驟3:獲取YAKINDU Statechart工具

Yakindu SCT正是為此而設(shè)計(jì)的:對(duì)系統(tǒng)建模并從中生成代碼。建模工具比簡(jiǎn)單的有限狀態(tài)機(jī)先進(jìn)得多,因?yàn)樗鼈兓贖arel的狀態(tài)圖理論。它們通過(guò)一些其他概念擴(kuò)展了常規(guī)自動(dòng)機(jī)理論-例如,歷史狀態(tài),其中離開(kāi)狀態(tài)圖可保存活動(dòng)狀態(tài),因此您可以稍后再返回等等。對(duì)于‘Ible,我們將不需要這些額外的功能。

Yakindu SCT基于Eclipse(最常用的IDE之一)。因此,我們可以使用市場(chǎng)上所有的Eclipse插件,并擁有一個(gè)已知的環(huán)境。它是開(kāi)源的,這意味著它是免費(fèi)的!首先,請(qǐng)?jiān)L問(wèn)statecharts.org,然后選擇“下載SCT”。您將需要輸入姓名,電子郵件地址和職業(yè)。下載該工具后,只需解壓縮它(右鍵單擊-》全部提取,或類似操作)。在里面,您會(huì)發(fā)現(xiàn)“ SCT”。啟動(dòng)它。 (不,不需要真正的安裝。)

在安裝Yakindu SCT之后,您將具有對(duì)FSM進(jìn)行建模的工具,但是我們將希望獲得在Arduino上運(yùn)行的代碼。有一個(gè)出色的Eclipse插件可以做到這一點(diǎn),您可以在http://www.baeyens.it/eclipse/上找到有關(guān)它的更多信息。它為您提供了Eclipse內(nèi)部的完整Arduino工具鏈,因此您可以輕松使用Arduino IDE以及Eclipse的智能代碼管理和編碼助手。在SCT中,轉(zhuǎn)到幫助-》安裝新軟件。安裝向?qū)Т蜷_(kāi)。單擊向?qū)в疑辖歉浇奶砑印?. 按鈕。將打開(kāi)一個(gè)對(duì)話框,要求您指定要從中安裝新軟件的更新存儲(chǔ)庫(kù)。在“名稱”字段中輸入一些文本。該文本原則上是任意的,但是您應(yīng)該選擇一些使其更容易在其他更新存儲(chǔ)庫(kù)中標(biāo)識(shí)此特定更新存儲(chǔ)庫(kù)的內(nèi)容。輸入更新存儲(chǔ)庫(kù)的名稱和位置(http://eclipse.baeyens.it/update/V4/stable)之后,單擊“確定”。 Eclipse建立與更新存儲(chǔ)庫(kù)的網(wǎng)絡(luò)連接,向其詢問(wèn)可用的軟件項(xiàng),并在安裝向?qū)е酗@示它們。在這里,您只需接受“ Arduino”選項(xiàng)。再單擊幾次“下一步”并在以后接受許可協(xié)議,它將要求您重新啟動(dòng)該工具。完成此操作后,插件將下載所有需要的庫(kù),因此您無(wú)需從現(xiàn)有的Arduino項(xiàng)目復(fù)制它們。接下來(lái),在Yakindu SCT安裝中安裝了Arduino工具。現(xiàn)在是時(shí)候結(jié)合兩者的可能性了。

注意:如果您尚未安裝Windows,請(qǐng)同時(shí)安裝官方的Arduino IDE。它帶有必需的驅(qū)動(dòng)程序。我不確定Mac上的情況。 Linux已經(jīng)包含驅(qū)動(dòng)程序,因此不需要安裝Arduino IDE。

步驟4:開(kāi)始創(chuàng)建狀態(tài)圖

我們現(xiàn)在將開(kāi)始一起對(duì)狀態(tài)圖進(jìn)行建模。首先,我們將創(chuàng)建一個(gè)新項(xiàng)目。您應(yīng)該在SCT/Eclipse的歡迎頁(yè)面上。 轉(zhuǎn)到文件-》新建-》項(xiàng)目。.. ,然后在主菜單中選擇 Arduino-》新建Arduino Sketch 。將出現(xiàn)新Eclipse項(xiàng)目的常規(guī)向?qū)?。您必須給您的項(xiàng)目起一個(gè)名字。我們將其命名為ArduinoFSM。在下一個(gè)窗口中,您可以指定arduino連接到的端口。如果您不知道并且不知道如何查找,請(qǐng)忽略此。現(xiàn)在,您可以單擊完成。

如果您改為選擇 New-》 Arduino Sketch ,則不會(huì)詢問(wèn)您arduino的連接位置。然后,使用 Project-》 Properties 進(jìn)行操作。如果您不知道如何確定Arduino的端口,此說(shuō)明的最后一步將為您提供幫助。

如果在創(chuàng)建項(xiàng)目后未關(guān)閉歡迎屏幕,請(qǐng)關(guān)閉它您自己的,使用標(biāo)簽中的X?,F(xiàn)在,您應(yīng)該具有與左側(cè)“項(xiàng)目資源管理器”中的第一張圖片相似的圖片。

我們現(xiàn)在要?jiǎng)?chuàng)建一個(gè)名為“ model”的新文件夾。右鍵單擊您的項(xiàng)目,然后選擇新建-》文件夾。鍵入名稱,然后單擊“完成”。

右鍵單擊該新文件夾,再次轉(zhuǎn)到“新建”。根據(jù)您的安裝,您可能可以直接添加新的Statechart模型,或者可能必須使用Other,選擇Yakindu,然后選擇Statechart模型?,F(xiàn)在,您應(yīng)該看到的是第二張圖片:一個(gè)進(jìn)入狀態(tài)和一個(gè)名為 StateA 的通用第一狀態(tài)。

左側(cè)的文本框允許您聲明相關(guān)的事件和變量狀態(tài)圖,右邊的區(qū)域是圖形狀態(tài)圖編輯器。

我們將需要一個(gè)事件:按鈕。雙擊左側(cè)的文本框,然后在界面下插入文本

in event button

,然后聲明有一個(gè)名為“ button”的傳入事件。另外,在該文本框中雙擊單詞“ default”,并給狀態(tài)圖取一個(gè)更好的名稱-“ LightCtrl”怎么樣?現(xiàn)在,添加另一個(gè)狀態(tài):只需在右側(cè)面板中單擊 State ,然后在圖形狀態(tài)圖編輯器中的某個(gè)位置。雙擊這兩個(gè)州的名稱,并為其命名一個(gè)帶有黑色輸入狀態(tài)的名稱,熄滅,然后將新?tīng)顟B(tài)點(diǎn)亮。現(xiàn)在,我們需要過(guò)渡:從面板中選擇過(guò)渡,單擊一個(gè)狀態(tài),保持并拖動(dòng)到另一狀態(tài)。這應(yīng)該構(gòu)成過(guò)渡。它從您第一次單擊的狀態(tài)變?yōu)榈诙€(gè)狀態(tài)。通過(guò)單擊您現(xiàn)在拖動(dòng)到第一個(gè)的狀態(tài)并拖動(dòng)到另一個(gè)狀態(tài)來(lái)添加第二個(gè)過(guò)渡,這樣您就可以在兩個(gè)方向上進(jìn)行過(guò)渡?,F(xiàn)在,單擊過(guò)渡。將出現(xiàn)一個(gè)文本字段。在這里,您可以輸入要進(jìn)行過(guò)渡的事件和輸出。在從關(guān)閉燈光到打開(kāi)燈光的過(guò)渡上,鍵入按鈕,在另一個(gè)按鈕上,在5秒后鍵入 (比測(cè)試的30秒要快)?,F(xiàn)在,您應(yīng)該擁有看起來(lái)像第三張圖片的東西!

現(xiàn)在就這些了。您有一個(gè)樓梯燈的工作模型!

步驟5:模擬狀態(tài)圖

Yakindu SCT的另一個(gè)不錯(cuò)的功能是您可以模擬狀態(tài)圖而無(wú)需事先編寫任何代碼。您可以嘗試使用狀態(tài)機(jī)來(lái)實(shí)現(xiàn)您想要的狀態(tài)。

模擬狀態(tài)圖非常簡(jiǎn)單。右鍵單擊Eclipse/SCT中的.sct文件,選擇運(yùn)行方式,然后選擇狀態(tài)圖模擬。

將打開(kāi)一個(gè)新透視圖。您應(yīng)該能夠看到第一個(gè)狀態(tài)是紅色,這是活動(dòng)狀態(tài)。 (看圖片)在右邊,應(yīng)該打開(kāi)了Simulation View。您可以通過(guò)在右下方的模擬視圖中單擊單詞 button 來(lái)模擬按鈕按下事件?;顒?dòng)狀態(tài)應(yīng)從“熄滅”更改為“點(diǎn)亮”。五秒鐘后,或單擊時(shí)間事件 Light_On_timer_event_0 后,活動(dòng)狀態(tài)將更改回 Light Off 。太棒了!現(xiàn)在,讓我們檢查一下如何在Arduino上使用它。

步驟6:將系統(tǒng)帶入現(xiàn)實(shí)世界

好吧,我們點(diǎn)擊了一下,使用了圖形編輯器(通常與低級(jí)語(yǔ)言相關(guān)聯(lián)),讓這件事栩栩如生。首先,我們需要一個(gè)代碼生成器,將狀態(tài)圖轉(zhuǎn)換為C代碼。

右鍵單擊您的模型文件夾,然后選擇 New-》 Code Generator Model ,這非常簡(jiǎn)單,盡管看起來(lái)一開(kāi)始就像是黑魔法。在向?qū)е袉螕糇约?,然后將代碼生成器附加到之前創(chuàng)建的狀態(tài)圖。注意:在同一窗口中,頂部有一個(gè)選擇器,可以輕松查看。使用它選擇C代碼生成器而不是Java代碼生成器,然后選中狀態(tài)圖旁邊的復(fù)選框,然后單擊完成。正常情況下,生成器現(xiàn)在應(yīng)該一直一直直接自動(dòng)運(yùn)行。檢查是否創(chuàng)建了兩個(gè)文件夾src和src-gen。如果不是這種情況,請(qǐng)轉(zhuǎn)到主菜單中的“項(xiàng)目”,然后檢查是否激活了“自動(dòng)生成”。如果不是,請(qǐng)這樣做,然后右鍵單擊您的項(xiàng)目,然后選擇“生成項(xiàng)目”。進(jìn)度條以及兩個(gè)提到的文件夾都應(yīng)出現(xiàn)。進(jìn)行任何更改后,還可以右鍵單擊生成器文件,然后選擇 Generate Code Artifacts 。

src-gen文件夾的內(nèi)容非常有趣。文件 LightCtrl.c 包含狀態(tài)圖的實(shí)現(xiàn)。檢查時(shí),您會(huì)發(fā)現(xiàn)一個(gè)函數(shù) LightCtrlIface_raise_button(LightCtrl *句柄)。您可以調(diào)用此函數(shù)來(lái)引發(fā)我們先前聲明的按鈕事件,例如,當(dāng)您檢查硬件按鈕的引腳并看到其具有高電平時(shí)。然后是文件 LightCtrlRequired.h ,您需要在其中查看。它聲明您需要實(shí)現(xiàn)的功能。對(duì)于此狀態(tài)圖,只有兩個(gè)功能: lightCtrl_setTimer 和 lightCtrl_unsetTimer 。我們需要這些功能,因?yàn)闋顟B(tài)圖在5s之后使用了構(gòu)造。這是一個(gè)非常方便的功能,但是我們的狀態(tài)圖代碼生成器不提供計(jì)時(shí)服務(wù),因?yàn)樗叨纫蕾囉谄脚_(tái)–您的計(jì)算機(jī)與微型Arduino的計(jì)時(shí)器處理方式不同,而Mac和Linux上的計(jì)時(shí)器處理方式與Windows上的處理方式不同。

幸運(yùn)的是,我將為您提供計(jì)時(shí)服務(wù),因此您無(wú)需自己實(shí)現(xiàn)。在您的項(xiàng)目中,創(chuàng)建一個(gè)新文件夾,將其命名為 scutils ,用于 s tate c hart 實(shí)用程序功能。您可以隨意命名,也可以選擇不創(chuàng)建該文件夾,這只是組織問(wèn)題。我們將在其中創(chuàng)建兩個(gè)文件,分別是 sc_timer_service.c 和 sc_timer_service.h 。從GitHub中復(fù)制

代碼:

sc_timer_service.h

sc_timer_service.c

使用YAKINDU SCT 2.7.0,在那里是一個(gè)新選項(xiàng),可用于獲得此可指導(dǎo)的項(xiàng)目:

在SCT中,轉(zhuǎn)到“文件”-》“新建”-》“示例。..”,選擇“ YAKINDU Statechart示例”,然后單擊“下一步”。在新的示例向?qū)е?,單擊“下載”以獲取最新的示例集。從arduino類別中選擇“ Arduino的有限狀態(tài)機(jī)”,然后單擊“完成”。該項(xiàng)目將被復(fù)制到您的工作區(qū)中。右鍵單擊它,然后單擊“刷新”-可以肯定。

現(xiàn)在,我們可以開(kāi)始在向?qū)傻? .ino文件中的Arduino代碼上工作。

除了 Arduino.h ,還包括 avr/sleep.h ,當(dāng)然還有我們的狀態(tài)機(jī)和計(jì)時(shí)器服務(wù): LightCtrl.h , LightCtrlRequired.h 和 sc_timer_service.h ?,F(xiàn)在,需要常規(guī)的Arduino東西:我們定義按鈕和LED的引腳,并將它們?cè)O(shè)置在設(shè)置功能內(nèi)(這就是它的用途)。然后,我們需要定義狀態(tài)圖期望我們定義的函數(shù)-如前所述,- lightCtrl_setTimer 和 lightCtrl_unsetTimer 。在這里,我們只使用計(jì)時(shí)器服務(wù),就完成了?,F(xiàn)在,我們應(yīng)該思考一下當(dāng)達(dá)到 Light On 狀態(tài)時(shí)實(shí)際上如何激活LED。基本上,我們有三個(gè)選項(xiàng):

我們可以檢查狀態(tài)機(jī)是否處于Light On狀態(tài),并根據(jù)該信息激活/禁用LED

我們可以進(jìn)入狀態(tài)圖,并在到達(dá)狀態(tài)時(shí)設(shè)置一個(gè)變量,以便我們可以輪詢

我們可以添加一個(gè)操作來(lái)管理狀態(tài)圖在過(guò)渡時(shí)調(diào)用的光。

第一個(gè)解決方案確實(shí)很糟糕。我們將有關(guān)于狀態(tài)圖外部的邏輯。如果我們重命名我們的州,它將停止正常工作;但是這些名稱是平淡無(wú)奇的,與邏輯無(wú)關(guān)??梢允褂米兞浚貏e是在使用桌面應(yīng)用程序時(shí)。我們可以每x毫秒左右與他們同步一次。在這里,我們要使用一個(gè)操作。在狀態(tài)圖的接口聲明中添加以下內(nèi)容:

operation setLight(LightOn: boolean): void

這聲明了一個(gè)函數(shù),該函數(shù)接受布爾值作為參數(shù),但不返回任何值(無(wú)效)。這對(duì)您來(lái)說(shuō)不是新手,只是這里的語(yǔ)法不同。請(qǐng)記住–狀態(tài)圖未綁定到特定語(yǔ)言,因此語(yǔ)法是通用的。此功能自動(dòng)顯示在 LightCtrlRequired.h 中。如果沒(méi)有,請(qǐng)保存狀態(tài)圖,右鍵單擊您的項(xiàng)目并進(jìn)行構(gòu)建。

此處聲明的函數(shù)如下所示:

extern void lightCtrlIface_setLight(const LightCtrl* handle, const sc_boolean lightOn);

輸入?yún)?shù)句柄為類型的LightCtrl,它是狀態(tài)圖的引用者。如果您不熟悉C:星號(hào)表示所謂的指針,那么該變量包含statechart變量的地址。這對(duì)我們有幫助,因?yàn)槲覀兛梢詫?duì)原始對(duì)象進(jìn)行操作,而不必創(chuàng)建其副本。因此,讓我們實(shí)現(xiàn)此功能:

void lightCtrlIface_setLight(const LightCtrl* handle, const sc_boolean lightOn) {

if(lightOn)

digitalWrite(LED_PIN, HIGH);

else

digitalWrite(LED_PIN, LOW);

}

如您所見(jiàn),此功能非常簡(jiǎn)單-我們甚至不使用狀態(tài)圖的句柄,我們只在LED上寫HIGH如果操作的參數(shù)為true,則為pin;否則為L(zhǎng)OW。

我們更改狀態(tài)圖本身,使其看起來(lái)像第一張圖片。

還記得第1步嗎?斜線左邊是過(guò)渡所需要的輸入,右邊是狀態(tài)機(jī)的輸出(如果進(jìn)行了過(guò)渡)。此處的輸出是使用這些參數(shù)調(diào)用指定的操作。

#include “Arduino.h”

#include “avr/sleep.h”

#include “src-gen/LightCtrl.h”

#include “src-gen/LightCtrlRequired.h”

#include “scutil/sc_timer_service.h”

#define BUTTON_PIN 3

#define LED_PIN 6

#define MAX_TIMERS 20 //number of timers our timer service can use

#define CYCLE_PERIOD 10 //number of milliseconds that pass between each statechart cycle

static unsigned long cycle_count = 0L; //number of passed cycles

static unsigned long last_cycle_time = 0L; //timestamp of last cycle

static LightCtrl lightctrl;

static sc_timer_service_t timer_service;

static sc_timer_t timers[MAX_TIMERS];

//! callback implementation for the setting up time events

void lightCtrl_setTimer(LightCtrl* handle, const sc_eventid evid, const sc_integer time_ms, const sc_boolean periodic){

sc_timer_start(&timer_service, (void*) handle, evid, time_ms, periodic);

}

//! callback implementation for canceling time events.

void lightCtrl_unsetTimer(LightCtrl* handle, const sc_eventid evid) {

sc_timer_cancel(&timer_service, evid);

}

void lightCtrlIface_setLight(const LightCtrl* handle, const sc_boolean lightOn) {

if(lightOn)

digitalWrite(LED_PIN, HIGH);

else

digitalWrite(LED_PIN, LOW);

}

//The setup function is called once at startup of the sketch

void setup()

{

pinMode(BUTTON_PIN, INPUT);

pinMode(LED_PIN, OUTPUT);

sc_timer_service_init(

&timer_service,

timers,

MAX_TIMERS,

(sc_raise_time_event_fp) &lightCtrl_raiseTimeEvent

);

lightCtrl_init(&lightctrl); //initialize statechart

lightCtrl_enter(&lightctrl); //enter the statechart

}

// The loop function is called in an endless loop

void loop()

{

unsigned long current_millies = millis();

if(digitalRead(BUTTON_PIN))

lightCtrlIface_raise_button(&lightctrl);

if ( cycle_count == 0L || (current_millies 》= last_cycle_time + CYCLE_PERIOD) ) {

sc_timer_service_proceed(&timer_service, current_millies - last_cycle_time);

lightCtrl_runCycle(&lightctrl);

last_cycle_time = current_millies;

cycle_count++;

}

}

此外,請(qǐng)按行號(hào)在本要點(diǎn)中檢查代碼。

第1-6行包含如前所述的包含。

第8行和第9行定義了我們將要用于arduino的硬件引腳。

第11行和第12行定義了狀態(tài)圖可以使用多少個(gè)計(jì)時(shí)器,以及狀態(tài)圖的每個(gè)計(jì)算周期之間應(yīng)經(jīng)過(guò)多少毫秒。

第15和16行聲明了一些變量,我們可以用它們來(lái)計(jì)數(shù)周期并管理最后一個(gè)周期的時(shí)間。

第17、19和21行聲明了使用狀態(tài)圖的重要變量:狀態(tài)圖本身,計(jì)時(shí)器服務(wù)和計(jì)時(shí)器數(shù)組。

第24行和第33行定義了狀態(tài)圖需要計(jì)時(shí)器使用的功能,第33行是設(shè)置前面討論過(guò)的LED的功能。

在第41行中,void setup()是Arduino的標(biāo)準(zhǔn)功能。它在啟動(dòng)時(shí)被調(diào)用一次。我們用它來(lái)初始化東西–我們的LED和按鈕引腳配置了它們的方向(INPUT是標(biāo)準(zhǔn)的,為清楚起見(jiàn),我們這樣做了),計(jì)時(shí)器服務(wù)被初始化,狀態(tài)圖被初始化并輸入。輸入意味著啟動(dòng)狀態(tài)機(jī),因此第一個(gè)狀態(tài)被激活-這是輸入狀態(tài)所指向的狀態(tài)。因此,在啟動(dòng)時(shí),指示燈熄滅。

在第59行中,跟隨著循環(huán)功能,Arduino一直在調(diào)用它。

在第61行中,我們使用millis()函數(shù)捕獲當(dāng)前時(shí)間,該函數(shù)由Arduino庫(kù)定義。

在第63行中,我們檢查按鈕是否被按下,如果按下,則引發(fā)按鈕事件。

在第66行中,我們檢查自上次循環(huán)狀態(tài)圖以來(lái)是否已超過(guò)CYCLE_PERIOD毫秒。

這會(huì)給我們的arduino帶來(lái)一些負(fù)擔(dān),這意味著我們可以可靠地將長(zhǎng)達(dá)10毫秒的時(shí)間用于自己的功能。

在第68行中,我們告訴計(jì)時(shí)器服務(wù)自上次調(diào)用以來(lái)已經(jīng)過(guò)去了多少時(shí)間,在第70行中告訴statechart運(yùn)行一個(gè)周期,在第72行中保存當(dāng)前時(shí)間,并增加周期計(jì)數(shù)在第73行。

使用arduino插件,您現(xiàn)在可以將arduino與LED和連接到計(jì)算機(jī)的按鈕連接起來(lái),并使用頂部工具欄中的按鈕將程序上傳到

電路如圖2和圖3所示。

LED通過(guò)大約200歐姆的電阻連接到數(shù)字引腳(6)。陰極連接到GND。

按鈕有四個(gè)引腳,請(qǐng)?jiān)诎聪掳粹o時(shí)檢查其中哪些始終連接以及哪些連接。然后,將數(shù)字引腳(此處使用3)連接到一側(cè),將下拉電阻連接到GND。這將使引腳停止處于“浮動(dòng)”狀態(tài)(不確定狀態(tài)),并將其保持在0 V電壓。當(dāng)按下按鈕并將另一側(cè)連接到VCC時(shí),該側(cè)“更強(qiáng)”,因?yàn)樗鼪](méi)有電阻,并且電壓高達(dá)5伏–基本上是一個(gè)分壓器,其中一個(gè)電阻為0歐姆。請(qǐng)?jiān)诖耸褂靡粋€(gè)較高的電阻,因?yàn)樗鼤?huì)限制通過(guò)按鈕的電流。最小值為1 kR。

如您所見(jiàn),該程序的邏輯完全獨(dú)立于我們狀態(tài)圖的實(shí)際大小。狀態(tài)圖具有2個(gè)或20個(gè)狀態(tài)都沒(méi)有關(guān)系-當(dāng)然,如果我們想做點(diǎn)什么,我們需要在這里和那里實(shí)現(xiàn)一個(gè)功能。但是void loop()內(nèi)部的主要代碼總是很小,并且允許模塊化程序體系結(jié)構(gòu)。我們只需要在代碼中處理從狀態(tài)圖到Arduino硬件的接口,自動(dòng)生成的狀態(tài)圖將處理其內(nèi)部邏輯。還記得我們討論過(guò)如何在再次按下按鈕時(shí)重置計(jì)時(shí)器嗎?現(xiàn)在,您可以使用“按鈕”作為保護(hù)事件,從“點(diǎn)亮”狀態(tài)添加到其自身的過(guò)渡,而無(wú)需在代碼中更改或添加一行。嘗試一下,然后開(kāi)始對(duì)軟件進(jìn)行建模,而不是編寫它!

步驟7:此外:查找您的Arduino端口

因此,您陷入困境,因?yàn)槟鸁o(wú)法弄清Arduino連接到哪個(gè)串行/USB端口。好的,您會(huì)在下面找到有關(guān)Windows和Linux的說(shuō)明。

Windows

將arduino插入計(jì)算機(jī),然后轉(zhuǎn)到“設(shè)備和打印機(jī)”(從開(kāi)始菜單或系統(tǒng)控制面板)。如圖所示,您的arduino應(yīng)該出現(xiàn)在這里-對(duì)我來(lái)說(shuō),端口為COM12。這可能會(huì)改變,例如,當(dāng)您使用另一個(gè)USB端口時(shí),重新啟動(dòng)系統(tǒng)。..如果仍然無(wú)法解決問(wèn)題,請(qǐng)檢查是否仍然正確。

Linux

使用您的arduino未連接,啟動(dòng)終端。輸入 dmesg 并返回,這將為您提供冗長(zhǎng)的文本輸出。插入您的arduino,然后再次輸入 dmesg 。最后應(yīng)該是一些有關(guān)arduino的消息,包括一個(gè)端口-例如,/dev/USB0,/dev/ttyAMC3-可以理解。如果您插入arduino且LED不亮,并且 dmesg 在插入之前和之后都顯示完全相同的內(nèi)容,則很可能是您的Arduino吐司了。

如果此方法不適合您,也可以在插入Arduino之前和之后嘗試 ls/dev/。這列出了所有可用的設(shè)備,并且在連接Arduino之后應(yīng)該能夠看到一個(gè)新設(shè)備。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • fsm
    fsm
    +關(guān)注

    關(guān)注

    0

    文章

    35

    瀏覽量

    12831
  • Arduino
    +關(guān)注

    關(guān)注

    188

    文章

    6473

    瀏覽量

    187418
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Simulink中的狀態(tài)機(jī)建模方法 Simulink數(shù)據(jù)可視化與分析功能

    1. Simulink中的狀態(tài)機(jī)建模方法 1.1 理解狀態(tài)機(jī)的基本概念 在開(kāi)始建模之前,了解狀態(tài)機(jī)的基本概念是必要的。狀態(tài)機(jī)由以下幾個(gè)部分組成:
    的頭像 發(fā)表于 12-12 09:27 ?618次閱讀

    何在DRA821U使用Linux實(shí)現(xiàn)快速引導(dǎo)

    電子發(fā)燒友網(wǎng)站提供《如何在DRA821U使用Linux實(shí)現(xiàn)快速引導(dǎo).pdf》資料免費(fèi)下載
    發(fā)表于 09-03 10:11 ?0次下載
    如<b class='flag-5'>何在</b>DRA821U<b class='flag-5'>上</b>使用Linux<b class='flag-5'>實(shí)現(xiàn)</b>快速引導(dǎo)

    觸發(fā)器和狀態(tài)機(jī)的關(guān)系是什么

    觸發(fā)器和狀態(tài)機(jī)在數(shù)字電路設(shè)計(jì)中有著緊密的關(guān)系,它們共同構(gòu)成了時(shí)序邏輯電路的基礎(chǔ),用于實(shí)現(xiàn)數(shù)據(jù)的存儲(chǔ)、處理和傳輸。
    的頭像 發(fā)表于 08-12 11:24 ?501次閱讀

    何在FPGA中實(shí)現(xiàn)狀態(tài)機(jī)

    在FPGA(現(xiàn)場(chǎng)可編程門陣列)中實(shí)現(xiàn)狀態(tài)機(jī)是一種常見(jiàn)的做法,用于控制復(fù)雜的數(shù)字系統(tǒng)行為。狀態(tài)機(jī)能夠根據(jù)當(dāng)前的輸入和系統(tǒng)狀態(tài),決定下一步的動(dòng)作和新的狀態(tài)。這里,我們將詳細(xì)探討如
    的頭像 發(fā)表于 07-18 15:57 ?663次閱讀

    玩轉(zhuǎn)Spring狀態(tài)機(jī)

    說(shuō)起Spring狀態(tài)機(jī),大家很容易聯(lián)想到這個(gè)狀態(tài)機(jī)和設(shè)計(jì)模式中狀態(tài)模式的區(qū)別是啥呢?沒(méi)錯(cuò),Spring狀態(tài)機(jī)就是狀態(tài)模式的一種
    的頭像 發(fā)表于 06-25 14:21 ?986次閱讀
    玩轉(zhuǎn)Spring<b class='flag-5'>狀態(tài)機(jī)</b>

    關(guān)于SMU狀態(tài)機(jī)的問(wèn)題求解

    我有一些關(guān)于 SMU 狀態(tài)機(jī)的問(wèn)題。 假設(shè)由于某種原因,SMU 已進(jìn)入故障狀態(tài)。 手冊(cè)指出,要返回運(yùn)行狀態(tài)并將 FSP 恢復(fù)到無(wú)故障狀態(tài),應(yīng)調(diào)用IfxSmu_releaseFSP()。
    發(fā)表于 05-29 08:18

    用NUCLEO可以直接利用現(xiàn)有ARDUINO資源不?

    如題,對(duì)3D打印比較感興趣,不過(guò)不會(huì)用Arduino,所以問(wèn)問(wèn)大家,用NUCLEO可以直接利用現(xiàn)有ARDUINO資源不。
    發(fā)表于 05-15 07:13

    請(qǐng)問(wèn)STM32F051用了操作系統(tǒng)RTX后還需要寫狀態(tài)機(jī)不?

    現(xiàn)在學(xué)會(huì)了rtx操作系統(tǒng)后,原來(lái)用狀態(tài)機(jī)的學(xué)的程序,可不可以不切割,直接單線程來(lái)執(zhí)行列?各位前前輩指點(diǎn)一下。多謝!
    發(fā)表于 05-08 06:11

    在Verilog中實(shí)現(xiàn)Moore型和Mealy型狀態(tài)機(jī)的方法簡(jiǎn)析

    編寫能夠被綜合工具識(shí)別的狀態(tài)機(jī),首先需要理解狀態(tài)機(jī)的基本概念和分類。狀態(tài)機(jī)(FSM)是表示有限個(gè)狀態(tài)以及在這些
    的頭像 發(fā)表于 05-01 11:38 ?1735次閱讀

    嵌入式編程,如何用 C 語(yǔ)言實(shí)現(xiàn)狀態(tài)機(jī)設(shè)計(jì)?

    狀態(tài)機(jī)模式是一種行為模式,通過(guò)多態(tài)實(shí)現(xiàn)不同狀態(tài)的調(diào)轉(zhuǎn)行為的確是一種很好的方法,只可惜在嵌入式環(huán)境下,有時(shí)只能寫純C代碼,并且還需要考慮代碼的重入和多任務(wù)請(qǐng)求跳轉(zhuǎn)等情形,因此實(shí)現(xiàn)起來(lái)著實(shí)
    發(fā)表于 04-23 11:00

    求助LabVIEW,狀態(tài)機(jī)里面反饋節(jié)點(diǎn)如何初始化問(wèn)題

    求助labview,狀態(tài)機(jī)里面反饋節(jié)點(diǎn)如何初始化,下次執(zhí)行這個(gè)狀態(tài)的時(shí)候初始化一次!謝謝謝謝!
    發(fā)表于 03-25 18:17

    如何采用“狀態(tài)機(jī)”解析UART數(shù)據(jù)幀

    如果一個(gè)系統(tǒng)接收上述“不定長(zhǎng)度”的協(xié)議幀,將會(huì)有一個(gè)挑戰(zhàn)--如何高效接收與解析。 為簡(jiǎn)化系統(tǒng)設(shè)計(jì),我們強(qiáng)烈建議您采用“狀態(tài)機(jī)”來(lái)解析UART數(shù)據(jù)幀。
    的頭像 發(fā)表于 03-25 14:29 ?754次閱讀
    如何采用“<b class='flag-5'>狀態(tài)機(jī)</b>”解析UART數(shù)據(jù)幀

    請(qǐng)問(wèn)GPIF狀態(tài)機(jī)的內(nèi)部信號(hào)需要延遲才能斷言嗎?

    dma_wm_thn 這樣的過(guò)渡觸發(fā)器需要一些周期的延遲才能斷言嗎? 在我的實(shí)踐中,DMA_WM_THN 觸發(fā)器似乎有 1 個(gè)時(shí)鐘周期延遲: ? 圖像是我的狀態(tài)機(jī)的一部分,數(shù)據(jù)總線是 32 位
    發(fā)表于 02-23 07:43

    什么是有限狀態(tài)機(jī)?如何解決傳統(tǒng)有限狀態(tài)機(jī)狀態(tài)爆炸」問(wèn)題?

    有限狀態(tài)機(jī)(Finite State Machine,簡(jiǎn)稱FSM)是一種用來(lái)進(jìn)行對(duì)象行為建模的工具,其作用主要是描述對(duì)象在它的生命周期內(nèi)所經(jīng)歷的狀態(tài)序列以及如何響應(yīng)來(lái)自外界的各種事件。
    的頭像 發(fā)表于 02-17 16:09 ?6303次閱讀
    什么是<b class='flag-5'>有限狀態(tài)機(jī)</b>?如何解決傳統(tǒng)<b class='flag-5'>有限狀態(tài)機(jī)</b>「<b class='flag-5'>狀態(tài)</b>爆炸」問(wèn)題?

    Verilog狀態(tài)機(jī)+設(shè)計(jì)實(shí)例

    的是有限狀態(tài)機(jī)(Finite-State Machine,F(xiàn)SM),簡(jiǎn)稱為狀態(tài)機(jī),表示在有限個(gè)狀態(tài)以及這些狀態(tài)之間的轉(zhuǎn)移和動(dòng)作等行為的數(shù)學(xué)模
    的頭像 發(fā)表于 02-12 19:07 ?4250次閱讀
    Verilog<b class='flag-5'>狀態(tài)機(jī)</b>+設(shè)計(jì)實(shí)例