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

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

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

非常實(shí)用,推薦一種面向?qū)ο笏季S的單片機(jī)程序框架

jf_pJlTbmA9 ? 來源:小麥大叔 ? 作者:小麥大叔 ? 2023-10-24 18:03 ? 次閱讀

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

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

最終代碼跑起來看似沒有問題(有可能也真的沒有問題),但是系統(tǒng)的可擴(kuò)展性很差,添加一個功能的時候會浪費(fèi)大量的時間,甚至導(dǎo)致整個代碼的崩潰。

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

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

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

Demo

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

#include
#include
#include
#include"timeslice.h"

//創(chuàng)建5個任務(wù)對象
TimesilceTaskObjtask_1,task_2,task_3,task_4,task_5;

//具體的任務(wù)函數(shù)
voidtask1_hdl()
{
printf(">>task1isrunning...n");
}

voidtask2_hdl()
{
printf(">>task2isrunning...n");
}

voidtask3_hdl()
{
printf(">>task3isrunning...n");
}

voidtask4_hdl()
{
printf(">>task4isrunning...n");
}

voidtask5_hdl()
{
printf(">>task5isrunning...n");
}

//初始化任務(wù)對象,并且將任務(wù)添加到時間片輪詢調(diào)度中
voidtask_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);
}

//開兩個線程模擬在單片機(jī)上的運(yùn)行過程
voidtimeslice_exec_thread()
{
while(true)
{
timeslice_exec();
}
}

voidtimeslice_tick_thread()
{
while(true)
{
timeslice_tick();
Sleep(10);
}
}

intmain()
{
task_init();

printf(">>tasknum:%dn",timeslice_get_task_num());
printf(">>tasklen:%dn",timeslice_get_task_timeslice_len( task_3));

timeslice_task_del( task_2);
printf(">>delettask2n");
printf(">>task2isexist:%dn",timeslice_task_isexist( task_2));

printf(">>tasknum:%dn",timeslice_get_task_num());
timeslice_task_del( task_5);printf(">>delettask5n");
printf(">>tasknum:%dn",timeslice_get_task_num());
printf(">>task3isexist:%dn",timeslice_task_isexist( task_3));

timeslice_task_add( task_2);printf(">>addtask2n");
printf(">>task2isexist:%dn",timeslice_task_isexist( task_2));

timeslice_task_add( task_5);printf(">>addtask5n");
printf(">>tasknum:%dn",timeslice_get_task_num());

printf("nn========timeslicerunning===========n");

std::threadthread_1(timeslice_exec_thread);
std::threadthread_2(timeslice_tick_thread);

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

return0;
}

運(yùn)行結(jié)果如下:

poYBAGGnJ7OAZ5XZAACMwYJDoAU530.png

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

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

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

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

h文件:

#ifndef_TIMESLICE_H
#define_TIMESLICE_H

#include"./list.h"

typedefenum
{
TASK_STOP,
TASK_RUN
}IsTaskRun;

typedefstructtimesilce
{
unsignedintid;
void(*task_hdl)(void);
IsTaskRunis_run;
unsignedinttimer;
unsignedinttimeslice_len;
ListObjtimeslice_task_list;
}TimesilceTaskObj;

voidtimeslice_exec(void);
voidtimeslice_tick(void);
voidtimeslice_task_init(TimesilceTaskObj*obj,void(*task_hdl)(void),unsignedintid,unsignedinttimeslice_len);
voidtimeslice_task_add(TimesilceTaskObj*obj);
voidtimeslice_task_del(TimesilceTaskObj*obj);
unsignedinttimeslice_get_task_timeslice_len(TimesilceTaskObj*obj);
unsignedinttimeslice_get_task_num(void);
unsignedchartimeslice_task_isexist(TimesilceTaskObj*obj);

#endifc文件:
#include"./timeslice.h"

staticLIST_HEAD(timeslice_task_list);

voidtimeslice_exec()
{
ListObj*node;
TimesilceTaskObj*task;

list_for_each(node, timeslice_task_list)
{

task=list_entry(node,TimesilceTaskObj,timeslice_task_list);
if(task->is_run==TASK_RUN)
{
task->task_hdl();
task->is_run=TASK_STOP;
}
}
}

voidtimeslice_tick()
{
ListObj*node;
TimesilceTaskObj*task;

list_for_each(node, timeslice_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;
}
}
}
}

unsignedinttimeslice_get_task_num()
{
returnlist_len( timeslice_task_list);
}

