99精品伊人亚洲|最近国产中文炮友|九草在线视频支援|AV网站大全最新|美女黄片免费观看|国产精品资源视频|精彩无码视频一区|91大神在线后入|伊人终合在线播放|久草综合久久中文

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

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

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

單片機(jī)程序時(shí)間輪片法框架

strongerHuang ? 來(lái)源:ERYUESANHI ? 作者:ERYUESANHI ? 2021-08-26 11:07 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

來(lái)源 | ERYUESANHI

編排 | strongerHuang

今天分享一篇單片機(jī)程序框架的文章。

程序架構(gòu)重要性

很多人尤其是初學(xué)者在寫代碼的時(shí)候往往都是想一點(diǎn)寫一點(diǎn),最開(kāi)始沒(méi)有一個(gè)整體的規(guī)劃,導(dǎo)致后面代碼越寫越亂,bug不斷。

最終代碼跑起來(lái)看似沒(méi)有問(wèn)題(有可能也真的沒(méi)有問(wèn)題),但是要加一個(gè)功能的時(shí)候會(huì)浪費(fèi)大量的時(shí)間,甚至導(dǎo)致整個(gè)代碼的崩潰。

所以,在一個(gè)項(xiàng)目開(kāi)始的時(shí)候多花一些時(shí)間在代碼的架構(gòu)設(shè)計(jì)上是十分有必要的。代碼架構(gòu)確定好了之后你會(huì)發(fā)現(xiàn)敲代碼的時(shí)候會(huì)特別快,并且在后期調(diào)試的時(shí)候也不會(huì)像無(wú)頭蒼蠅一樣胡亂找問(wèn)題。當(dāng)然,調(diào)試也是一門技術(shù)。

在學(xué)習(xí)實(shí)時(shí)操作系統(tǒng)的過(guò)程中,發(fā)現(xiàn)實(shí)時(shí)操作系統(tǒng)框架與個(gè)人的業(yè)務(wù)代碼之間的耦合性就非常低,都是只需要將業(yè)務(wù)代碼通過(guò)一定的接口函數(shù)注冊(cè)好后就交給操作系統(tǒng)托管了,十分方便。

但是操作系統(tǒng)的調(diào)度過(guò)于復(fù)雜,這里就使用操作系統(tǒng)的思維方式來(lái)重構(gòu)這個(gè)時(shí)間片輪詢框架。實(shí)現(xiàn)該框架的完全解耦,用戶只需要包含頭文件,并且在使用過(guò)程中不需要改動(dòng)已經(jīng)寫好的庫(kù)文件。

Demo

首先來(lái)個(gè)demo,該demo是使用電腦開(kāi)兩個(gè)線程:一個(gè)線程模擬單片機(jī)的定時(shí)器中斷產(chǎn)生時(shí)間片輪詢個(gè)時(shí)鐘,另一個(gè)線程則模擬主函數(shù)中一直運(yùn)行的時(shí)間片輪詢調(diào)度程序。

#include 《thread》#include 《stdio.h》#include 《windows.h》#include “timeslice.h”

// 創(chuàng)建5個(gè)任務(wù)對(duì)象TimesilceTaskObj task_1, task_2, task_3, task_4, task_5;

// 具體的任務(wù)函數(shù)void task1_hdl(){ printf(“》》 task 1 is running 。..

”);}

void task2_hdl(){ printf(“》》 task 2 is running 。..

”);}

void task3_hdl(){ printf(“》》 task 3 is running 。..

”);}

void task4_hdl(){ printf(“》》 task 4 is running 。..

”);}

void task5_hdl(){ printf(“》》 task 5 is running 。..

”);}

