1. 程式人生 > >bat指令碼編譯微控制器程式

bat指令碼編譯微控制器程式

最近做一個專案,要求寫一個指令碼檔案來編譯微控制器原始檔。當時就納悶了,編寫微控制器源程式的Keil平臺不是已經夠強大了,為什麼還要單獨寫一個bat指令碼來對源程式進行編譯???經過向大神請教,原來大神編寫了智慧家居的控制程式,除錯時對於不同的家電都需要修改不同的巨集定義(對於任何家電的控制都用一個巨集定義來表示),這樣每次除錯時都得進Keil編譯器,很浪費時間,再說由於有時候改動並不一定在已開啟IED的情況,也不想每次都必須開啟Keil來編譯。於是就需要編寫一個指令碼檔案來實現對源程式的編譯,並且根據輸入的不同能選擇不同的巨集定義來編譯,這樣就不需要每次都執行Keil了。

寫bat指令碼就得先明白它的命令語句。由於bat指令碼檔案是將一系列的DOS命令按一定的順序集合為一個可執行的文字檔案,該文字檔案能按要求完成指定的功能,其副檔名為BAT或者CMD。(小知識:通過按下Ctrl+C組合鍵可強行終止一個批處理的執行過程。),所以下面我只列出我所使用的命令解釋:

常用命令:
  1.REM和::  2.ECHO和@  3.PAUSE  4.GOTO和:  5.IF...else...  6.ERRORLEVEL  7.SET  8.FOR  9.%

1.REM 和 ::
REM為註釋命令,一般用來給程式加上註解,該命令後的內容不被執行,但能回顯。
::也起到註釋作用,而且更簡潔有效,與rem不同的是,::後的字元行在執行時都不會回顯,無論是否用echo on開啟命令列回顯狀態。
2.ECHO 和 @
@字元放在命令前將關閉命令回顯,無論此時echo是否為開啟狀態。ECHO命令的常用功能如下:
(1)打開回顯或關閉回顯功能
     格式:echo [{on|off}]
如果想關閉“ECHO OFF/ON”自身的顯示,在命令列前加上“@”。

(2)輸出提示資訊
     格式:ECHO 資訊內容
(3)輸出空行,即相當於輸出一個回車
     格式:ECHO.
需要注意的是命令列中的“.”要緊跟ECHO後面,中間不能有空格。
(4)建立新檔案或增加檔案內容
     格式:ECHO 檔案內容>檔名稱
           ECHO 檔案內容>>檔名稱
其中>、>>為重定向符號,表示將內容輸出到指定檔案。

3.PAUSE
暫停命令,執行該命令後會顯示“請按任意鍵繼續”,按下任意鍵後則終止暫停狀態,如想顯示其他提示語,可與ECHO聯用,例:echo 其他提示語 & pause > nul
4.GOTO 和 :
GOTO為跳轉指令,跳轉到以:開頭的標號處,若標籤匹配,則執行標籤後的命令,標籤的名稱可以隨便起,但最好是有意義的字串,GOTO語句就是根據:和標籤來尋找下一步執行的位置。
5.IF...else...
條件語句,依據判斷值來執行相關的命令,主要有以下形式:
   IF [NOT] ERRORLEVEL number command

   IF [NOT] string1==string2 command
   IF [NOT] EXIST filename command
其中command命令可以是多條命令的組合,組合命令中也可以巢狀使用條件或迴圈命令。
6.ERRORLEVEL
命令執行返回值,用於判斷命令執行狀態,預設值為0,一般命令執行出錯或者警告會使ERRORLEVEL值為1、2、3,可依據該值確定發生錯誤的級別。
7.SET
顯示、設定或刪除環境變數,格式如下:
SET [variable=[string]]

variable  指定環境變數
string    指定要賦給環境變數的一系列字串
8.FOR
迴圈命令,基本格式為:
FOR %%variable IN (set) DO command [command-parameters]
%%variable  指定一個單一字母表示需替換的引數
set         指定一個或多個檔案,可使用萬用字元
command     指定對每個檔案執行的命令
command-parameters  指定引數或命令列開關
FOR迴圈帶引數的用法有很多,可使用"FOR /? >檔名稱"語句將FOR的幫助文件輸出到指定檔案,方便檢視。

9.%
批處理變數引導符,可作為批處理的引用引數。引用變數用%var%,呼叫程式外部引數用%1至%9等等。
%0 批處理檔案本身,包括完整的路徑和副檔名
%1 第一個引數
%9 第九個引數
%* 從第一個引數開始的所有引數
引數%0可以實現呼叫批處理自身的特殊功能,以達到批處理本身迴圈的目的,也可以複製檔案自身等等。

用命令列編譯微控制器的原始檔流程是:編譯原始檔生成OBJ,然後連結OBJ,之後轉換成HEX檔案。這樣就OK了,很簡單。 
51.exe 編譯c檔案,BL51.EXE連結OBJ, OH51.EXE轉換檔案成HEX。