voidtimeslice_task_init(TimesilceTaskObj*obj,void(*task_hdl)(void),unsignedintid,unsignedinttimeslice_len)
{
obj->id=id;
obj->is_run=TASK_STOP;
obj->task_hdl=task_hdl;
obj->timer=timeslice_len;
obj->timeslice_len=timeslice_len;
}

voidtimeslice_task_add(TimesilceTaskObj*obj)
{
list_insert_before( timeslice_task_list, obj->timeslice_task_list);
}

voidtimeslice_task_del(TimesilceTaskObj*obj)
{
if(timeslice_task_isexist(obj))
list_remove( obj->timeslice_task_list);
else
return;
}

unsignedchartimeslice_task_isexist(TimesilceTaskObj*obj)
{
unsignedcharisexist=0;
ListObj*node;
TimesilceTaskObj*task;

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

returnisexist;
}

unsignedinttimeslice_get_task_timeslice_len(TimesilceTaskObj*obj)
{
returnobj->timeslice_len;
}

底層侵入式雙向鏈表

該鏈表是linux內(nèi)核中使用十分廣泛,也十分經(jīng)典,其原理具體可以參考文章:

https://www.cnblogs.com/skywang12345/p/3562146.html

h文件:

#ifndef_LIST_H
#define_LIST_H
#defineoffset_of(type,member)(unsignedlong) ((type*)0)->member
#definecontainer_of(ptr,type,member)((type*)((char*)(ptr)-offset_of(type,member)))

typedefstructlist_structure
{
structlist_structure*next;
structlist_structure*prev;
}ListObj;

#defineLIST_HEAD_INIT(name){ (name), (name)}
#defineLIST_HEAD(name)ListObjname=LIST_HEAD_INIT(name)

voidlist_init(ListObj*list);
voidlist_insert_after(ListObj*list,ListObj*node);
voidlist_insert_before(ListObj*list,ListObj*node);
voidlist_remove(ListObj*node);
intlist_isempty(constListObj*list);
unsignedintlist_len(constListObj*list);

#definelist_entry(node,type,member)
container_of(node,type,member)

#definelist_for_each(pos,head)
for(pos=(head)->next;pos!=(head);pos=pos->next)

#definelist_for_each_safe(pos,n,head)
for(pos=(head)->next,n=pos->next;pos!=(head);
pos=n,n=pos->next)

#endif

c文件:

#include"list.h"

voidlist_init(ListObj*list)
{
list->next=list->prev=list;
}