// 初始化任務(wù)對(duì)象,并且將任務(wù)添加到時(shí)間片輪詢調(diào)度中void task_init(){ timeslice_task_init(&task_1, task1_hdl, 1, 10); timeslice_task_init(&task_2, task2_hdl, 2, 20); timeslice_task_init(&task_3, task3_hdl, 3, 30); timeslice_task_init(&task_4, task4_hdl, 4, 40); timeslice_task_init(&task_5, task5_hdl, 5, 50); timeslice_task_add(&task_1); timeslice_task_add(&task_2); timeslice_task_add(&task_3); timeslice_task_add(&task_4); timeslice_task_add(&task_5);}

// 開(kāi)兩個(gè)線程模擬在單片機(jī)上的運(yùn)行過(guò)程void timeslice_exec_thread(){ while (true) { timeslice_exec(); }}

void timeslice_tick_thread(){ while (true) { timeslice_tick(); Sleep(10); }}

int main(){ task_init();

printf(“》》 task num: %d

”, timeslice_get_task_num()); printf(“》》 task len: %d

”, timeslice_get_task_timeslice_len(&task_3));

timeslice_task_del(&task_2); printf(“》》 delet task 2

”); printf(“》》 task 2 is exist: %d

”, timeslice_task_isexist(&task_2));

printf(“》》 task num: %d

”, timeslice_get_task_num());

timeslice_task_del(&task_5); printf(“》》 delet task 5

”);

printf(“》》 task num: %d

”, timeslice_get_task_num());

printf(“》》 task 3 is exist: %d

”, timeslice_task_isexist(&task_3)); timeslice_task_add(&task_2); printf(“》》 add task 2

”); printf(“》》 task 2 is exist: %d

”, timeslice_task_isexist(&task_2));

timeslice_task_add(&task_5); printf(“》》 add task 5

”);

printf(“》》 task num: %d

”, timeslice_get_task_num());

printf(“

========timeslice running===========

”);

std::thread thread_1(timeslice_exec_thread); std::thread thread_2(timeslice_tick_thread);

thread_1.join(); thread_2.join();

return 0;}

由以上例子可見(jiàn),這個(gè)框架使用十分方便,甚至可以完全不知道其原理,僅僅通過(guò)幾個(gè)簡(jiǎn)單的接口就可以迅速創(chuàng)建任務(wù)并加入到時(shí)間片輪詢的框架中,十分好用。

時(shí)間片輪詢架構(gòu)

其實(shí)該部分主要使用了面向?qū)ο蟮乃季S,使用結(jié)構(gòu)體作為對(duì)象,并使用結(jié)構(gòu)體指針作為參數(shù)傳遞,這樣作可以節(jié)省資源,并且有著極高的運(yùn)行效率。

其中最難的部分是侵入式鏈表的使用,這種鏈表在一些操作系統(tǒng)內(nèi)核中使用十分廣泛,這里是參考RT-Thread實(shí)時(shí)操作系統(tǒng)中的侵入式鏈表實(shí)現(xiàn)。

h文件:

#ifndef _TIMESLICE_H#define _TIMESLICE_H

#include “。/list.h”

typedef enum { TASK_STOP, TASK_RUN} IsTaskRun;

typedef struct timesilce{ unsigned int id; void (*task_hdl)(void); IsTaskRun is_run; unsigned int timer; unsigned int timeslice_len; ListObj timeslice_task_list;} TimesilceTaskObj;

void timeslice_exec(void);void timeslice_tick(void);void timeslice_task_init(TimesilceTaskObj* obj, void (*task_hdl)(void), unsigned int id, unsigned int timeslice_len);void timeslice_task_add(TimesilceTaskObj* obj);void timeslice_task_del(TimesilceTaskObj* obj);unsigned int timeslice_get_task_timeslice_len(TimesilceTaskObj* obj);unsigned int timeslice_get_task_num(void);unsigned char timeslice_task_isexist(TimesilceTaskObj* obj);

#endif

c文件:

#include “。/timeslice.h”

static LIST_HEAD(timeslice_task_list);

void timeslice_exec(){ ListObj* node; TimesilceTaskObj* task;

list_for_each(node, ×lice_task_list) { task = list_entry(node, TimesilceTaskObj, timeslice_task_list); if (task-》is_run == TASK_RUN) { task-》task_hdl(); task-》is_run = TASK_STOP; } }}

