<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                * 導師視頻講解:[**去聽課**](https://www.bilibili.com/video/BV1k34y1D7Vz?p=24) >[success] **技術支持說明:** >**1**.一般以自主學習為主 > **2**.可到官方問答社區中提問:[**去提問**](https://bbs.csdn.net/forums/zigbee) > **3**.工程師**會盡快**解答社區問題,但他們是一線開發,【**難以保證**】解答時效,解答辛苦,感謝理解! <br/> 本節內容將以一個簡單的例子來說明任務的調度機制。 <br/> ## **基礎理論** 系統進行任務調度過程中涉及到任務、任務池、優先級、輪詢和系統調度周期幾個概念,接下來分別介紹一下這幾個概念。 * **任務(Task)**:可以理解為需要處理器處理的具體任務,例如“在1秒后開燈”或者“關燈”等等。 ### * **任務池**:是一個可以存儲多個任務的緩沖區,例如一個任務池中可以存放“1秒后開燈”、“2秒后關燈”、“3秒后開燈”及“1分鐘后關燈”這幾個任務。系統會在指定的時間去執行任務池中的各個任務。 ### * **優先級**:由于可能存在在同一個時刻需要執行多個任務的情況,所以需要區分在這個時刻優先處理哪些任務、延后處理哪些任務,而優先級是用來標記每一個任務的優先等級。在相同條件下,系統會優先處理高優先級的任務,同時低優先級的任務需要等待處理。另外,系統也可能會中斷優先級較底的任務,轉而去處理優先級較高的任務。 ### * **輪詢**:系統會**每隔一段時間**在任務池中檢查有沒有現在需要處理的任務,這個過程稱為輪詢。 ### * **操作系統調度周期**:調度周期是指輪詢概念中“**每隔一段時間**”的具體時間長度。系統調度周期也是任務的最小時間周期,例如系統調度周期是1秒鐘,但是存在一個任務是“0.1秒后關燈”,該任務雖然要求0.1秒后關燈,但由于0.1秒小于系統調度周期,所以這個任務在1秒后才會被執行。 <br/> ## **動手實現系統調度** **總體流程** 本節課配套的工程代碼如圖所示。 ![](https://img.kancloud.cn/f8/30/f83071b576a1ab69b872dd2fb53aaaba_380x294.png =200x) ### 打開main.c文件,其中的主函數代碼如下: ``` void main() { initLed();//初始化LED燈 taskListInit();//初始化任務池 addTask(2000, TASK_LED_ON);//往任務池中添加一個任務,即2s后打開LED addTask(3000, TASK_LED_OFF);//往任務池中添加一個任務,即3s后關閉LED //每隔1ms輪詢1次 while(1) { delayMs(1);//暫停1ms polling();//輪詢 } } ``` ### >[info] 上述代碼簡單地模擬了系統調度過程,其目的是為了讓讀者能更通俗地理解,難免會有些不夠嚴謹的地方。 在主函數中首先初始化了任務池,然后向任務池添加了兩個任務,分別是“2秒后開燈”和“3秒后關燈”,接著便進入了while循環。delayMs函數讓程序等待1毫秒后才接著運行,polling函數讓程序去查看有沒有需要處理的任務。就這樣,這段代碼實現了每隔1毫秒就去查看有沒有需要處理的任務,于是模擬了一個系統調度周期為1毫秒的系統輪詢。 <br/> #### **任務池的實現** 適用于任務池的數據結構有多種,比如隊列(先進先出)、堆棧(先進后出)和樹狀結構(遍歷)。這些數據結構的實現方式可以是靜態的數組或者是動態的鏈表等。為了便于讀者理解,此處使用靜態的數組作為任務池數據結構的實現。 ### 定義一個結構體來表示一個任務,代碼如下: ``` /** @brief 任務結構體的定義*/ typedef struct task_t { bool occupy;//是否已占用:true表示當前有任務;false表示當前沒有任務 uint16_t task;//任務內容 uint16_t expire;//等待時間 } task_t; ``` ### 于是我們可以定義一個結構體數組來表示任務池,代碼如下: ``` /** @brief 任務池的定義 */ #define TASK_LIST_SIZE 5 static task_t taskList_g[TASK_LIST_SIZE]; ``` 接著,我們定義4個API來操作任務池。 ### **1. taskListInit(void)** 任務池初始化函數taskListInit(void)把數組中的的每個元素的occupy值設置為false,表示該元素沒有存放任務,代碼如下: ``` /* * 任務池初始化 */ static void taskListInit() { //把所有任務都設置為未使用 for (uint16_t i = 0; i < TASK_LIST_SIZE; i++) taskList_g[i].occupy = false; } ``` ### **2. addTask(uint16_t?expire,?uint16_t?event)** 增加任務函數addTask首先查找整個數組看看有沒有沒被占用(occupy=false)的元素。如果找到了,把任務信息保存到該數組元素中,并把標志位occupy設置為“占用”(occupy=true),代碼如下: ``` /* * 往任務池中添加任務 * @param expire 延遲多久執行 * @param task 任務內容 */ static void addTask(uint16_t expire, uint16_t task) { for (uint16_t i = 0; i < TASK_LIST_SIZE; i++) { if(taskList_g[i].occupy) continue; taskList_g[i].task = task; taskList_g[i].expire = expire; taskList_g[i].occupy = true; break; } } ``` ### **3. polling()** 輪詢函數polling查找整個數組,看看有沒有數組元素被“占用”且對應的任務到期。如有,則處理該任務,并在處理后釋放該數組元素控件,即把occupy設置為false,代碼如下: ``` /* * 輪詢 */ static void polling() { for (uint16_t i = 0; i < (sizeof(taskList_g)/sizeof(taskList_g[0])); i++) if (taskList_g[i].occupy && (--taskList_g[i].expire == 0)) { //執行任務 taskHandler(taskList_g[i].task); //釋放任務池中的空間 taskList_g[i].occupy = false; } } ``` 其中,每執行一次for循環expire的值都會自減1,如果expire的值減至0表示該任務已經到時間執行了,便調用任務處理函數執行任務。另外,由于在任務池前面的任務會被優先遍歷并被執行,因此越靠前的任務的優先級也就越高了。 ### **4. taskHandler(uint16_t task)** 任務處理函數taskHandler(uint16\_t task)的工作內容是根據各個任務內容來進行相應的處理。需要注意的是,我們在處理完對應的任務后,又重新往任務池添加了新的任務,比如TASK\_LED\_ON也就是開LED,然后我們又設置了TASK\_LED\_OFF任務,從而達到周期性任務的效果,代碼如下: ``` /* * 執行指定的任務 * * @param task 任務 */ static void taskHandler(uint16_t task) { /* 根據指定的任務,執行對應的操作 */ if (task == TASK_LED_ON) { LED = LED_ON;//開燈 printf("Set Led On!\n"); //執行完任務后,重新往任務池中添加一個開燈任務 addTask(2000, TASK_LED_ON); } else if(task == TASK_LED_OFF) { LED = LED_OFF;//關燈 printf("Set Led Off!\n"); //執行完任務后,重新往任務池中添加一個關燈任務 addTask(2000, TASK_LED_OFF); } } ``` <br/> ## **調試仿真** 單擊集成開發環境IAR 10.10.1中的Download and Debug按鈕進行程序的編譯、鏈接和下載并進入仿真模式,如圖所示。 ![](https://img.kancloud.cn/5d/fc/5dfc616049266d2b1444a8b72b578273_2560x646.png =600x) 進入仿真模式之后,單擊Go按鈕運行程序,如圖所示。 ![](https://img.kancloud.cn/cf/5f/cf5fa458755a09195f984335fc03cc43_2560x828.png =200x) 程序運行后,可以看到在Terminal I/O窗口中交替輸出Set Led On和Set Led Off,如圖所示。 ![](https://img.kancloud.cn/57/22/5722b099513c11dabe96260477440733_1000x564.png =200x) <br/> <br/> ## **項目定制** * 如需項目定制開發,可掃碼添加項目經理好友(注明“**項目定制**”) * 定制范圍:**NB-IoT**、**CATn(4G)**、**WiFi**、**ZigBee**、**BLE Mesh**以及**STM32**、**嵌入式Linux**等IoT技術方案 * 善學坊官網:[www.sxf-iot.com](https://www.sxf-iot.com/) ![](https://img.kancloud.cn/ca/73/ca739f92cab220a3059378642e3bd502_430x430.png =200x) * 非項目定制**勿擾**,此處**非**技術支持
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看