山寨所长“建立通用处理程序”之stm32

[复制链接]
5986|34
手机看帖
扫描二维码
随时随地手机跟帖
tiger84|  楼主 | 2010-5-25 10:23 | 显示全部楼层 |阅读模式
最近有些时间,看了下所长的建立通用处理程序,敬佩不已,若早得此宝典,俺会少走很多弯路。

其实也就是照抄所长的,希望所长不要见怪。

弟才疏学浅,错误之处在所难免,希望各位兄弟指正,拍砖。

内存分配篇
// memory.h

#ifndef _MEMORY_H
#define _MEMORY_H
#ifdef _MemoryH
//用户可以使用的变量
#else
//-----------------------------------------------------------
//内存初始化
//内存初试指针总是指向RAM最后
//-----------------------------------------------------------
extern unsigned char *MyHeap(void);
extern void Memory_Init(unsigned char *pRamStart);
//-------------------------------------------------------------------------
//析构
//-------------------------------------------------------------------------
extern void Memory_Destory(void);
//-------------------------------------------------------------------------
//内存分配
//返回分配后的起始指针
//-------------------------------------------------------------------------
extern unsigned char * Memory_Malloc( unsigned int mSize );
//-------------------------------------------------------------------------
//用指定数据清除内存
//-------------------------------------------------------------------------
extern void Memory_Memset( unsigned char *pRam, unsigned char mChar, unsigned int mLen );
#endif
#endif


// memory.c
//-------------------------------------------------------------------------
//内存管理
//-------------------------------------------------------------------------
#define _MemoryH
#include "Memory.h"
#include "global.h"
/* Use a symbol defined by ILINK option, a symbol that in the
configuration file was made available to the application */
static int HeapSize = 0x6000;  // 与icf文件里的__ICFEDIT_size_heap__同步更新
/* The section that contains our heap */
#pragma section = "HEAP"
unsigned char *MyHeap(void)
{
/* First get start of statically allocated section */
    unsigned char *p = __section_begin("HEAP");
    /* then we zero it, using the imported size */
    for (int i = 0; i < HeapSize; ++i)
    {
        p[i] = 0;
    }
   
    return p;
}

//-----------------------------------------------------------
//使用的变量
struct InMemory{
unsigned char *pRStart;
};
struct InMemory sInMemory;
//-------------------------------------------------------------------------
//内存初始化
//-------------------------------------------------------------------------
void Memory_Init(unsigned char *pRamStart)
{
    sInMemory.pRStart = pRamStart;
}
//-------------------------------------------------------------------------
//析构
//-------------------------------------------------------------------------
void Memory_Destory(void)
{
   
}
//-------------------------------------------------------------------------
//内存分配
//返回分配后的起始指针
//-------------------------------------------------------------------------
unsigned char * Memory_Malloc( unsigned int mSize )
{
    unsigned char *p;
   
    if(mSize)
    {
        p = sInMemory.pRStart;
        sInMemory.pRStart += mSize;        
        return p;
    }
    else
    {
        return 0;
    }
}
//-------------------------------------------------------------------------
//用指定数据清除内存
//-------------------------------------------------------------------------
void Memory_Memset( unsigned char *pRam, unsigned char mChar, unsigned int mLen )
{
    while( mLen-- )
    {
        *pRam++ = mChar;
    }
}
tiger84|  楼主 | 2010-5-25 10:24 | 显示全部楼层
本帖最后由 tiger84 于 2010-5-25 10:34 编辑

stm32完全可以用库自带的malloc了,为了山寨,就依然和所长的一样。

初始化时这样用,
Memory_Init((unsigned char *)MyHeap());

使用特权

评论回复
tiger84|  楼主 | 2010-5-25 10:27 | 显示全部楼层
记得以前曾经有很多兄弟为所长的队列争吵过,这里贴上一个,欢迎拍砖,指正。
// queue.h文件
#ifndef AFX_QUEUE_H
#define AFX_QUEUE_H
#include "stm32f10x.h"


