轉載自http://chamberplus.myweb.hinet.net/misc_1.htm


        剛接觸寫韌體的工程師,往往可能是以前是寫個人電腦的應用軟體的機會很多,或許,現在寫韌體的工程師越來越少呢?還是現在寫單晶片的系統工具比較好呢?所 以,許多寫韌體工程師所受的韌體程式訓練或機會不多,一上機寫韌體,就當作寫個人電腦的程式一般的寫法,一路往下寫。其實,我沒有說這樣子不行,但是,當 您看完我這篇文章之後,或許,您會有不同的看法?

        我以前看或寫引擎控制程式都是組合語言,後來寫掃描器的韌體或是USB也都是組語。當然,以這些工作機會,是用不到 8051 的C組譯器(Keil C)。但那時,KEIL C 也剛推出整合性高階語言的開發環境,我就自學把KEIL C學起來。後來很巧,我接了MP3 系統開發計畫時,就剛好派上用場,這件事讓我體會到一點:技能總是在工作中磨練,但若是未來您可能會接觸到的,您可能要提早自己自學,這樣子,等機會一來,您就比別人多一份機會了。就像投資您自己一樣,像這種屬於基本技能的東西,還是得好好的投資一下自己。

        寫MP3 系統程式,因為牽涉許多DOS  File  system 的東西,用C寫的確是比較快一點,但卻也發現用高階C寫韌體的許多盲點。後來,看到公司內有一些部門在招一些寫韌體工程師時,竟也以資訊系為優先考量,結 果整個部門幾乎都是寫軟體出身的韌體發展部門?結果是什麼呢?開給IC設計部門的規格,所需求的記憶體空間就大到很難想像?8051 要寫到 1MBytes ?! 真是很誇張,對工程師來說:寫不出精緻的韌體,剩下的便是作苦工的寫程式。不知您是否可以體會到這點?!

        什麼是精緻的韌體?我想您寫韌體在上機前,做了多少前置準備動作?還是,接到一個案子就批哩叭啦的從第一行往下寫?其實,寫韌體最難能可貴就是它是一份系統整合工作除了程式語言以外,就是您對系統他所展現的專業知識這話怎麼說?譬如說:當您寫完引擎控制程式後,您不只知道引擎控制韌體怎麼寫而已,還深深的體會到引擎機械系統的瞭解。我常常說:您作一行就是要入一行。所謂入一行,不是會寫寫基本程式而已,您還能體會到那一行的種種問題。這樣子,您才能出奇制勝,當然啊。當您要換工作時,您就會明明白白的知道您為什麼會離開原來的那一行?

        好~我就舉一兩個例子來說明這件事情:

首先,您還記得我在單晶片與引擎控制 (二)--- 數學篇 中舉的例子嗎?

        針對引擎的轉速,您是用一個integer 來宣告 呢?還是用 八位元的255 來表示呢?若您是寫軟體出身的,鐵定一定是用 Integer 來宣告,那因為在引擎控制系統中會用到許多這個變數,包括許多查表功能,那您查表公式是不是也是一路用integer 來運算呢?!結果當然對CPU執行效率或變數memory 需求一定不得了。我上述的那個問題就發生了。我列一張表格您可以看看:

Engine Speed

 RPM

 Reference Period

 RPMX

0   0
200 Tm0  
400 Tm1 16
600 Tm2  
800 Tm3 32
1000 Tm4  
1200 Tm5 48
1400 Tm6  
1600 Tm7 64
1800 Tm8  
2000 Tm9 80
2400 Tm10 96
2800 Tm11 112
3200 Tm12 128
3600 Tm13 144
4000 Tm14 160
4400 Tm15 176
4800 Tm16 192
5200 Tm17 208
5600 Tm18 224
6000 Tm19 240
6400 Tm20 255

    以一具四缸四行程引擎來說:要跑到6400 轉,已經是不得了的事了,何況若超過 6400轉之後,其實已不需要查表作精準的控制了。那您從右邊的變數,您看到了什麼?就是對應到引擎轉速的八位元數值。而每一個 Byte 對應就是 25轉/byte 。對查表或控制來說,已經綽綽有餘了,但是對您寫韌體來說多方便啊。(另外,對於 RPM 的讀取信號,當然就是用單晶片的 timer ,這不用講大家都知道,但您把他轉成怎樣的數據呢?)再看一張圖表:

Load Units

 (N)

 MAP_LD

 TPS(%)

0 20 0
8    
16 25 6.25
24    
32 30 12.50
40    
48 35 18.75
56    
64 40 25.00
72    
80 45 31.25
88    
96 50 37.50
112 55 43.75
128 60 50.00
144 65 56.25
160 70 62.50
176 75 68.75
192 80 75.00
208 85 81.25
224 90 87.50
240 95 93.75
256 100 100.00

            引擎控制中,查表就是利用引擎轉速與引擎負載(一般有時會用油門位置(TPS)來表示)。TPS = 100%就是表示油門全開,此時對應的就是外面的大氣壓了。左邊就是我們程式要運算用的變數,您有沒有發現一件事: 引擎轉速的變數是粗量化,而油門負載變數是細量化;但是都是以 255為主要全量變數。           

            再來討論一個變數:點火進角。再來考考您,您怎麼宣告?!因為在引擎控制中,點火進角只會發生在上死點前後約九十度以內而已。但又需要達到小數點的精準度,您該不會用一個 Float 變數宣告吧!答案就看一個公式:

                    N = (Deg+11) *256/90 ;

這是一個全量變數的轉換,將您要的 90 範圍轉換成 255 的解析度。如此一來,您整個系統程式的數學系統,就完全統一在八位元的環境裡了。無論是查表或作內差公式(副程式),就變得很簡單了。更不用說您整個查表的表格就精簡多了:以下就是一個點火進角的查表表格:

400 PRM

DB 97 (23 DEG)  20  KPA-MAP
DB 97 (23 DEG)  30
DB 97 (23 DEG)  40
DB 91 (21 DEG)  50
DB 85 (19 DEG)  60
DB 77 (16 DEG)  70
DB 65 (12 DEG)  80
DB 60 (10 DEG)  90
DB 57 ( 9 DEG)  100
800RPM
DB 100 (24 DEG)  20  KPA-MAP
DB 97 (23 DEG)  30
DB 94 (22 DEG)  40
DB 91 (21 DEG)  50
DB 85 (19 DEG)  60
DB 80 (18 DEG)  70
DB 74 (15 DEG)  80
DB 71 (14 DEG)  90
DB 71 (14 DEG)  100
1200RPM
DB 108 (27 DEG)  20  KPA-MAP
DB 105 (26 DEG)  30
DB 102 (25 DEG)  40
DB 100 (24 DEG)  50
DB 97 (23 DEG)  60
DB 94 (22 DEG)  70
DB 91 (21 DEG)  80
DB 85 (19 DEG)  90
DB 80 (18 DEG)  100
1600RPM
... ...  
... ...  

         經過這樣子的數學系統的轉換後,程式就精簡多了,而且當您的引擎上限增加時,您還是可以演用這樣子的數學系統。如此這樣子,您會跟我說:組合語言很難維護?我想是您的數學系統沒有模組化吧。其實我講的這些東西,是不是跟您以前在念工程數學時,那個無因次化的東西很像啊?!因為您的程式裡是看不到RPM = 400 或油門開度 100% 這些物理數值,取代是的標準的八位元的數學系統,除非您是將 八位元換成 十六位元,否則,您整個系統程式,無論應用到哪一款車款或引擎都可以移植的。還有誰會跟我說組語是很難移植的?!

        或許,您會跟我說:這是引擎控制特殊應用。那您就錯了。我後來利用這個觀念寫了一支掃描器的韌體。

        這是我另一個例子:以彩色的RGB三條線來說:以 600DPI 來說需要 6ms * 3 = 18ms !而以步進馬達控制來說:不同的DPI的掃瞄速度來說:需要不同定點的馬達控制換相,以達到掃瞄速度的調整。所以,我就將最大的掃瞄解析度 600 DPI 的 18 msec 訂為最大變量 : 255。不同的掃瞄解析度有著不同的馬達換相時間點。所以就可以得到這樣一個表格:

_ColorPixelMotorControlTGEventTBL: ;;--- 8 Bit/Color/Pixel