void timeslice_tick(){ ListObj* node; TimesilceTaskObj* task;

list_for_each(node, ×lice_task_list) { task = list_entry(node, TimesilceTaskObj, timeslice_task_list); if (task-》timer != 0) { task-》timer--; if (task-》timer == 0) { task-》is_run = TASK_RUN; task-》timer = task-》timeslice_len; } } }}

unsigned int timeslice_get_task_num(){ return list_len(×lice_task_list);}

void timeslice_task_init(TimesilceTaskObj* obj, void (*task_hdl)(void), unsigned int id, unsigned int timeslice_len){ obj-》id = id; obj-》is_run = TASK_STOP; obj-》task_hdl = task_hdl; obj-》timer = timeslice_len; obj-》timeslice_len = timeslice_len;}

void timeslice_task_add(TimesilceTaskObj* obj){ list_insert_before(×lice_task_list, &obj-》timeslice_task_list);}

void timeslice_task_del(TimesilceTaskObj* obj){ if (timeslice_task_isexist(obj)) list_remove(&obj-》timeslice_task_list); else return;}

unsigned char timeslice_task_isexist(TimesilceTaskObj* obj){ unsigned char isexist = 0; ListObj* node; TimesilceTaskObj* task;

list_for_each(node, ×lice_task_list) { task = list_entry(node, TimesilceTaskObj, timeslice_task_list); if (obj-》id == task-》id) isexist = 1; }

return isexist;}

unsigned int timeslice_get_task_timeslice_len(TimesilceTaskObj* obj){ return obj-》timeslice_len;}

底層侵入式雙向鏈表

該鏈表是linux內(nèi)核中使用十分廣泛,也十分經(jīng)典,其原理具體可以參考文章:https://www.cnblogs.com/skywang12345/p/3562146.html

h文件:

#ifndef _LIST_H#define _LIST_H

#define offset_of(type, member) (unsigned long) &((type*)0)-》member#define container_of(ptr, type, member) ((type *)((char *)(ptr) - offset_of(type, member)))

typedef struct list_structure{ struct list_structure* next; struct list_structure* prev;} ListObj;

#define LIST_HEAD_INIT(name) {&(name), &(name)}#define LIST_HEAD(name) ListObj name = LIST_HEAD_INIT(name)

void list_init(ListObj* list);void list_insert_after(ListObj* list, ListObj* node);void list_insert_before(ListObj* list, ListObj* node);void list_remove(ListObj* node);int list_isempty(const ListObj* list);unsigned int list_len(const ListObj* list);

#define list_entry(node, type, member) container_of(node, type, member)

#define list_for_each(pos, head) for (pos = (head)-》next; pos != (head); pos = pos-》next)

#define list_for_each_safe(pos, n, head) for (pos = (head)-》next, n = pos-》next; pos != (head); pos = n, n = pos-》next)

#endif

c文件:

#include “l(fā)ist.h”

void list_init(ListObj* list){ list-》next = list-》prev = list;}

void list_insert_after(ListObj* list, ListObj* node){ list-》next-》prev = node; node-》next = list-》next;

list-》next = node; node-》prev = list;}

void list_insert_before(ListObj* list, ListObj* node){ list-》prev-》next = node; node-》prev = list-》prev;

list-》prev = node; node-》next = list;}

void list_remove(ListObj* node){ node-》next-》prev = node-》prev; node-》prev-》next = node-》next;

node-》next = node-》prev = node;}

int list_isempty(const ListObj* list){ return list-》next == list;}

unsigned int list_len(const ListObj* list){ unsigned int len = 0; const ListObj* p = list; while (p-》next != list) { p = p-》next; len++; }

return len;}

到此,一個(gè)全新的,完全解耦的,十分方便易用時(shí)間片輪詢框架完成。

責(zé)任編輯:haq

