Keil 的輔助工具和部份高級技巧
在前面的幾講中我們介紹了工程的建立方法,常用的調試方法,除此之外,Keil 還提供 了一些輔助工具如外圍接口、性能分析、變量來源分析、代碼作用分析等,幫助我們了解程 的性能、查找程序中的隱藏錯誤,快速查看程序變量名信息等,這一講中將對這些功工具作 一介紹,另外還將介紹 Keil 的部份高級調試技巧。
一、 輔助工具
這部份功能并不是直接用來進行程序調試的,但可以幫助我們進行程序的調試、程序性 能的分析,同樣是一些很有用的工具。
1、外圍接口
為了能夠比較直觀地了解單片機中定時器、中斷、
并行端口、串行端口等常用外設的使用情況,Keil 提 供了一些外圍接口對話框,通過 Peripherals 菜單選擇, 該菜單的下拉菜單內容與你建立項目時所選的 CPU 有關,如果是選擇的 89C51 這一類“標準”的 51 機, 那么將會有 Interrupt(中斷)、I/O Ports(并行 I/O 口)、 Serial(串行口)、Timer(定時/計數器)這四個外圍設
圖 1 外圍設備之并行端口
備菜單。打開這些對話框,列出了外圍設備的當前使用情況,各標志位的情況等,可以在這 些對話框中直觀地觀察和更改各外圍設備的運行情況。
下面我們通過一個簡單例子看一看并行端口的外圍設備對話框的使用。例 4:
MOV |
A,#0FEH |
|
LOOP: |
MOV |
P1,A |
RL |
A |
|
CALL |
DELAY ;延時 100 毫秒 |
|
JMP |
LOOP |
其中延時 100 毫秒的子程序請自行編寫。
編 譯 、 連 接 進 入 調 試 后 , 點 擊 Peripherals->I/O-Ports->Port 1 打開,如圖 1 所示,全速運 行,可以看到代表各位的勾在不斷變化(如果看不到變化, 請點擊 View->Periodic Window Updata),這樣可以形象地 看出程序執行的結果。
注:如果你看到的變化極快,甚至看不太清楚,那么 說明你的計算機性能好,模擬執行的速度快,你可以試著 將加長延時程序的時間以放慢速度。模擬運行速度與實際 運行的速度無法相同是軟件模擬的一個固有弱點。
點擊 Peripherals->I/O-Ports->Timer0 即出現圖 2 所示 定時/計數器 0 的外圍接口界面,可以直接選擇 Mode 組中 的下拉列表以確定定時/計數工作方式,0-3 四種工作方式,
圖 2 外圍設備之定時器
設定定時初值等,點擊選中 TR0,status 后的 stop 就變成了 run,如果全速運行程序,此時
th0,tl0 后的值也快速地開始變化(同樣要求 Periodic Window Updata 處于選中狀態),直觀地 演示了定時/計數器的工作情況(當然,由于你的程序未對此寫任何代碼,所以程序不會對 此定時/計數器的工作進行處理)。
2、性能分析
Keil 提供了一個性能分析工具,利用該工具,我們可以了解程序中哪些部份的執行時間 最長,調用次數最多,從而了解影響整個程序中執行速度的瓶頸。下面通過一個實例來看一 看這個工具如何使用,例 5:
#include "reg51.h"
sbit P1_0=P1^0; //定義 P1.0
void mDelay(unsigned char DelayTime)
{ unsigned int j=0;
for(;DelayTime>0;DelayTime--)
{ for(j=0;j<125;j++) {;} }
}
void mDelay1(unsigned char DelayTime)
{ unsigned int j=0;
for(;DelayTime>0;DelayTime--)
{ for(j=0;j<125;j++) {;} }
}
void main()
{ unsigned int i;
for(;;){ mDelay(10); // 延時 10
毫秒
i++;
if(i==10)
{ P1_0=!P1_0; i=0; mDelay1(10);}
} }
編譯連接。進入調試狀態后使用菜單 View->Performance Analyzer Window,打開性能分 析對話框,進入該對話框后,只有一項 unspecified,點鼠標右鍵,在快捷菜單中選擇 Setup PA 即打開性能分析設置對話框,對于 C 語言程序,該對話框右側的“Function Symbol”下的 列表框給出函數符號,雙擊某一符號,該符號即出現在 Define Performance Analyzer 下的編 緝框中,每輸入一個符號名字,點擊 Define 按鈕,即將該函數加入其上的分析列表框。對 于匯編語言源程序,Function Symbol 下的列表框中不會出現子程序名,可以直接在編緝框 中輸入子程序名,點擊 Close 關閉窗口,回到性能分析窗口,此時窗口共有 4 個選項。全速 執行程序,可以看到 mDelay 和 mDelay1 后出現一個藍色指示條,配合上面的標尺可以直觀 地看出每個函數占整個執行時間的比例,點擊相應的函數名,可以在該窗口的狀態欄看到更 詳細的數據,其中各項的含義如下:
Min:該段程序執行所需的最短時間;Max:該段程序執行所需的最長時間;Avg:該 段程序執行所花平均時間;Total:該段程序到目前為目總共執行的時間;%:占整個執行時 間的百分比;count:被調用的次數。
本程序中,函數 mDelay 和 mDelay1 每次被調用都花費同樣的時間,看不出 Min、Max、
和 Avg 的意義,實際上,由于條件的變化,某些函數執行的時間不一定是一個固定的值, 借助于這些信息,可以對程序有更詳細的了解。下面將 mDelay1 函數略作修改作一演示。
void mDelay1(unsigned char DelayTime)
{ static unsigned char k;
unsigned int j=0;
for(;DelayTime>0;DelayTime--)
{ for(;j<k;j++)
{;}
} k++; }
程序中定義了一個靜態變量 K,每次調用該變量加 1,而 j 的循環條件與 k 的大小有關,
這使每次執行該程序所花的時間不一樣。編譯、執行該程序,再次觀察性能分析窗口,可以
看出 Min、Max、Avg 的意義。
3、變量來源瀏覽
該窗口用于觀察程序中變量名的有關信息,如該變量名在那一個函數中被定義、在哪里 被調用,共出現多少次等。在 Source Browse 窗口中提供了完善的管理方法,如過濾器可以 分門別類地列出各種類別的變量名,可以對這些變量按 Class(組)、Type(類型)、Space
(所在空間)、Use(調用次數)排序,點擊變量名,可以在窗口的右側看到該變量名的更 詳細的信息。
4、代碼作用范圍分析
在你寫的程序中,有些代碼可能永遠不會被執行到(這是無效的代碼),也有一些代碼 必須在滿足一定條件后才能被執行到,借助于代碼范圍分析工具,可以快速地了解代碼的執 行情況。
進入調試后,全速運行,然后按停止按鈕,停下來后,可以看到在源程序的左列有三種 顏色,灰、淡灰和綠,其中淡灰所指的行并不是可執行代碼,如變量或函數定義、注釋行等 等,而灰色行是可執行但從未執行過的代碼,而綠色則是已執行過的程序行。使用調試工具 條上的 Code Coverage Window 可打開代碼作用范圍分析的對話框,里面有各個模塊代碼執 行情況的更詳細的分析。如果你發現全速運行后有一些未被執行到的代碼,那么就要仔細分 析,這些代碼究竟是無效的代碼還是因為條件沒有滿足而沒有被執行到。
二、部份高級調試技巧
Keil 內置了一套調試語言,很多高級調試技巧與此有關,但是全面學習這套語言并不現 實,這不是這么幾期連載可以勝任的,這里僅介紹部份較為實用的功能,如要獲得更詳細的 信息,請參考 Keil 自帶的幫助文件 GS51.PDF。
1、串行窗口與實際硬件相連
Keil 的串行窗口除可以模擬串行口的輸入和輸出功能外還可以與 PC 機上實際的串口相 連,接受串口輸入的內容,并將輸出送到串口。這需要在 Keil 中進行設置。方法是首先在 輸出窗口的 Command 頁用 MODE 命令設置串口的工作方式,然后用 ASSIGN 命令將串行 窗口與實際的串口相關聯,下面我們通過一個實例來說明如何操作。例 6:
ORG 0000H JMP START
ORG 3+4*8 ;串行中斷入口
JMP SER_INT START:
MOV SP,#5FH ;堆棧初始化
CALL SER_INIT ;串行口初始化 A SETB EA ;
SETB ES ;
JMP $ ;主程序到此結束
SER_INT:
JBC RI,NEXT ; 如果串口接收到字 符,轉
JMP SEND ;否則轉發送處理
NEXT:
MOV A,SBUF ;從 SBUF 中取字符
MOV SBUF,A ;回送到發送 SBUF 中
JMP OVER SEND:
clr ti
OVER:
reti
SER_INIT: ;中斷初始化
MOV SCON,#50H
ORL TMOD,#20H
ORL PCON,#80H
MOV TH1,#0FDH ;設定波特率 SETB TR1 ;定時器 1 開始運行 SETB REN ;允許接收
SETB SM2
RET END
這個程序使用了中斷方式編寫串行口輸入/輸出程序,它的功能是將接串行口收到的字 符回送,即再通過串行口發送出去。
正確輸入源文件、建立工程、編譯連接沒有錯后,可進行調試,使用 Keil 自帶的串行 窗口測試功能是否正確,如果正確,可以進行下一步的連機試驗。
為簡單實用,我們不借助于其它的硬件,而是讓 PC 機上的兩個串口互換數據,即 COM1 發送 COM2 接收,而 COM2 發送則由 COM1 接收,為此,需要做一根連接線將這兩個串口 連起來,做法很簡單,找兩個可以插入 PC 機串口的 DIN9 插座(母),然后用一根 3 芯線將 它們連起來,連線的方法是:
2——3
3——2
5——5
接好線把兩個插頭分別插入 PC 機上的串口 1 與串口 2。找一個 PC 機上的串口終端調 試軟件,如串口精靈之類,運行該軟件,設置好串口參數,其中串口選擇 2,串口參數設置 為:
19200,n,8,1 其含義是波特率為 19200,無奇偶校驗,8 位數據,1 位停止位。 在 Keil 調試窗口的 command 頁中輸入:
>mode com1 19200,0,8,1
>assign com1 <sin>sout
注意兩行最前面的“>”是提示符,不要輸入,第二行中的“<”和“>”即“小于”和 “大于”符號,中間的是字母“s”和“input”的前兩個字母,最后是字母“s”和“output” 的前三個字母。
第一行命令定義串口 1 的波特率為 19200,無奇偶校驗,8 位數據,1 位停止位。第二 行是將串口 1(com1)分配給串行窗口。
全速運行程序,然后切換串口精靈,開始發送,會看到發送后的數據會立即回顯到窗口 中,說明已接收到了發送過來的數據。切換到 uVison,查看串行窗口 1,會看到這里的確接 收到了串口精靈送來的內容。
2、從端口送入信號
程序調試中如果需要有信號輸入,比如數據采集類程序,需要從外界獲得數據,由于 Keil 的調試完全是一個軟件調試工具,沒有硬件與之相連,所以不可能直接獲得數據,為此 必須采用一些替代的方法,例如,某電路用 P1 口作為數據采集口,那么可以使用的一種方 法是利用外圍接口,打開 PORT 1,用鼠標在點擊相應端口位,使其變為高電平或低電平, 就能輸入數據。顯然,這種方法對于要輸獲得數據而不是作位處理來說太麻煩了,另一種方 法是直接在 command 頁輸入 port1=數值,以下是一個小小的驗證程序。例 7:
LOOP: MOV A,P1
JZ NEXT
MOV R0,#55H JMP LOOP
NEXT: MOV R0,#0AAH JMP LOOP
END
該程序從 P1 口獲得數據,如果 P1 口的值是 0,那么就讓 R0 的值為 0AAH,否則讓 R0 的值為 55H。輸入源程序并建立工程,進入調試后,在觀察窗口加入 R0,然后全速運行程 序,注意確保 View->Periodic Window Updata 處于選中狀態,然后在 Command 后輸入 PORT1=0 回車后可以發現觀察窗口中的 R0 的值變成了 0AAH,然后再輸入 PORT1=1 或其 它非零值,則 R0 的值會變為 55H。
同樣的道理,可以用 port0、port2、port3 分別向端口 0、2、3 輸入信號。
3、直接更改內存值
在程序運行中,另一種輸入數據的方法是直接更改相應的內存單元的值,例如,某數據 采集程序,使用 30H 和 31H 作為存儲單元,采入的數據由這兩個單元保存,那么我們更改
了 30H 和 31H 單元的值就相當于這個數據采集程序采集到了數據,這可以在內存窗口中直 接修改(參考上一講),也可以通過命令進行修改,命令的形式是: _WBYTE (地址,數據),
其中地 址是 指待寫 入內 存單元 的地 址,而 數據 則是待 寫入 該地址 的數 據。例 如
_WBYTE(0x30,11)會將值 11 寫入內存地址十六進制 30H 單元中。