我們來講一個8051 很基本,卻很容易發生問題的系統應用問題,
而這個問題有時一開始時,您也不容易察覺的。
其實,這個問題對許多單晶片微處理器來說,也是常見的。
這個問題是系統中斷問題。....
中斷處理程序幾乎是標準的處理器的重要關鍵技術,而一般所謂的多核心多重處理器,
也是借重這種中斷處理程序所延伸的,我想這一種中斷觀念也是業界所公認的標準作法。
以前我之前有提過一棵所謂的多核心處理器,他也是利用硬體來做分時多工,
所以基本上他也是一種隱性之中斷處理方式的...基本精神都是沒變的!
當然啊...因為現在所謂的IC 設計與周邊電路的成熟應用來看,這種觀念會更發揮的淋漓盡致的,
下圖是一個變種8051的中斷向量表:從表中我們可以很清楚的看到許多過去標準8051 所沒有
看到的一些硬體中斷功能...有些甚至還在某一個中斷向量之下再進一步細分的,
如圖中所沒有標示的USB 中斷...因為USB 中斷還要分Control Token...Out Token ... In Token.等等。
所以,您會發現:如果像我之前提過的那一種試圖用硬體分時多工做成的號稱多核心處理器,
在這一方面的擴充性就會顯得比較沒彈性一點了...因為畢竟他還是共用同一組系統Clock Source 。
系統資源是有限的...而唯一能夠提高系統性能的方法:就是提高系統Clock 頻率!
這也是所有單晶片微處理器所強調或追求的方向。
所以,我們就會看到所謂的25MHz...48MHz...96Mhz ...甚至操到2~300 MHz以上的。
以現在IC設計與IC 製程技術來說:都已經不成問題了。
----
好了,講我們這一次的主題:系統韌體的中斷處理程序。
中斷處理程序會對我們寫韌體會造成什麼影響?!主要就是:Interrupt Latency(中斷延遲時間)
及所謂堆疊區(Stack)的影響,而Stack 的主要還是來自於一般變數的儲存(當然還包括硬體
本身的中斷向量位置的存入與回取的動作!)
我常開玩笑說:您再快的微處理器也是會發生中斷『打架』的事情的啦!...
而我們並不擔心中斷系統打架,因為本中斷就有所謂的優先順序的...
這本來就是延伸我們人類的基本觀念:我們大腦也是單向處理能力的,
一次一時也只能處理一件事,一心多用是很容易出事的啦!
所以以8051 的標準C 的中斷處理程序是如何寫的呢?!
extern bit alarm;
int alarm_count;
void falarm (void) interrupt 1 using 3 {
alarm_count *= 2;
alarm = 1;
}
----上式中的 interrupt 1 所代表的就是:中斷向量位置。
(您可以查上表中的那個Timer 0中的priority order 就是 1)
這一點我們就很清楚的瞭解到的啦!但另外一個 using 2 ...就比較沒有標準用法了,
一般人也很容易忽略到...而往往系統有時會因此發生問題的,
而這種問題對一些比較沒經驗的工程師來說:有時會被稱所謂的靈異現象!
是真的靈異現象嗎?!非也...其實都是自己在系統規劃與韌體編寫上發生問題所造成的。
我們先來看這個 using 2 是拿來幹啥用的?!...他就是拿來指定中斷處理程序要拿哪一組
Register Bank 來用?!...這對於Keil C 這種編譯組譯器來說是很重要的!
我們都知道一般 8051 有四組通用Register Bank ,一般高階C 組譯成組合語言時,
他們會大量使用這些Registers (R0..R7),這是我們用C 在寫程式時,不容易察覺的!
我們來看上式程式組譯後的結果:
; FUNCTION falarm (BEGIN)
0000 C0E0 PUSH ACC
0002 C0D0 PUSH PSW
; SOURCE LINE # 5
; SOURCE LINE # 6
0004 E500 R MOV A,alarm_count+01H
0006 25E0 ADD A,ACC
0008 F500 R MOV alarm_count+01H,A
000A E500 R MOV A,alarm_count
000C 33 RLC A
000D F500 R MOV alarm_count,A
; SOURCE LINE # 7
000F D200 E SETB alarm
; SOURCE LINE # 8
0011 D0D0 POP PSW
0013 D0E0 POP ACC
0015 32 RETI
; FUNCTION falarm (END)
----
我們可以看到兩個指令:PUSH ACC 及PUSH PSW..(有的甚至還有PUSH DPH/PUSH DPL)。
而從一般程式跳入中斷程式到完成這一個PUSH 的動作時間,就是我們常說的Interrupt Latency !
...其實,以現在高速的微處理器來說:這一點時間都已經不算什麼了。
倒是您把記憶體中的變數或堆疊區給搞亂了,那才真的會造成捉問題累死人的事啊!
我們來看PUSH PSW 是做什麼?!
PSW Register (all 8051 and 251 variants)
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
CY | AC | FO | RS1 | RS0 | OV | UD | P |
The following table describes the status bits in the PSW:
RS1 RS0 Working Register Bank and Address
0 0 Bank0 (D:0x00 - D:0x07)
0 1 Bank1 (D:0x08 - D:0x0F)
1 0 Bank2 (D:0x10 - D:0x17)
1 1 Bank3 (D:0x18H - D:0x1F)
Symbol Function
CY | Carry flag |
AC | Auxiliary Carry flag (For BCD Operations) |
F0 | Flag 0 (Available to the user for General Purpose) |
RS1, RS0 | Register bank select: RS1 RS0 Working Register Bank and Address 0 0 Bank0 (D:0x00 - D:0x07) 0 1 Bank1 (D:0x08 - D:0x0F) 1 0 Bank2 (D:0x10 - D:0x17) 1 1 Bank3 (D:0x18H - D:0x1F) |
0V | Overflow flag |
UD | User definable flag |
P | Parity flag |
— | Reserved for future use (251 Only) |
Z | Zero flag (251 Only) |
N | Negative flag (251 Only) |
------------------------------------------------------------------------------------
就是拿來切不同的Register Bank 的!....所以一般人都會容易犯這一個錯誤的!
不去明確的要求組譯器指定不同的Bank...這本來就是我們在系統規劃裡的一個重要事項。
沒有稍微搞過硬體或韌體的純軟體工程師就很容易犯這個錯誤,而往往這個錯誤會
讓一些比較沒經驗的工程師,一時會捉不到問題點...搞了老半天,就會怪IC 有問題。
尤其像現在這種變種的8051 來說:他的中斷向量變得比較多了,
但他的Register Bank 還是只是維持四組,處理這種問題就要變得更小心了。
所以事前的系統規劃或是在韌體撰寫與系統完成後的系統驗證工作,
就顯得非常重要...而不是一上機,就批哩趴啦的把程式寫完就交差了事...
而沒有詳細的去分析與驗證系統...往往這種中斷程序打架造成Register Bank錯亂之事,
真的很難抓問題...因為可能連ICE 的Debug 功能也無法精準的掌握...這本來就是人為疏失啊!
我記得以前我們在大公司裡也曾經發生這種問題,而造成硬體設計工程師與軟體工程師們之間,
互不信任與造成許多不必要的紛擾...
---
我要說明一下的是:不是只有中斷向量程式可以加註這一段 using 2 而已,
其實,一般標準副程式也是可以加這一句話的,
如此一來能更能夠掌握每一段副程式之間的變數交換與資料傳遞的:
void Example_Subroutine(unsigned char Variables) using 1{
....
...
}
瞭解嗎?!...
希望這一篇簡單的系統應用資訊也可以提供一些有用的資訊給您!
謝謝!