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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

RTThread入门

發布時間:2024/3/26 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 RTThread入门 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

RT-Thread入門

1.初識RT-Thread

嵌入式系統是一種完全嵌入在裝置或設備內部,為滿足特定需求而設計的計算機系統,譬如生活中常見的嵌入式系統就有:電視機頂盒、路由器、電冰箱、微波爐與移動電話等。

嵌入式操作系統是應用于嵌入式系統的軟件。

2.動態內存堆的使用

  • 裸機系統動態內存
    動態內存配置
    動態內存使用
  • RTT動態內存
    動態內存配置
    動態內存使用(源碼解析)
  • 動態內存注意事項
    內存復位
    內存泄漏
  • 其他相關API
    rt_realloc
    rt_calloc

2.1 簡述堆棧

在單邊機應用中,我們經常提到堆棧這個詞,實際上堆和棧是兩個不同的概念。
(stack):由編譯器自動分配釋放
(heap):一般由程序員分配和釋放

int a = 0; //全局初始化區 char *p1; //全局未初始化區 main() {int b; //棧char s[] = "abc"; //棧char *p2; //棧char *p3 = "123456"; //123456\0在常量區,p3在棧上。static int c = 0; //全局靜態初始化區p1 = (char*)malloc(10); //堆p2 = (char*)malloc(20); //堆 }

全局初始化區
全局靜態初始化區
全局未初始化區
常量區
棧區
堆區

2.2 MDK裸機系統動態內存配置和使用

使用方式1:startup_stm32f103xe.s

; Amount of memory (in bytes) allocated for Stack ; Tailor this value to your application needs ; <h> Stack Configuration ; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8> ; </h>Stack_Size EQU 0x00000400AREA STACK, NOINIT, READWRITE, ALIGN=3 Stack_Mem SPACE Stack_Size __initial_sp; <h> Heap Configuration ; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8> ; </h>Heap_Size EQU 0x00000200AREA HEAP, NOINIT, READWRITE, ALIGN=3 __heap_base Heap_Mem SPACE Heap_Size __heap_limit

棧空間的設置和堆空間的設置

使用方式2:

char *p; p = (char*)malloc(10) free(p);

2.3 RT-Thread動態內存配置和使用

與裸機系統下使用相差不大。
RT-Thread中,使用動態內存前,需要使用動態內存函數rt_system_heap_init 配置好動態內存區。
之后,使用rt_malloc及rt_free函數獲得動態內存及釋放動態內存。

char*p; p = (char *)rt_malloc(10); rt_free(p);

2.3.1 rt_system_heap_init

board.c

rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);

參數為起始地址和結束地址,兩地址之間的空間作為動態內存的空間
可以從芯片總的內存空間中提取一部分作為動態內存空間。

起始地址 HEAP_BEGIN

#define HEAP_BEGIN ((void *)&Image$$RW_IRAM1$$ZI$$Limit)

ImageRWIRAM1RW_IRAM1RWI?RAM1ZI$$Limit 是一個鏈接器導出的符號。代表ZI段的結束,也就是程序執行區的RAM結束后的地址,另一個角度,也就是我們執行區RAM未使用的區域的起始地址。

從工程的map文件中,可以看到:

Total RO Size (Code + RO Data) 63528 ( 62.04kB)Total RW Size (RW Data + ZI Data) 22576 ( 22.05kB)Total ROM Size (Code + RO Data + RW Data) 63676 ( 62.18kB)

整個工程中用到的靜態RAM空間用掉了22.05K
芯片總RAM有64K,除去用掉的22.05K的空間,剩余的空間的起始地址,在MDK中使用 宏

Image$$RW_IRAM1$$ZI$$Limit 表示。

結束地址 HEAP_END

#define HEAP_END STM32_SRAM_END #define STM32_SRAM_END (0x20000000 + STM32_SRAM_SIZE * 1024)

使用片內RAM的結束地址作為動態內存的結束地址。

2.4 動態內存堆使用注意點

內存復位
當我們每次申請到新的內存塊之后,建議對所申請到的內存塊進行清零操作。

