Keil 微库(MicroLib)深度解析
目录
-
- Keil 微库(MicroLib)介绍
-
- 微库与单片机操作的交互机制
-
- 1.堆内存管理绑定
-
- 1. 堆管理绑定启动文件链接符号
- 2.微库malloc 内存分配流程
- 3.不使用微库,自定义 malloc/free
- 4.freertos内存管理的优势
-
- 为什么标准微库方案存在耦合性问题?
- FreeRTOS堆管理设计的核心思想
- 参考freertos的设计思想设计实现完全解耦的通用堆管理方案
- 2. I/O 重定向机制
-
- 1. 关键重定向函数清单
- 2.I/O 重定向机制(可支持串口重定向printf)
Keil 微库(MicroLib)介绍
Keil 微库是 ARM 公司专门为嵌入式系统设计的高度优化的精简版 C 标准库,相比完整标准库,它具有以下核心特性:
特性 | 微库 | 完整标准库 |
---|---|---|
代码大小 | 约 2-10KB | 20-100KB+ |
内存占用 | 极小堆栈要求 | 较大内存需求 |
功能支持 | 仅基础功能 | 完整 ISO C 功能 |
重定向机制 | 简单函数重定向 | 复杂文件系统支持 |
启动速度 | 极快初始化 | 较慢初始化 |
适用场景 | 资源受限的裸机系统 | 带操作系统的复杂应用 |
keil中勾选了这个就是启用微库(MicroLib)
微库与单片机操作的交互机制
1.堆内存管理绑定
堆符号定义,用不用微库是我自己的选择,我也可以用这个定义的符号自己编写内存管理函数,甚至我们可以不定义这个堆的符号,我还可以自己像freertos一样定义应该大的数组自行管理,和宏定义符号管理是一个道理只不过是和微库做了一个关系链接,相当于一个宏定义让我和微库都知道这个堆的大小边界,同理还有栈的定义符号__initial_sp 是异常向量表中给sp赋值的值,而栈的大小定义符号仅仅只是一个定义,处理器不会根据这个栈的大小自动检测栈溢出,完全依赖程序员保证
1. 堆管理绑定启动文件链接符号
/* 微库内部直接使用启动文件定义的符号 */
extern uint8_t __heap_base[]; // 堆起始地址
extern uint8_t __heap_limit[]; // 堆结束地址void *_sbrk(int incr) {static uint8_t *heap_ptr = __heap_base;uint8_t *prev = heap_ptr;if(heap_ptr + incr > __heap_limit) return (void*)-1; // 堆溢出heap_ptr += incr;return prev;
}
与启动文件的链接符号绑定进行微库的堆内存管理
2.微库malloc 内存分配流程
void *malloc(size_t size) {// 1. 添加块头信息(4字节)size_t total_size = size + sizeof(block_header);// 2. 调用 _sbrk 申请内存block_header *blk = _sbrk(total_size);// 3. 设置块信息blk->size = size;blk->used = 1;return (void*)(blk + 1); // 返回用户可用地址
}
3.不使用微库,自定义 malloc/free
模仿微库使用链接符号绑定,进行堆内存管理
// 定义堆边界(由链接脚本或外部声明)
extern uint8_t __heap_base[];
extern uint8_t __heap_limit[];// 内存块结构
typedef struct block {size_t size;struct block *next;uint8_t used; // 使用标志
} block_t;static block_t *head = (block_t*)__heap_base;void heap_init(void) {head->size = (size_t)(__heap_limit - __heap_base) - sizeof(block_t);head->next = NULL;head->used = 0;
}void* my_malloc(size_t size) {block_t *curr = head;while (curr) {if (!curr