色婷婷AⅤ一区二区三区|亚洲精品第一国产综合亚AV|久久精品官方网视频|日本28视频香蕉

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 基于STM32原子戰(zhàn)艦板內(nèi)存管理源碼

          基于STM32原子戰(zhàn)艦板內(nèi)存管理源碼

          作者: 時(shí)間:2016-12-01 來源:網(wǎng)絡(luò) 收藏
          struct _m_mallco_dev //內(nèi)存管理控制器
          {
          void (*init)(u8); //初始化
          u8 (*perused)(u8); //內(nèi)存使用率
          u8 *membase[2]; //內(nèi)存池 管理2個(gè)區(qū)域的內(nèi)存
          u16 *memmap[2]; //內(nèi)存管理狀態(tài)表
          u8 memrdy[2]; //內(nèi)存管理是否就緒
          };
          extern struct _m_mallco_dev mallco_dev; //在mallco.c里面定義,定義全局變量,結(jié)構(gòu)體變量mallco_dev
          void mymemset(void *s,u8 c,u32 count); //設(shè)置內(nèi)存
          void mymemcpy(void *des,void *src,u32 n);//復(fù)制內(nèi)存
          void mem_init(u8 memx); //內(nèi)存管理初始化函數(shù)(外/內(nèi)部調(diào)用)
          u32 mem_malloc(u8 memx,u32 size); //內(nèi)存分配(內(nèi)部調(diào)用)
          u8 mem_free(u8 memx,u32 offset); //內(nèi)存釋放(內(nèi)部調(diào)用)
          u8 mem_perused(u8 memx); //獲得內(nèi)存使用率(外/內(nèi)部調(diào)用)
          ////////////////////////////////////////////////////////////////////////////////
          //用戶調(diào)用函數(shù)
          void myfree(u8 memx,void *ptr); //內(nèi)存釋放(外部調(diào)用)
          void *mymalloc(u8 memx,u32 size); //內(nèi)存分配(外部調(diào)用)
          void *myrealloc(u8 memx,void *ptr,u32 size);//重新分配內(nèi)存(外部調(diào)用)
          #endif
          這部分代碼,定義了很多關(guān)鍵數(shù)據(jù),比如內(nèi)存塊大小的定義:MEM1_BLOCK_SIZE和MEM2_BLOCK_SIZE,都是32字節(jié)。內(nèi)存池總大小,內(nèi)部為40K,外部為200K(最大支持到近1M字節(jié),不過為了方便演示,這里只管理200K內(nèi)存)。MEM1_ALLOC_TABLE_SIZE和MEM2_ALLOC_TABLE_SIZE,則分別代表內(nèi)存池1和2的內(nèi)存管理表大小。
          從這里可以看出,如果內(nèi)存分塊越小,那么內(nèi)存管理表就越大,當(dāng)分塊為2字節(jié)1個(gè)塊的時(shí)候,內(nèi)存管理表就和內(nèi)存池一樣大了(管理表的每項(xiàng)都是u16類型)。顯然是不合適的,我們這里取32字節(jié),比例為1:16,內(nèi)存管理表相對(duì)就比較小了。
          主函數(shù)部分:
          int main(void)
          {
          u8 key;
          u8 i=0;
          u8 *p=0;
          u8 *tp=0;
          u8 paddr[18]; //存放的內(nèi)容“P Addr:+p地址的ASCII值”
          u8 sramx=0; //默認(rèn)為內(nèi)部sram
          Stm32_Clock_Init(9); //系統(tǒng)時(shí)鐘設(shè)置
          uart_init(72,9600); //串口初始化為9600
          delay_init(72); //延時(shí)初始化
          led_init(); //初始化與LED連接的硬件接口
          LCD_Init(); //初始化LCD
          usmart_dev.init(72); //初始化USMART
          Key_Init(); //按鍵初始化
          FSMC_SRAM_Init(); //初始化外部SRAM,因?yàn)橛玫搅送獠縮ram
          mem_init(SRAMIN); //初始化內(nèi)部?jī)?nèi)存池,SRAMIN==0
          mem_init(SRAMEX); //初始化外部?jī)?nèi)存池,SRAMEX==1
          POINT_COLOR=RED;//設(shè)置字體為紅色
          LCD_ShowString(60,50,200,16,16,"WarShip STM32");
          LCD_ShowString(60,70,200,16,16,"MALLOC TEST");
          LCD_ShowString(60,90,200,16,16,"WANG YAN");
          LCD_ShowString(60,110,200,16,16,"2013/12/16");
          LCD_ShowString(60,130,200,16,16,"key_right:Malloc key_left:Free");
          LCD_ShowString(60,150,200,16,16,"wake_up:SRAMx key_down:Read");
          POINT_COLOR=BLUE;//設(shè)置字體為藍(lán)色
          LCD_ShowString(60,170,200,16,16,"SRAMIN");
          LCD_ShowString(60,190,200,16,16,"SRAMIN USED: %");
          LCD_ShowString(60,210,200,16,16,"SRAMEX USED: %");
          while(1)
          {
          key=Key_Scan(0);//不支持連按
          switch(key)
          {
          case 0://沒有按鍵按下
          break;
          case key_right: //KEY0按下
          p=mymalloc(sramx,2048);//申請(qǐng)2K字節(jié),即64個(gè)內(nèi)存塊的空間
          if(p!=NULL)sprintf((char*)p,"Memory Malloc Test%03d",i);//向p寫入一些內(nèi)容
          break;
          case key_down: //KEY1按下
          if(p!=NULL) //NULL==0;
          {
          sprintf((char*)p,"Memory Malloc Test%03d",i);//更新顯示內(nèi)容
          // LCD_ShowString(60,270,200,16,16,p);
          LCD_ShowString(60,250,200,16,16,p);//顯示P的內(nèi)容
          printf("Memory Malloc Test%03d",i);//將“Memory Malloc Test”用串口輸出,利用串口助手可以看到輸出的結(jié)果
          //"03"表示參數(shù)“i”的值只顯示3位,%-輸出控制符;d-將“i”以十進(jìn)制的形式輸出;i的范圍0--255;輸出參數(shù)可以是多個(gè),可以參考郝斌老師的相關(guān)視頻;
          //輸出控制符包含:%Ld--L代表long類型;%c--代表字符類型;:%X--代表16進(jìn)制并大寫;
          }
          break;
          case key_left: //KEY2按下
          myfree(sramx,p);//釋放內(nèi)存
          p=0; //指向空地址
          break;
          case wake_up: //KEY UP按下
          sramx=!sramx;//切換當(dāng)前malloc/free操作對(duì)象
          if(sramx)LCD_ShowString(60,170,200,16,16,"SRAMEX");
          else LCD_ShowString(60,170,200,16,16,"SRAMIN");
          break;
          }
          if(tp!=p)
          {//在內(nèi)存paddr值處顯示:“P Addr:0X%08X”,“0X%08X”以大寫16進(jìn)制顯示參數(shù)tp(32位),“08”表示8位數(shù)。0X AAAA AAAA
          //剛進(jìn)入程序時(shí),因?yàn)閳?zhí)行了“mem_init(SRAMIN);”初始化函數(shù),所以p==0;所以LCD不會(huì)有顯示
          //因?yàn)槌绦蛞婚_始就有“u8 *tp=0;”,所以若不按下任何按鍵LCD就不會(huì)顯示下面的內(nèi)容(即“if(tp!=p)”控制的顯示內(nèi)容);
          tp=p;//PAddr顯示的是指針p本身的地址值;指針值是u32類型
          sprintf((char*)paddr,"P Addr:0X%08X",(u32)tp);//將指針p本身的地址值在LCD上打印出來即顯示
          LCD_ShowString(60,230,200,16,16,paddr); //顯示p的地址
          if(p)
          LCD_ShowString(60,250,200,16,16,p);//顯示P的內(nèi)容,即指針p內(nèi)存儲(chǔ)的數(shù)據(jù)“Memory Malloc Test%03d”
          else LCD_Fill(60,250,239,266,WHITE); //p=0,清除顯示
          }
          delay_ms(10);
          i++;
          if((i%20)==0)//DS0閃爍.
          {
          LCD_ShowNum(60+96,190,mem_perused(SRAMIN),3,16);//顯示內(nèi)部?jī)?nèi)存使用率
          LCD_ShowNum(60+96,210,mem_perused(SRAMEX),3,16);//顯示外部?jī)?nèi)存使用率
          led0=!led0;
          }
          }
          }
          總結(jié):通過內(nèi)存管理的學(xué)習(xí),更加深刻的領(lǐng)會(huì)到指針是c語言的靈魂,對(duì)c語言的知識(shí)是一個(gè)鞏固和提高;同時(shí)也學(xué)習(xí)到了sprintf()函數(shù)的運(yùn)用技巧。
          本章希望利用USMART調(diào)試內(nèi)存管理,所以在USMART里面添加了mymalloc和myfree兩個(gè)函數(shù),用于測(cè)試內(nèi)存分配和內(nèi)存釋放。大家可以通過USMART自行測(cè)試。
          4,下載驗(yàn)證:
          在代碼編譯成功之后,我們通過下載代碼到ALIENTEK戰(zhàn)艦STM32開發(fā)板上,得到如圖所示界面:
          可以看到,內(nèi)外內(nèi)存的使用率均為0%,說明還沒有任何內(nèi)存被使用,此時(shí)我們按下KEY0,就可以看到內(nèi)部?jī)?nèi)存被使用5%(每按下一次申請(qǐng)2K的空間,lcd上顯示的使用率遞增5%;20*2K==40K)了,同時(shí)看到下面提示了指針p所指向的地址(其實(shí)就是被分配到的內(nèi)存地址)和內(nèi)容。多按幾次KEY0,可以看到內(nèi)存使用率持續(xù)上升(注意對(duì)比p的值,可以發(fā)現(xiàn)是遞減的,說明是從頂部開始分配內(nèi)存!),此時(shí)如果按下KEY2,可以發(fā)現(xiàn)內(nèi)存使用率降低了5%,但是再按KEY2將不再降低,說明“內(nèi)存泄露”了。這就是前面提到的對(duì)一個(gè)指針多次申請(qǐng)內(nèi)存,而之前申請(qǐng)的內(nèi)存又沒釋放,導(dǎo)致的“內(nèi)存泄露”。
          按KEY_UP按鍵,可以切換當(dāng)前操作內(nèi)存(內(nèi)部?jī)?nèi)存/外部?jī)?nèi)存),KEY1鍵用于更新p的內(nèi)容,更新后的內(nèi)容將重新顯示在LCD模塊上面。
          本章,我們還可以借助USMART,測(cè)試內(nèi)存的分配和釋放,有興趣的朋友可以動(dòng)手試試。如右圖USMART測(cè)試內(nèi)存管理函數(shù)所示。
          /////////////////////////插補(bǔ):printf和sprintf函數(shù)的用法////////////////////////////
          printf和sprintf函數(shù)的用法非常重要,用于程序參數(shù)調(diào)試。這兩個(gè)函數(shù)都包含在系統(tǒng)啟動(dòng)代碼“stdio.h”頭文件中;
          1,例:printf("Memory Malloc Test%03d",i);//將“Memory Malloc Test”用串口輸出,利用串口助手可以看到輸出的結(jié)果;
          "03"表示參數(shù)“i”的值只顯示3位,%d-輸出控制符;d-將“i”以十進(jìn)制的形式輸出;i的范圍0--255(因?yàn)槭莡8類型);輸出參數(shù)可以是多個(gè),可以參考郝斌老師的相關(guān)視頻;輸出控制符包含:%Ld--L代表long類型;%c--代表字符類型;:%X--代表16進(jìn)制并大寫;%s-字符串類型
          2,如何理解字符串打印函數(shù)int sprintf(char * __restrict /*s*/, const char * __restrict /*format*/, ...) __attribute__((__nonnull__(1,2)));?
          在內(nèi)存管理實(shí)驗(yàn)中例如,sprintf((char*)p,"Memory Malloc Test%03d",i)函數(shù)的使用問題:
          1),第一個(gè)形參(char*)p的意思是(第一個(gè)形參必須是指針類型),第二個(gè)形參即字符串“Memory Malloc Test%03d”存儲(chǔ)在內(nèi)存中的具體指針值,因?yàn)樽址莡8類型即char*類型,所以“(char*)p”與之呼應(yīng);因?yàn)榈诙€(gè)形參“Memory Malloc Test%03d”中有輸出控制符“%03d”,所以第一個(gè)形參(char*)p的值是變化的(因?yàn)閰?shù)“i”的值在變);這里輸出控制符“%03d”的意思可以參考printf()函數(shù);
          也就是說,sprintf函數(shù)的第一個(gè)形參必須是指針類型,它是第二個(gè)形參(輸出內(nèi)容)在存儲(chǔ)器中存儲(chǔ)的首地址,是一個(gè)指針變量,第三個(gè)形參就是要輸出的參數(shù);所以說sprintf函數(shù)包含的內(nèi)容很多,作用很大。
          2),sprintf函數(shù)的作用是在顯示屏中顯示相關(guān)參數(shù),即向p寫入一些內(nèi)容即Memory Malloc Test%03d”;
          結(jié)合LCD_ShowString(60,270,200,16,16,p)的顯示結(jié)果更好理解,即顯示P的存儲(chǔ)內(nèi)容即在相應(yīng)的坐標(biāo)處“Memory Malloc Test%03d”;”
          3),例子:
          u8 s[8];
          char* who = "I"; //將字符“I”賦給char* 類型變量who;
          char* whom = "STM32"; //將字符串“STM32”賦給char* 類型變量whom;
          sprintf(s, "%s love %s.", who, whom); //產(chǎn)生:"I love STM32. " 這字符串寫到s中
          LCD_ShowString(60,250,200,16,16,s);
          //sprintf(s, "%10.3f", 3.1415626); //產(chǎn)生:" 3.142",浮點(diǎn)型顯示
          4),sprintf函數(shù)一般情況下是用在需要字符顯示的場(chǎng)合,比如你要顯示一個(gè)數(shù)字,通常的做法是取出某一位然后加上0x30這個(gè)數(shù),這樣一位一位來比較麻煩,用sprintf這個(gè)函數(shù)呢,一次性就給你搞定了
          比如你想打印3.1415926這個(gè)數(shù)值到液晶上顯示,通常的做法代碼就很多而且亂,有了這個(gè)函數(shù)呢,直接這樣
          float PI=3.1415926;
          u16 strbuffer[10];
          sprintf(strbuffer,"PI=:%09d",PI);
          然后直接將strbuffer這個(gè)數(shù)組送去顯示即可,或者打印到串口,這樣就可以直接字符顯示了
          注意:sprintf函數(shù)必須結(jié)合LCD顯示函數(shù)使用才能有效!并且形參必須定義好合適的數(shù)據(jù)類型;sprintf()函數(shù)的最大作用就是非常方便的在LCD顯示屏上顯示自己想要的數(shù)據(jù)類型!參考關(guān)于sprintf函數(shù)的實(shí)驗(yàn)。
          3,疑問?
          a,在51單片機(jī)中,如何將sprintf函數(shù)包含進(jìn)51的啟動(dòng)代碼中?如果不將sprintf函數(shù)包含進(jìn)51的頭文件,顯示屏肯定不能用sprintf函數(shù)顯示數(shù)據(jù)。
          b,在stdio.h中,找到的是int sprintf(char * __restrict /*s*/, const char * __restrict /*format*/, ...) __attribute__((__nonnull__(1,2)));怎么看不到函數(shù)內(nèi)容?
          sprintf是C語言標(biāo)準(zhǔn)庫提供的函數(shù), 包含在stdio.h中, 只要在文件頭#include 即可.
          原型為int sprintf ( char * str, const char * format, ... );
          /////////////////////////插補(bǔ):printf和sprintf函數(shù)的用法////////////////////////////
          上一頁 1 2 3 下一頁

          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