struct QueueBuffer{
u8  *buf; //缓冲区起始点
u16 front;
u16 rear;
u16 queue_len;   // 初始化时赋值,然后只读
};
//------------------------------------------------------------
//构造
//------------------------------------------------------------
extern void Queue_Init(void);
//-------------------------------------------------
//析构,释放在init()中使用到的硬件资源
//------------------------------------------------------------
extern void Queue_Destory(void);
//------------------------------------------------------------
//申请注册缓冲队列
//返回struct QueueBuffer结构指针。
//------------------------------------------------------------
extern struct QueueBuffer *Queue_Register( unsigned int mSize );
//------------------------------------------------------------
//将数据压入队列
//------------------------------------------------------------
extern void Queue_Push( struct QueueBuffer *pQueueBuffer, unsigned char mData );
//------------------------------------------------------------
//将数据弹出队列
//------------------------------------------------------------
extern unsigned char Queue_Pop( struct QueueBuffer *pQueueBuffer );
//------------------------------------------------------------
//读出队列指定序号数据
//------------------------------------------------------------
extern unsigned char Queue_Read( struct QueueBuffer *pQueueBuffer, unsigned char mId );
//------------------------------------------------------------
//返回队列数据个数
//------------------------------------------------------------
extern unsigned short Queue_Num( struct QueueBuffer *pQueueBuffer );
//------------------------------------------------------------
//队列清空
//------------------------------------------------------------
extern void Queue_Clear( struct QueueBuffer *pQueueBuffer );

extern int Queue_is_empty(struct QueueBuffer *pQueueBuffer);
extern int Queue_is_full(struct QueueBuffer *pQueueBuffer);

#endif                  

// queue.c文件
#include "global.h"

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

#include "queue.h"
#include "memory.h"

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

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

}

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

    pQueueBuffer = (struct QueueBuffer *)Memory_Malloc( sizeof(struct QueueBuffer));
    Memory_Memset((unsigned char*)pQueueBuffer, 0, sizeof(struct QueueBuffer));

    pQueueBuffer->buf = (u8 *)Memory_Malloc(mSize);
    Memory_Memset((unsigned char*)&pQueueBuffer->buf[0], 0,mSize);
   
    pQueueBuffer->front = 1;
    pQueueBuffer->rear  = 0;
    pQueueBuffer->queue_len = mSize;
   
    return pQueueBuffer;
}
int Queue_is_empty(struct QueueBuffer *pQueueBuffer)
{
    return ((pQueueBuffer->rear + 1)%(pQueueBuffer->queue_len) == pQueueBuffer->front);
}

int Queue_is_full(struct QueueBuffer *pQueueBuffer)
{
    return ((pQueueBuffer->rear + 2)%(pQueueBuffer->queue_len) == pQueueBuffer->front);
}


//------------------------------------------------------------
//将数据压入队列
//------------------------------------------------------------
void Queue_Push( struct QueueBuffer *pQueueBuffer, unsigned char mData )
{   
  //  if(Queue_is_full(pQueueBuffer))
  //  {        
//       while(1);
  //  }
    pQueueBuffer->rear = (pQueueBuffer->rear + 1)%(pQueueBuffer->queue_len);
    pQueueBuffer->buf[pQueueBuffer->rear] = mData;  
}
//------------------------------------------------------------
//将数据弹出队列
//------------------------------------------------------------
unsigned char Queue_Pop( struct QueueBuffer *pQueueBuffer )
{
    unsigned char data;
//   if(Queue_is_empty(pQueueBuffer))
//   {
  //      while(1);
//   }

    data = pQueueBuffer->buf[pQueueBuffer->front];
    pQueueBuffer->front = (pQueueBuffer->front + 1)% (pQueueBuffer->queue_len);
   
    return data;
}

//------------------------------------------------------------
//读出队列指定序号数据
//------------------------------------------------------------
unsigned char Queue_Read( struct QueueBuffer *pQueueBuffer, unsigned char mId )
{
   
    return 0;   
}
//------------------------------------------------------------
//返回队列数据个数
//------------------------------------------------------------
u16 Queue_Num( struct QueueBuffer *pQueueBuffer )
{
    u16 len;

    if(Queue_is_empty(pQueueBuffer))
    {
        return 0;
    }

    if(Queue_is_full(pQueueBuffer))
    {
        return (pQueueBuffer->queue_len - 1);
    }

    if(pQueueBuffer->rear >= pQueueBuffer->front)
    {
        len = pQueueBuffer->rear - pQueueBuffer->front + 1;
    }
    else
    {
        len = ((pQueueBuffer->queue_len - 1) - pQueueBuffer->front + 1) + pQueueBuffer->rear + 1;
    }
   
    return len;
}

//------------------------------------------------------------
//队列清空
//------------------------------------------------------------
void Queue_Clear( struct QueueBuffer *pQueueBuffer )
{   
    Memory_Memset((unsigned char*)&pQueueBuffer->buf[0], 0,pQueueBuffer->queue_len);
    pQueueBuffer->front = 1;
    pQueueBuffer->rear = 0;
}