CP600: db #01000001B, 119, 118, 28, 30, 24, 2, 30, 90             ;; 600 DPI
CP300: db #01000010B, 79, 78, 38, 40, 12, 4, 0, 20, 40, 60        ;; 300 DPI
CP150: db #10000100B, 59, 58, 58, 60, 6, 4, 10, 25, 40, 55        ;; 150 DPI
CP75:  db #10000010B,  79, 78, 38, 40, 3, 8, 0, 10, 20, 30, 40, 50, 60, 70 ;;75 DPI
CP600K: db #01000001B, 119, 118, 28, 30, 24, 4, 10, 40, 70, 100   ;;9
;;---
_ColorLineMotorControlTGEventTBL: ;;--- 8 Bit/Color/Line

CL600:; db #01000001B, 119, 28, 28, 30, 4, 2, 30, 90              ;; 600 DPI
CL300:; db #01000010B, 119, 38, 38, 40, 4, 4, 15, 45, 75, 105     ;; 300 DPI
CL150:; db #00000010B, 119, 38, 38, 40, 3, 4, 15, 45, 75, 105     ;; 150 DPI
CL75: ; db #00000010B, 119, 38, 38, 40, 3, 8, 0, 15, 30, 45, 60, 75, 90, 105 ;; 75 DPI
CL600K:; db #01000001B, 119, 28, 28, 30, 4, 4, 5, 35, 65, 95
;;---
_GrayMotorControlTGEventTBL: ;;--- 8 Bit/Gray/Line

GL600: db #01000100B, 59, 58, 58, 60, 8, 2, 15, 45                 ;; 600 DPI
GL300: db #11000010B, 39, 38, 38, 40, 20, 4, 5, 15, 25, 35         ;; 300 DPI
GL150: db #10000010B, 39, 38, 38, 40, 8, 4, 5, 15, 25, 35          ;; 150 DPI
GL75: db #10000010B, 79, 78, 38, 40, 8, 8, 0, 10, 20, 30, 40, 50, 60, 70 ;; 75 DPI
GL600K: db #01000100B, 59, 58, 58, 60, 8, 4, 5, 20, 35, 50

 

        中間的那個 0~255 數值就是對應我馬達控制換相發生的作用值。結果,這個計畫,我花了一個月作紙上作業的數學分析,再花兩個月寫程式,程式一 release無論是馬達加減速或掃瞄速度控制都沒問題。重點是:整個程式含USB 控制程式外加步進馬達加減速再加掃瞄色彩控制等我只用不到 8KBytes 程式寫完。還有,就是因應不同的客戶或 CCD/CIS 感應器,只要抽換 Table就可以了,程式本體邏輯控制都不需要作更改。您說組語很難維護?!我還得再質疑一次這種說法。PS : 這個計畫是一家國際大廠的一張給台灣OEM的單,工廠在大陸,對不起喔~我一次也沒跑大陸就把案子給結了。

        結論:經由以上的例子,我想表達的是:當您接到一個案子,是寫系統的韌體時,您自己想一想,您花了多少時間在紙上作推演演算過,還是就直接上機一邊寫一邊想,您的前置分析工作做了多少?其實,這些工作都是學校教給您的,只是您畢了業就還給老師了。我也知道當上級長官把任務交付給您了。您也想很快的做出成果,但您有沒有想過,每次寫程式或韌體時,最累倒不是寫程式或韌體本身,而是調整整個系統穩定的問題,若您能多花一點時間先作一些數學或系統分析。我想事後的Debug 得時間會少很多。更何況 您用八位元的單晶片寫程式時,您覺得在八位元裡寫程式比較容易出錯呢?還是CALL 了一大堆副程式後,容易出錯呢?!

        最後,我來舉一個很好笑的例子,看您自己會不會跟這例子的人很像?!我們知道 Keil C 會將您的高階語言組譯成組語,您會利用這個組譯的組語,把他再移植到您的組語環境來寫,以期望增加程式性能。甚至一些數學運算,您就直接把整段組譯程式移植到組語中。在我 單晶片與引擎控制 (二)--- 數學篇所舉的以3.14 圓周率的計算 :您是不是有點捨本逐末呢?!還在CALL 那整段除法副程式呢?(就算您整段移回來,用高階寫或組語都是一樣的哩)還是在紙上先利用數學分析 將*201/64 = *201+右移六次。求出常數再計算呢?!

        您是寫韌體呢?還是在寫軟體呢?!

ccchiu 發表在 痞客邦 PIXNET 留言(0) 人氣()