国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

建湖人才網(wǎng)最新招聘百度seo發(fā)帖推廣

建湖人才網(wǎng)最新招聘,百度seo發(fā)帖推廣,臨淄房產(chǎn)信息網(wǎng),網(wǎng)站維護(hù)與建設(shè)本教程基于韋東山百問網(wǎng)出的 DShanMCU-RA6M5開發(fā)板 進(jìn)行編寫,需要的同學(xué)可以在這里獲取: https://item.taobao.com/item.htm?id728461040949 配套資料獲取:https://renesas-docs.100ask.net 瑞薩MCU零基礎(chǔ)入門系列教程匯總: ht…

本教程基于韋東山百問網(wǎng)出的 DShanMCU-RA6M5開發(fā)板 進(jìn)行編寫,需要的同學(xué)可以在這里獲取: https://item.taobao.com/item.htm?id=728461040949

配套資料獲取:https://renesas-docs.100ask.net

瑞薩MCU零基礎(chǔ)入門系列教程匯總: https://blog.csdn.net/qq_35181236/article/details/132779862


第1章 單片機(jī)程序的設(shè)計(jì)模式

本章目標(biāo)

  • 理解裸機(jī)程序設(shè)計(jì)模式
  • 了解多任務(wù)系統(tǒng)中程序設(shè)計(jì)的不同

1.1 裸機(jī)程序設(shè)計(jì)模式

裸機(jī)程序的設(shè)計(jì)模式可以分為:輪詢、前后臺、定時(shí)器驅(qū)動、基于狀態(tài)機(jī)。前面三種方法都無法解決一個(gè)問題:假設(shè)有 A、B 兩個(gè)都很耗時(shí)的函數(shù),無法降低它們相互之間的影響。第 4 種方法可以解決這個(gè)問題,但是實(shí)踐起來有難度。

假設(shè)一位職場媽媽需要同時(shí)解決 2 個(gè)問題:給小孩喂飯、回復(fù)工作信息,場景如圖所示,

后面將會演示各類模式下如何寫程序:

image1

1.1.1 輪詢模式

示例代碼如下:

 // 經(jīng)典單片機(jī)程序: 輪詢void main(){while (1){喂一口飯();回一個(gè)信息();}}

在 main 函數(shù)中是一個(gè) while 循環(huán),里面依次調(diào)用 2 個(gè)函數(shù),這兩個(gè)函數(shù)相互之間有影響:如果“喂一口飯”太花時(shí)間,就會導(dǎo)致遲遲無法“回一個(gè)信息”;如果“回一個(gè)信息”太花時(shí)間,就會導(dǎo)致遲遲無法“喂下一口飯”。

使用輪詢模式編寫程序看起來很簡單,但是要求 while 循環(huán)里調(diào)用到的函數(shù)要執(zhí)行得非常快,在復(fù)雜場景里反而增加了編程難度。

1.1.2 前后臺

所謂“前后臺”就是使用中斷程序。假設(shè)收到同事發(fā)來的信息時(shí),電腦會發(fā)出“滴”的一聲,這時(shí)候媽媽才需要去回復(fù)信息。示例程序如下:

 // 前后臺程序void main(){while (1){// 后臺程序喂一口飯();}}// 前臺程序
void 滴_中斷()
{回一個(gè)信息();
}
  • main 函數(shù)里 while 循環(huán)里的代碼是后臺程序,平時(shí)都是 while 循環(huán)在運(yùn)行;
  • 當(dāng)同事發(fā)來信息,電腦發(fā)出“滴”的一聲,觸發(fā)了中斷。媽媽暫停喂飯,去執(zhí)行“滴_中斷”給同事回復(fù)信息;

在這個(gè)場景里,給同事回復(fù)信息非常及時(shí):即使正在喂飯也會暫停下來去回復(fù)信息。“喂一口飯”無法影響到“回一個(gè)信息”。但是,如果“回一個(gè)信息”太花時(shí)間,就會導(dǎo)致 “喂一口飯”遲遲無法執(zhí)行。