使用特权

评论回复
tiger84|  楼主 | 2010-5-25 10:32 | 显示全部楼层
这个队列是这样定义的,数组中的一个元素始终保留不用。
当队列为空时,rear的值必须比front小1
也就是
(rear + 1)%QUEUE_SIZE == front

当满足下列条件时,队列为“满”
(rear + 2)%QUEUE_SIZE == front

之所以在结构体中引进了queue_len,是为了队列大小的灵活性,它只在注册的时候写,然后不会再变。

使用特权

评论回复
tiger84|  楼主 | 2010-5-25 10:40 | 显示全部楼层
本帖最后由 tiger84 于 2010-5-31 10:10 编辑

串口处理
简单说明 串口1用来显示,无中断,查询发送
         串口2中断发送,中断接收

// usart.h
#ifndef __USART__H__
#define __USART__H__

#define UART2_RX_QUEUE_SIZE  1024
#define UART2_TX_QUEUE_SIZE  1024


void usart_init(int usart_num);

int USART2_SendDataLen( unsigned char *pData,int len);

#endif

// usart.c
#include "global.h"

// 串口队列
struct UART_STRUCT
{
    struct QueueBuffer  *psSend;    //发送队列指针
    struct QueueBuffer  *psReci;    //接收队列指针
};
struct UART_STRUCT pUart2;      //定义串口的结构体

//串口接收
#define Uart2_Rx_Push(x)       Queue_Push(pUart2.psReci,x)
#define Uart2_Rx_Pop()         Queue_Pop(pUart2.psReci)
#define Uart2_Rx_Num()         Queue_Num(pUart2.psReci)
#define Uart2_Rx_Full()        Queue_is_full(pUart2.psReci)
#define Uart2_Rx_Empty()       Queue_is_empty(pUart2.psReci)
#define Uart2_Rx_Clr()         do{Queue_Clear(pUart2.pReci);}while(0)

// 串口发送
#define Uart2_Tx_Push(x)       Queue_Push(pUart2.psSend,x)
#define Uart2_Tx_Pop()         Queue_Pop(pUart2.psSend)
#define Uart2_Tx_Num()         Queue_Num(pUart2.psSend)
#define Uart2_Tx_Full()        Queue_is_full(pUart2.psSend)
#define Uart2_Tx_Empty()       Queue_is_empty(pUart2.psSend)
#define Uart2_Tx_Clr()         do{Queue_Clear(pUart2.psend);}while(0)


/*******************************************************************************
* Function Name  : usart_init()
* Description    : This routine is called to set the configuration value
*                  Then each class should configure device themself.
* Input          : None.
* Output         : None.
* Return         : Return USB_SUCCESS, if the request is performed.
*                  Return USB_UNSUPPORT, if the request is invalid.
*******************************************************************************/

void usart_init(int usart_num)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
   
    if(USE_USART1 == usart_num)
    {
        // 配置时钟
        /* Enable GPIOx clock */
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
        /* Enable USARTx clocks */
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);      

        // 配置IO
        /* Configure USARTx_Tx as alternate function push-pull */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        /* Configure USARTx_Rx as input floating */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_Init(GPIOA, &GPIO_InitStructure);      
               
        USART_InitStructure.USART_BaudRate = 115200;
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;
        USART_InitStructure.USART_StopBits = USART_StopBits_1;
        USART_InitStructure.USART_Parity = USART_Parity_No ;
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
        /* Configure the USARTx */
        USART_Init(USART1, &USART_InitStructure);
        /* Enable USART2 Receive interrupts */
      //  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);        
        /* Enable the USARTx */
        USART_Cmd(USART1, ENABLE);     
        
    }
    else if(USE_USART2 == usart_num)
    {
        /* Enable GPIOx clock */
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
        /* Enable USARTx clocks */
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);      

        /* Configure USARTx_Tx as alternate function push-pull */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        /* Configure USARTx_Rx as input floating */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_Init(GPIOA, &GPIO_InitStructure);


        USART_InitStructure.USART_BaudRate = 115200;
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;
        USART_InitStructure.USART_StopBits = USART_StopBits_1;
        USART_InitStructure.USART_Parity = USART_Parity_No ;
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
        /* Configure the USARTx */
        USART_Init(USART2, &USART_InitStructure);   

        pUart2.psSend=Queue_Register(UART2_TX_QUEUE_SIZE);
        pUart2.psReci=Queue_Register(UART2_RX_QUEUE_SIZE);      

        /* Enable USART2 Receive interrupts */
        USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
        USART_ITConfig(USART2, USART_IT_TXE, ENABLE);
        
        /* Enable the USARTx */
        USART_Cmd(USART2, ENABLE);  

      
           
        
        
    }     
   
}


