日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

解剖8051内核如何进行多任务切换

發布時間:2023/12/20 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 解剖8051内核如何进行多任务切换 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最近在玩新唐單片機,這個跟我之前用的51內核是一樣的,然后今天覺得跑下多任務,自己研究了下,跟幾個同學還討論了,發現有些人對切換過程還不是十分明白,所以發個文章出來。

直接上代碼

#include?"MS51_16K.h"/**?UART0?initial?setting*?include?sys.c?in?Library?for?modify?HIRC?value?to?24MHz*?include?uart.c?in?Library?for?UART?initial?setting*/ void?initialize_UART0(void) {MODIFY_HIRC(HIRC_24);P06_PUSHPULL_MODE;UART_Open(24000000,UART0_Timer3,115200);ENABLE_UART0_PRINTF; }void?delay_ms(unsigned?int?n) {unsigned?int?i;for(i=0;i<n;i++)_delay_(); }void?Timer_ISR?(void)???interrupt?17?????//ISR?for?self?wake-up?timer {_push_(SFRS);clr_WKTF;???????????????????????????????????//clear?interrupt?flag_pop_(SFRS); }void?initialize_Timer(void) {WKCON?=?0x00;?????????????????????//timer?base?10k,?Pre-scale?=?1/16//RWK?=?0XFF;?????????????????????//??if?prescale?is?0x00,?never?set?RWK?=?0xffRWK?=?0X00;ENABLE_WKT_INTERRUPT;?????????????//?enable?WKT?interruptENABLE_GLOBAL_INTERRUPT;set_EIPH1_PWKTH;set_WKCON_WKTR; }#define?MAX_TASKS?2???????/*任務槽個數.必須和實際任務數一至*/ #define?MAX_TASK_DEP?100???/*最大棧深.最低不得少于2個,保守值為12*/ unsigned?char?idata?task_stack[MAX_TASKS][MAX_TASK_DEP];/*任務堆棧.*/ unsigned?int?task_id;????/*當前活動任務號*/ unsigned?int?max_task?=?0;unsigned?char?idata?task_sp[MAX_TASKS];void?task_switch() {task_sp[task_id]?=?SP;if(++task_id?==?max_task)task_id?=?0;SP?=?task_sp[task_id]; }void?task_load(unsigned?int?fn,?int?tid) {task_sp[tid]?=?task_stack[tid]+1;task_stack[tid][0]?=?(unsigned?int)fn?&?0xff;task_stack[tid][1]?=?(unsigned?int)fn?>>?8;++max_task; }void?task1() {static?unsigned?char?i;printf("task,SP:%x\n",(int)SP);while(1){i++;printf("task#1\n");delay_ms(100);task_switch();} }void?task2() {static?unsigned?char?j;while(1){j+=2;printf("task#2\n");delay_ms(100);task_switch();} }void?switch_to(unsigned?int?tid) {task_id?=?tid;SP?=?task_sp[tid];return; }void?main(void) {initialize_UART0();Disable_WDT_Reset_Config();printf("~~~~~~~~~~~~~~~~MainStart...\n");task_load(task1,?0);//將task1函數裝入0號槽task_load(task2,?1);//將task2函數裝入1號槽switch_to(0);printf("~~~~~~~~~~~~~~~~MainEnd...\n");? }

單片機運行輸出

代碼很簡單,就是兩個任務進行不斷的切換,每個任務進行相應時間的延遲。

先說下第一個函數

把任務函數轉載到二維數組保存起來,而且任務函數地址和任務的tid編號要對應。

void?task_load(unsigned?int?fn,?int?tid) {task_sp[tid]?=?task_stack[tid]+1;task_stack[tid][0]?=?(unsigned?int)fn?&?0xff;task_stack[tid][1]?=?(unsigned?int)fn?>>?8;++max_task; }

task_sp 用來表示任務的數組

task_stack 用來保存任務函數的地址

說下這行代碼

task_sp[tid]?=?task_stack[tid]+1;

后面的 + 1 ,不知道大家有沒有疑惑。

+1 簡單理解就是指向了下一個位置

再解剖第二個函數,等下你就知道這個作用的奇特

用來做任務的切換,先保存之前運行的任務函數地址,再改變任務id,把對應任務id的函數地址賦值給SP。

void?task_switch() {task_sp[task_id]?=?SP;if(++task_id?==?max_task)task_id?=?0;SP?=?task_sp[task_id]; }

它是妙處不是在這個函數的本身,而是只有比較深入的了解函數調用的過程,才明白其中的奧妙。

SP 是堆棧指針,用來保存當前堆棧的位置

上面的函數是在進入函數的時候,把當前堆棧的值保存在 stak_sp 中,然后更改stak_sp 的值,再賦值給SP。

說如何切換吧

void?switch_to(unsigned?int?tid) {task_id?=?tid;SP?=?task_sp[tid];return; }

調用函數?switch_to(0)?之前 堆棧和PC指針是這樣的

調用函數?switch_to(0)?之后

我們需要把PC之前的值,保存在SP里面,然后呢,PC就開始執行switch_to函數體里面的內容。

然后,改變SP的值,讓SP的值等于需要執行函數的地址

函數退出的時候,PC指針又會從SP堆棧位置拿到之前保存的那個地址「實際上已經被我們修改了」,去繼續執行。

就是通過這樣不斷的切換,完成了多個函數交換執行。

這是最基本的多任務系統,代碼也不是非常完整,喜歡研究的同學,可以再看看網上的例程。

我這次用的是芯唐 MS51FB9AE 芯片。

有做這方便的同學,歡迎一起討論~


推薦閱讀:

專輯|Linux文章匯總

專輯|程序人生

專輯|C語言

我的知識小密圈

關注公眾號,后臺回復「1024」獲取學習資料網盤鏈接。

歡迎點贊,關注,轉發,在看,您的每一次鼓勵,我都將銘記于心~

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的解剖8051内核如何进行多任务切换的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。