打印

从今天开始农民讲习所大人的培训教程!

[复制链接]
4186|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zhaor|  楼主 | 2007-8-31 15:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
盼望所长大人、各位大侠以及学有所得朋友指点和监督!先道一声:谢谢了!
首先学习内存管理的函数。
下面是内存管理的C函数
//内存管理
#include<reg52.h>
#include "Memory.h"
//内存初始化  内存初始指针指向RAM最后

unsigned char  idata  *pRamEad;
//初始化
void Memory_Init()
   {
    pRamEad=0;
        
    }
    
//析构
/**************************/
    void Memory_Destory(void)
    {
    
    }
    
//内存分配
//返回分配后的初始指针
unsigned char  idata *Memory_Malloc(unsigned char Msize)
{
    pRamEad-=Msize;
    return  pRamEad;
    }
//用于指定数据清除内存    

void Memory_Memset(unsigned char  idata *pRam,unsigned char mChar,  unsigned char mLen)
{
  while(mLen--)
  {
      *pRam++=mChar;
      
      }                
 }
下面是内存管理的头文件:
#ifdef _MemoryH
    //用户可以使用的变量

#else
    //----------------------------------------------------------
    //内存初始化
    //内存初试指针总是指向RAM最后
    //----------------------------------------------------------
    extern void Memory_Init(unsigned char *pRamEnd);

    //----------------------------------------------------------
    //析构
    //----------------------------------------------------------
    extern void Memory_Destory(void);

    //----------------------------------------------------------
    //内存分配
    //返回分配后的起始指针
    //----------------------------------------------------------
    extern unsigned char * Memory_Malloc( unsigned char mSize );

    //----------------------------------------------------------
    //用指定数据清除内存
    //----------------------------------------------------------
    extern void Memory_Memset( unsigned char idata *pRam, unsigned char mChar, unsigned char mLen );

#endif
这是在主函数的调用

Memory_Init((unsigned char idata *)0xff );//内部RAM的最后端
注意绿色部分!头文件和C函数以及调用是不一样的!不知道是为什么?有什么问题?

相关帖子

沙发
567| | 2007-8-31 20:09 | 只看该作者

有错误的,不能照抄,关键是理解意思。

使用特权

评论回复
板凳
kukucat| | 2007-8-31 20:49 | 只看该作者

好,先占个座听~~

使用特权

评论回复
地板
ketp| | 2007-8-31 21:51 | 只看该作者

这样搞你怎么知道用了多少内存?

使用特权

评论回复
5
wjy1107| | 2007-8-31 23:52 | 只看该作者

需要活学活用。

使用特权

评论回复
6
农民讲习所| | 2007-9-1 08:56 | 只看该作者

#ifdef _MemoryH
    //用户可以使用的变量

#else
    //-----------------------------------------------------------
    //内存初始化
    //内存初试指针总是指向RAM最后
    //-----------------------------------------------------------
    extern void Memory_Init(unsigned char idata *pRamEnd);

    //-------------------------------------------------------------------------
    //析构
    //-------------------------------------------------------------------------
    extern void Memory_Destory(void);

    //-------------------------------------------------------------------------
    //内存分配
    //返回分配后的起始指针
    //-------------------------------------------------------------------------
    extern unsigned char * Memory_Malloc( unsigned char mSize );

    //-------------------------------------------------------------------------
    //用指定数据清除内存
    //-------------------------------------------------------------------------
    extern void Memory_Memset( unsigned char idata *pRam, unsigned char mChar, unsigned char mLen );

#endif




//-------------------------------------------------------------------------
//内存管理
//-------------------------------------------------------------------------
#define _MemoryH

#include <reg52.h>
#include "Memory.h"

//-----------------------------------------------------------
//使用的变量
struct InMemory{
    unsigned char idata *pREnd;
};
struct InMemory sInMemory;


//-------------------------------------------------------------------------
//内存初始化
//内存初试指针总是指向RAM最后
//-------------------------------------------------------------------------
void Memory_Init(unsigned char idata *pRamEnd)
{
    sInMemory.pREnd = pRamEnd;
}

//-------------------------------------------------------------------------
//析构
//-------------------------------------------------------------------------
void Memory_Destory(void)
{
}

