來講一個系統應用的觀念,如果您也是常寫一些MCU 韌體程式的話,或許,會有一些幫助吧。
尤其是作一些機電整合的韌體程式,
寫這種程式,您就不要把那一般寫LED 跑馬燈的程式觀念拿來湊合。
我個人覺得:如果,只是要您寫個簡單的I/O 控制程式,或是一個簡單的步進馬達控制程式,
您可能就是把我們手指頭上的十個手指拿出來湊合的寫。
反正是程式嘛,就是幫我們人腦做事的嘛!
不過呢...說也奇怪,現在因為我國的電子產業發達,會寫韌體程式的工程師滿街都是,
大家也都習以為常,所以啦~也沒有人在乎每個人寫程式的風格或技巧。每個公司裡,
都會把新人當舊人用----意思就是說:您來公司上班,這些寫程式的觀念就應該在上
一家公司時,就要被教導或訓練的...就像我們的中等教育一樣:
喔...國中時,老師說:這個題目以後您們高中老師會教;
高中時,老師說:這個題目您們國中老師就有教了,我不用再教一遍了。
結果,還是靠學生自己自求多福!
今天我們來講一個一般系統輸入參數的處理問題,
譬如說是一個類比輸入參數(A/D Parameter)。
我們都知道:雖然是類比輸入,但是我們在韌體程式的讀取過程,
卻仍然是數位分時處理方式(Discrete)。還是得一個、一個值慢慢讀進來。
難免就會發生所謂多久取一個值?!(連續性)...還有一個很重要的觀念:
軟體濾波處理。(Filter)
硬體電路上的濾波電路是鐵定有的(一般都只是低通濾波),
但您怎麼知道輸入的值會不會有波動峰值呢?瞬間的變化時合理嗎?!
尤其是一些屬於比較機械特性的參數,譬如環境溫度、電瓶電壓等...
這些東西都是屬於自然現象的參數。(廢話...這種東西才需要A/D啊)
所以,在軟體上也必須有一些軟體濾波作法,,,我相信如果您幸運一點的話,
剛好有個老鳥工程師願意帶您,而也願意傾囊相授教您...
您可能就知道這個東西就是:讀個十遍或二十遍,然後取平均就好了!????????
(人家教您的口頭禪:去極值,取均值。)
------------------------
以前我也是這樣子作,因為大家受的教育是一樣的,而且如我所說的:
就是把我們手指頭上的十個手指拿出來湊合的寫!!不是嗎?!
反正這種東西就當小學算術拿出來用吧!所以才有人信誓旦旦的說:
"我國中就開始寫程式了。"
對啊!我國的電腦教育多成功啊,連中小學生都會寫程式啊,
那為什麼全世界有名的軟體公司都沒有在我國呢?!那我們搞的系統東西為何還
那麼不精緻呢?!等您看完我這一篇文章之後,您就知道為什麼了...好~
我們來解釋:什麼是濾波器,所謂濾波器有所謂的一階濾波器(First Order Lag Filter)
那個二階以上的就不要講了!反正,一階的作法都沒有多少人知道,幹嘛講二階的呢?!
其實,這些觀念都是我們在學校的工程數學裡都有教的,只是我們都不會應用。
(所以您就不要說國中就有教了!要不然,我們幹嘛還要讀到研究所後才去上班寫程式?!
反過來講:如果您念到大學畢業,然後寫程式都沒用到學校教的,那幹嘛念這麼多?!)
一般一階濾波的公式就是:
Value(n) = Value(n-1)+ KF(RawValue - Value(n-1))
其中: Value(n) 就是我們要求的新值,
Value(n-1) 就是我們的上一個值,中間有個時間差(t)。
RawValue 就是我們一般從A/D 裡讀到的原始值,就是未濾波值。
KF 就是濾波常數。
-----
這樣的公式,大家都會,在學校、補習班老師也拿這個出個一兩百習題給您作,
考研究所時也拿出來考!結果,大家考過之後成績都不錯...
然後出社會要寫程式時,就全忘光了,不知道拿出來用?
(說真的~還真的不知道怎麼用呢!)
還記得以上我提到所謂數位分時取樣(discrete)及一階濾波觀念,他牽涉到一個時間觀念。
所以啦...在新舊值之間,就存在一個很自然的物理特性,
在數學上我們也稱之為自然對數(Exponential)!
(查一下維基百顆的說明吧:這下您就懂了吧!
The exponential function is used to model phenomena when a constant change in the independent variable gives the same proportional change (increase or decrease) in the dependent variable)
而這個自然對數就是有時間觀念在裡面...因為很簡單,我們在工程上無論是機械或是電子,
我們都可以用這個自然對數來描述參數變化的前後關係...而上式中的那個KF 就是這個東西。
KF = 1-e**(-Looptime/T) where T = Time Constant of the filter。
這個式子是不是從您學校畢業後,再也沒出現在您的工作領域了?!
更不用說:您在寫韌體程式?!
那您就好奇了...這個東西要怎麼用?!...這跟我用一般A/D 讀電壓有關係嗎?!
那我們來作個簡單的實驗:譬如您一個簡單的電瓶電壓為 30 V。
您該如何即時來處理這個電壓變化呢?!譬如:
您每 15 mSec 讀一次 A/D ,然後讀十遍(150 mSec)之後,您才得到一個新的平均值。
當然啊,老前輩會跟您說:您還要在程式裡,加入一段判斷式:萬一誤差太大的,
就捨棄不納入平均計算。什麼是誤差太大?!基準是什麼?!為什麼要讀十遍?!
讀八遍不行嗎?!讀16 遍不是更好嗎?!直接右移四次不是更好嗎?!...
萬一有一次捨棄了...剩下15 個值時?怎麼辦?!...
----那您跟我說:這樣子的推理觀念的數學依據(科學依據)是什麼?!大家高興就好?!
那做出來的東西,他今天高興就正常...明天他不高興就給您出狀況...那大家幹嘛還學科學?!
所以依據工程數學上的式子解釋:如果您依據一階濾波器的公式,
您只要在每兩個15 mSec 之間就可以取得一個濾波後的新值...
上式中的 Looptime 就是您這個 15 mSec~
而時間常數您可以取 500mSec。在機械上或是許多類比訊號上是綽綽有餘的。
好~我們在依據上述的公式來算:
如果您電瓶電壓的舊值是 30 V...當您讀到新的A/D 值為 40 V時。
好吧 ...這個值算誤差太大呢?還是合理?!...原來十根手指頭的算法,就沒有章法了。
但如果我們把他真正的套到上述的公式裡:我們以一階濾波器原理公式:算出的答案是:
Value(n) = 30 + (1-e**(-15/500))(40-30)
= 30 +(0.02955447)*10 = 30.2955447 V。
以一般自然現象的結果來看:瞬間40 V 我們認為是不合理的,
但如果經過 500 mSec 的連續讀到這個值時,這個東西可能是真的值了...
但以我們這個一階濾波器公式來看,,,他 500mSec後的值也差不多這個值了!
不信您可以實際去算一算。
(注意喔,.當您第二次帶公示時,這個Value(n-1) 是30.2955447 而不是30 !!
依此類推...(500 mSec 大概要算34 遍)。
好了...這個答案跟您說:您根本不需要去15 mSec 讀十遍...還在那取其中幾次算?!
...500 mSec 您算三遍,也不一定比較準...程式在判斷式上,還要寫個落落長...
也不知道在算什麼?!也沒工程數學根據?下回寫程式還是心裡虛虛的!
------
好了...本單元的議題講完了。大家都應該知道結果了吧...有那麼簡單嗎?!
但問題來了...您知道這個自然對數的值是多少嗎?! e = 2.718281828(維基百科) !
如果您是用PC 來寫程式,當然沒問題啊...用Double Floating 宣告,給他用力的
往下算就對了!但很不幸的 ,一般這一種應用都是在單晶片微處理器(微控器)上,
如果更不幸是8 Bits 的MCU 的話!(應該幾乎都是吧!)那就更不幸了...
唉~算了...我們還是回到十根手指頭算吧!
所以,您就知道為什麼您寫韌體程式老是沒有成就感的道理了吧!...
當然不行這樣子啊...我們還是得把這個工程數學給套進韌體程式才行啊...
我就先賣個關子,讓大家當作習題練習一下...
先跟各位講個答案:在一個8 Bits 的引擎控制單晶片的韌體程式裡,
這一段稱為First Order Lag Filter,
他的程式大小是(用組合語言寫的...) 32 Bytes,
執行時間是 87~88 Cycles(當KF = 0時是12 Cycles)。
提示:老話題...您還是得用八位元的思維去推導這個運算式...一切就變得很簡單了!
所以,下回您要搞什麼引擎控制器(什麼ECU)...就不要拿著手上十個手指頭,
扳一扳~掐指一算,就劈哩啪啦亂搞...因為下回您不知道您要碰到什麼奇怪的自然現象...
而您的工程數學基礎都不在!
-----------------
續篇連結:
2.一個A/D 的系統應用問題(續篇-實驗結果)
3.一個A/D 的系統應用問題(續篇-精進版)
4.一個A/D 的系統應用問題(續篇-範例版)