RM新时代网站-首页

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

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

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

如何使用Arduino millis函數(shù)執(zhí)行多任務處理

科技觀察員 ? 來源:circuitdigest ? 作者:Abhimanyu Pandit ? 2022-09-06 14:41 ? 次閱讀

多任務處理將計算機帶入了一場革命,其中一個或多個程序可以同時運行,從而提高了效率、靈活性、適應性和生產(chǎn)力。在嵌入式系統(tǒng)中,微控制器還可以處理多任務并同時執(zhí)行兩個或多個任務,而不會停止當前指令。

在本教程中,我們將學習Arduino 如何使用 Arduino millis 函數(shù)執(zhí)行多任務處理。通常在 Arduino 中使用delay()函數(shù)來執(zhí)行LED 閃爍等周期性任務,但此 delay() 函數(shù)會暫停程序一段確定的時間,并且不允許執(zhí)行其他操作。所以這篇文章解釋了我們?nèi)绾伪苊馐褂?delay() 函數(shù)并將其替換為 millis()以同時執(zhí)行多個任務并使 Arduino 成為一個多任務控制器。

什么是多任務處理?

多任務處理只是意味著同時執(zhí)行多個任務或程序。幾乎所有操作系統(tǒng)都具有多任務處理功能。這種操作系統(tǒng)被稱為MOS(多任務操作系統(tǒng))。MOS 可以是移動或桌面 PC 操作系統(tǒng)。計算機中多任務處理的一個很好的例子是,當用戶同時運行電子郵件應用程序、互聯(lián)網(wǎng)瀏覽器、媒體播放器、游戲時,如果用戶不想使用該應用程序,如果不關(guān)閉,它就會在后臺運行。最終用戶同時使用所有這些應用程序,但操作系統(tǒng)采用這個概念有點不同。讓我們討論一下操作系統(tǒng)如何管理多任務。

pYYBAGMW60iAYtxhAABWB9UQiL8404.png

如圖所示,CPU 將時間分成三個相等的部分,并將每個部分分配給每個任務/應用程序。這就是大多數(shù)系統(tǒng)中多任務處理的方式。Arduino Multitasking的概念幾乎相同,只是時間分布會有所不同。由于 Arduino 與筆記本電腦/手機/PC 相比以低頻運行且 RAM 運行,因此分配給每個任務的時間也會有所不同。Arduino 還有一個廣泛使用的delay()函數(shù)。但在開始之前,讓我們討論一下為什么我們不應該在任何項目中使用delay()函數(shù)。

為什么要使用 millis() ?

為了克服使用延遲帶來的問題,開發(fā)人員應該使用millis()函數(shù),一旦你習慣了它就很容易使用,它會使用100%的CPU性能而不會在執(zhí)行指令時產(chǎn)生任何延遲。millis()是一個函數(shù),它只返回自 Arduino 板開始運行當前程序而不凍結(jié)程序以來經(jīng)過的毫秒數(shù)。大約 50 天后,該時間數(shù)將溢出(即回到零)。

就像Arduino有delayMicroseconds()一樣,它也有micro版本的millis()作為micros()。micros 和 millis 之間的區(qū)別在于,micros() 將在大約 70 分鐘后溢出,而 millis() 則為 50 天。因此,根據(jù)應用程序,您可以使用millis() 或micros()。

使用毫秒()而不是延遲():

要使用millis()進行計時和延遲,您需要記錄并存儲動作發(fā)生的時間以開始時間,然后每隔一段時間檢查定義的時間是否已經(jīng)過去。如前所述,將當前時間存儲在一個變量中。

無符號長 currentMillis = millis();

我們需要另外兩個變量來確定是否已經(jīng)過了所需的時間。我們已將當前時間存儲在currentMillis變量中,但我們還需要知道計時周期何時開始以及該周期有多長。因此聲明了 Interval 和previousMillis。間隔將告訴我們時間延遲,previosMillis 將存儲事件最后發(fā)生的時間。

unsigned long previousMillis; 
無符號長周期 = 1000;

為了理解這一點,讓我們以一個簡單的閃爍 LED 為例。period = 1000 將告訴我們 LED 將閃爍 1 秒或 1000 毫秒。

