|
现在非常多的的MCU性能都还不错,同时用户也会去扩展一些外部RAM,这样如果高效便捷的管理这些内存是一个重要话题。 今天给大家分享一份源码:基于无操作系统的STM32单片机开发,功能强大,可申请到地址空间连续的不同大小的内存空间,且用户接口简单,使用方便。 源码说明 源码包含memory.h 和 memory.c 两个文件(嵌入式C/C++代码的“标配”),其源码中包含重要的注释。 头文件memory.h :包含结构体等定义,函数API申明等; 源文件memory.c :是实现内存管理相关API函数的原型。头文件memory.h 头文件是相关的定义和申请:- #ifndef __MEMORY_H__, m5 d* \' J" h7 q8 t
- #define __MEMORY_H__
" ?% j6 N' N5 h0 @1 W I - 5 t$ m' O3 s9 x$ a8 k& c
- #include "stdio.h"- c& ?8 Z; G9 G$ B) B
- #include "string.h"1 h+ l7 B0 [* S8 R6 _ @* m
- #include "includes.h"$ G# R' `- [& {# s! u2 X3 _
- //用户使用
- \# v) i% \1 w, I& c/ @ - typedef struct
" M* Y) k0 u% Q. Q' ?- ?" U - {7 B4 E g: }$ z% q u
- void *addr; //申请到的内存的起始地址, s) c+ n! Z! q
- uint32_t size; //申请到的内存的大小,按照块大小分配,大于等于申请大小
- o( C4 V8 z3 P7 w8 {5 d- q: O - uint16_t tb; //申请表序号,申请内存时分配,释放内存时使用,用户不使用
# X/ I/ D! k& a" [5 | - }DMEM;: Z! K, y4 \* G
- //若返回空,则申请失败
- `: u+ c5 K! D - DMEM *DynMemGet(uint32_t size);
* I# f" S" \" @9 [( u
! D; A3 O) k m5 P: s8 j5 M/ z- void DynMemPut(DMEM *pDmem);7 Z$ Q! ?' y5 ^. `* U9 K
% o$ {) f/ u) O, R8 I- #endif //__MEMORY_H__
复制代码
. d3 F% S9 s1 V) o" s) Y F# g 这里的代码比较简单,也是常规的写法,重点是要理解结构体成员的含义。 ' T* t( M! |. I8 x$ O c
源文件memory.c 源文件主要就是实现内存管理的函数,源码比较多,这里才分为三部分。
0 e4 |$ B1 g4 u) p8 ]1 } x! r1、相关的定义
2 S$ V) P) ?" T3 E# F% J- #include "memory.h"
' j/ S# s( Z, q0 H) D+ s) K$ x - $ I1 {( i* B0 C( ?9 k8 Z" U
- #define DMEM_BLOCK_SIZE 256 //内存块大小为128字节
. \: D5 K1 f: K& U - #define DMEM_BLOCK_NUM 20 //内存块个数为40个8 G; @ v: N. t
- #define DMEM_TOTAL_SIZE (DMEM_BLOCK_SIZE*DMEM_BLOCK_NUM) //内存总大小
6 L9 \+ C0 N7 h, D+ D
% A. U6 W- o r( r8 R& d+ ?6 Y0 x3 l- static uint8_t DMEMORY[DMEM_TOTAL_SIZE];7 | \2 x& c- y* X9 e( Z m3 Y
- static DMEM_STATE DMEMS = {0};6 A. j8 ~ T+ z" r
3 A3 }, Z& v0 ~- typedef enum1 Y, g, I; E( ]% d
- {
- n6 L' L) z: O( f+ K: [; U* E - DMEM_FREE = 0,
, n; e3 d3 C: S. v8 A% b/ ^( c2 a - DMEM_USED = 1,
3 \( C2 j4 s& }3 ? - }DMEM_USED_ITEM;
# A) }" S/ u" M" Z& U' h1 p
2 A% G7 Z) r+ s7 w- typedef struct4 Z, O' [5 k) R9 H2 F1 @
- {
1 o5 S9 Q! }9 j$ c5 a8 \ - DMEM_USED_ITEM used; //使用状态
7 c# f/ a: v+ | - uint16_t blk_s; //起始块序号( d& a8 n0 f& n L4 G% C
- uint16_t blk_num; //块个数$ S; e, r$ h" U7 f7 D
- }DMEM_APPLY;; P2 T e' `6 l/ r% P6 t$ z. l5 K
# T0 i7 S7 f/ }) c, l- typedef struct
0 \" t4 j. R. j! b {5 N - {6 K0 c& _" P8 K' ^) d
- DMEM_USED_ITEM tb_blk[DMEM_BLOCK_NUM];
$ v) [' g" |8 k8 }+ O - DMEM tb_user[DMEM_BLOCK_NUM]; //用户申请内存信息
; l& b3 [% w T4 c6 Y$ | - DMEM_APPLY tb_apply[DMEM_BLOCK_NUM]; //系统分配内存信息
, P* Z9 @5 \2 b: t+ P, t3 H# I - uint16_t apply_num; //内存申请表占用数目
/ E9 ^, H! a( O - uint16_t blk_num; //内存块占用数目
) g0 N8 I% x: L6 W5 }, U7 s - }DMEM_STATE;
复制代码 - b2 X3 M7 N/ a4 s5 r q; ]9 S
2、内存分配函数DynMemGet, D2 E) L, H+ D1 F- S
- DMEM *DynMemGet(uint32_t size)
- {- Y- a" i1 p ?( k) T - {# E% b( x4 |0 U9 h
- uint16_t loop = 0;/ h& n9 ^% P8 n7 J: p8 Q2 {. B
- uint16_t find = 0;
+ B1 `7 k; ^$ K+ f8 ? - uint16_t blk_num_want = 0;
% D$ n4 v4 F. ^, | - DMEM * user = NULL;
8 D3 O- [% Y# |8 ^$ g( g* P0 k - DMEM_APPLY *apply = NULL;
+ I7 |8 l" ]1 {; u: ]) }9 x - 6 Y7 p: `3 F% x$ |! y3 f* Q% x3 H) {
- //申请内存大小不能为04 n% n+ m( L' Z# R1 K9 w. a
- if(size == 0) { return NULL; }
7 U. n& y0 V9 ^. m8 u- M# }. Q - //申请内存不可超过总内存大小0 o' ~3 E% R8 ~7 b$ _" T
- if(size > DMEM_TOTAL_SIZE) { return NULL; }# n |( n( Y- y
- //申请内存不可超过剩余内存大小' u+ j+ d" J8 {9 H F2 ^
- if(size > (DMEM_BLOCK_NUM - DMEMS.blk_num) * DMEM_BLOCK_SIZE) { return NULL; }8 B& T% @2 G% C* y# q" J3 s y
- //申请表必须有空余% A5 y% t6 k+ o) F- M. S* C
- if(DMEMS.apply_num >= DMEM_BLOCK_NUM) { return NULL; }! M- Q* T6 }& m5 ]
# X2 }, Z% Q: x- M4 S- //计算所需连续块的个数$ {3 K. E2 U, _4 ]) H. z
- blk_num_want = (size + DMEM_BLOCK_SIZE - 1) / DMEM_BLOCK_SIZE;9 E; H `/ N- o/ B* d
, E$ A( D- t L; ?# B- //寻找申请表, }. B1 r7 | }7 Y
- for(loop = 0; loop < DMEM_BLOCK_NUM; loop++)$ d9 l3 O5 \9 m$ m8 Q& M o
- {
6 v+ \( v7 C8 A9 R - if(DMEMS.tb_apply[loop].used == DMEM_FREE). t3 u( S+ K& [, y2 V5 F/ u
- {2 j! f* {* t8 I. K S* K4 L3 ~. c8 |
- apply = &DMEMS.tb_apply[loop]; //申请表已找到9 F3 ~( M7 A$ P! y! L1 }+ o
- user = &DMEMS.tb_user[loop]; //用户表对应找到
+ U& x3 v2 L. b6 J' L, r - user->tb = loop; //申请表编号记录
9 u3 P( ~; T- F6 | I* R4 ~$ J- K - user->size = blk_num_want * DMEM_BLOCK_SIZE; //分配大小计算
6 P" N- S) @1 L1 r* b$ S - break;$ L) l& w# I( M1 s
- }5 A9 j. s9 h+ O: U* j9 g
- }$ y& v. l; C; y; @- @, E0 R6 f
l( [- s T( ~6 D- //没有找到可用申请表,理论上是不会出现此现象的,申请表剩余已在上面校验
4 K5 ~4 I: M0 K - if(loop == DMEM_BLOCK_NUM) { return NULL; }0 ?' Z! j6 J- z `1 ?! l/ P& J
- 8 R3 e1 R) c# Z# y7 l/ \
- //寻找连续内存块+ `' n: C9 A0 ?6 E' g4 D
- for(loop = 0; loop < DMEM_BLOCK_NUM; loop++)! L' F- j/ c) }. L( O) G# C
- {
' K* {( Q# w$ ^6 f# C - if(DMEMS.tb_blk[loop] == DMEM_FREE)
. n4 U3 y$ I) |# @7 }0 B - {//找到第一个空闲内存块6 `7 `. Z8 c$ `) }6 G! F
- for(find = 1; (find < blk_num_want) && (loop + find < DMEM_BLOCK_NUM); find ++) a; C; ^) P' A+ F3 F$ g! u1 O
- {//找到下一个空闲内存块1 l6 G& D/ n! W) @- M* g1 ^
- if(DMEMS.tb_blk[loop + find] != DMEM_FREE)
* U$ q" n* P& h) } N# U - {//发现已使用内存块7 B0 W) A. ]; G- H* w+ m
- break;* ]: p! [$ A1 E* ]1 I: A
- }
" \: I* E! R( M5 Q) A - }
2 g0 d! l& |/ y3 L' }: y - if(find >= blk_num_want)0 w+ B6 k" t) g
- {//寻找到的空闲内存块数目已经够用
9 f7 V9 M- W) P" i& U9 u" f - user->addr = DMEMORY + loop * DMEM_BLOCK_SIZE; //计算申请到的内存的地址! D4 B( t- M- X: {, v4 a! k
- apply->blk_s = loop; //记录申请到的内存块首序号9 p3 Q, ]1 H n3 Y' B
- apply->blk_num = blk_num_want; //记录申请到的内存块数目
8 [7 y$ }7 D/ d- i - for(find = 0 ; find < apply->blk_num; find++)
( q2 n0 G0 q. M( L1 x - {; j$ d: x& A( \/ j% j) q; h
- DMEMS.tb_blk[loop + find] = DMEM_USED;6 k! |7 ]2 H/ X- r9 o9 D1 a! d+ y
- }
1 S% F: x- }: I9 ]5 Q( p - apply->used = DMEM_USED; //标记申请表已使用
4 f/ u1 `, y# j+ ~% r4 b - DMEMS.apply_num += 1;& T- F/ f0 ^" T( e
- DMEMS.blk_num += blk_num_want;5 L+ n* Z' X, @( V- i! t
/ p8 J' ^6 u& \* n0 \- return user;
8 T5 }2 \; G. e) \. @3 \1 u - }
4 ] P' U; X: P% |% ? - else
( w+ |8 w; m# M) q - {//寻找到的空闲内存块不够用,从下一个开始找5 e# E }7 R; t0 | P
- loop += find;
1 u% G i. I6 q& \ - }: B3 I. K: h( `) ?* P: U2 w ?
- }4 G' z0 `' G5 @6 b6 S9 Y. j
- }- G0 g) j# X7 ?- o4 t* Z7 `$ {8 |! X
( c' U6 } R" X- //搜索整个内存块,未找到大小适合的空间 A1 K% I4 q; v$ x% _: _
- return NULL;% Y5 J2 N$ l5 s* ~9 h( K8 i- i% Q
- }
复制代码 . g0 o" |. i7 k& g2 x
! ^, y: {- _1 @; i' G0 i3 R' w3、内存释放函数DynMemPut( W3 H1 s$ x, j( U) K" z( J( L
- void DynMemPut(DMEM *user)
* U! n% U D! i+ `: v! Q$ A( j - {; N. X6 @( d& [: D) |5 O; |
- uint16_t loop = 0;
6 @$ X* j6 L" h( ^ - //若参数为空,直接返回& P6 M: s3 D. t: ^4 F6 `
- if(NULL == user) { return; }
- Z9 T3 {$ c9 e! m; l - 6 c7 _2 W6 ~! Y5 o7 \ m7 a) p. T8 F
- //释放内存空间
) w. J1 G: I3 A5 M4 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++)
! x2 I {% B& C - {
1 e# K0 E2 Y5 ]- n5 H. ]/ r" A& G - DMEMS.tb_blk[loop] = DMEM_FREE;; ^, J& c) `) b
- DMEMS.blk_num -= 1;
- F- l; _0 S; z3 y4 Q: W - }
1 H, R4 _" u8 y$ P& r. X& j( I- u - //释放申请表
1 z" n# w9 z1 r' X8 Z( m& `! E7 s - DMEMS.tb_apply[user->tb].used = DMEM_FREE;* n: B' z. [6 L
- DMEMS.apply_num -= 1;$ ` O+ w; L# X( N& b2 F
- }
复制代码 / W5 g* J! P I8 }/ ?
代码中包含注释,注释描述的比较清楚,也比较容易理解。
6 K D' R7 R& B9 V1 F5 C( `2 ]
8 Q! l/ M! y0 E' ?2 W- Y
. Q+ M2 O- m# @! [5 z8 L% n' b4 y. N3 r+ n5 p
转载自:STM32嵌入式开发
( x# v9 _8 {: y |