//-------------------------------------------------------------------------
//内存分配
//返回分配后的起始指针
//-------------------------------------------------------------------------
unsigned char * Memory_Malloc( unsigned char mSize )
{
    if( mSize ){
        sInMemory.pREnd -= mSize;
        return sInMemory.pREnd+1;
    }
    else {
        return 0;
    }
}

//-------------------------------------------------------------------------
//用指定数据清除内存
//-------------------------------------------------------------------------
void Memory_Memset( unsigned char idata *pRam, unsigned char mChar, unsigned char mLen )
{
    while( mLen-- ){
        *pRam++ = mChar;
    }
}




使用特权

评论回复
7
zhaor|  楼主 | 2007-9-1 09:44 | 只看该作者

盼望的人出现了!高兴!!

多谢所长大人啊!
还有问题啊!我看到所长的程序只是在初始化的时候用到了这个函数Memory_Init( (unsigned char idata *)0xff );    
指向了内存了最后!所长说在模块中和通用函数加载使用,但是我没有看到!清除内存,也没有看到用!

使用特权

评论回复
8
农民讲习所| | 2007-9-1 09:49 | 只看该作者

比如使用通用队列时

队列函数是通用的,要使用的RAM缓冲大小是通过入口参数在初始化调用时才确定,这时候就使用了动态分配。
很多场合会用,特别是建立通用函数库。没有这个函数,函数通用库几乎不可能建立。


动态分配都是只在初始化时用,工作过程中禁止使用。

分配内存后,要清0,确保不出现异常。

使用特权

评论回复
9
ETUAL| | 2007-9-1 13:52 | 只看该作者

请教一个问题

请教一个问题:

自己写的内存管理函数,跟C语言自己分配变量会不会搞混?
例如,我用自己写的内存管理函数分配了一块内存
但是编译器怎么知道,这块空间已经被占用,他给其他变量
分配空间的时候不用这一块??通过什么机制来实现的?
一直看不懂,也想不懂这一点。请指教一下。

使用特权

评论回复
10
zhaor|  楼主 | 2007-9-1 17:09 | 只看该作者

所长大人,我编译你的队列模块,也通不过啊!

写了一个小时,修改几次,也是不行!

使用特权

评论回复
11
农民讲习所| | 2007-9-1 17:24 | 只看该作者

:

//---------------------------------------------------------------------------
//通用缓冲队列
//----------------------------------------------------------------------------
struct QueueBuffer{
    unsigned char idata *aBufferStart;        //缓冲区起始点
    unsigned char idata *aBufferEnd;        //缓冲区结束点
    unsigned char idata *pIn;                //写指针
    unsigned char idata *pOut;                //读指针
    unsigned char mCount;                    //缓冲区数据个数
};

#ifdef _QueueH
    //用户可以使用的变量

#else
    //------------------------------------------------------------
    //构造
    //------------------------------------------------------------
    extern void Queue_Init(void);

    //------------------------------------------------------------
    //析构,释放在init()中使用到的硬件资源
    //------------------------------------------------------------
    extern void Queue_Destory(void);

    //------------------------------------------------------------
    //申请注册缓冲队列
    //返回struct QueueBuffer结构指针。
    //------------------------------------------------------------
    extern struct QueueBuffer idata * Queue_Register( unsigned char mSize );

    //------------------------------------------------------------
    //将数据压入队列
    //------------------------------------------------------------
    extern void Queue_Push( struct QueueBuffer idata *pQueueBuffer, unsigned char mData );

    //------------------------------------------------------------
    //将数据弹出队列
    //------------------------------------------------------------
    extern unsigned char Queue_Pop( struct QueueBuffer idata *pQueueBuffer );

    //------------------------------------------------------------
    //读出队列指定序号数据
    //------------------------------------------------------------
    extern unsigned char Queue_Read( struct QueueBuffer idata *pQueueBuffer, unsigned char mId );

    //------------------------------------------------------------
    //返回队列数据个数
    //------------------------------------------------------------
    extern unsigned char Queue_Num( struct QueueBuffer idata *pQueueBuffer );

    //------------------------------------------------------------
    //队列清空
    //------------------------------------------------------------
    extern void Queue_Clear( struct QueueBuffer idata *pQueueBuffer );

#endif


//---------------------------------------------------------------------------
//通用缓冲队列
//----------------------------------------------------------------------------
#define _QueueH

#include <reg52.h>
#include "Memory.h"
#include "Queue.h"


//----------------------------------------------------------------------------
//构造
//----------------------------------------------------------------------------
void Queue_Init(void){ }