安裝目錄\C51.exe   C51Test.c

安裝目錄\BL51.exe  C51Test.obj TO Test

安裝目錄\OH51.exe  Test

注意:不要忘記把標頭檔案複製到 \C51\INC 庫目錄中,以後使用比較方便。

在bat檔案中執行C51編譯器和工具,必須手動建立以下環境變數:
SET PATH=安裝目錄\C51\BIN;%PATH%
SET Dir=源程式目錄...
SET C51INC=安裝目錄\C51\INC
SET C51LIB=安裝目錄\C51\LIB
C51有很多控制命令,這就就可以實現對巨集定義的選取:
C51編譯器提供許多控制命令控制編譯,控制命令由一個或多個字母或數字組成,位於要編譯的檔名之後,控制命令分為三類:原始檔控制,目標控制,和列表控制。詳細的控制命令及其說明可參考“安裝目錄\C51\HLP\c51.chm(或c51.pdf)”的幫助文件。其中DEFINE,DEBUG,INCDIR,WARNINGLEVEL控制命令的說明如下:

DEFINE
縮寫:DF
預設值:無
引數:一個或多個符合C語言約定的名稱,用逗號分隔。
描述:在編譯命令列中定義預處理標誌。

DEBUG
縮寫:DB
預設值:沒有除錯資訊被生成
引數:無
描述:指示編譯器在obj檔案中包含除錯資訊。

INCDIR
縮寫:無
預設值:無
引數:原始檔中include所包含檔案的路徑
描述:指定編譯器include所包含檔案的位置,編譯器接收最多 512個路徑宣告,如果指定多個路徑宣告,路徑名必須用分號隔開。


WARNINGLEVEL
縮寫:WL
預設值:WARNINGLEVEL (2)
引數:0-2之間的一個數值
描述:通過指定warning的等級可忽略某些編譯器警告。

概念都解釋完了,那麼不多說了,直接看bat的源程式如下,該程式可以擴充套件:

::close echo
@echo off

::clean screen
cls

:: SET C51INC=C:\keil\C51\INC\Atmel\;C:\Keil\C51\INC\
:: SET C51LIB=C:\Keil\C51\LIB
set BINPath=BIN的路徑
set C51LIB=LIB的路徑

::SET source program Directory and source filename
set DIRName=bat檔案所在目錄
set Status=0
set SourceFile=%~nx1
set ObjName=%~n1

::set the macro defined constant values
set valueone="0"
set valuetwo="1"
set valuethree="P0^0"

::set the macro defined alias
set aliasone=a
set aliastwo=b
set aliasthree=LED

::dispaly This programme is to make the C51 programme automate
echo This programme is to make the C51 programme automate

::if input not correct
if "%1"=="" goto InputErr
if "%1"=="/?" goto InputErr
if "%1"=="help" goto InputErr
if not "%~x1"==".c" goto InputErr
if "%2"=="" (goto InputErrtwo) else if not "%2"=="0" (
	if not "%2"=="1" (goto InputErrtwo)
    )
if "%3"=="" (goto InputErrtwo) else if not "%3"=="0" (
	if not "%3"=="1" (goto InputErrtwo)
    )
if "%4"=="" (goto InputErrtwo) else if not "%4"=="0" (
	if not "%4"=="1" (goto InputErrtwo)
	)
	
@echo Go to workplace
D:
cd %DIRName%

@echo Clean have existed file
goto Clean

:valuejudge
if "%2"=="1" (
	if "%3"=="1" (
		if "%4"=="1" (goto defineone) else goto definetwo
	) else (
		if "%4"=="1" (goto definethree) else goto definefour
		)
) else if "%3"=="1" (
		if "%4"=="1" (goto definefive) else goto definesix
	) else (
		if "%4"=="1" (goto defineseven) else goto defineeight
		)

:LinkHEX
::else link the .obj file
%BINPath%BL51.exe %C51LIB%C51s.lib,%ObjName%.obj TO %ObjName%
if errorlevel 1 goto LinkErr
@echo Link Success...

::generate .hex file
%BINPath%OH51.exe %ObjName%
if errorlevel 1 goto HEXErr
@echo HEX Generate Success...
set Status=1
goto judge

:defineone
@echo building %ObjName%.c to %ObjName%.obj
::build c51 programmer
%BINPath%C51.exe %SourceFile% DF (%aliasone%='%valueone%',%aliastwo%='%valuetwo%',%aliasthree%='%valuethree%') DB INCDIR (外部庫路徑) WL (1)
::if error, pause to see error
if errorlevel 1 goto BuildErr
@echo building Success...
@echo.
@echo macro define sequence: 111
goto LinkHEX

:definetwo
@echo building %ObjName%.c to %ObjName%.obj
::build c51 programmer
%BINPath%C51.exe %SourceFile% DF (%aliasone%='%valueone%',%aliastwo%='%valuetwo%') DB INCDIR (外部庫路徑) WL (1)
::if error, pause to see error
if errorlevel 1 goto BuildErr
@echo building Success...
@echo.
@echo macro define sequence: 110
goto LinkHEX

