单向链表内存管理
单向链表内存管理是结合
C
语言中的
malloc
和
free
的思路,以及
uCOSii
的内存管理方法,实现的。可以通过本程序,深入学习
void
型数据指针的加减运算和强制转换。
内存管理:从物理空间上看,它是由管理对象的
内存池
,申请到节点的
偏移量表
和
内存控制块
三部分组成的。
内存池是多个节点构成的,节点最小为4个字节,节点的容量必须为4的倍数。
偏移量表用来记录同批次申请了多少个节点,为释放节点做准备。
内存控制块是一个特殊的数据结构,用来记录根节点地址、下一个可用的节点地址、节点的字节数、节点的总数量、可用节点数量、偏移量数组的起始地址和偏移量数组中元素的字节数等。
单向链表在内存管理应用中比较常见。下面重点讲解:
程序举例:
#include "MyMalloc.h"
#include "stdio.h" //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()
#if OS_MAX_MEM_PART == 1u //只有1个内存池
__align(4) uint8_t RAM1_Array[RAM1_NumberOfBlock][RAM1_BlockSize] __attribute__((at(RAM1_StartAddress)));
u16 OffsetAddressArray1[RAM1_NumberOfBlock] __attribute__((at(OffsetAddressArray1_StartAddress)));
#endif
#if OS_MAX_MEM_PART >= 2u //至少有2个内存池
__align(4) uint8_t RAM1_Array[RAM1_NumberOfBlock][RAM1_BlockSize] __attribute__((at(RAM1_StartAddress)));
__align(4) uint8_t RAM2_Array[RAM2_NumberOfBlock][RAM2_BlockSize] __attribute__((at(RAM2_StartAddress)));
u16 OffsetAddressArray1[RAM1_NumberOfBlock] __attribute__((at(OffsetAddressArray1_StartAddress)));
u16 OffsetAddressArray2[RAM2_NumberOfBlock] __attribute__((at(OffsetAddressArray2_StartAddress)));
#endif
OS_MEM OSMemTbl[OS_MAX_MEM_PART];//声明内存控制块
OS_MEM *OSMemFreeList; //内存控制块指针
OS_MEM *MemoryControlBlock1_Pointer;//内存控制块指针
OS_MEM *MemoryControlBlock2_Pointer;//内存控制块指针
OS_MEM_DATA My_OS_MEM_DATA;
void OS_MemInit(void);
OS_MEM *OSMemCreate (void *mem_addr,uint32_t nblks,uint32_t blksize,void *offset_addr,uint16_t offsetarray_size,uint8_t *perr);
void *OSMemGet(OS_MEM *pmem,u32 size,uint8_t *perr);
int8_t OSMemPut(OS_MEM *pmem,void *pblk);
int8_t OSMemQuery(OS_MEM *pmem,OS_MEM_DATA *p_mem_data);
void MEMORY_Test(void);
#if OS_MAX_MEM_PART >= 2u //至少有2个内存池
void MEMORY2_Test(void);
#endif
//函数功能:对两个内存控制块进行初始化,OSMemFreeList指向"内存控制块0的首地址"
void OS_MemInit(void)
{
int8_t *pdest;//声明pdest为"一维指针"
int16_t size;
OS_MEM *pmem;//声明pmem为"OS_MEM型结构指针"
int16_t current,next;
pdest=(int8_t *)&OSMemTbl[0];//将"内存控制块0的首地址"保存到pdest
size=sizeof(OSMemTbl);//求内存控制块OSMemTbl[]有多少个字节
while(size>0)//将内存控制块清0
{
*pdest++ = (int8_t)0;
size--;
}
#if OS_MAX_MEM_PART == 1u //只有1个内存池
OSMemFreeList=(OS_MEM *)&OSMemTbl[0];
//将"内存控制块0的首地址"保存到OSMemFreeList
#endif
#if OS_MAX_MEM_PART >= 2u //至少有2个内存池
for(current=0;current< OS_MAX_MEM_PART-1;current++)
{
pmem = &OSMemTbl[current];//将"内存控制块current的首地址"保存到pmem
next=current+1;
pmem->OSMemFreeList = (void *)&OSMemTbl[next];//将"内存控制块next的首地址"保存到pmem->OSMemFreeList
}
pmem= &OSMemTbl[current];
//将"内存控制块current的首地址"保存到pmem
//这里的OSMemTbl[current]是最后一个内存控制块
pmem->OSMemFreeList=(void *)0;
//由于"最后一个内存控制块"没有"下一个内存控制块"了,所有设置"下一个内存控制块的地址"为0
OSMemFreeList=(OS_MEM *)&OSMemTbl[0];//将"内存控制块0的首地址"保存到OSMemFreeList
#endif
}
//函数功能:初始化内存池和内存控制块
//addr为根节点地址
//nblks为节点的总数量
//blksize为节点的字节数
//返回值为内存控制块指针
OS_MEM *OSMemCreate (void *mem_addr,uint32_t nblks,uint32_t blksize,void *offset_addr,uint16_t offsetarray_blksize,uint8_t *perr)
{
OS_MEM *pmem;//声明pmem为"OS_MEM型结构指针"
uint8_t *pblk;//声明pblk为"一维指针"
void **plink;//声明plink为"void型二维指针"
uint32_t loops;
uint32_t i;
if(mem_addr == (void *)0)//根节点地址mem_addr为0
{
*perr = OS_FAIL;
return ((OS_MEM *)0);
}
if(((int32_t)mem_addr & (sizeof(void *) - 1u)) != 0u) //根节点地址mem_addr不是4字节对齐
{
*perr = OS_FAIL;
return ((OS_MEM *)0);
}
if(nblks < 2)//节点的总数量只有1个
{
*perr = OS_FAIL;
return ((OS_MEM *)0);
}
if (blksize < sizeof(void *))//节点的字节数小于4
{
*perr = OS_FAIL;
return ((OS_MEM *)0);
}
pmem = OSMemFreeList;//读取内存控制块指针
if (OSMemFreeList != (OS_MEM *)0)
{
OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList;
//将"下一个内存控制块的首地址"保存到OSMemFreeList,为初始化下一个内存池做准备
}
plink = (void **)mem_addr;//将"void型一维指针mem_addr"强制转换为"void型二维指针"保存到plink中
pblk = (uint8_t *)mem_addr;//将"void型一维指针mem_addr"强制转换为"uint8_t型一维指针"保存到pblk中
loops = nblks-1;//nblks为节点的总数量
for(i=0;i<loops;i++)
{
pblk +=blksize;//将"下一个节点的首地"址保存到"uint8_t型一维指针pblk"
*plink = (void *)pblk;//将"uint8_t型一维指针pblk"强制转换为"void型一维指针"保存到"void型一维指针(*plink)"中
plink = (void **)pblk;//将"uint8_t型一维指针pblk"强制转换为"void型二维指针"保存到"void型二维指针plink"中
}
*plink = (void *)0;
//由于"最后一个节点"没有"下一个节点"了,所有设置"下一个节点的地址"为0
pmem->OSMemAddr= mem_addr;
pmem->OSMemFreeList = mem_addr;
pmem->OSMemNFree= nblks;
pmem->OSMemNBlks = nblks;
pmem->OSMemBlkSize = blksize;
pmem->OffsetAddr=offset_addr;
pmem->OffsetArrayBlockSize=offsetarray_blksize;
return (pmem);
}
//函数功能:根据"内存控制块指针pmem",申请节点
//pmem为内存控制块指针
void *OSMemGet(OS_MEM *pmem,u32 size,uint8_t *perr)
{
void *pblk;//声明pblk为"void型一维指针"
void *pStartBlock,*p;//声明pStartBlock为"void型一维指针"
void *pOffsetArray;
u32 nmemb; //需要的内存块数
u32 i,step;
if (pmem == (OS_MEM *)0)
{//内存控制块指针pmem为0
*perr = OS_FAIL;
return ((void *)0);
}
if(size==0)
{//不需要分配
*perr = OS_FAIL;
return ((void *)0);
}
nmemb=size/pmem->OSMemBlkSize;
//计算需要多少个整块, MyBlockSize[memx]为块的大小
if( size%pmem->OSMemBlkSize ) nmemb++;
//剩余的字节空间不满一个块的,则按一个整块操作
//pmem->OSMemBlkSize为块的大小
if(pmem->OSMemNFree >= nmemb)//"空闲节点计数器"大于等于nmemb,说明空闲节点足够被申请
{
pStartBlock = pmem->OSMemFreeList;
//从内存控制块中,读取下一个节点的首地址,并将它保存到pStartBlock中,这就是"申请到的节点"的首地址
pmem->OSMemFreeList = *(void **)pStartBlock;
//在内存池中,将"pblk为首地址数据块"强制转换为"void型二维指针",其"所指向单元的内容"为指针数据
//将读到的指针数据保存到pmem->OSMemFreeList中,这就是"申请到的节点"的下一个节点的首地址
pmem->OSMemNFree--;//空闲节点计数器减1;
size=(u8*)pStartBlock-(u8*)pmem->OSMemAddr;//计算偏移地址
size=size/pmem->OSMemBlkSize;size=size*pmem->OffsetArrayBlockSize;
pOffsetArray=pmem->OffsetAddr;
pOffsetArray=(void *)((uint8_t*)pOffsetArray+size);
*(u16*)pOffsetArray=(u16)nmemb;//记录偏移节点号码
p=pStartBlock;
for(i=0;i<nmemb-1;i++)//连续申请(nmemb-1)个节点
{
pblk = pmem->OSMemFreeList;
//从内存控制块中,读取下一个节点的首地址,并将它保存到pblk中,这就是"申请到的节点"的首地址
pmem->OSMemFreeList = *(void **)pblk;
//在内存池中,将"pblk为首地址数据块"强制转换为"void型二维指针",其"所指向单元的内容"为指针数据
//将读到的指针数据保存到pmem->OSMemFreeList中,这就是"申请到的节点"的下一个节点的首地址
pmem->OSMemNFree--;//空闲节点计数器减1;
step=(uint8_t*)pblk-(uint8_t*)p;//计算"地址的差值"
if(step!=pmem->OSMemBlkSize)//"地址的差值"不等于"节点的大小"
{//先释放"不连续的节点"
*(void **)pblk = pmem->OSMemFreeList;
//将pblk强制转换为"void型二维指针",其"所指向单元的内容"为指针域
//从内存控制块中,读取"待释放的节点的下一个节点的首地址",并将它保存到指针域
pmem->OSMemFreeList = pblk;//将"待释放的节点指针"保存到内存控制块中,记录"下一个节点的首地址"
pmem->OSMemNFree++;//空闲节点计数器加1;
pOffsetArray=(uint8_t*)pOffsetArray-2;//指向上一个偏移节点
*(u16*)pOffsetArray=0;//记录偏移节点号码
pblk=p;//准备释放连续的节点
while(pblk>=pStartBlock)//地址不连续释放
{
*(void **)pblk = pmem->OSMemFreeList;
//将pblk强制转换为"void型二维指针",其"所指向单元的内容"为指针域
//从内存控制块中,读取"待释放的节点的下一个节点的首地址",并将它保存到指针域
pmem->OSMemFreeList = pblk;//将"待释放的节点指针"保存到内存控制块中,记录"下一个节点的首地址"
pmem->OSMemNFree++;//空闲节点计数器加1;
pblk=(void*)((uint8_t*)pblk- pmem->OSMemBlkSize);
//指向下一个节点,这里必须用(void*)强制转换,才会正确
pOffsetArray=(uint8_t*)pOffsetArray-2;//指向上一个偏移节点
*(u16*)pOffsetArray=0;//记录偏移节点号码
}
*perr=OS_FAIL;//建立失败标志
return ((void *)0);//返回0
}
pOffsetArray=(void *)((uint8_t*)pOffsetArray+2);//指向下一个偏移节点
*(u16*)pOffsetArray=nmemb;//记录偏移节点号码
p=pblk;//更新
}
*perr = OS_SUCCESS;//建立成功标志
return (pStartBlock);//返回"申请到的节点"的首地址
}
*perr=OS_FAIL;//建立失败标志
return ((void *)0);//返回0
}
//函数功能:释放节点
//pmem为内存控制块指针
//pblk为待释放的节点指针
int8_t OSMemPut(OS_MEM *pmem,void *pblk)
{
int32_t size;
u32 nmemb;//需要释放的内存字节数
void *pOffsetArray;
void *pEndBlock;//声明pEndBlock为"void型一维指针"
u8 i;
void *p;
if(pmem == (OS_MEM *)0) return (OS_FAIL);
if(pblk == (void *)0) return (OS_FAIL);
if(pmem->OSMemNFree >= pmem->OSMemNBlks) return (OS_FULL);
size=(u8*)pblk-(u8*)pmem->OSMemAddr;//计算已申请的字节数量
if(size<0) return (OS_FAIL);
size=size/pmem->OSMemBlkSize;//已用的节点下标值
size=size*pmem->OffsetArrayBlockSize;//计算在偏移数组中的偏移量
pOffsetArray=(void *)pmem->OffsetAddr;
//读取偏移数据的首指针,这里必须用(void*)强制转换,才会正确
pOffsetArray=(void *)((uint8_t*)pOffsetArray+size);
//指向偏移数组的节点,这里必须用(void*)强制转换,才会正确
size=(*(u16*)pOffsetArray);//读取申请到的节点数量
size--;
nmemb=size*pmem->OffsetArrayBlockSize;//计算需要释放的字节数
pOffsetArray=(void *)((u8*)pOffsetArray+nmemb);
//指向待释放偏移地址的最后一个节点,这里必须用(void*)强制转换,才会正确
nmemb=size*pmem->OSMemBlkSize;//计算需要释放的字节数
pEndBlock=(void *)((uint8_t*)pblk+nmemb);
//最后一个待释放节点首地址,这里必须用(void*)强制转换,才会正确
while(pblk<=pEndBlock)
{
p=(u8*)pEndBlock;
for(i=0;i<pmem->OSMemBlkSize;i++)//将节点清0
{
*(u8*)p = 0;
p=(u8*)p+1;//指向待修改数据区
}
*(void **)pEndBlock = pmem->OSMemFreeList;//将下一个节点的首地址保存到该节点的地址域
pmem->OSMemFreeList = pEndBlock;//将"待释放的节点指针"保存到内存控制块中,记录"下一个节点的首地址"
pmem->OSMemNFree++;//空闲节点计数器加1;
pEndBlock=(void *)((uint8_t*)pEndBlock-pmem->OSMemBlkSize);
//修改最后一个待释放节点首地址,这里必须用(void*)强制转换,才会正确
*(u16*)pOffsetArray=0;
pOffsetArray=(void *)((uint8_t*)pOffsetArray-2);
//这里必须用(void*)强制转换,才会正确
}
return (OS_SUCCESS);
}
int8_t OSMemQuery(OS_MEM *pmem,OS_MEM_DATA *p_mem_data)
{
if (pmem == (OS_MEM *)0) return (OS_FAIL);
if (p_mem_data == (OS_MEM_DATA *)0) return (OS_FAIL);
p_mem_data->OSAddr = pmem->OSMemAddr; //从内存控制块中读取"根节点地址"
p_mem_data->OSFreeList = pmem->OSMemFreeList; //从内存控制块中读取"下一个节点的地址"
p_mem_data->OSBlkSize = pmem->OSMemBlkSize; //从内存控制块中读取"节点的字节数量"
p_mem_data->OSNBlks = pmem->OSMemNBlks; //从内存控制块中读取"节点的总数量"
p_mem_data->OSNFree = pmem->OSMemNFree; //从内存控制块中读取"可用节点的数量"
p_mem_data->OSNUsed = p_mem_data->OSNBlks - p_mem_data->OSNFree;
//"已用节点数量" = "节点的总数量" - "可用节点的数量"
return(OS_SUCCESS);
}
const char RootNode_REG[]="\r\nRootNode=0x";
const char NextNode_REG[]=" NextNode=0x";
const char TotalNumberOfNode_REG[]=" TotalNumberOfNode=";
const char SizeOfNode_REG[]=" SizeOfNode=";
const char Bytes_REG[]="Bytes";
const char NumberOfUsedNode_REG[]=" NumberOfUsedNode=";
const char NumberOfFreeNode_REG[]=" NumberOfFreeNode=";
const char Mymemory_REG[]="\r\nMymemory: ";
const char Offset_REG[]="\r\nOffset: ";
void Do_OSMemQuery(void)
{
u32 *pblk;//声明pblk为"u32型一维指针"
u16 *p;
u8 i;
OSMemQuery(MemoryControlBlock1_Pointer,&My_OS_MEM_DATA);
printf("%s",RootNode_REG);printf("%p",My_OS_MEM_DATA.OSAddr); //打印根节点地址
printf("%s",NextNode_REG);printf("%p",My_OS_MEM_DATA.OSFreeList);//打印下一节点地址
// printf("%s",SizeOfNode_REG);printf("%u",My_OS_MEM_DATA.OSBlkSize);printf("%s",Bytes_REG);//打印节点字节数
// printf("%s",NumberOfUsedNode_REG);printf("%u",My_OS_MEM_DATA.OSNUsed);//打印已用节点数量
// printf("%s",NumberOfFreeNode_REG);printf("%u",My_OS_MEM_DATA.OSNFree);//打印未用节点数量
// printf("%s",TotalNumberOfNode_REG);printf("%u",My_OS_MEM_DATA.OSNBlks);//打印节点总数量
printf(" %u + %u = %u",My_OS_MEM_DATA.OSNFree,My_OS_MEM_DATA.OSNUsed,My_OS_MEM_DATA.OSNBlks);
printf("%s",Mymemory_REG);
pblk=(u32 *)&RAM1_Array[0];
for(i=0;i<RAM1_TotalNumberOfBytes/4;i++)
{
printf(" 0x%08X",*pblk);
pblk++;
}
printf("%s",Offset_REG);
p=OffsetAddressArray1;
for(i=0;i<OffsetAddressArray1_TotalNumberOfBytes/2;i++)
{
printf(" 0x%04X",*p);
p++;
}
}
void MEMORY_Test(void)
{
u8 err;
u8 *ptr1,*ptr2;
u8 *p1,*p2;
printf("\r\n\r\nReady...");
Do_OSMemQuery();
printf("\r\nmalloc1:");
ptr1 = OSMemGet(MemoryControlBlock1_Pointer,8,&err);//根据"内存控制块指针MemoryControlBlock1_Pointer",申请一个节点
if(ptr1!=NULL)
{
p1=ptr1;
*(u32*)p1=0x12345678;
p1=p1+4;
*(u32*)p1=0x98765432;
}
Do_OSMemQuery();
printf("\r\nmalloc2:");
ptr2 = OSMemGet(MemoryControlBlock1_Pointer,16,&err);
if(ptr2!=NULL)
{
p2=ptr2;
*(u32*)p2=0xABCDEF00;
p2=p2+4;
*(u32*)p2=0xFEDCBA11;
p2=p2+4;
*(u32*)p2=0x12345678;
p2=p2+4;
*(u32*)p2=0x98765432;
}
Do_OSMemQuery();
printf("\r\nfree1:");
if(ptr2!=NULL)//后申请的先释放
{
OSMemPut(MemoryControlBlock1_Pointer,ptr2);//释放一个内存块,首地址为ptr2
Do_OSMemQuery();
ptr2=NULL;
}
printf("\r\nfree2:");
if(ptr1!=NULL)//先申请的后释放
{
OSMemPut(MemoryControlBlock1_Pointer,ptr1);//释放一个内存块,首地址为ptr1
Do_OSMemQuery();
ptr1=NULL;
}
}
#if OS_MAX_MEM_PART >= 2u //至少有2个内存池
void Do_OSMemQuery2(void)
{
u32 *pblk;//声明pblk为"u32型一维指针"
u8 i;
u16 *p;
OSMemQuery(MemoryControlBlock2_Pointer,&My_OS_MEM_DATA);
printf("%s",RootNode_REG);printf("%p",My_OS_MEM_DATA.OSAddr); //打印根节点地址
printf("%s",NextNode_REG);printf("%p",My_OS_MEM_DATA.OSFreeList);//打印下一节点地址
// printf("%s",SizeOfNode_REG);printf("%u",My_OS_MEM_DATA.OSBlkSize);printf("%s",Bytes_REG);//打印节点字节数
// printf("%s",NumberOfUsedNode_REG);printf("%u",My_OS_MEM_DATA.OSNUsed);//打印已用节点数量
// printf("%s",NumberOfFreeNode_REG);printf("%u",My_OS_MEM_DATA.OSNFree);//打印未用节点数量
// printf("%s",TotalNumberOfNode_REG);printf("%u",My_OS_MEM_DATA.OSNBlks);//打印节点总数量
printf(" %u + %u = %u",My_OS_MEM_DATA.OSNFree,My_OS_MEM_DATA.OSNUsed,My_OS_MEM_DATA.OSNBlks);
printf("%s",Mymemory_REG);
pblk=(u32 *)&RAM2_Array[0];
for(i=0;i<RAM2_TotalNumberOfBytes/4;i++)
{
printf(" 0x%08X",*pblk);
pblk++;
}
printf("%s",Offset_REG);
p=OffsetAddressArray2;
for(i=0;i<OffsetAddressArray2_TotalNumberOfBytes/2;i++)
{
printf(" 0x%04X",*p);
p++;
}
}
void MEMORY2_Test(void)
{
u8 err;
u8 *ptr1,*ptr2;
u8 *p1,*p2;
printf("\r\n\r\nReady...");
Do_OSMemQuery2();
printf("\r\nmalloc1:");
ptr1 = OSMemGet(MemoryControlBlock2_Pointer,1,&err);//根据"内存控制块指针MemoryControlBlock2_Pointer",申请一个节点
if(ptr1!=NULL)
{
p1=ptr1;
*(u32*)p1=0x12345678;
p1=p1+4;
*(u32*)p1=0x98765432;
}
Do_OSMemQuery2();
printf("\r\nmalloc2:");
ptr2 = OSMemGet(MemoryControlBlock2_Pointer,1,&err);
if(ptr2!=NULL)
{
p2=ptr2;
*(u32*)p2=0xABCDEF00;
p2=p2+4;
*(u32*)p2=0xFEDCBA11;
}
Do_OSMemQuery2();
printf("\r\nfree1:");
if(ptr2!=NULL)//后申请的先释放
{
OSMemPut(MemoryControlBlock2_Pointer,ptr2);//释放一个内存块,首地址为ptr2
Do_OSMemQuery2();
ptr2=NULL;
}
printf("\r\nfree2:");
if(ptr1!=NULL)//先申请的后释放
{
OSMemPut(MemoryControlBlock2_Pointer,ptr1);//释放一个内存块,首地址为ptr1
Do_OSMemQuery2();
ptr1=NULL;
}
}
#endif
#ifndef _MyMalloc_H
#define _MyMalloc_H
#include "stm32f10x.h" //使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t
#define OS_MAX_MEM_PART 2 //内存池数量为2
#if OS_MAX_MEM_PART == 1u //只有1个内存池
#define RAM1_TotalNumberOfBytes 32 //定义内部堆区的大小为32字节
#define RAM1_BlockSize 4 //每个存储块大小为4,必须为4的倍数
#define RAM1_NumberOfBlock (RAM1_TotalNumberOfBytes/RAM1_BlockSize)
//存储块的数量
//由于一个指针变量占用4字节,所以块的大小一定要为4的倍数
#define RAM1_StartAddress 0x20001000
extern __align(4) uint8_t RAM1_Array[RAM1_NumberOfBlock][RAM1_BlockSize];
#define OffsetAddressArray1_StartAddress (RAM1_StartAddress+RAM1_TotalNumberOfBytes)
#define OffsetAddressArray1_BlockSize 2 //每个存储块大小为2
#define OffsetAddressArray1_TotalNumberOfBytes (RAM1_NumberOfBlock*OffsetAddressArray1_BlockSize)
extern u16 OffsetAddressArray1[RAM1_NumberOfBlock];
#endif
#if OS_MAX_MEM_PART >= 2u //至少有2个内存池
#define RAM1_TotalNumberOfBytes 32 //定义内部堆区的大小为32字节
#define RAM1_BlockSize 4 //每个存储块大小为4,必须为4的倍数
#define RAM1_NumberOfBlock (RAM1_TotalNumberOfBytes/RAM1_BlockSize)
//存储块的数量
//由于一个指针变量占用4字节,所以块的大小一定要为4的倍数
#define RAM1_StartAddress 0x20001000
extern __align(4) uint8_t RAM1_Array[RAM1_NumberOfBlock][RAM1_BlockSize];
#define RAM2_StartAddress (RAM1_StartAddress+RAM1_TotalNumberOfBytes)
#define RAM2_TotalNumberOfBytes 32 //定义内部堆区的大小为32字节
#define RAM2_BlockSize 8 //每个存储块大小为8,必须为4的倍数
#define RAM2_NumberOfBlock RAM2_TotalNumberOfBytes/RAM2_BlockSize
//存储块的数量
//由于一个指针变量占用4字节,所以块的大小一定要为4的倍数
extern __align(4) uint8_t RAM2_Array[RAM2_NumberOfBlock][RAM2_BlockSize];
#define OffsetAddressArray1_StartAddress (RAM2_StartAddress+RAM2_TotalNumberOfBytes)
#define OffsetAddressArray1_BlockSize 2 //每个存储块大小为2
#define OffsetAddressArray1_TotalNumberOfBytes (RAM1_NumberOfBlock*OffsetAddressArray1_BlockSize)
extern u16 OffsetAddressArray1[RAM1_NumberOfBlock];
#define OffsetAddressArray2_StartAddress (OffsetAddressArray1_StartAddress+OffsetAddressArray1_TotalNumberOfBytes)
#define OffsetAddressArray2_BlockSize 2 //每个存储块大小为2
#define OffsetAddressArray2_TotalNumberOfBytes (RAM2_NumberOfBlock*OffsetAddressArray2_BlockSize)
extern u16 OffsetAddressArray2[RAM2_NumberOfBlock];
#endif
typedef struct os_mem
{
void *OSMemAddr; /*根节点地址*/
void *OSMemFreeList;/*下一个节点的地址*/
uint32_t OSMemBlkSize;/*节点的字节数*/
uint32_t OSMemNBlks; /*节点的总数量”*/
uint32_t OSMemNFree;/*可用节点数量*/
void *OffsetAddr;/*偏移量数组的起始地址*/
uint16_t OffsetArrayBlockSize;/*偏移量数组中元素的字节数*/
}OS_MEM;
extern OS_MEM *MemoryControlBlock1_Pointer;//内存控制块指针
extern OS_MEM *MemoryControlBlock2_Pointer;//内存控制块指针
typedef struct os_mem_data
{
void *OSAddr; //根节点地址
void *OSFreeList; //可用的下一个节点的地址
int32_t OSBlkSize; //节点的字节数
int32_t OSNBlks; //节点的总数量
int32_t OSNFree; //可用节点数量
int32_t OSNUsed; //已用节点数量
}OS_MEM_DATA;
extern OS_MEM_DATA My_OS_MEM_DATA;
#define OS_SUCCESS 0u
#define OS_FAIL 1u
#define OS_FULL 2u
extern void OS_MemInit(void);
extern OS_MEM *OSMemCreate (void *mem_addr,uint32_t nblks,uint32_t blksize,void *offset_addr,uint16_t offsetarray_size,uint8_t *perr);
extern void *OSMemGet(OS_MEM *pmem,u32 size,uint8_t *perr);
extern int8_t OSMemPut(OS_MEM *pmem,void *pblk);
extern int8_t OSMemQuery(OS_MEM *pmem,OS_MEM_DATA *p_mem_data);
extern void MEMORY_Test(void);
extern void MEMORY2_Test(void);
#endif
#include "stm32f10x.h" //使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t
#include "MyMalloc.h"
#include "USART1.h"
#include "stdio.h"
void delay(int x);
const char CPU_Reset_REG[]="\r\nCPU reset!\r\n";
int main(void)
{
uint8_t err;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
USART1_Serial_Interface_Enable(115200);
printf("%s",CPU_Reset_REG);//调试串口输出"\r\nCPU reset!\r\n"
OS_MemInit();
MemoryControlBlock1_Pointer=OSMemCreate( RAM1_Array,\
RAM1_NumberOfBlock,\
RAM1_BlockSize,\
OffsetAddressArray1,\
OffsetAddressArray1_BlockSize,\
&err);
MemoryControlBlock2_Pointer=OSMemCreate(RAM2_Array,\
RAM2_NumberOfBlock,\
RAM2_BlockSize,\
OffsetAddressArray2,\
OffsetAddressArray2_BlockSize,\
&err);
while(1)
{
MEMORY_Test();
MEMORY2_Test();
delay(14400000); //系统时钟为72MHz,延时为1000ms;
}
}
//函数功能:当系统时钟为72MHz时,延时5x/72000000个us
void delay(int x)
{
int i;
for(i=0;i<x;i++);
}
测试结果如下:
本人对指针的理解,水平有限。 欢迎学习和交流!!!
版权声明:本文为weixin_42550185原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。