|
现在非常多的的MCU性能都还不错,同时用户也会去扩展一些外部RAM,这样如果高效便捷的管理这些内存是一个重要话题。 今天给大家分享一份源码:基于无操作系统的STM32单片机开发,功能强大,可申请到地址空间连续的不同大小的内存空间,且用户接口简单,使用方便。
' f0 N) X% M, S$ n' P9 |
源码说明 源码包含memory.h 和 memory.c 两个文件(嵌入式C/C++代码的“标配”),其源码中包含重要的注释。 头文件memory.h :包含结构体等定义,函数API申明等; 源文件memory.c :是实现内存管理相关API函数的原型。0 F1 E3 j. C+ {+ k+ A' T
头文件memory.h 头文件是相关的定义和申请:
8 ]9 r/ t( u1 j! [- #ifndef __MEMORY_H__5 k5 A+ D9 r) C, o8 Q
- #define __MEMORY_H__
5 h9 s$ t0 Z) M+ R
: c/ ~) Q0 `9 m) |9 q- #include "stdio.h"
: ^7 Q: n9 X4 _4 I - #include "string.h") m7 c ?+ f: ]' T4 ^$ `! A
- #include "includes.h"
& j; c5 T' F1 b - //用户使用
" g5 \# i- I T# ~2 u - typedef struct
# V, ]# q Q* |, j, y - {
( b+ Z* }9 M' ?/ T |6 \. n1 Y4 x | - void *addr; //申请到的内存的起始地址
2 t; \% l! {7 ]: ]# ?9 _* Y; ^- k% t - uint32_t size; //申请到的内存的大小,按照块大小分配,大于等于申请大小
) Q: r) Q! x; X$ y2 B) \ - uint16_t tb; //申请表序号,申请内存时分配,释放内存时使用,用户不使用
+ B' L7 D8 v* }' f7 a - }DMEM;
+ }7 a) J4 b! ^# Y% Z( N! I - //若返回空,则申请失败! M% c$ G/ q) q0 L9 X# l
- DMEM *DynMemGet(uint32_t size);* n8 h A# z* q' F5 }. y4 [
- 5 J: |7 z4 o1 ?
- void DynMemPut(DMEM *pDmem);
" h/ r6 O2 q: g# h4 i3 V - w# H( a9 I( m
- #endif //__MEMORY_H__
复制代码
7 `8 A: N( O- L5 {6 v5 z
8 V( s. e" y6 ~( p4 b* | 这里的代码比较简单,也是常规的写法,重点是要理解结构体成员的含义。
: b1 j/ A. k# Z/ M/ G
源文件memory.c 源文件主要就是实现内存管理的函数,源码比较多,这里才分为三部分。
: X# B, V# {! O- Z1、相关的定义" f% i. @: _2 v2 [3 p
- #include "memory.h"
f/ _2 m1 h' y. y- h
+ B+ z& }$ b5 i+ U6 w- #define DMEM_BLOCK_SIZE 256 //内存块大小为128字节! e+ w' r4 g' x& @" u
- #define DMEM_BLOCK_NUM 20 //内存块个数为40个9 W: `+ N/ ?7 t0 I( L' x+ D) [
- #define DMEM_TOTAL_SIZE (DMEM_BLOCK_SIZE*DMEM_BLOCK_NUM) //内存总大小
" A- a# Q( V9 t8 J0 [
[; X( A+ M6 l- static uint8_t DMEMORY[DMEM_TOTAL_SIZE];
1 r& ~3 r+ E. `5 B - static DMEM_STATE DMEMS = {0};
& T; j x, U& e0 d& c* \/ A5 u4 y9 w
$ }; L5 x! z/ @) h& L* f- typedef enum
" u6 c( _4 {+ s' K% s - {
* \" b# U$ Z9 v7 N - DMEM_FREE = 0,; e6 g- I5 @" g4 l4 g! e4 U
- DMEM_USED = 1,
6 I6 ^3 V2 v2 `" m - }DMEM_USED_ITEM;4 e" W& m: ^8 \, |
- 6 h' P8 Z3 m/ L0 z& |
- typedef struct+ ^3 J- Q1 \* m( k- Z& |
- {
' a0 k- r9 A; y! |+ j - DMEM_USED_ITEM used; //使用状态
& ^: v4 Q0 D2 X# k - uint16_t blk_s; //起始块序号5 r0 J) t& s" f
- uint16_t blk_num; //块个数
P$ q# `% l ~- o) V9 W - }DMEM_APPLY;
" P$ @- A/ d8 z+ T Y! |. A: W - ( M% A% @. T1 K% S: T' S
- typedef struct
6 v' S3 y. L6 M% ?: b* S/ f9 X: ? - {5 C; Z- ^; ^/ E+ H6 j1 J
- DMEM_USED_ITEM tb_blk[DMEM_BLOCK_NUM];
% n2 M" n/ T" r& [8 ?; v( A( Q - DMEM tb_user[DMEM_BLOCK_NUM]; //用户申请内存信息* x# |( Q* u0 K7 B t: a
- DMEM_APPLY tb_apply[DMEM_BLOCK_NUM]; //系统分配内存信息/ r( j) w; l( b2 \4 s8 _# `
- uint16_t apply_num; //内存申请表占用数目0 D A# ]6 d2 D8 V% S' D! j
- uint16_t blk_num; //内存块占用数目. d& ?, h" Q0 K$ x: v5 B; _3 P. J
- }DMEM_STATE;
复制代码 , k8 o- ?0 R" {6 q
3 W6 H3 [; K2 x/ `2、内存分配函数DynMemGet
$ H! S- U6 w& k0 @8 T* n+ U- DMEM *DynMemGet(uint32_t size)
$ ~( u4 U. W$ |+ ^* c- L. Y - { _. l6 R' G, m1 N$ |; \
- uint16_t loop = 0;2 Q" Z4 M: p2 H& M8 i/ d7 @* a v; k! a
- uint16_t find = 0;
; I9 J6 F/ j+ W6 v+ Y6 W8 S5 r6 q - uint16_t blk_num_want = 0;
/ b+ ~ Q- j& s& m3 j - DMEM * user = NULL;( \0 Z$ Q; X3 C3 B0 Z! I
- DMEM_APPLY *apply = NULL;
( Z: D0 n8 o" i) ]3 O, S) n
1 K" o7 J+ R8 L0 S4 i- //申请内存大小不能为0
* B. v. R/ D' |; B3 L9 y - if(size == 0) { return NULL; }
* k2 O |4 `; c1 z4 j! M - //申请内存不可超过总内存大小
2 v# H# ^& d% ]) H2 b+ r( l. a- i- d - if(size > DMEM_TOTAL_SIZE) { return NULL; }' e1 c9 Z# A9 X& d8 L
- //申请内存不可超过剩余内存大小% p0 A/ b w0 {1 ]
- if(size > (DMEM_BLOCK_NUM - DMEMS.blk_num) * DMEM_BLOCK_SIZE) { return NULL; } \" j! c1 C& Y8 a J) y3 g
- //申请表必须有空余
' a% h V6 J2 y, I - if(DMEMS.apply_num >= DMEM_BLOCK_NUM) { return NULL; }4 D# p* N( R7 Q( Z& H
" }" d) J: F% {9 X3 ^- //计算所需连续块的个数
) v2 P# W' t$ d; ~% {/ ^& j* T! N% S - blk_num_want = (size + DMEM_BLOCK_SIZE - 1) / DMEM_BLOCK_SIZE;. ^" i2 {+ f8 o
- 6 U, a1 o8 T4 U5 q, ]- ^; A% f+ Q$ o
- //寻找申请表' }1 b& Q3 L- f' q+ V
- for(loop = 0; loop < DMEM_BLOCK_NUM; loop++)0 k# i; H9 F$ f- r) u
- {0 o0 w% a: H0 O0 J4 E1 ?
- if(DMEMS.tb_apply[loop].used == DMEM_FREE)
1 C5 k, ?' ]/ D5 m. h5 R9 U7 L - {" E/ @, r" W" v/ }
- apply = &DMEMS.tb_apply[loop]; //申请表已找到; s& {1 N/ ~' M. t7 B- d& g
- user = &DMEMS.tb_user[loop]; //用户表对应找到
. M: U! J2 \# C' n4 J, f$ l$ g. |+ ] - user->tb = loop; //申请表编号记录
! Q7 R' T% Y7 e% Q1 y" q; q - user->size = blk_num_want * DMEM_BLOCK_SIZE; //分配大小计算
; z5 T" f8 W' n% f6 ~# C. K - break;
0 K9 J& C' B" i) { - }' u* Z9 e* o ? ?; Z! B
- }
2 b; B" X9 \* j. \ }( U* U- W
u- s+ O) B& J F- //没有找到可用申请表,理论上是不会出现此现象的,申请表剩余已在上面校验
7 A5 z4 b0 Y& v6 u" a; p6 N - if(loop == DMEM_BLOCK_NUM) { return NULL; }8 @1 [% ~( C( N% _/ E X
K5 e$ ^1 Y# a3 p' h- //寻找连续内存块
7 v, w! r7 G$ s6 M/ }$ i6 u - for(loop = 0; loop < DMEM_BLOCK_NUM; loop++)- n. k# h7 |% G9 n3 U5 i7 m
- {
3 I0 Y9 t1 q1 E1 n% a* k - if(DMEMS.tb_blk[loop] == DMEM_FREE)) L. R9 u/ |/ k# F
- {//找到第一个空闲内存块7 d+ z6 z; o0 R$ h X+ h
- for(find = 1; (find < blk_num_want) && (loop + find < DMEM_BLOCK_NUM); find ++)
" ~; ~4 M; y; k+ m0 ] - {//找到下一个空闲内存块
) o3 ]: `' s" L1 V% e - if(DMEMS.tb_blk[loop + find] != DMEM_FREE)2 s( t3 x: B: ?4 h
- {//发现已使用内存块1 u. h4 M+ o9 T3 \, S- E
- break;$ G; A# z6 M7 D0 Y4 h
- }
* r6 i: b5 a# H) j1 c* d9 S - }# F0 g0 m/ k; J5 v: {" r/ M6 `
- if(find >= blk_num_want)' m9 h0 ], l( L
- {//寻找到的空闲内存块数目已经够用
' ~# O3 k% `1 t* v - user->addr = DMEMORY + loop * DMEM_BLOCK_SIZE; //计算申请到的内存的地址
k* t: q Y& x! M7 g+ l4 j8 ^ - apply->blk_s = loop; //记录申请到的内存块首序号
% k/ D! ?: f j9 G, ^% d. E$ g' F - apply->blk_num = blk_num_want; //记录申请到的内存块数目; q- D, Z9 c- X9 a" y6 z/ s
- for(find = 0 ; find < apply->blk_num; find++)
$ T& _, y" e0 u a% Y/ g5 A - {
( G; r3 }5 ?9 B# q5 l5 w - DMEMS.tb_blk[loop + find] = DMEM_USED;$ D9 D# l1 n' Z+ T* \
- }
2 ~9 M. {" O4 h9 T6 l$ W - apply->used = DMEM_USED; //标记申请表已使用
) m/ x. m/ M+ M0 Z" Z C, W4 @( f - DMEMS.apply_num += 1;
& e& P" B% _3 o" Y% o& s; t. X - DMEMS.blk_num += blk_num_want;
% f/ B7 L% C) x$ [$ H, Y - 4 c! g; p2 T5 H5 I- f
- return user;/ [2 U3 {; o0 B; g: c4 H
- }
, }6 h3 D, L/ v* t" T, ^2 ~ - else
- L! }' X+ {3 v/ |4 d - {//寻找到的空闲内存块不够用,从下一个开始找
, b6 P4 [4 V' h; l% T4 o8 i: k# L - loop += find;
" m2 A0 E& U8 r* R - }6 ?' Q. L; p' v+ [* [
- }" u2 A& C- e/ i& v* U$ g
- }
- B; p+ E( o3 G- t' M$ y
# c4 d- w, y# D' d( M- //搜索整个内存块,未找到大小适合的空间
& a2 F6 }' l ^ - return NULL;7 P: |! ^# {6 g1 ^- w
- }
复制代码
; ]3 y3 L1 [/ n+ b" t" b
! m% C! P" A( y3、内存释放函数DynMemPut
: ~6 n/ t7 W2 g& N0 w! ^- void DynMemPut(DMEM *user)
) s* Y' M! ]9 Q6 j6 R - {
?/ g0 z& T3 S& J% G; i8 p - uint16_t loop = 0;0 [$ C4 V; D+ |/ \0 x
- //若参数为空,直接返回8 ^$ X) K+ {/ C/ u# t" a5 U
- if(NULL == user) { return; }
: ]9 I7 u" M$ D @+ e* _
0 q# P/ q* ]7 ^ c' N2 x- //释放内存空间
( ` e' j3 h8 }+ P( ?0 Q' ~; e/ u - for(loop = DMEMS.tb_apply[user->tb].blk_s; loop < DMEMS.tb_apply[user->tb].blk_s + DMEMS.tb_apply[user->tb].blk_num; loop++)
& D" ?* d$ n0 n# c, o7 W - {
% Z0 i% J* x% [" L7 o% q+ | - DMEMS.tb_blk[loop] = DMEM_FREE;9 p/ @! q0 a8 i) G3 e$ R
- DMEMS.blk_num -= 1;! k" Y& h$ w/ T6 A& V }( U5 e0 |
- }: {, N, _3 F* T
- //释放申请表7 X$ |$ y# K# G/ }$ U
- DMEMS.tb_apply[user->tb].used = DMEM_FREE;
/ O# l2 L% O$ n3 k% ^1 _ - DMEMS.apply_num -= 1;+ D1 X1 t+ b- _; @
- }
复制代码 ; G. m1 s- Q, |) y) O7 l1 B
+ C4 q! x' B) @7 H
+ v4 L$ v# j9 f: y' G/ C. o( E$ M2 @
代码中包含注释,注释描述的比较清楚,也比较容易理解。! c% o: @ }# W7 t$ v1 C# m1 w
& ^5 V& k" e$ \. I$ ~+ N+ @ |