:definethree
@echo building %ObjName%.c to %ObjName%.obj
::build c51 programmer
%BINPath%C51.exe %SourceFile% DF (%aliasone%='%valueone%',%aliasthree%='%valuethree%') DB INCDIR (外部庫路徑) WL (1)
::if error, pause to see error
if errorlevel 1 goto BuildErr
@echo building Success...
@echo.
@echo macro define sequence: 101
goto LinkHEX

:definefour
@echo building %ObjName%.c to %ObjName%.obj
::build c51 programmer
%BINPath%C51.exe %SourceFile% DF (%aliasone%='%valueone%') DB INCDIR (外部庫路徑) WL (1)
::if error, pause to see error
if errorlevel 1 goto BuildErr
@echo building Success...
@echo.
@echo macro define sequence: 100
goto LinkHEX

:definefive
@echo building %ObjName%.c to %ObjName%.obj
::build c51 programmer
%BINPath%C51.exe %SourceFile% DF (%aliastwo%='%valuetwo%',%aliasthree%='%valuethree%') DB INCDIR (外部庫路徑) WL (1)
::if error, pause to see error
if errorlevel 1 goto BuildErr
@echo building Success...
@echo.
@echo macro define sequence: 011
goto LinkHEX

:definesix
@echo building %ObjName%.c to %ObjName%.obj
::build c51 programmer
%BINPath%C51.exe %SourceFile% DF (%aliastwo%='%valuetwo%') DB INCDIR (外部庫路徑) WL (1)
::if error, pause to see error
if errorlevel 1 goto BuildErr
@echo building Success...
@echo.
@echo macro define sequence: 010
goto LinkHEX

:defineseven
@echo building %ObjName%.c to %ObjName%.obj
::build c51 programmer
%BINPath%C51.exe %SourceFile% DF (%aliasthree%='%valuethree%') DB INCDIR (外部庫路徑) WL (1)
::if error, pause to see error
if errorlevel 1 goto BuildErr
@echo building Success...
@echo.
@echo macro define sequence: 001
goto LinkHEX

:defineeight
@echo building %ObjName%.c to %ObjName%.obj
::build c51 programmer
%BINPath%C51.exe %SourceFile% DB INCDIR (外部庫路徑) WL (1)
::if error, pause to see error
if errorlevel 1 goto BuildErr
@echo building Success...
@echo.
@echo macro define sequence: 000
goto LinkHEX

:Clean
if exist "%ObjName%.lst" del "%ObjName%.lst"
if exist "%ObjName%.m51" del "%ObjName%.m51"
if exist "%ObjName%.obj" del "%ObjName%.obj"
if exist "%ObjName%" del "%ObjName%"
if %Status% == 0 (
   if exist "%ObjName%.hex" del "%ObjName%.hex"
   ::Delay,unit is s
   ping -n 3 127.0.0.0>nul
   goto valuejudge
)

:judge
if %Status% == 1 goto HEXOK
@echo Hex generate fail!
pause
goto ReturnDir

:BuildErr
@echo Sorry!%ObjName%.obj generate fail...
pause
goto ReturnDir

:LinkErr
@echo Sorry!Link fail...
pause
goto ReturnDir

:HexErr
@echo Sorry!HEX generate fail...
pause
goto ReturnDir

:InputErr
echo Please enter correct C51 file name
echo Usage:[BAT file name] [C51 file name].c [value1(0 or 1)] [value2(0 or 1)] [value3(0 or 1)]
pause
goto ReturnDir

:InputErrtwo
echo Please enter correct C51 define value
echo Usage:[BAT file name] [C51 file name].c [value1(0 or 1)] [value2(0 or 1)] [value3(0 or 1)]
pause
goto ReturnDir

:HEXOK
@echo.
@echo OK!%ObjName%.hex have generated...
pause
goto ReturnDir

:ReturnDir
C:

@echo on
執行BAT檔案輸入命令格式:
BAT檔名 源程式名稱.c [1 or 0] [1 or 0] [1 or 0]
%0   %1   %2%3    %4
%0為BAT檔案本身,%1為所要編譯的原始檔,其中字尾.c不能少,%2、%3、%4為選擇進行巨集定義的語句,只能為0或1,0表示不需要對應的巨集定義語句,1表示選擇了對應的巨集定義語句。巨集定義語句的別名和常量通過SET語句設定:
SET VARONE="0"; SET VARTWO="1"; SET VARTHREE="P0^0"
SET ALIASONE=A; SET ALIASTWO=B; SET ALIASTHREE=LED
如果想修改巨集定義中的別名和常量,只需修改SET中等號右邊的字元即可。

參考資料:

1.http://www.cnblogs.com/glaivelee/archive/2009/10/07/1578737.html

2.http://www.cnblogs.com/gleam/archive/2012/02/14/2350990.html

個人成果,轉載請註明出處!!!