//----------------------------------------------------------------------------
//析构,释放在init()中使用到的硬件资源
//----------------------------------------------------------------------------
void Queue_Destory(void){ }

//------------------------------------------------------------
//申请注册缓冲队列
//返回struct QueueBuffer结构指针。
//------------------------------------------------------------
struct QueueBuffer idata * Queue_Register( unsigned char mSize )
{
    struct QueueBuffer idata *pQueueBuffer;
        
    pQueueBuffer = (struct QueueBuffer idata * )Memory_Malloc( sizeof(struct QueueBuffer) );                //分配记录队列信息的结构变量
    Memory_Memset( (unsigned char idata *)pQueueBuffer, 0, sizeof(struct QueueBuffer) );                    //记录队列信息的结构变量清0

    pQueueBuffer->aBufferStart = pQueueBuffer->pIn = pQueueBuffer->pOut = Memory_Malloc( mSize );    //分配队列所需内存
    pQueueBuffer->aBufferEnd = pQueueBuffer->aBufferStart + mSize;                                    //队列结束指针

    return pQueueBuffer;
}

#pragma NOAREGS
//------------------------------------------------------------
//将数据压入队列
//------------------------------------------------------------
void Queue_Push( struct QueueBuffer idata * pQueueBuffer, unsigned char mData )
{
    unsigned char idata *p;
    p = pQueueBuffer->pIn;

    *p++ = mData;
    if (p == pQueueBuffer->aBufferEnd){
        p = pQueueBuffer->aBufferStart;
    }
    pQueueBuffer->pIn = p;

    pQueueBuffer->mCount ++;
}

//------------------------------------------------------------
//将数据弹出队列
//------------------------------------------------------------
unsigned char Queue_Pop( struct QueueBuffer idata *pQueueBuffer )
{
    unsigned char mData;
    unsigned char idata *p;
    p = pQueueBuffer->pOut;

    mData = *p;
    if( ++p == pQueueBuffer->aBufferEnd ){
        p = pQueueBuffer->aBufferStart;
    }
    pQueueBuffer->pOut = p;

    pQueueBuffer->mCount --;

    return mData;
}

//------------------------------------------------------------
//读出队列指定序号数据
//------------------------------------------------------------
unsigned char Queue_Read( struct QueueBuffer idata *pQueueBuffer, unsigned char mId )
{
      unsigned char idata *pTemp;

      pTemp = pQueueBuffer->pOut + mId;
      if( pTemp < pQueueBuffer->aBufferEnd )return(*pTemp);
      else return( *(pTemp - pQueueBuffer->aBufferEnd + pQueueBuffer->aBufferStart) );
}

//------------------------------------------------------------
//返回队列数据个数
//------------------------------------------------------------
unsigned char Queue_Num( struct QueueBuffer idata *pQueueBuffer )
{
    return pQueueBuffer->mCount;
}
#pragma AREGS

//------------------------------------------------------------
//队列清空
//------------------------------------------------------------
void Queue_Clear( struct QueueBuffer idata *pQueueBuffer )
{
    B = IE;                                        //清零阶段禁止中断,防止被使用
    EA = 0;
    pQueueBuffer->pIn = pQueueBuffer->pOut = pQueueBuffer->aBufferStart;
    pQueueBuffer->mCount = 0;
    IE = B;
}

使用特权

评论回复
12
农民讲习所| | 2007-9-1 17:34 | 只看该作者

不会混

动态分配的RAM,可以这样看:
   如果没有动态,那么需要的RAM必须放在变量区,占用RAM大小是一样的。只不过RAM是放在未使用到的RAM区,通常在C编译器的内部变量__bss_end+1的位置之后,表示前面是变量区,后面未用。

  51的RAM有些特殊,在__bss_end之后是堆栈区,所以干脆我们就直接从最后往前分配。如果发生和堆栈区重叠,那么不使用动态分配改用静态时,C编译器会同样通不过:超过内部RAM大小。所以这个问题没关系,只要我们注意到运行时保留足够的堆栈空间就行。

使用特权

评论回复
13
农民讲习所| | 2007-9-1 17:37 | 只看该作者

下例子是我在ARM9 s3c2410上的例子