常量 int ledPin = 4; // 連接的 LED 引腳號
int ledState = LOW; // 用于設(shè)置 LED 狀態(tài)
unsigned long previousMillis = 0; //將存儲上次 LED 閃爍的時間
const long period = 1000; // 以毫秒為單位閃爍的周期

void setup() { 
  pinMode(ledPin, OUTPUT); // 將 ledpin 設(shè)置為輸出
}
 
void loop() { 
unsigned long currentMillis = millis(); // 存儲當前時間
  if (currentMillis - previousMillis >= period) { // 檢查是否經(jīng)過了 1000ms 
   previousMillis = currentMillis; // 保存上次閃爍 LED 的時間
   if (ledState == LOW) { // 如果 LED 關(guān)閉,則將其打開,反之亦然
     ledState = HIGH; 
   } 其他 { 
ledState = 低;
} 
   digitalWrite(ledPin, ledState);//設(shè)置帶ledState的LED再次閃爍
} 
}

在這里,語句《if (currentMillis - previousMillis 》= period)》檢查 1000 毫秒是否已過。如果 1000 毫秒過去了,則 LED 閃爍并再次進入相同狀態(tài)。這種情況還在繼續(xù)。就是這樣,我們已經(jīng)學會了使用毫秒而不是延遲。這樣它就不會在特定的時間間隔內(nèi)停止程序。

Arduino 中的中斷與其他微控制器中的工作方式相同。Arduino UNO 板有兩個獨立的引腳,用于在 GPIO 引腳 2 和 3 上附加中斷。我們在Arduino 中斷教程中詳細介紹了它,您可以在其中了解有關(guān)中斷及其使用方法的更多信息。

在這里,我們將通過同時處理兩個任務來展示 Arduino 多任務處理。這些任務將包括兩個 LED 以不同的時間延遲閃爍以及一個按鈕,該按鈕將用于控制 LED 的開/關(guān)狀態(tài)。所以三個任務將同時執(zhí)行。

poYBAGMW60KALgZpAATs0CDzeeE572.png

所需組件

Arduino UNO

三個 LED(任何顏色)

電阻(470、10k)

跳線

面包板

電路原理

演示使用Arduino Millis() 函數(shù)的電路圖 非常簡單,無需附加太多組件,如下所示。

poYBAGMW6zuABeMrAACZlx-F4jI138.png

為多任務處理編程 Arduino UNO

為多任務編程 Arduino UNO 只需要上面解釋的 millis() 工作原理背后的邏輯。建議在開始對 Arduino UNO 進行多任務編程之前,一次又一次地練習使用millis閃爍 LED ,以使邏輯清晰并讓自己對 millis() 感到滿意。在本教程中,中斷還與 millis() 同時用于多任務處理。該按鈕將是一個中斷。因此,只要產(chǎn)生中斷,即按下按鈕,LED 就會切換到 ON 或 OFF 狀態(tài)。

編程從聲明連接 LED 和按鈕的引腳號開始。

詮釋 led1 = 6; 
詮釋 led2 = 7; 
int toggleLed = 5; 
int 按鈕 = 2;

接下來我們編寫一個變量來存儲 LED 的狀態(tài)以備將來使用。

詮釋 ledState1 = 低;
詮釋 ledState2 = 低;

正如上面閃爍示例中所解釋的,period 和 previousmillis 的變量被聲明為比較并為 LED 生成延遲。第一個 LED 每 1 秒閃爍一次,另一個 LED 在 200ms 后閃爍。

unsigned long previousMillis1 = 0; 
常量長周期1 = 1000;
unsigned long previousMillis2 = 0; 
常量長周期2 = 200;

另一個毫秒函數(shù)將用于生成去抖動延遲,以避免多次按下按鈕。將有與上述類似的方法。

int debouncePeriod = 20;  
int debounceMillis = 0;

這三個變量將用于存儲按鈕的狀態(tài)為中斷、切換 LED 和按鈕狀態(tài)。

bool buttonPushed = false; 
int ledChange = 低;  
詮釋最后狀態(tài)=高;