聲明:本文內(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)投訴
  • 單片機(jī)
    +關(guān)注

    關(guān)注

    6067

    文章

    44982

    瀏覽量

    650291
  • 框架
    +關(guān)注

    關(guān)注

    0

    文章

    404

    瀏覽量

    17888
  • 程序
    +關(guān)注

    關(guān)注

    117

    文章

    3826

    瀏覽量

    82959

原文標(biāo)題:?jiǎn)纹瑱C(jī)面向?qū)ο笏季S的架構(gòu):時(shí)間輪片法

文章出處:【微信號(hào):strongerHuang,微信公眾號(hào):strongerHuang】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    STC單片機(jī)范例程序

    電子發(fā)燒友網(wǎng)站提供《STC單片機(jī)范例程序.zip》資料免費(fèi)下載
    發(fā)表于 06-04 16:27 ?4次下載

    2.4寸TFT彩屏配套測(cè)試程序-51單片機(jī)

    如題,2.4寸TFT彩屏配套測(cè)試程序-51單片機(jī)。
    發(fā)表于 06-04 16:26 ?0次下載

    單片機(jī)Debug工具性能對(duì)比 單片機(jī)調(diào)試常用命令

    單片機(jī)(Microcontroller Unit, MCU)調(diào)試是嵌入式開(kāi)發(fā)中的一個(gè)重要環(huán)節(jié),它幫助開(kāi)發(fā)者發(fā)現(xiàn)和修復(fù)代碼中的錯(cuò)誤,優(yōu)化程序性能。不同的單片機(jī)和開(kāi)發(fā)環(huán)境可能使用不同的調(diào)試工具和命令
    的頭像 發(fā)表于 12-19 09:56 ?1409次閱讀

    單片機(jī)編程語(yǔ)言有哪些選擇

    單片機(jī)(Microcontroller Unit,MCU)編程是指為單片機(jī)編寫程序的過(guò)程,這些程序控制單片機(jī)的行為和功能。單片機(jī)廣泛應(yīng)用于嵌
    的頭像 發(fā)表于 11-01 14:13 ?2413次閱讀

    單片機(jī)怎么寫入程序

    程序通常涉及以下幾個(gè)步驟: 選擇單片機(jī)和開(kāi)發(fā)環(huán)境 : 確定項(xiàng)目需求,選擇合適的單片機(jī)型號(hào)。 安裝相應(yīng)的開(kāi)發(fā)環(huán)境,如Keil、IAR、MPLAB等。 硬件連接 : 將單片機(jī)連接到開(kāi)發(fā)板或
    的頭像 發(fā)表于 10-21 11:21 ?2404次閱讀

    單片機(jī)的中斷機(jī)制

    單片機(jī)的中斷機(jī)制是一種重要的處理方式,它允許單片機(jī)在執(zhí)行主程序的過(guò)程中,能夠暫停當(dāng)前任務(wù),轉(zhuǎn)而處理外部或內(nèi)部緊急事件。這種機(jī)制極大地提高了系統(tǒng)的響應(yīng)速度和處理能力,使得單片機(jī)在各種應(yīng)用
    的頭像 發(fā)表于 10-17 18:03 ?1966次閱讀

    keil可以讀出單片機(jī)程序

    Keil是一款廣泛應(yīng)用于單片機(jī)程序開(kāi)發(fā)的軟件,它提供了包括C編譯器、宏匯編、連接器、庫(kù)管理和一個(gè)功能強(qiáng)大的仿真調(diào)試器等在內(nèi)的完整開(kāi)發(fā)方案。然而,關(guān)于Keil是否能直接“讀出”單片機(jī)程序
    的頭像 發(fā)表于 09-02 10:32 ?2129次閱讀

    單片機(jī)燒錄程序用什么軟件

    單片機(jī)燒錄程序單片機(jī)開(kāi)發(fā)過(guò)程中的一個(gè)重要環(huán)節(jié),涉及到將編寫好的程序代碼通過(guò)燒錄器寫入單片機(jī)的ROM中,以實(shí)現(xiàn)對(duì)
    的頭像 發(fā)表于 09-02 10:05 ?3418次閱讀

    單片機(jī)燒錄程序可以重新燒嗎

    單片機(jī)(Microcontroller Unit, MCU)是一種集成電路芯片,它將計(jì)算機(jī)的CPU、存儲(chǔ)器、輸入/輸出接口等集成在一塊芯片上,用于控制各種電子設(shè)備。單片機(jī)燒錄程序是指將編寫
    的頭像 發(fā)表于 09-02 10:04 ?3125次閱讀

    單片機(jī)燒錄程序時(shí)為什么一直在檢測(cè)

    單片機(jī)燒錄程序時(shí),如果軟件一直在顯示“正在檢測(cè)單片機(jī)”,可能是由多種原因?qū)е碌?。以下是一些常?jiàn)的原因及其解決方法: 1. 連接問(wèn)題 USB轉(zhuǎn)串口接觸不良 :檢查單片機(jī)與電腦的連接是否穩(wěn)
    的頭像 發(fā)表于 09-02 09:57 ?8050次閱讀

    單片機(jī)燒錄程序的線比單片機(jī)上的少還能燒錄嗎

    單片機(jī)燒錄原理 單片機(jī)燒錄是指將編寫好的程序代碼通過(guò)一定的方式傳輸?shù)?b class='flag-5'>單片機(jī)的存儲(chǔ)器中,使其能夠按照程序的指令運(yùn)行。這個(gè)過(guò)程通常需要使用燒錄器
    的頭像 發(fā)表于 09-02 09:54 ?1072次閱讀

    單片機(jī)燒錄程序的線叫什么

    單片機(jī)燒錄程序時(shí)所使用的線,根據(jù)不同的燒錄方式和接口標(biāo)準(zhǔn),可能會(huì)有所不同。以下是一些常見(jiàn)的單片機(jī)燒錄接口和對(duì)應(yīng)的線: JTAG接口 : JTAG(Joint Test Action Group
    的頭像 發(fā)表于 09-02 09:52 ?2354次閱讀

    單片機(jī)燒錄程序的基本步驟是什么

    單片機(jī)燒錄程序單片機(jī)開(kāi)發(fā)過(guò)程中非常重要的一步,它涉及到將編寫好的程序代碼通過(guò)一定的方式傳輸?shù)?b class='flag-5'>單片機(jī)內(nèi)部的存儲(chǔ)器中,使
    的頭像 發(fā)表于 09-02 09:47 ?2746次閱讀

    stm32單片機(jī)燒錄程序會(huì)擦除原來(lái)的程序

    在STM32單片機(jī)燒錄程序的過(guò)程中, 通常情況下會(huì)擦除原來(lái)的程序 ,并將新程序寫入單片機(jī)的閃存(Flash)中。這一過(guò)程是通過(guò)燒錄工具(如S
    的頭像 發(fā)表于 09-02 09:42 ?4674次閱讀

    藍(lán)牙模塊如何實(shí)現(xiàn)單片機(jī)和手機(jī)端數(shù)據(jù)互傳

    ZX-D30、ZX-D37、ZX-D32等。 藍(lán)牙模塊設(shè)置 : 將藍(lán)牙模塊與單片機(jī)連接。通常,藍(lán)牙模塊通過(guò)串口(UART)與單片機(jī)通信。 設(shè)置藍(lán)牙模塊的工作模式和參數(shù),例如波特率、名稱、停止位、數(shù)據(jù)位等。這通常通過(guò)發(fā)送特定的AT命令來(lái)完成。 編寫
    的頭像 發(fā)表于 07-24 17:59 ?5603次閱讀
    藍(lán)牙模塊如何實(shí)現(xiàn)<b class='flag-5'>單片機(jī)</b>和手機(jī)端數(shù)據(jù)互傳