繼續(xù)改進(jìn),假設(shè)小孩吞下飯菜后會發(fā)出“啊”的一聲,媽媽聽到后才會喂下一口飯。喂飯、回復(fù)信息都是使用中斷函數(shù)來處理。示例程序如下:


// 前后臺程序
void main()
{while (1){// 后臺程序}
}// 前臺程序
void 滴_中斷()
{回一個(gè)信息();
}// 前臺程序
void 啊_中斷()
{喂一口飯();
}

main 函數(shù)中的 while 循環(huán)是空的,程序的運(yùn)行靠中斷來驅(qū)使。如果電腦聲音“滴”、小孩聲音“啊”不會同時(shí)、相近發(fā)出,那么“回一個(gè)信息”、“喂一口飯”相互之間沒有影響。在不能滿足這個(gè)前提的情況下,比如“滴”、“啊”同時(shí)響起,先“回一個(gè)信息”時(shí)就會耽誤“喂一口飯”,這種場景下程序遭遇到了輪詢模式的缺點(diǎn):函數(shù)相互之間有影響。

1.1.3 定時(shí)器驅(qū)動

定時(shí)器驅(qū)動模式,是前后臺模式的一種,可以按照不用的頻率執(zhí)行各種函數(shù)。比如需要每 2 分鐘給小孩喂一口飯,需要每 5 分鐘給同事回復(fù)信息。那么就可以啟動一個(gè)定時(shí)器,讓它每 1 分鐘產(chǎn)生一次中斷,讓中斷函數(shù)在合適的時(shí)間調(diào)用對應(yīng)函數(shù)。示例代碼如下:

// 前后臺程序: 定時(shí)器驅(qū)動
void main()
{while (1){// 后臺程序}
}// 前臺程序: 每 1 分鐘觸發(fā)一次中斷
void 定時(shí)器_中斷()
{static int cnt = 0;cnt++;if (cnt % 2 == 0){喂一口飯();}else if (cnt % 5 == 0){回一個(gè)信息();}
}

main 函數(shù)中的 while 循環(huán)是空的,程序的運(yùn)行靠定時(shí)器中斷來驅(qū)使。

  • 定時(shí)器中斷每 1 分鐘發(fā)生一次,在中斷函數(shù)里讓 cnt 變量累加(代碼第 14 行)。
  • 第 15 行:進(jìn)行求模運(yùn)算,如果對 2 取模為 0,就“喂一口飯”。這相當(dāng)于每發(fā)生 2 次中斷就“喂一口飯”。
  • 第 19 行:進(jìn)行求模運(yùn)算,如果對 5 取模為 0,就“回一個(gè)信息”。這相當(dāng)于每發(fā)生 5 次

中斷就“回一個(gè)信息”。

這種模式適合調(diào)用周期性的函數(shù),并且每一個(gè)函數(shù)執(zhí)行的時(shí)間不能超過一個(gè)定時(shí)器周期。如果“喂一口飯”很花時(shí)間,比如長達(dá) 10 分鐘,那么就會耽誤“回一個(gè)信息”;反過來也是一樣的,如果“回一個(gè)信息”很花時(shí)間也會影響到“喂一口飯”;這種場景下程序遭遇到了輪詢模式的缺點(diǎn):函數(shù)相互之間有影響。

1.1.4 基于狀態(tài)機(jī)

當(dāng)“喂一口飯”、“回一個(gè)信息”都需要花很長的時(shí)間,無論使用前面的哪種設(shè)計(jì)模式,都會退化到輪詢模式的缺點(diǎn):函數(shù)相互之間有影響??梢允褂脿顟B(tài)機(jī)來解決這個(gè)缺點(diǎn),示例代碼如下:

// 狀態(tài)機(jī)
void main()
{while (1){喂一口飯();回一個(gè)信息();}
}

在 main 函數(shù)里,還是使用輪詢模式依次調(diào)用 2 個(gè)函數(shù)。

關(guān)鍵在于這 2 個(gè)函數(shù)的內(nèi)部實(shí)現(xiàn):使用狀態(tài)機(jī),每次只執(zhí)行一個(gè)狀態(tài)的代碼,減少每次執(zhí)行的時(shí)間,代碼如下:

void 喂一口飯(void)
{static int state = 0;switch (state){case 0:{/* 舀飯 *//* 進(jìn)入下一個(gè)狀態(tài) */state++;break;}case 1:{/* 喂飯 *//* 進(jìn)入下一個(gè)狀態(tài) */state++;break;}case 2:{/* 舀菜 *//* 進(jìn)入下一個(gè)狀態(tài) */state++;break;}case 2:{/* 喂菜 *//* 恢復(fù)到初始狀態(tài) */state = 0;break;}}
}void 回一個(gè)信息(void)
{static int state = 0;switch (state){case 0:{/* 查看信息 *//* 進(jìn)入下一個(gè)狀態(tài) */state++;break;}case 1:{/* 打字 *//* 進(jìn)入下一個(gè)狀態(tài) */state++;break;}case 2:{/* 發(fā)送 *//* 恢復(fù)到初始狀態(tài) */state = 0;break;}}
}

以“喂一口飯”為例,函數(shù)內(nèi)部拆分為 4 個(gè)狀態(tài):舀飯、喂飯、舀菜、喂菜。每次執(zhí)行“喂一口飯”函數(shù)時(shí),都只會執(zhí)行其中的某一狀態(tài)對應(yīng)的代碼。以前執(zhí)行一次“喂一口飯”函數(shù)可能需要 4 秒鐘,現(xiàn)在可能只需要 1 秒鐘,就降低了對后面“回一個(gè)信息”的影響。

同樣的,“回一個(gè)信息”函數(shù)內(nèi)部也被拆分為 3 個(gè)狀態(tài):查看信息、打字、發(fā)送。每次執(zhí)行這個(gè)函數(shù)時(shí),都只是執(zhí)行其中一小部分代碼,降低了對“喂一口飯”的影響。

使用狀態(tài)機(jī)模式,可以解決裸機(jī)程序的難題:假設(shè)有 A、B 兩個(gè)都很耗時(shí)的函數(shù),怎樣降低它們相互之間的影響。但是很多場景里,函數(shù) A、B 并不容易拆分為多個(gè)狀態(tài),并且這些狀態(tài)執(zhí)行的時(shí)間并不好控制。所以這并不是最優(yōu)的解決方法,需要使用多任務(wù)系統(tǒng)。

1.2 多任務(wù)系統(tǒng)

1.2.1 多任務(wù)模式

對于裸機(jī)程序,無論使用哪種模式進(jìn)行精心的設(shè)計(jì),在最差的情況下都無法解決這個(gè)問題:假設(shè)有 A、B 兩個(gè)都很耗時(shí)的函數(shù),無法降低它們相互之間的影響。使用狀態(tài)機(jī)模式時(shí),如果函數(shù)拆分得不好,也會導(dǎo)致這個(gè)問題。本質(zhì)原因是:函數(shù)是輪流執(zhí)行的。假設(shè)“喂一口飯”需要 t1~t5 這 5 段時(shí)間,“回一個(gè)信息需要”ta~te 這 5 段時(shí)間,輪流執(zhí)行時(shí):先執(zhí)行完 t1~t5,再執(zhí)行 ta~te,如下圖所示:

image2

對于職場媽媽,她怎么解決這個(gè)問題呢?她是一個(gè)眼明手快的人,可以一心多用,她這

樣做:

  • 左手拿勺子,給小孩喂飯
  • 右手敲鍵盤,回復(fù)同事
  • 兩不耽誤,小孩“以為”媽媽在專心喂飯,同事“以為”她在專心聊天
  • 但是腦子只有一個(gè)啊,雖然說“一心多用”,但是誰能同時(shí)思考兩件事?
  • 只是她反應(yīng)快,上一秒鐘在考慮夾哪個(gè)菜給小孩,下一秒鐘考慮給同事回復(fù)什么信息
  • 本質(zhì)是:交叉執(zhí)行,t1~t5 和 ta~te 交叉執(zhí)行,如下圖所示:

image3

基于多任務(wù)系統(tǒng)編寫程序時(shí),示例代碼如下:

// RTOS 程序
喂飯任務(wù)()
{while (1){喂一口飯();}
}回信息任務(wù)()
{while (1){回一個(gè)信息();}
}void main()
{// 創(chuàng)建 2 個(gè)任務(wù)create_task(喂飯任務(wù));create_task(回信息任務(wù));// 啟動調(diào)度器start_scheduler();
}
  • 第 21、22 行,創(chuàng)建 2 個(gè)任務(wù);
  • 第 25 行,啟動調(diào)度器;
  • 之后,這 2 個(gè)任務(wù)就會交叉執(zhí)行了;

基于多任務(wù)系統(tǒng)編寫程序時(shí),反而更簡單了:

  1. 上面第 2~8 行是“喂飯任務(wù)”的代碼;
  2. 第 10~16 行是“回信息任務(wù)”的代碼,編寫它們時(shí)甚至都不需要考慮它和其他函數(shù)的相互影響。就好像有 2 個(gè)單板:一個(gè)只運(yùn)行“喂飯任務(wù)”這個(gè)函數(shù)、另一個(gè)只運(yùn)行“回信息任務(wù)”這個(gè)函數(shù)。

多任務(wù)系統(tǒng)會依次給這些任務(wù)分配時(shí)間:你執(zhí)行一會,我執(zhí)行一會,如此循環(huán)。只要切換的間隔足夠短,用戶會“感覺這些任務(wù)在同時(shí)運(yùn)行”。如下圖所示:

image4

1.2.2 互斥操作

多任務(wù)系統(tǒng)中,多個(gè)任務(wù)可能會“同時(shí)”訪問某些資源,需要增加保護(hù)措施以防止混亂。比如任務(wù) A、B 都要使用串口,能否使用一個(gè)全局變量讓它們獨(dú)占地、互斥地使用串口?示例代碼如下:

// RTOS 程序
int g_canuse = 1;
void uart_print(char *str)
{if (g_canuse){g_canuse = 0;printf(str);g_canuse = 1;}
}task_A()
{while (1){uart_print("0123456789\n");}}task_B()
{while (1){uart_print("abcdefghij");}
}void main()
{// 創(chuàng)建 2 個(gè)任務(wù)create_task(task_A);create_task(task_B);// 啟動調(diào)度器start_scheduler();
}

程序的意圖是:task_A 打印“0123456789”,task_B 打印“abcdefghij”。在 task_A 或task_B 打印的過程中,另一個(gè)任務(wù)不能打印,以避免數(shù)字、字母混雜在一起,比如避免打印這樣的字符:“012abc”。

第 6 行使用全局變量 g_canuse 實(shí)現(xiàn)互斥打印,它等于 1 時(shí)表示“可以打印”。在進(jìn)行實(shí)際打印之前,先把 g_canuse 設(shè)置為 0,目的是防止別的任務(wù)也來打印。

這個(gè)程序大部分時(shí)間是沒問題的,但是只要它運(yùn)行的時(shí)間足夠長,就會出現(xiàn)數(shù)字、字母混雜的情況。下圖把 uart_print 函數(shù)標(biāo)記為①~④個(gè)步驟:

void uart_print(char *str)
{if (g_canuse){g_canuse = 0;printf(str);  ③g_canuse = 1;}
}

如果 task_A 執(zhí)行完①,進(jìn)入 if 語句里面執(zhí)行②之前被切換為 task_B:在這一瞬間,g_canuse 還是 1。

task_B 執(zhí)行①時(shí)也會成功進(jìn)入 if 語句,假設(shè)它執(zhí)行到③,在 printf 打印完部分字符比如“abc”后又再次被切換為 task_A。

task_A 繼續(xù)從上次被暫停的地方繼續(xù)執(zhí)行,即從②那里繼續(xù)執(zhí)行,成功打印出“0123456789”。這時(shí)在串口上可以看到打印的結(jié)果為:“abc0123456789”。

是不是“①判斷”、“②清零”間隔太遠(yuǎn)了,uart_print 函數(shù)改進(jìn)成如下的代碼呢?

void uart_print(char *str)
{g_canuse--;        ① 減一 if (g_canuse == 0) ② 判斷{printf(str);   ③ 打印}g_canuse++;        ④ 加一
}

即使改進(jìn)為上述代碼,仍然可能產(chǎn)生兩個(gè)任務(wù)同時(shí)使用串口的情況。因?yàn)椤阿贉p一”這個(gè)操作會分為 3 個(gè)步驟:a.從內(nèi)存讀取變量的值放入寄存器里,b.修改寄存器的值讓它減一,c.把寄存器的值寫到內(nèi)存上的變量上去。

如果task_A執(zhí)行完步驟a、b,還沒來得及把新值寫到內(nèi)存的變量里,就被切換為task_B:在這一瞬間,g_canuse 還是 1。

task_B 執(zhí)行①②時(shí)也會成功進(jìn)入 if 語句,假設(shè)它執(zhí)行到③,在 printf 打印完部分字符比如“abc”后又再次被切換為 task_A。

task_A 繼續(xù)從上次被暫停的地方繼續(xù)執(zhí)行,即從步驟 c 那里繼續(xù)執(zhí)行,成功打印出“0123456789”。這時(shí)在串口上可以看到打印的結(jié)果為:“abc0123456789”。

從上面的例子可以看到,基于多任務(wù)系統(tǒng)編寫程序時(shí),訪問公用的資源的時(shí)候要考慮“互斥操作”。任何一種多任務(wù)系統(tǒng)都會提供相應(yīng)的函數(shù)。

1.2.3 同步操作

如果任務(wù)之間有依賴關(guān)系,比如任務(wù) A 執(zhí)行了某個(gè)操作之后,需要任務(wù) B 進(jìn)行后續(xù)的處理。如果代碼如下編寫的話,任務(wù) B 大部分時(shí)間做的都是無用功。

// RTOS 程序
int flag = 0;void task_A()
{while (1){// 做某些復(fù)雜的事情// 完成后把 flag 設(shè)置為 1flag = 1;}
}void task_B()
{while (1){if (flag){// 做后續(xù)的操作}}
}void main()
{// 創(chuàng)建 2 個(gè)任務(wù)create_task(task_A);create_task(task_B);// 啟動調(diào)度器start_scheduler();
}

上述代碼中,在任務(wù) A 沒有設(shè)置 flag 為 1 之前,任務(wù) B 的代碼都只是去判斷 flag。而任務(wù) A、B 的函數(shù)是依次輪流運(yùn)行的,假設(shè)系統(tǒng)運(yùn)行了 100 秒,其中任務(wù) A 總共運(yùn)行了 50秒,任務(wù) B 總共運(yùn)行了 50 秒,任務(wù) A 在努力處理復(fù)雜的運(yùn)算,任務(wù) B 僅僅是浪費(fèi) CPU 資源。

如果可以讓任務(wù) B 阻塞,即讓任務(wù) B 不參與調(diào)度,那么任務(wù) A 就可以獨(dú)占 CPU 資源加快處理復(fù)雜的事情。當(dāng)任務(wù) A 處理完事情后,再喚醒任務(wù) B。示例代碼如下:

//RTOS 程序
void task_A()
{while (1){// 做某些復(fù)雜的事情// 釋放信號量,會喚醒任務(wù) B;}
}void task_B()
{while (1){// 等待信號量, 會讓任務(wù) B 阻塞// 做后續(xù)的操作}
}void main()
{// 創(chuàng)建 2 個(gè)任務(wù)create_task(task_A);create_task(task_B);// 啟動調(diào)度器start_scheduler();
}
  • 第 15 行:任務(wù) B 運(yùn)行時(shí),等待信號量,不成功時(shí)就會阻塞,不在參與任務(wù)調(diào)度。
  • 第 7 行: 任務(wù) A 處理完復(fù)雜的事情后,釋放信號量會喚醒任務(wù) B。
  • 第 16 行:任務(wù) B 被喚醒后,從這里繼續(xù)運(yùn)行。

在這個(gè)過程中,任務(wù) A 處理復(fù)雜事情的時(shí)候可以獨(dú)占 CPU 資源,加快處理速度。


本章完
http://aloenet.com.cn/news/40306.html

相關(guān)文章:

  • 鄭州做網(wǎng)站的公司網(wǎng)店推廣實(shí)訓(xùn)報(bào)告
  • 搭建獨(dú)立站網(wǎng)絡(luò)營銷公司名字大全
  • 網(wǎng)站設(shè)計(jì)行業(yè)現(xiàn)狀品牌推廣方案模板
  • 做農(nóng)業(yè)的公司管理網(wǎng)站廣告推廣公司
  • 用記事本做網(wǎng)站怎么添加表格近期熱點(diǎn)新聞事件50個(gè)
  • 做網(wǎng)站還能掙錢企業(yè)網(wǎng)絡(luò)營銷成功案例
  • 如何建立和設(shè)計(jì)公司網(wǎng)站中國十大it培訓(xùn)機(jī)構(gòu)排名
  • 拿別的公司名字做網(wǎng)站張家界seo
  • 單頁關(guān)鍵字優(yōu)化免費(fèi)的電腦優(yōu)化軟件
  • 微信公眾號用什么開發(fā)安卓手機(jī)優(yōu)化軟件哪個(gè)好
  • 政府加強(qiáng)網(wǎng)站建設(shè)的意義可以免費(fèi)發(fā)布廣告的平臺有哪些
  • 深圳做網(wǎng)站的給說代發(fā)百度關(guān)鍵詞排名
  • 中文域名注冊網(wǎng)站惡意點(diǎn)擊競價(jià)時(shí)用的什么軟件
  • 制作好的網(wǎng)站有哪些內(nèi)容怎樣做引流推廣
  • 網(wǎng)上做設(shè)計(jì)網(wǎng)站梅州seo
  • 做旅游網(wǎng)站的數(shù)據(jù)怎么來百度營銷推廣登錄
  • 國外最新十大新聞上海最專業(yè)的seo公司
  • 網(wǎng)絡(luò)設(shè)置網(wǎng)站網(wǎng)絡(luò)營銷專業(yè)是做什么的
  • .net做網(wǎng)站用什么框架網(wǎng)絡(luò)營銷模式有哪些?
  • 北京建網(wǎng)站的公司免費(fèi)人脈推廣軟件
  • 深入解析wordpress...seo關(guān)鍵詞排名優(yōu)化評價(jià)
  • 中國建設(shè)銀行個(gè)人網(wǎng)站登錄seo自學(xué)網(wǎng)官方
  • 制作一個(gè)自己的網(wǎng)站100個(gè)成功營銷策劃案例
  • 教育部網(wǎng)站 專業(yè)建設(shè)方案seo培訓(xùn)中心
  • php網(wǎng)站文件下載怎么做seo搜索引擎優(yōu)化教程
  • 貴陽市花溪區(qū)建設(shè)局網(wǎng)站百度sem是什么意思
  • 網(wǎng)站源碼防盜原理微信營銷的方法7種
  • 卡盟自助網(wǎng)站建設(shè)武漢網(wǎng)站推廣優(yōu)化
  • 洛陽設(shè)計(jì)公司官網(wǎng)seo兼職
  • h5制作軟件推薦菏澤資深seo報(bào)價(jià)