定義引腳的動作,哪個引腳將作為 INPUT 或 OUTPUT 工作。

  pinMode(led1,輸出);             
  pinMode(led2,輸出);
  pinMode(toggleLed,輸出);
  pinMode(按鈕,輸入);

現(xiàn)在通過附加中斷與 ISR 和中斷模式的定義來定義中斷引腳。請注意,建議在聲明attachInterrupt()函數(shù)時使用digitalPinToInterrupt(pin_number)將實際的數(shù)字引腳轉(zhuǎn)換為特定的中斷號。

attachInterrupt(digitalPinToInterrupt(pushButton), pushButton_ISR, CHANGE);

中斷子程序被編寫,它只會改變buttonPushed標志。需要注意的是,中斷子程序要盡可能的短,所以盡量寫,盡量減少多余的指令。

無效 pushButton_ISR() 
{ 
  buttonPushed = true; 
}

循環(huán)首先將毫秒值存儲在 currentMillis 變量中,該變量將存儲每次循環(huán)迭代時經(jīng)過的時間值。

無符號長 currentMillis = millis();

多任務處理共有三個功能,1 秒閃爍一個 LED,200 毫秒閃爍第二個 LED,如果按下按鈕,則關(guān)閉/打開 LED。所以我們將寫三個部分來完成這個任務。

第一個是通過比較經(jīng)過的毫秒數(shù)每 1 秒切換一次 LED 狀態(tài)。

if (currentMillis - previousMillis1 >= period1) { 
    previousMillis1 = currentMillis;  
    如果(ledState1 == 低){ 
      ledState1 = 高;
    } 其他 { 
      ledState1 = 低;
    } 
    digitalWrite(led1, ledState1);   
  }

類似地,第二次它通過比較經(jīng)過的毫秒數(shù)每 200 毫秒后切換一次 LED。解釋已經(jīng)在本文前面進行了解釋。

  if (currentMillis - previousMillis2 >= period2) { 
    previousMillis2 = currentMillis;  
    如果(ledState2 == 低){ 
      ledState2 = 高;
    } 其他 { 
      ledState2 = 低;
    } 
    digitalWrite(led2, ledState2); 
  }

最后,buttonPushed標志被監(jiān)控??,在產(chǎn)生 20ms 的去抖動延遲后,它只是切換 LED 的狀態(tài),對應于作為中斷附加的按鈕。

  if (buttonPushed = true) // 檢查是否調(diào)用了 ISR 
  { 
    if ((currentMillis - debounceMillis) > debouncePeriod && buttonPushed) // 產(chǎn)生 20ms 的去抖延遲以避免多次按下
    { 
      debounceMillis = currentMillis; // 保存最后的去抖動延遲時間
      if (digitalRead(pushButton) == LOW && lastState == HIGH) // 按下按鈕后改變LED 
      { 
        ledChange = ! 領(lǐng)導改變;
        digitalWrite(toggleLed, ledChange);   
        最后狀態(tài) = 低;
      } 
      else if (digitalRead(pushButton) == HIGH && lastState == LOW)     
      { 
        lastState = HIGH; 
      } 
     buttonPushed = 假;
    } 
  }

這樣就完成了Arduino millis?() 教程。請注意,為了習慣使用millis(),只需練習在其他一些應用程序中實現(xiàn)此邏輯即可。

/* 使用 Arduino millis() 函數(shù)進行多任務處理

作者:CircuitDigest (circuitdigest.com)

*/


詮釋 led1 = 6; // led1 連接在引腳 6

int led2 = 7; // led1 連接在引腳 7

int toggleLed = 5; // 按鈕控制的 LED 連接在引腳 5

int pushButton = 2; // 將按鈕連接到引腳 2,這也是中斷引腳


詮釋 ledState1 = 低;// 判斷 led1 和 led2 的狀態(tài)

int ledState2 = LOW;


unsigned long previousMillis1 = 0; //存儲上次 LED1 閃爍的時間

const long period1 = 1000; // led1 閃爍的時間,單位為 ms


unsigned long previousMillis2 = 0; //存儲上次 LED2 閃爍的時間

const long period2 = 200; // led1 閃爍的時間,單位為 ms


int debouncePeriod = 20; // 20ms 的去抖動延遲

int debounceMillis = 0; // 類似于previousMillis


