STM32编译过程及程序组成
source code(源代码)的c文件和汇编S文件通过Keil中的armcc/armasm生成.o文件(Object code),然后再通过armlink工具生成.axf文件(镜像文件,可通过ST-link进行烧录)再通过fromelf生成.bin/.hex文件
程序的组成、存储与运行
左边是C程序组成,右边是STM32程序组成
text:是的代码段:RAM.以上是数据段:ROM
程序存储
生成反汇编指令 fromelf --text -c --output LedTask\LedTask.text LedTask\LedTask.axf
MDK生成的主要文件分析
map文件分析
SCT文件分析
hex文件分析
bin文件分析
生成bin文件 fromelf --bin --output LedTask\LedTask.bin LedTask\LedTask.axf
内存管理概念及其应用
静态内存和动态内存的区别
静态内存:
静态内存是指在程序开始运行时由编译器分配的内存,它的分配是在程序开始编译时完成的,不占用CPU资源。
程序中的各种变量,在编译时系统已经为其分配了所需的内存空间,当该变量在作用域内使用完毕时,系统会
自动释放所占用的内存空间。
变量的分配与释放,都无须程序员自行考虑。
动态内存:
动态内存分配是按输入信息的大小分配所需要的内存单元,他的特点是按需分配,内存分配在堆区。
用户无法确定空间大小,或者空间太大,栈上无法分配时,会采用动态内存分配。
区别
时间不同:
静态分配发生在程序编译和连接的时候。动态分配则发生在程序调入和执行的时候。
空间不同:
堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由函数malloc进行分配。不过栈的动态分配和堆不同,他的动态分配是由编译器进行释放,无需我们手工实现。
C标准库-动态内存分配接口
#include <stdlib.h>
void *malloc(size_t size);
void free(void *ptr);
void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);
C标准库动态内存的缺陷
1、这些函数在小型嵌入式系统中并不总是可用的,小型嵌入式设备中的 RAM 不足。
2、它们的实现可能非常的大,占据了相当大的一块代码空间。
他们几乎都不是安全的。
3、它们并不是确定的,每次调用这些函数执行的时间可能都不一样。
4、它们有可能产生碎片。
5、这两个函数会使得链接器配置得复杂。
6、如果允许堆空间的生长方向覆盖其他变量占据的内存,它们会成为 debug 的灾难。
STM32系统内存分配需求
没有虚拟内存机制,需要用户亲自管理。
对内存的分配时间要求更为苛刻,分配内存的时间必须是确定的
RAM比较小,需要比较好的内存分配算法解决内存碎片问题
FreeRTOS动态内存分配
heap_1:只能分配,不能释放
heap_2:支持分配也支持释放,但没有内存碎片管理
heap_3:封装C库的malloc和free。添加了线程保护
heap_4:有分配有释放有管理。
heap_5:可以扩展外部ram
内存管理函数应用
实验需求
API
void Delay_Task(void const * argument)
{
/* USER CODE BEGIN Delay_Task */
EventBits_t KeyEventBits;
uint8_t *HeapBuf = NULL;
/* Infinite loop */
for(;;)
{
/*
1、修改事件标志组等待状态为 触发后清除标志
2、检测按键,处理相关功能
*/
KeyEventBits = xEventGroupWaitBits(KeyEventGroup,
KEY3_EVENT_BIT|KEY4_EVENT_BIT|KEY5_EVENT_BIT|KEY6_EVENT_BIT,
pdTRUE,
pdFALSE,
portMAX_DELAY);
printf("Key is Down Key Event Bit is %x\r\n",KeyEventBits);
switch(KeyEventBits){
case KEY3_EVENT_BIT:
if(HeapBuf == NULL){
HeapBuf = pvPortMalloc(100);
}
else{
printf("plese press K4 free!\r\n");
}
break;
case KEY4_EVENT_BIT:
if(HeapBuf != NULL){
vPortFree