TencentOS浅学过程记录
TencentOS淺學過程記錄
- 前言
- 一、RTOS
- 二、學習資料來源
- 三、初步學習過程中的疑難問題解決
- 任務調度以及輪詢時間片
- 消息隊列與郵箱隊列
- 互斥鎖
- 任務中為什么一定要加while(1)循環
- 內存管理
- 三、實操問題解決
- 使用TencentOS中的shell(即**CLI命令行**)
- RTOS新手學習一定要注意**堆棧大小**
- 使用動態內存時記得要去tos_config.h文件中修改配置
- 提醒
前言
大三下生產實習作業,基于LoRaWAN的物聯網應用,剛好有一個選題是關于RTOS的,之前對于RTOS也有過一些了解,但是一直沒有真正的學習使用過,剛好借這個機會學習一波。(這里主要分享一下我在對于騰訊TencentOS學習使用過程中的一些收獲與問題解決過程)
一、RTOS
實時操作系統的概念這里不再贅述。相較于之前順序執行的裸機編程,RTOS多任務執行以及阻塞機制使得程序執行效率更高,一些沒有必要執行的代碼可以利用阻塞機制使它僅在必要的時候執行,任務重要性可以按照優先級分配,整體看起來就是我們想要哪些代碼執行,哪些代碼不執行都是可以控制調節的,這樣可以使重要的任務一直得到有效執行,這樣程序執行效率有很大提高。
二、學習資料來源
當前開源的RTOS非常多,剛開始我有了解到RT-Thread,Freertos,TencentOS,uCOS等等,但是對于新手大佬推薦RT-Thread比較多,畢竟是國產開源,相關資料手冊等等都是中文編寫,目前使用也比較廣泛,各處學習網站也有非常多的問題解決博客。當然TencentOS也是中文資料,只不過目前使用沒幾年使用量不是特別大,除過騰訊開源庫中的資料其他可借鑒的博客也比較少。至于為什么選擇TencentOS,作業時間留的有點短,杰杰大佬說TencentOS源碼實現非常精簡,沒有特別復雜的數據結構在里面,對于新手接觸RTOS,簡單了解體驗RTOS中的一些任務通信機制非常友好好上手(當然C語言基礎得不錯)(不同公司開源的RTOS內部任務同步以及通信機制大同小異),作業時間只有一個月,TencentOS正合我意。
我在學習過程中主要借鑒的學習資料有:
以上以Github開源庫為主要資料,杰杰大佬的專欄寫于2019年左右,但是目前TencentOS在一些方面更新了很多,總之就是許多代碼不是以前的代碼了,但是大同小異,杰杰大佬專欄中對于郵箱,信號量,互斥鎖,事件等等的講解非常有助于對TencentOS中相關任務機制的理解。由于更新比較多,學習者在學習過程中還是有必要閱讀一下相關源碼的(會C就可以,源碼參考杰杰大佬的專欄會相對比較好理解)。
GitHub中資料比較齊全
其他的在CSDN上也是零零散散能找到多少是多少。
三、初步學習過程中的疑難問題解決
這里主要指在運行github提供的內核開發指南中的例程源碼時,嘗試性的修改代碼產生的一系列問題以及對一些概念的理解。
任務調度以及輪詢時間片
1.任務調度:每一次任務調度即進入knl_sched()的時候,系統會去查找就緒態任務中優先級最高的任務。如果優先級最高的任務不止一個(相同優先級的任務會按順序掛載在同一個列表中),系統會在同一優先級任務列表中選取第一個進行執行;
2.輪詢時間片處理:當進入輪訓時間片處理程序時,系統會獲取當前任務以及當前任務的優先級,然后判斷該優先級列表中是否還有同優先級的任務處于就緒態,如果有就按照輪詢時間片機制,輪詢時間片數值依次減少。如果沒有同優先級任務處于就緒狀態,系統將不再執行輪詢時間片機制。(這也就是說輪詢時間片僅在當任務就緒列表中同一個優先級的任務有兩個以上時才會起作用,否則是不會起作用的);在輪詢時間片起作用的情況下,當一個任務執行時間超出輪詢時間片的時間設定后,系統會把相同優先級任務列表中第一個任務調換到最后一個,那么下一次系統調度即執行knl_sched()時取最高優先級的第一個任務(原先的任務插到了列表中的最后一個,這個時候已經實現了任務被輪詢時間片強行切到了另外一個任務)
代碼注釋簡單如下:
總結:這個功能很雞肋,大部分時間沒什么用,而且這是一種強行切換,如果你的任務中存在互斥鎖,強行切換導致互斥鎖沒有來的及釋放,一定會出問題。(總之這是一種強行切換,一般情況下只有在任務中不加os_delay()時才會用到,而且在切換時不對原先任務中的互斥鎖等同步機制進行應急處理)。感覺沒什么用。
消息隊列與郵箱隊列
TencentOS里面提供了消息隊列,郵箱隊列以及優先級消息隊列,優先級郵箱隊列。底層實現主要是兩個分別是環形隊列和優先級隊列來實現,這兩個區別就是,環形隊列按照先入先出,優先級隊列寫入時會記錄寫入的優先級,彈出時會按照優先級高低先后彈出。另外就是消息隊列和郵箱隊列的區別,消息隊列僅傳遞指針,郵箱隊列可以傳遞較大的內存塊,底層實現都是環形隊列,只不過消息隊列存入的是指針即一個32位的地址,郵箱隊列可以存入一個結構體中的所有數據。
uint8_t msg_pool[MESSAGE_MAX * sizeof(void *)];//消息隊列存儲池MESSAGE_MAX*地址占內存大小(更小)typedef struct mail_st {char *message;int payload; } mail_t; uint8_t mail_pool[MAIL_MAX * sizeof(mail_t)];//郵箱隊列存儲池MAIL_MAX*結構體占內存大小(更大)我的理解:郵箱隊列可以保證數據存入郵箱,數據沒有被接收之前不會丟失,但是消息隊列中的地址數據未被接收之前如果該地址指向的內存數據發生變化,那么接收到之后的數據可能并不是你想傳遞的數據。(如果數據被更改時間間隔足夠長的話可以使用)。這個時候我覺得消息隊列還挺雞肋的,我還沒有想到一個消息隊列的合理利用場景,糾結于傳送地址,但地址數據發生改變不就亂了,希望大佬看到可以指點一下。這塊指出一下,不同的RTOS如騰訊還有FreeRTOS中的同步及通信機制原理上差不多但是使用時還是有區別的,比如FreeRTOS中的消息隊列和TencentOS中的郵箱一樣傳遞的是數據不是指針。
互斥鎖
互斥鎖中有一個優先級翻轉的概念,優先級翻轉會對程序中任務執行產生很大的危害,高優先級的任務得不到有效執行,舉一個簡單的優先級翻轉的例子:有四個任務A,B,C,優先級分別為1,2,3,并且A與C在爭奪互斥鎖,某一時刻A,B均處于阻塞態,任務C獲取到互斥鎖,此時鎖處于閉鎖狀態。接下來A任務到達就緒態,因為優先級高搶斷C執行但是獲取不到鎖進入阻塞態。這是B到達就緒態,由于B不需要互斥鎖且優先級高于C,所以B搶斷C執行。在這個過程中A想要執行就必須等待B執行完之后切換到C,C執行完才能輪到A。然而A是優先級最高的任務,這樣會使得系統中優先級最高的任務無法得到有效執行,嚴重的話會導致程序崩潰。
TencentOS采用了優先級繼承策略,當任務A申請鎖的時候,發現鎖在C的手里且C的優先級低于A的優先級,那么立馬將C的優先級提高到和A等同的優先級,那么C執行過程中就不會被B打斷,即A只要等C執行完就可以執行了,不用等待B的執行。這樣一定程度上削弱了優先級翻轉的危害。
當信號量為1的時候也可以當做互斥鎖用,但是由于信號量沒有設計優先級繼承的東西,所有有可能造成優先級翻轉。
任務中為什么一定要加while(1)循環
在RTOS初學過程中,有些時候就忘記寫while(1)了,執行后發現咋突然就停下來了,甚是奇怪。每個任務也是一個函數,切換任務時會保存上一個任務的上下文。如果沒有while(1),程序執行完最后一句就結束了,函數執行結束后函數里面的變量等等都會被釋放掉,該任務就被直接銷毀了,只有讓任務執行函數處于循環當中,函數不會結束,任務才不會被銷毀。任務才能夠在調度時保存上下文,下次從原先離開的地方繼續執行。這也就是我們在使用過程中看到任務函數只在while(1)內部執行,切換任務從哪里離開,下次就從哪里開始。
內存管理
TencentOS中有兩種內存管理,分別是靜態內存管理和動態內存管理。
靜態內存是在全局變量區開辟一塊待分配的內存,可以對這片內存進行管理(申請釋放定長內存塊)。
動態內存是指在堆區申請釋放定長內存塊。
內存泄漏:申請的內存塊使用完之后一定要釋放,并且申請內存的獲得的首地址不能丟失,相關內存泄漏的知識可以參考其他博文。
動態內存管理參考示例:
總結:按照我的理解,動態內存的使用是在當原先任務堆棧大小設置的較小,而實際任務中需要使用更大的內存,也就是說,原先任務堆棧大小不能滿足程序運行的需要,為了程序正常運行,我們需要從堆區開辟一塊動態內存來使得程序正常運行,程序運行完之后把內存釋放掉用于其他。
三、實操問題解決
這塊主要是我在完成生產實習作業過程中即實際開始自己碼代碼過程中遇到的疑難問題解決。
使用TencentOS中的shell(即CLI命令行)
命令行類似一種對話框,基本邏輯就是PC端通過串口輸入命令,單片機破解命令執行對應的功能函數。TencentOS自帶shell中包括了help(查詢有哪些命令,分別是哪些功能)、ps(每個任務的堆棧大小以及實際運行中的堆棧深度),還有free(查詢程序內存使用情況)。我們也可以添加自己的命令對單片機進行控制。(總之使用起來非常方便)
shell文件位置(開源庫中的文件)
shell中的文件全部移進去,包含一些頭文件啥的,反正都在github下載的這些文件中,找一下就有。
最后總共就這么多就夠了。
TencentOS的shell是用字符輸入輸出隊列配合信號量實現的。簡單來說就是你在串口助手界面輸入一個字符,shell代碼會將獲取到的字符塞入到字符隊列中去,同時信號量加一。另一邊任務函數會根據信號量的多少進行字符循環獲取保存并回傳給PC,信號量為零則進行阻塞。當任務函數檢測到有\n,\r時則會跳出循環,將之前保存的字符與命令庫中的命令進行對比,如果對比正確則執行響應函數,對比錯誤就回傳"command not found\r\n"
核心代碼如下:
效果:
RTOS新手學習一定要注意堆棧大小
任務程序運行都是在分配的堆棧內存中運行的,如果分配的堆棧內存不夠,程序就會直接暴斃(進入硬件錯誤中斷)。所以新手在調試程序過程中可以嘗試:
1.硬件錯誤中斷中加入printf函數用于提醒你進入了硬件中斷(這個時候首先考慮堆棧內存不夠問題)
2.如果直接導入了shell文件,可以通過"ps"命令直接進行獲取當前任務的吃棧深度。一般所有的任務堆棧大小盡量先設置的大一些,然后ps命令看一下最大吃棧深度有多深,最后根據最大吃棧深度調整任務堆棧大小(單片機內存還是要省著用的)
stk size代表設定的堆棧大小,stk depth代表程序實際運行時所使用到的最大棧深度
3.TencentOS提供了,獲取最大吃棧深度的函數
使用動態內存時記得要去tos_config.h文件中修改配置
可以把最初給的大小根據實際情況改大一點,否則后邊的大內存申請會有問題。
#define TOS_CFG_MMHEAP_DEFAULT_POOL_SIZE 0xA00 // 配置TencentOS tiny默認動態內存池大小提醒
代碼中有詳細注釋
總結
以上是生活随笔為你收集整理的TencentOS浅学过程记录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 建设规划合理、高效便捷的现代物流中心——
- 下一篇: AMD锐龙R3 5400U性能怎么样?相