voidlist_insert_after(ListObj*list,ListObj*node)
{
list->next->prev=node;
node->next=list->next;

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

voidlist_insert_before(ListObj*list,ListObj*node)
{
list->prev->next=node;
node->prev=list->prev;

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

voidlist_remove(ListObj*node)
{
node->next->prev=node->prev;
node->prev->next=node->next;

node->next=node->prev=node;
}

intlist_isempty(constListObj*list)
{
returnlist->next==list;
}

unsignedintlist_len(constListObj*list)
{
unsignedintlen=0;
constListObj*p=list;
while(p->next!=list)
{
p=p->next;
len++;
}

returnlen;
}

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

來源:小麥大叔

免責(zé)聲明:本文為轉(zhuǎn)載文章,轉(zhuǎn)載此文目的在于傳遞更多信息,版權(quán)歸原作者所有。本文所用視頻、圖片、文字如涉及作品版權(quán)問題,請聯(lián)系小編進(jìn)行處理

審核編輯 黃宇

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

    關(guān)注

    6026

    文章

    44455

    瀏覽量

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

    關(guān)注

    0

    文章

    397

    瀏覽量

    17361
收藏 人收藏

    評論

    相關(guān)推薦

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

    單片機(jī)(Microcontroller Unit,MCU)是一種集成電路芯片,它將計(jì)算機(jī)的CPU、存儲器、輸入/輸出接口等功能集成在個芯片上。單片機(jī)廣泛應(yīng)用于嵌入式系統(tǒng)和物聯(lián)網(wǎng)設(shè)備中
    的頭像 發(fā)表于 10-21 11:21 ?82次閱讀

    單片機(jī)有哪些中斷類型

    單片機(jī)中斷是指在單片機(jī)執(zhí)行程序的過程中,當(dāng)外部設(shè)備或內(nèi)部條件發(fā)生某個特定事件時,能夠暫停當(dāng)前正在執(zhí)行的程序,轉(zhuǎn)而去執(zhí)行個特定的服務(wù)
    的頭像 發(fā)表于 10-17 18:12 ?172次閱讀

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

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

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

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

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

    單片機(jī)燒錄程序單片機(jī)開發(fā)過程中的個重要環(huán)節(jié),涉及到將編寫好的程序代碼通過燒錄器寫入單片機(jī)的R
    的頭像 發(fā)表于 09-02 10:05 ?526次閱讀

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

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

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

    單片機(jī)燒錄程序單片機(jī)開發(fā)過程中非常重要的步,它涉及到將編寫好的程序代碼通過
    的頭像 發(fā)表于 09-02 09:47 ?466次閱讀

    單片機(jī)中斷功能及其應(yīng)用

    單片機(jī)中斷功能及其應(yīng)用? 單片機(jī)中斷是指在程序執(zhí)行過程中,根據(jù)特定的條件或事件自動暫時中斷當(dāng)前程序的執(zhí)行,轉(zhuǎn)而執(zhí)行特定的中斷服務(wù)程序。中斷是
    的頭像 發(fā)表于 01-30 14:45 ?4373次閱讀

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

    單片機(jī)芯片的程序寫入是通過將程序代碼寫入單片機(jī)芯片的非易失性存儲器(如Flash)中實(shí)現(xiàn)的。 在計(jì)算機(jī)科學(xué)和電子工程領(lǐng)域,單片機(jī)
    的頭像 發(fā)表于 01-05 14:06 ?7339次閱讀

    pic單片機(jī)匯編程序實(shí)例

    以下是個簡單的PIC單片機(jī)匯編程序示例,這個程序將實(shí)現(xiàn)個LED閃爍的功能。 首先,我們需要了解PIC
    的頭像 發(fā)表于 12-14 11:01 ?1587次閱讀

    你用過哪些編程語言開發(fā)單片機(jī)?

    C語言是最常用的一種用于單片機(jī)的開發(fā)語言,也是一種高級編程語言,具有較好的可移植性和可讀性。對于單片機(jī),通常使用嵌入式C來進(jìn)行開發(fā)。 舉例:用C語言寫
    發(fā)表于 12-04 10:18 ?1147次閱讀

    個線程模擬單片機(jī)程序框架分享

    首先來個demo,該demo是使用電腦開兩個線程:個線程模擬單片機(jī)的定時器中斷產(chǎn)生時間片輪詢個時鐘,另個線程則模擬主函數(shù)中直運(yùn)行的時間片輪詢調(diào)度
    發(fā)表于 11-19 10:39 ?2263次閱讀
    <b class='flag-5'>一</b>個線程模擬<b class='flag-5'>單片機(jī)</b><b class='flag-5'>程序</b><b class='flag-5'>框架</b>分享

    一種基于AVR單片機(jī)的以太網(wǎng)路由器設(shè)計(jì)

    電子發(fā)燒友網(wǎng)站提供《一種基于AVR單片機(jī)的以太網(wǎng)路由器設(shè)計(jì).pdf》資料免費(fèi)下載
    發(fā)表于 10-31 09:19 ?2次下載
    <b class='flag-5'>一種</b>基于AVR<b class='flag-5'>單片機(jī)</b>的以太網(wǎng)路由器設(shè)計(jì)

    一種單片機(jī)機(jī)通信系統(tǒng)的設(shè)計(jì)

    電子發(fā)燒友網(wǎng)站提供《一種單片機(jī)機(jī)通信系統(tǒng)的設(shè)計(jì).pdf》資料免費(fèi)下載
    發(fā)表于 10-30 11:11 ?0次下載
    <b class='flag-5'>一種</b><b class='flag-5'>單片機(jī)</b>多<b class='flag-5'>機(jī)</b>通信系統(tǒng)的設(shè)計(jì)

    單片機(jī)與Internct網(wǎng)絡(luò)通信的一種具體實(shí)現(xiàn)方案

    電子發(fā)燒友網(wǎng)站提供《單片機(jī)與Internct網(wǎng)絡(luò)通信的一種具體實(shí)現(xiàn)方案.pdf》資料免費(fèi)下載
    發(fā)表于 10-25 10:40 ?3次下載
    <b class='flag-5'>單片機(jī)</b>與Internct網(wǎng)絡(luò)通信的<b class='flag-5'>一種</b>具體實(shí)現(xiàn)方案