记录学习嵌入式遇到的问题(二)复杂工程管理示例
在一个实际工程的创建和管理中,其众多的各种文件常会因各种原因而分别放在不同的文件目录之下。总而言之,为了清楚有序,开发人员应该为工程设置多个文件目录来存储源代码、编译过程中产生的中间文件及第三方的文件等。设计者应该充分的利用批处理文件和makefile文件的强大功能,负责建立起不同的文件目录,来使整个工程规范有序,来减少不必要的错误。
下面用一个例子来说明批处理文件和 makefile文件在工程管理上的作用。
(1)程序的目录组织
文件目录的层次根据开发人员的风格来定,没有标准的要求,但要尽可能的让别人容易理解!
在本例中第三方的源程序存储在TPS文件夹中,用户自己的源程序以及连接文件存储在SOURCE文件夹中,编译过程中产生的.obj文件复制在OBJ临时文件夹中以备查询,批处理文件和 makefile文件被存放在目录TEST,同时该目录还要负责存放将来创建出来的最终可执行文件TEST.EXE,WORK文件夹也常常被叫做工作目录,其作用就是为编译和连接工作提供一种场所,所以在WORK文件夹中需要访问其他的文件夹,如:SOURCE文件夹等。例如:在WORK文件夹中访问SOURCE,则该目录的路径就为..\SOURCE
(因为是在WORK的上一级目录中,若SOURCE在WORK的上上一级目录,则路径就为..\..\SOURCE
)其中,WORK以及OBJ文件夹为临时文件夹,在程序编译完成之后会被删除。
此图为运行批处理文件后的文件结构截图:
最初始的文件结构为:
(2)批处理文件
批处理文件要负责临时文件目录的创建及删除,同时还要负责 makefile文件的启动。本例批处理文件代码如下:
ECHO OFF
ECHO *******************************************************************************
ECHO * uC/OS-II
ECHO * The Real-Time Kernel
ECHO *
ECHO * (c) Copyright 1992-2002, Jean J. Labrosse, Weston, FL
ECHO * All Rights Reserved
ECHO *
ECHO * Filename : MAKETEST.BAT
ECHO * Description : Batch file to create the application.
ECHO * Output : TEST.EXE will contain the DOS executable
ECHO * Usage : MAKETEST
ECHO * Note(s) : 1) This file assume that we use a MAKE utility.
ECHO *******************************************************************************
ECHO *
ECHO ON
REM 在当前目录的上一级目录创建WORK临时文件夹
MD ..\WORK
REM 在当前目录的上一级目录创建OBJ临时文件夹
MD ..\OBJ
REM 在当前目录的上一级目录创建TPS文件夹
MD ..\TPS
REM 进入WORK文件夹
CD ..\WORK
REM 进入TEST文件夹把连接文件TEST.MAK文件夹复制到WORK文件夹下并命名为TEST.MAK
COPY ..\TEST\TEST.MAK TEST.MAK
REM 启动makefile文件
C:\BC31\BIN\MAKE -f TEST.MAK
REM 进入TEST文件夹
CD ..\TEST
(3)makefile文件
makefile文件代码如下:
###############################################################################
# uC/OS-II
# The Real-Time Kernel
#
# (c) Copyright 2002, Jean J. Labrosse, Weston, FL
# All Rights Reserved
#
#
# Filename : TEST.MAK
###############################################################################
#
#/*$PAGE*/
###############################################################################
# TOOLS
###############################################################################
#
BORLAND=C:\BC31 # 用BORLAND代替地址C:\BC31
CC=$(BORLAND)\BIN\BCC # 用CC代替指令BCC
ASM=$(BORLAND)\BIN\TASM # 用ASM代替指令TASM(汇编编译命令)
LINK=$(BORLAND)\BIN\TLINK # 用LINK代替指令TLINK
TOUCH=$(BORLAND)\BIN\TOUCH # 用TOUCH代替指令TOUCH
###############################################################################
# DIRECTORIES
###############################################################################
#
TPS=..\TPS # 用TPS代替由当前目录返回上一级目录TPS中
OBJ=..\OBJ # 用OBJ代替由当前目录返回上一级目录OBJ中
SOURCE=..\SOURCE # 用SOURCE代替由当前目录返回上一级目录SOURCE中
TARGET=..\TEST # 用TARGET代替由当前目录返回上一级目录TEST中
WORK=..\WORK # 用WORK代替由当前目录返回上一级目录WORK中
OS=\UCOS-II\COMMON\SOURCE # 用OS代替目录\UCOS-II\COMMON\SOURCE
PC=\UCOS-II\COMMON\BLOCKS\PC\BC31 # 用PC代替目录\UCOS-II\COMMON\BLOCKS\PC\BC31
PORT=\UCOS-II\COMMON\Ix86L\BC31 # 用PORT代替目录\UCOS-II\COMMON\Ix86L\BC31
###############################################################################
# COMPILER FLAGS
#
# -1 Generate 80186 code
# -B Compile and call assembler
# -c Compiler to .OBJ
# -G Select code for speed
# -I Path to include directory
# -k- Standard stack frame
# -L Path to libraries directory
# -ml Large memory model
# -N- Do not check for stack overflow
# -n Path to object directory
# -O Optimize jumps
# -Ob Dead code elimination
# -Oe Global register allocation
# -Og Optimize globally
# -Ol Loop optimization
# -Om Invariant code motion
# -Op Copy propagation
# -Ov Induction variable
# -v Source debugging ON
# -vi Turn inline expansion ON
# -wpro Error reporting: call to functions with no prototype
# -Z Suppress redundant loads
###############################################################################
#
C_FLAGS=-c -ml -1 -G -O -Ogemvlbpi -Z -d -n..\obj -k- -v -vi- -wpro -I$(BORLAND)\INCLUDE -L$(BORLAND)\LIB
# 用C_FLAGS来代替编译命令
###############################################################################
# ASSEMBLER FLAGS
#
# /MX Case sensitive on globals
# /ZI Full debug info
# /O Generate overlay code
###############################################################################
#
ASM_FLAGS=/MX /ZI /O # 用ASM_FLAGS代替汇编程序标志
###############################################################################
# LINKER FLAGS
###############################################################################
#
LINK_FLAGS= # 用LINK_FLAGS代替连接标志
###############################################################################
# MISCELLANEOUS
###############################################################################
#
INCLUDES= $(SOURCE)\INCLUDES.H \
$(SOURCE)\OS_CFG.H \
$(PORT)\OS_CPU.H \
$(PC)\PC.H \
$(OS)\uCOS_II.H
# 用INCLUDES代替需要引入的头文件的位置
###############################################################################
# CREATION OF .EXE FILE
###############################################################################
$(TARGET)\TEST.EXE: \ # 进入TEST文件夹生成TEST.EXE文件
$(WORK)\INCLUDES.H \ # 需要的中间文件
$(OBJ)\OS_CPU_A.OBJ \ # 需要的中间文件
$(OBJ)\OS_CPU_C.OBJ \ # 需要的中间文件
$(OBJ)\PC.OBJ \ # 需要的中间文件
$(OBJ)\TEST.OBJ \ # 需要的中间文件
$(OBJ)\uCOS_II.OBJ \ # 需要的中间文件
$(SOURCE)\TEST.LNK # 需要的中间文件
COPY $(SOURCE)\TEST.LNK # 把TEST.LNK复制到当前文件夹(WORK)
$(LINK) $(LINK_FLAGS) @TEST.LNK # 执行连接命令
COPY $(OBJ)\TEST.EXE $(TARGET)\TEST.EXE # 把TEST.EXE复制到TEST文件夹
COPY $(OBJ)\TEST.MAP $(TARGET)\TEST.MAP # 把TEST.MAP复制到TEST文件夹
DEL TEST.MAK # 删除连接文件
###############################################################################
# CREATION OF .OBJ (Object) FILES
###############################################################################
$(OBJ)\OS_CPU_A.OBJ: \
$(PORT)\OS_CPU_A.ASM # 需要的中间文件
COPY $(PORT)\OS_CPU_A.ASM OS_CPU_A.ASM # 复制OS_CPU_A.ASM到当前文件夹
$(ASM) $(ASM_FLAGS) $(PORT)\OS_CPU_A.ASM,$(OBJ)\OS_CPU_A.OBJ # 汇编语言的编译命令
$(OBJ)\OS_CPU_C.OBJ: \
$(PORT)\OS_CPU_C.C \ # 需要的中间文件
COPY $(PORT)\OS_CPU_C.C OS_CPU_C.C # 复制
$(CC) $(C_FLAGS) OS_CPU_C.C # C语言编译命令
$(OBJ)\PC.OBJ: \
$(PC)\PC.C \ # 需要的中间文件
$(INCLUDES) # 需要的中间文件
COPY $(PC)\PC.C PC.C # 复制
$(CC) $(C_FLAGS) PC.C # C语言编译命令
$(OBJ)\TEST.OBJ: \
$(SOURCE)\TEST.C \ # 需要的中间文件
$(INCLUDES) # 需要的中间文件
COPY $(SOURCE)\TEST.C TEST.C # 复制
$(CC) $(C_FLAGS) TEST.C # C语言编译命令
$(OBJ)\uCOS_II.OBJ: \
$(OS)\uCOS_II.C \
$(INCLUDES)
COPY $(OS)\uCOS_II.C uCOS_II.C # C语言编译命令
$(CC) $(C_FLAGS) uCOS_II.C # C语言编译命令
$(WORK)\INCLUDES.H: \
$(INCLUDES) # 需要的中间文件
COPY $(SOURCE)\INCLUDES.H INCLUDES.H # 复制
COPY $(SOURCE)\OS_CFG.H OS_CFG.H # 复制
COPY $(PC)\PC.H PC.H # 复制
COPY $(PORT)\OS_CPU.H OS_CPU.H # 复制
COPY $(OS)\uCOS_II.H uCOS_II.H # 复制
(4)SOURCE文件夹中的部分源码
test.c:
/*
**********************************************
*说明:我的第一个在PC上的uC/OS-II任务
*By:jack ailson
*Time:2013.08.09
**********************************************
*/
#include "includes.h"
#define TASK_STK_SIZE 512//任务堆栈的长度
OS_STK MyTaskStk[TASK_STK_SIZE];//定义任务堆栈区
OS_STK YouTaskStk[TASK_STK_SIZE];
INT16S key;//用于退出uC/OS-II的按键
INT8U x=0,y=0;//字符显示的位置
void MyTask(void *pdata);//声明一个自己的任务
void YouTask(void *pdata);
/*
***********************************************
*主函数:void main(void);
***********************************************
*/
void main(void)
{
char* s_M="M";//定义要显示的字符
OSInit();//初始化uC/OS-II
PC_DOSSaveReturn();//保存DOS环境
PC_VectSet(uCOS,OSCtxSw);//安装uC/OS-II任务切换中断向量
OSTaskCreate(MyTask,s_M,&MyTaskStk[TASK_STK_SIZE-1],0);//创建任务
OSStart();//启动多任务管理
}
/*
***********************************************
*任务:void MyTask(void *pdata);
***********************************************
*/
void MyTask(void *pdata)
{
char *s_Y="Y";
INT8U lockcal=0;
#if OS_CRITICAL_METHOD==3
OS_CPU_SR cpu_sr;
#endif
pdata=pdata;
OS_ENTER_CRITICAL();//进入临界段(关中断)
PC_VectSet(0x08,OSTickISR);//安装uC/OS-II时钟中断向量
PC_SetTickRate(OS_TICKS_PER_SEC);//设置uC/OS-II时钟频率
OS_EXIT_CRITICAL();//退出临界段(开中断)
OSStatInit();//初始化uC/OS-II的统计任务
OSTaskCreate(YouTask,s_Y,&YouTaskStk[TASK_STK_SIZE-1],2);
for(;;)
{
if (lockcal==5)
{
OSSchedLock();
}
if (lockcal==10)
{
lockcal=0;
OSSchedUnlock();
}
lockcal++;
if (x>27)
{
x=0;
y+=2;
}
PC_DispChar(x,y,*(char*)pdata,DISP_BGND_BLACK+DISP_FGND_YELLOW);//字符显示
x++;
//如果按下ESC键,则退出uC/OS-II
if (PC_GetKey(&key)==TRUE)//检查是否有按键按下
{
if (key==0x1b)
{
PC_DOSReturn();//返回DOS
}
}
OSTimeDlyHMSM(0,0,3,0);//延时3S
}
}
/*
***********************************************
*任务:void YouTask(void *pdata);
***********************************************
*/
void YouTask(void *pdata)
{
INT8U cal=0;
#if OS_CRITICALS_METHOD==3
OS_CPU_SR cpu_sr;
#endif
pdata=pdata;
for(;;)
{
if (cal==20)
{
OSTaskSuspend(0);
}
if (cal==40)
{
cal=0;
OSTaskResume(0);
}
cal++;
if (x>27)
{
x=0;
y+=2;
}
PC_DispChar(x,y,*(char*)pdata,DISP_BGND_BLACK+DISP_FGND_GREEN);
x++;
OSTimeDlyHMSM(0,0,1,0);
}
}
(5)运行结果
运行前的文件结构:
运行前的SOURCE文件夹中的内容:
运行前的TEST文件夹中的内容:
运行时的截图:
(1)执行批处理文件
(2)批处理文件执行成功
(3)执行test.exe
(4)执行成功
运行过程:一行一行的在屏幕上输出MY(M与Y随机),速度比较缓慢。
运行后的文件结构:
运行后的OBJ文件中的内容:
运行后的TEST文件夹中的内容:
运行后的WORK文件夹中的内容:
注:本文章仅供参考,只用文章中的3段代码是实现不了最后的结果的,还需要其他文件。如需资料可评论。
上一篇: ARM汇编笔记
下一篇: STM32学习笔记(11)电容触摸按键