//-------------------------------------------------------------------------
//内存初始化
//内存初试指针总是指向RAM最后
//Image$$RW$$Limit是变量区最后结束地址,后面紧跟4*256的栈区SVC_Stack、IRQ_Stack、FIQ_Stack、保留
//-------------------------------------------------------------------------
void Memory_Init(void)
{
    this.pRamHeap = (unsigned char *)(Image$$ZI$$Limit+256*4+1024);
}

把堆栈区留出来之后的空间,是我们可以当作动态RAM的区域来使用的。

使用特权

评论回复
14
农民讲习所| | 2007-9-1 17:39 | 只看该作者

AVR上的例子

#define Memory_InitDefault()        do{ Memory_Init( &__bss_end + 1 ); }while(0)

使用特权

评论回复
15
ETUAL| | 2007-9-2 14:19 | 只看该作者

今天仔细看了一下

  51的RAM有些特殊,在__bss_end之后是堆栈区,所以干脆我们就直接从最后往前分配。如果发生和堆栈区重叠,那么不使用动态分配改用静态时,C编译器会同样通不过:超过内部RAM大小。所以这个问题没关系,只要我们注意到运行时保留足够的堆栈空间就行。

今天仔细看了一下keil CX51的说明书,确实是那样,系统先分配变量,然后在变量后面是堆栈空间。终于理解了所长将内存分配指针移动到尾部的用意了。

另外,我上网查了一下__bss_end ,貌似这个是AVR单片机编译器ICCAVR编译器的?如果想看一下keil的那些内部函数,和一些内部运行机制,应该看些什么资料呢?

谢谢所长的指点了,hoho~~~

使用特权

评论回复
16
zhaor|  楼主 | 2007-9-3 08:40 | 只看该作者

今天基本理解内存管理和队列!

但是怎么用心里还是没有数!随着课程的深入,我想会理解的!但是看着电脑学习很是累眼啊!所长你的书什么时候出版啊?到时候买两本,看一本,保存一本!呵呵!

使用特权

评论回复
17
ifree64| | 2007-10-14 17:31 | 只看该作者

c51的内存布局是怎样的?

在PC机上一个C语言程序的内存布局通常是:

高地址    +-----------------+
          |                 |
          |                 |
          +-----------------+
          |       栈        |
          + - - - - - - - - +
          |                 |
          |                 |
          |                 |
          |                 |
          |                 |
          |                 |
          |                 |
          |                 |
          |                 |
          |                 |
          |                 |
          |                 |
          + - - - - - - - - +
          |                 |
          |       堆        |
          +-----------------+  
          |    未初始化的   |
          |      数据       | 
          |                 |
          +-----------------+    
          |                 |
          |  初始化的数据   |
          +-----------------+                
          |                 |
          |                 |
          |  正文段(代码)  |
          |                 |
低地址    +-----------------+         

其中,函数中定义的局部变量是在栈中分配的,由malloc分配的空间在堆中分配;栈由高地址向低地址增长,堆由运行时管理。

但在51单片机中有点不同,我知道的是:正文段是在ROM当中,这一点就不管了,
但51的栈是有低地址向高增长的,从这个就知C51的内存布局应和PC上的程序不同。那么是怎样的呢?

我的问题是:
1、局部变量在哪里分配?使用栈了吗?
2、所长提到的“51的RAM有些特殊,在__bss_end之后是堆栈区”这个__bss_end是那个段的结束?这个之后是向高地址还是向低地址?

能不能推荐一个介绍这些细节的参考资料?谢谢!

使用特权

评论回复
18
datouyuan| | 2007-10-14 22:11 | 只看该作者

回答楼上的:

1、局部变量在哪里分配?使用栈了吗?

答:我讲的是在只使用51自身RAM的情形下,51局部变量一般在寄存器组,如数量大于8个和全局变量一样分配在堆栈区之前,C编译时会把全局变量字节数和(有最大局部变量的子函数)局部变量字节数,构成位变量的字节数保留,堆栈区安排在之后。__bss_end最小等于前面几个字节数之和,不仔细安排的话一般会大于。

2、所长提到的“51的RAM有些特殊,在__bss_end之后是堆栈区”这个__bss_end是那个段的结束?这个之后是向高地址还是向低地址?

答:向高地址。

使用特权

评论回复
19
ifree64| | 2007-10-17 15:56 | 只看该作者

谢谢楼上,基本明白了。

C51中,函数参数和局部变量全都采用静态分配。
由编译器分析调用关系,然后决定那些变量可以覆盖。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

41

主题

347

帖子

0

粉丝