单向链表内存管理

  • Post author:
  • Post category:其他


单向链表内存管理


单向链表内存管理是结合


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 版权协议,转载请附上原文出处链接和本声明。