p = (char *)rt_malloc(10); if(p!=RT_NULL) {rt_memset(p,0,10); //對申請到的內存清零 }

內存泄漏
內存泄漏(Memory Leak)是指程序中已動態分配的堆內存,由于某種原因未釋放或無法釋放,造成系統內存的浪費,導致程序運行速度減慢甚至系統崩潰等嚴重后果。

我們在使用動態內存時需要注意:rt_malloc 需要和 rt_free 配套使用。

2.5 其他動態內存相關的API

void *rt_realloc(void *rmem,rt_size_t newsize)

在已分配內存塊的基礎上重新分配內存塊的大小(增加或減少)
在進行重新分配內存塊時,原來的內存塊數據保持不變(縮小的情況下,后面的數據被自動截斷)

void *rt_calloc(rt_size_t count,rt_size_t size)

從內存堆中分配連續內存地址的多個相同大小的內存塊

2.6 動態內存使用的Demo代碼

int i = 0;char *ptr = RT_NULL; //內存塊指針for(i=0;;i++){ptr = rt_malloc(1<<i); //每次申請 (1<<i)大小的內存if(ptr != RT_NULL){rt_kprintf("rt_malloc OK! size=%d\n",(1<<i));rt_memset(ptr,0,(1<<i)); //清空申請到的內存rt_kprintf("rt_memset OK!\n");rt_free(ptr); //釋放申請到的內存rt_kprintf("rt_free OK!\n");}else{rt_kprintf("rt_malloc Err!\n");return -1;}}

3.線程的創建

3.1 線程的概念

RT-Thread名為實施線程RTOS,那么什么叫線程?

  • 人們在生活中處理復雜問題時,慣用的方法是“分而治之”,即把一個大問題分解成多個相對簡單、比較容易解決的小問題。小問題逐個被解決了,大問題也就隨之解決了。同樣,在設計一個較為復雜的應用程序時,也通常吧一個大型任務分解成多個小任務,然后通過運行這些小任務,最終達到完成大任務的目的。
  • 在RT-Thread中,與上述小任務對應的程序實體就叫做“線程”(或任務),RT-Thread就是一個能對這些小“線程”進行管理和調度的多”線程“操作系統。
  • 線程是實現任務的載體,它是RT-Thread中最基本的調度單位,它描述了一個任務執行的運行環境,也描述了這個任務所處的優先等級。
  • 3.2 線程的組成

    RT-Thread中,線程由三部分組成:線程代碼(入口函數)、線程控制塊線程堆棧

    線程代碼

    //無限循環結構 void thread_entry(void *parameter) {while(1){/* 等待事件發生 *//* 處理事件 */} }//順序執行結構 void thread_entry(void *parameter) {/* 事務1處理 *//* 事務2處理 *//* 事務N處理 */ }

    無限循環結構中一般加入讓出CPU的API調用,否則這個線程一直占用CPU,其他線程無法被執行。

    線程控制塊

    線程控制塊是操作系統用于管理線程的一個數據結構。它會存放線程的一些信息,例如優先級、線程名稱、線程狀態等,也包括線程與線程之間連接用的鏈表結構,線程等待事件集合等。

    struct rt_thread struct tr_thread *rt_thread_t

    線程棧

    RT-Thread每個線程都具有獨立的棧空間,當進行線程切換時,系統會將當前線程的上下文保存在線程棧中,當線程要恢復運行時,再從線程棧中讀取上下文信息,恢復線程的運行。

    線程上下文是指線程執行的環境,具體說就是各個變量和數據,包括所有寄存器變量、堆棧信息、內存信息等。

    線程棧在形式上是一段連續的內存空間,我們可以通過定義一個數組或者申請一段動態內存來作為線程的棧。

    3.3 線程創建

    創建線程

    創建動態線程

    rt_thread_t rt_thread_create(const char *name,void (*entry)(void *parameter),void *parameter,rt_uint32_t stack_size,rt_uint8_t priority,rt_uint32_t tick);

    創建靜態線程

    rt_err_t rt_thread_init(struct rt_thread *thread,const char *name,void (*entry)(void *parameter),void *parameter,void *stack_start,rt_uint32_t stack_size,rt_uint8_t priority,rt_uint32_t tick);

    動態線程的線程控制塊和線程棧都是自動分配的。
    創建靜態線程需要提前定義好線程控制塊和線程棧。

    啟動線程

    rt_err_t rt_thread_startup(rt_thread_t thread);

    調用此函數后,創建的線程會被加入到線程的就緒隊列,執行調度。

    3.4 靜態線程VS動態線程

    相關資源分配形式
    靜態線程需要將線程控制塊與線程棧先定義出來,動態線程不需要,動態線程的線程控制塊和線程棧是自動分配的。

    運行效率
    1.如果動態線程和靜態線程的線程控制塊和線程棧都處于芯片的RAM中,則動態線程和靜態線程的運行效率沒有區別。
    2.如果系統使用了外擴的外部RAM,動態線程的線程控制塊和線程棧是處于外部RAM中。則動態線程的運行效率有所下降。
    3.兩種方式創建的線程,本質上沒有區別。

    3.5 線程創建Demo

    /* 創建兩個線程,一個動態線程,一個靜態線程 */#define THREAD_PORITY 25 #define THREAD_SLICE 5 #define THREAD_STCK_SIZE 512//動態線程 rt_thread_t tid1 = RT_NULL; //靜態線程 struct rt_thread thread2; //靜態線程 char thread2_stack[THREAD_STCK_SIZE];/*** @brief 線程1的入口函數* * @param parameter [IN]線程的參數*/ void my_thread1_entry(void *parameter) {uint32_t count = 0;while(1){count ++;rt_kprintf("thread1 count = %d\r\n",count);rt_thread_mdelay(100);}}/*** @brief 線程2的入口函數* * @param parameter [IN]線程的參數*/ void my_thread2_entry(void *parameter) {uint32_t count = 0;for(count=0;count<10;count++){rt_kprintf("thread2 count = %d\r\n",count);}rt_kprintf("thread2 exit\r\n"); }int main(void) { //創建動態線程tid1 = rt_thread_create("thread1",my_thread1_entry,RT_NULL,THREAD_STCK_SIZE,THREAD_PORITY,THREAD_SLICE);if(tid1 != RT_NULL){rt_thread_startup(tid1); //將線程添加到線程就緒隊列rt_kprintf("thread1 creater OK!\r\n");}else{rt_kprintf("thread1 creater Err!\r\n");}//創建靜態線程rt_thread_init(&thread2,"thread2",my_thread2_entry,RT_NULL,&thread2_stack[0],THREAD_STCK_SIZE,THREAD_PORITY-1,THREAD_SLICE);rt_thread_startup(&thread2); //將線程2添加到線程就緒列表return 0; }

    運行結果:

    thread1 creater OK!
    msh >thread2 count = 0
    thread2 count = 1
    thread2 count = 2
    thread2 count = 3
    thread2 count = 4
    thread2 count = 5
    thread2 count = 6
    thread2 count = 7
    thread2 count = 8
    thread2 count = 9
    thread2 exit
    thread1 count = 1
    thread1 count = 2
    thread1 count = 3
    thread1 count = 4
    thread1 count = 5
    thread1 count = 6

    4.跑馬燈線程實例

    4.1 線程狀態

    線程狀態轉換圖

    4.2 系統滴答時鐘

    ? 每個操作系統中都存在一個“系統心跳”時鐘,是操作系統中最小的時鐘單位。這個時鐘負責系統和時間相關的一些操作。作為操作系統運行的時間尺度,心跳時鐘是由硬件定時器的定時中斷產生。
    ? 系統的心跳時鐘我們也稱之為系統滴答或時鐘節拍,系統滴答的頻率需要我們根據CPU的處理能力來決定。
    ? 時鐘節拍使得內核可以將線程延時若干個整數倍時鐘節拍,以及線程等待事件發生時,提供等待超時的依據。
    ? 頻率越快,內核函數介入系統運行的幾率就越大,內核占用的處理器時間就越長,系統的負荷就變大;頻率太小,時間處理精度又不夠。
    ? 我們在STM32平臺上一般設置系統滴答的頻率為100Hz,即每個滴答的時間是10ms。

    4.2.1 STM32上系統滴答的配置

    //board.c void SystemClock_Config(void) {...//設置系統中斷時間HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / RT_TICK_PER_SECOND);... }//系統定時器中斷 void SysTick_Handler(void) {...rt_tick_increase();... }//rt_config.h #define RT_TICK_PER_SECOND 100 //配置滴答頻率為100Hz

    rt_thread_mdealy(500) 延時500ms。這個API的延時就是由系統滴答完成的。

    4.3 GPIO驅動架構操作IO

    IO初始化

    void rt_pin_mode(rt_base_t pin,rt_base_t mode); pin:引腳索引 mode:引腳模式PIN_MODE_OUTPUTPIN_MODE_INPUTPIN_MODE_INPUT_PULLUPPIN_MODE_INPUT_PULLDOWNPIN_MODE_OUTPUT_OD

    IO寫入

    void rt_pin_write(rt_base_t pin,rt_base_t value); pin:引腳索引 value:引腳電平PIN_HIGHPIN_LOW

    IO讀出

    int rt_pin_read(rt_base_t pin); pin:引腳索引 返回值:引腳電平

    4.4 跑馬燈Demo

    /* 跑馬燈 */ #include <rtthread.h> #include <rtdevice.h> #include <drv_gpio.h>//線程信息 #define THREAD_PORITY 25 #define THREAD_SLICE 5 #define THREAD_STCK_SIZE 512//線程控制塊指針 rt_thread_t led_tid = RT_NULL;//LED引腳 #define MY_LED_PIN 14/*** @brief 線程的入口函數* * @param parameter [IN]線程的參數*/ void led_entry(void *parameter) {//設置LED引腳為推挽輸出rt_pin_mode(MY_LED_PIN,PIN_MODE_OUTPUT); while(1){rt_pin_write(MY_LED_PIN,PIN_HIGH); //引腳置高rt_thread_delay(50); //延時50個時鐘節拍 rt_thread_sleep(50)rt_pin_write(MY_LED_PIN,PIN_LOW); //引腳置低rt_thread_mdelay(500); //延時500ms}}int main(void) { //創建線程led_tid = rt_thread_create("led",led_entry,RT_NULL,THREAD_STCK_SIZE,THREAD_PORITY,THREAD_SLICE);if(led_tid != NULL){rt_thread_startup(led_tid); //加入到線程就緒隊列}return 0; }

    4.5 線程棧大小分配

    ? 先將線程棧大小設置一個固定值(比如2048),在線程運行時通過查看線程棧的使用情況,了解線程棧使用的實際情況,根據實際情況設置合理的線程棧大小。

    msh >list_thread thread pri status sp stack size max used left tick error ------ --- ------- ---------- ---------- ------ ---------- --- led 25 suspend 0x00000074 0x00000200 24% 0x00000005 000 tshell 20 ready 0x00000080 0x00001000 07% 0x00000005 000 tidle 31 ready 0x00000054 0x00000100 35% 0x00000010 000 msh >

    ? 一般將線程棧最新大使用量設置為70%。

    5.線程的時間片輪詢調度

    5.1 線程優先級

    ? 優先級和時間片是線程的兩個重要參數

    總結

    以上是生活随笔為你收集整理的RTThread入门的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    主站蜘蛛池模板: 日本黄色性视频 | 久操视频网站 | 日美av | 少妇视频| aaa人片在线 | 91精品国产电影 | 999国产精品亚洲77777 | 黄瓜视频91 | 99久久婷婷国产综合精品 | 亚洲熟女综合色一区二区三区 | 亚洲乱码国产乱码精品精剪 | 国家队动漫免费观看在线观看晨光 | 短篇山村男同肉耽h | 亚洲精品激情 | 日韩精品无码一区二区 | 国产精品久久久久久久妇 | 18无码粉嫩小泬无套在线观看 | 日韩人妻一区二区三区蜜桃视频 | 亚洲欧美一区二区三 | 色婷婷香蕉在线一区二区 | 希岛婚前侵犯中文字幕在线 | 亚洲乱妇 | 粉嫩av国产一区二区三区 | 国产成人精品aa毛片 | 国产在线国偷精品免费看 | 福利在线看 | 精品人伦一区二区 | 日韩不卡一区二区三区 | 无码人妻精品一区二区 | 亚洲国产成人久久 | 91插插插插插插插插 | 亚洲永久网站 | 日韩中文字幕网站 | 山外人精品影院 | 久久久久久久久久久91 | 三级黄色生活片 | 91老肥熟| 天天看片天天操 | 韩国三级av | 欧美色交 | 高清一区二区三区 | 97在线视频人妻无码 | 91污网站| 黄色美女免费网站 | 日韩在线影视 | 五月婷婷色综合 | 国内三级在线 | 色桃av | 红猫大本营在线观看的 | 欧美午夜精品一区二区 | 69视频网站| 中国浓毛少妇毛茸茸 | 欧美亚洲精品天堂 | 天堂成人在线视频 | 国产主播啪啪 | 国产在线视频福利 | 99精品视频免费 | 成人小视频在线看 | 光棍影院av | 麻豆国产精品777777在线 | 侵犯女教师一区二区三区 | 伊人久久一区二区三区 | 精品国产一区二区三区久久久蜜月 | 亚洲精品网站在线播放gif | 欧美色妞网| 亚洲视频一区二区三区在线观看 | 久久亚洲精品国产 | 极品三级 | 男女av网站| 自拍偷拍欧美激情 | 日韩专区第一页 | 精品久久久久久中文字幕人妻最新 | 欧美高清一区二区 | 日本在线播放 | 福利视频导航网 | 国产免费色视频 | 一级片在线观看免费 | 91麻豆国产福利精品 | 久久丫精品久久丫 | 国产性猛交96 | 国产高清精品软件丝瓜软件 | 亚洲国产精一区二区三区性色 | 日韩欧美国产高清91 | 国产精品扒开腿做爽爽爽a片唱戏 | 久久精品韩国 | 日本黄网免费 | 在线高清免费观看 | 国产精选毛片 | 欧美精品成人久久 | 一级特黄肉体裸片 | 色中文字幕 | 男女一级黄色 | 成全影视在线观看第8季 | 午夜精品999| 波多野结衣在线观看一区二区 | 四虎精品视频 | 超碰五月| 在线高清av| 丰满熟女人妻一区二区三区 |