bool buttonPushed = false; // 中斷例程按鈕狀態(tài)

int ledChange = LOW; // 跟蹤 LED 狀態(tài) last

int lastState = HIGH; // 跟蹤最后一個按鈕狀態(tài)



無效設(shè)置(){

pinMode(led1,輸出);// 將引腳定義為輸入或輸出

pinMode(led2, OUTPUT);

pinMode(toggleLed,輸出);

pinMode(按鈕,輸入);

attachInterrupt(digitalPinToInterrupt(pushButton), pushButton_ISR, CHANGE); // 使用中斷 pin2

}


無效 pushButton_ISR()

{

buttonPushed = true; // ISR 應該盡可能短

}


void loop() {

unsigned long currentMillis = millis(); // 存儲當前時間


if (currentMillis - previousMillis1 >= period1) { // 檢查是否經(jīng)過了 1000ms

previousMillis1 = currentMillis; // 保存上次閃爍 LED 的時間

if (ledState1 == LOW) { // 如果 LED 關(guān)閉,則將其打開,反之亦然

ledState1 = HIGH; //更改下一次迭代的 LED 狀態(tài)

} else {

ledState1 = LOW;

}

digitalWrite(led1, ledState1); //用ledState設(shè)置LED再次閃爍

}


if (currentMillis - previousMillis2 >= period2) { // 檢查是否經(jīng)過了 1000ms

previousMillis2 = currentMillis; // 保存上次閃爍 LED 的時間

if (ledState2 == LOW) { // 如果 LED 關(guān)閉,則將其打開,反之亦然

ledState2 = HIGH;

} 其他 {

ledState2 = 低;

}

digitalWrite(led2, ledState2);//設(shè)置帶ledState的LED再次閃爍

}


if (buttonPushed = true) // 檢查是否調(diào)用了 ISR

{

if ((currentMillis - debounceMillis) > debouncePeriod && buttonPushed) // 產(chǎn)生 20ms 的去抖延遲以避免多次按下

{

debounceMillis = currentMillis; // 保存最后的去抖動延遲時間

if (digitalRead(pushButton) == LOW && lastState == HIGH) // 按下按鈕后改變LED

{

ledChange = ! 領(lǐng)導改變;

digitalWrite(toggleLed, ledChange);

最后狀態(tài) = 低;

}

else if (digitalRead(pushButton) == HIGH && lastState == LOW)

{

lastState = HIGH;

}

buttonPushed = 假;

}

}

}

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

    關(guān)注

    3

    文章

    4327

    瀏覽量

    62569
  • Arduino
    +關(guān)注

    關(guān)注

    188

    文章

    6468

    瀏覽量

    186952
  • 多任務處理
    +關(guān)注

    關(guān)注

    0

    文章

    2

    瀏覽量

    4790