// return 返回可发送字节数
int USART2_SendDataLen( unsigned char *pData,int len)
{
    int i;
    unsigned char *p;

    p = pData;

    for(i = 0; i < len; i++)
    {
        if(!Uart2_Tx_Full())
        {
            Uart2_Tx_Push(*p++);
        }
        else
        {
            break;
        }
        
    }
    USART_ITConfig(USART2, USART_IT_TXE, ENABLE);//只要发送寄存器为空,就会一直有中断,因此,要是不发送数据时,把发送中断关闭,只在开始发送时,才打开

    return (i + 1);   
}
  
void USART2_IRQHandler(void)
{
  
    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
    {
        /* Read one byte from the receive data register */   
        Uart2_Rx_Push(USART_ReceiveData(USART2));        
    }

     //发送中断
    if( USART_GetITStatus(USART2, USART_IT_TXE) == SET  )
    {   
        if(!Uart2_Tx_Empty())
        {
            USART_SendData(USART2, Uart2_Tx_Pop());
        }
        else
        {
            USART_ITConfig(USART2, USART_IT_TXE, DISABLE);
        }   
        
    }

        

}

使用特权

评论回复
tiger84|  楼主 | 2010-5-25 13:43 | 显示全部楼层
竟然连拍砖的人都没有----:'(
惭愧,走人---

使用特权

评论回复
香水城| | 2010-5-25 13:48 | 显示全部楼层
哈哈,太高深了,帮你顶一下,:lol

使用特权

评论回复
huangqi412| | 2010-5-25 13:50 | 显示全部楼层
帮顶...被仙人跳的小老虎:lol

使用特权

评论回复
ecomputer| | 2010-5-25 14:38 | 显示全部楼层
做个标记,有空再来研究

使用特权

评论回复
maomao2126| | 2010-5-25 15:12 | 显示全部楼层
太深奥了, 软内存管理??

使用特权

评论回复
tiger84|  楼主 | 2010-5-25 15:29 | 显示全部楼层
谢谢各位,呵呵。
这里解释下,这里的内存管理实际上并不是真正意义上的内存管理,它只是简单的把全局变量定义到了1个专门的区域,也就是自定义的堆里面,而且没有释放功能,谈不上内存管理,只是山寨所长的程序而已。不过可以参考IAR的帮助文件,能直接用malloc。
若自己写个内存管理,挺麻烦的,主要问题就是会产生内存碎片。

使用特权

评论回复
xuyiyi| | 2010-5-26 05:11 | 显示全部楼层
哈哈,帮你顶一下.

使用特权

评论回复
auzxj| | 2010-5-26 08:45 | 显示全部楼层
没看明白:funk:

使用特权

评论回复
tiger84|  楼主 | 2010-5-26 11:12 | 显示全部楼层
忘记说了一点,需要把intial_sp 赋值 0x2000a000
堆大小为0x6000
栈大小为0x4000
内存分配表如下:
HEAP                        0x20000000  0x6000  <Block>
   HEAP             uninit   0x20000000  0x6000  <Block tail>
  CSTACK                      0x20006000  0x4000  <Block>
   CSTACK           uninit   0x20006000  0x4000  <Block tail>
.iar.dynexit                0x2000a000   0x1d4  <Block>

如果使用库自带的malloc,则malloc的范围在0x2000 0000  ---0x2000 5ffff
其他变量分配 0x2000a000----0x2000 FFFF

使用特权

评论回复
mochou| | 2010-5-28 10:23 | 显示全部楼层
也顶下.

使用特权

评论回复
路过打酱油| | 2010-5-28 10:34 | 显示全部楼层
顶下

使用特权

评论回复
编程菜鸟| | 2010-5-28 12:45 | 显示全部楼层
看不懂也顶下

使用特权

评论回复
初入江湖| | 2010-6-10 09:03 | 显示全部楼层
也顶下

使用特权

评论回复
jiushi| | 2010-10-23 20:43 | 显示全部楼层
不懂,但顶一下

使用特权

评论回复
无冕之王| | 2010-10-24 12:30 | 显示全部楼层
有点高深了,帮顶

使用特权

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

本版积分规则

个人签名:专注ARM及linux性能优化

101

主题

862

帖子

0

粉丝