收藏 人收藏

    評論

    相關(guān)推薦

    關(guān)于多任務處理的問題

    本帖最后由 mr.pengyongche 于 2013-4-30 03:08 編輯 我用DSP6713BIOS做多任務處理,一個硬中斷,一個軟中斷,一個任務任務優(yōu)先級最低,作為
    發(fā)表于 07-10 16:11

    多任務編程多任務處理是指什么

    嵌入式Linux應用編程-多任務編程多任務處理是指用戶可在同一時間內(nèi)運行多個應用程序,每個正在執(zhí)行的應用程序被稱為一個任務。Linux就是一
    發(fā)表于 12-22 08:30

    任務裸機系統(tǒng)與多任務系統(tǒng)的區(qū)別在哪

    總體概述與任務裸機系統(tǒng)與多任務系統(tǒng)的區(qū)別任務的定義與切換裸機系統(tǒng)與多任務系統(tǒng)的區(qū)別裸機系統(tǒng)包括輪詢系統(tǒng),前后臺系統(tǒng)輪詢系統(tǒng):在進行初始化過后,循環(huán)執(zhí)
    發(fā)表于 02-18 07:03

    什么是多任務系統(tǒng)?FreeRTOS任務與協(xié)程簡析

    功能,初學者必須先掌握——任務的創(chuàng)建、刪除、掛起和恢復等操作。本章節(jié)分為如下幾部分:*什么是多任務系統(tǒng)*FreeRTOS任務與協(xié)程*初次使用*任務狀態(tài)*
    發(fā)表于 02-18 06:38

    【晶心科技ADP-Corvette-T1開發(fā)板試用體驗】corvette T1的多任務調(diào)度學習

    arduino多任務并行首先是聲明自己的回調(diào)函數(shù)void t1Callback();void t2Callback();void t3Callback();然后創(chuàng)建任務也就是Task的
    發(fā)表于 07-10 23:36

    多任務系統(tǒng)中的堆棧使用

    現(xiàn)場及保存任務上下文(CPU寄存器)。在多任務處理開始之前執(zhí)行的C代碼將使用C棧。只有當應用程序的第一個任務開始運行時,棧才會從C棧中轉(zhuǎn)移到
    發(fā)表于 01-05 13:52

    使用<cont.h>進行協(xié)作式多任務處理?

    編程,但我是電子產(chǎn)品的菜鳥,所以我很高興它運行得很好)并且想要某種協(xié)作的多任務處理框架來管理它。我真的很喜歡但我無法讓它工作。即使在玩弄 Arduino 鏈接器參數(shù)時,我也沒有運氣。我查看了其他幾個庫,但我
    發(fā)表于 02-23 06:57

    求助,有沒有人能夠?qū)崿F(xiàn)協(xié)作式多任務處理

    當前實現(xiàn)的“多任務Arduino-on-ESP8266 才能為二進制文件的 RF 部分提供服務;這意味著使用 delay(0) 或 yield() 或確保 loop() 函數(shù)完成時間不超過
    發(fā)表于 02-24 06:35

    51單片機多任務同時執(zhí)行

    51單片機多任務同時執(zhí)行。RTX51 Tiny是一種實時操作系統(tǒng)(RTOS),可以用它來建立多個任務函數(shù))同時執(zhí)行的應用(從宏觀上看是同時
    發(fā)表于 08-03 16:58

    arduino平臺millis()函數(shù)有什么作用?

    有關(guān)arduino平臺millis()函數(shù),有什么作用?
    發(fā)表于 10-20 06:30

    uCOS-II多任務編程設(shè)計

    uCOS-II多任務編程設(shè)計方法,在用戶任務函數(shù)中,必須包含至少一次對操作系統(tǒng)服務函數(shù)的調(diào)用,否則比其優(yōu)先級低的任務將無法得到運行機會,這是
    發(fā)表于 10-27 15:25 ?8次下載
    uCOS-II<b class='flag-5'>多任務</b>編程設(shè)計

    如何使用51單片機進行多任務機制及應用

    傳統(tǒng)的單片機程序一般采用單任務機制,單任務系統(tǒng)具有簡單直觀、易于控制的優(yōu)點。然而由于程序只能按順序依次執(zhí)行,缺乏靈活性,只能使用中斷函數(shù)實時地處理
    發(fā)表于 04-15 18:24 ?8次下載
    如何使用51單片機進行<b class='flag-5'>多任務</b>機制及應用

    使用millis函數(shù)作為使用延遲的替代方法

    電子發(fā)燒友網(wǎng)站提供《使用millis函數(shù)作為使用延遲的替代方法.zip》資料免費下載
    發(fā)表于 10-18 09:50 ?0次下載
    使用<b class='flag-5'>millis</b><b class='flag-5'>函數(shù)</b>作為使用延遲的替代方法

    PicoSem:Arduino框架下的Raspberry多任務

    電子發(fā)燒友網(wǎng)站提供《PicoSem:Arduino框架下的Raspberry多任務.zip》資料免費下載
    發(fā)表于 06-13 09:21 ?1次下載
    PicoSem:<b class='flag-5'>Arduino</b>框架下的Raspberry<b class='flag-5'>多任務</b>

    Arduino上的多任務處理

    電子發(fā)燒友網(wǎng)站提供《Arduino上的多任務處理.zip》資料免費下載
    發(fā)表于 06-14 11:05 ?0次下載
    <b class='flag-5'>Arduino</b>上的<b class='flag-5'>多任務</b><b class='flag-5'>處理</b>
    RM新时代网站-首页