事有缘起,說來話長。當年的電子製作愛好者,什麼電子産品都想拆來看一下。為何小小零件集合後變得奇妙,諸如原子粒收音機,接上電源便聽得電台廣播聲音。上世紀七八十年代,玩過那麼一些東西,留下袛有點滴記憶。興趣未能餬口,揾食佔據生活日常,直至半退休生活初期,才慢慢抓回失落的興趣,新的舊的一大堆,有待探索。
那時候的電子儀器是天價般離地,DIY總有它的實在性。計頻器可能是當時玩無線電不可或缺的東西,沒能力負擔一台示波器,總不能少了計頻工具吧。辛苦地儲錢,花幾百塊錢,買了個紅色數字LED頻率計套件。某年搬家,忍心掉棄了,沒有留下照片。
時代進步,電子産品因為普及,價格反向下行。回歸電子世界後,見到的都想買來研究。可是年紀漸大,精力有限,那來這多時間。買這款頻率計套件,沒有特別理由,袛因實在太便宜,用作練習焊接技巧亦不錯。這類套件在淘寶隨處可見,採用了PC16F628芯片作核心處理,十分簡潔,變種亦很多,但都袛得簡單使用說明。對什麼數碼管顯示英文字母感到茫然,究竟那是什麼呢。經過Google順藤摸瓜,尋源指向 DL4YHF的綱頁,始知背後的真身。由它引伸變異版本的DIY,各具參考價值。因為日子久遠,部份連結已失效。
其中較喜歡以下幾款:
- KC7ZOW 在他的網頁介紹以PCB光板做成外殼,並提供幾種前置放大模式的參考。作品帶古舊味道,把內容製成PDF檔案,方便查閱。
- F8FII 將數碼管擴展至6個,顯示方式固定為 XX.XXX.X MHz,他的網頁說明了原委,袛須硬件些少改動,靠修改原始碼來實現。
- PY2BBS 主要為硬件的構建,在其網頁提供了清淅的原理圖及PCB圖,方便直接拿用來DIY。
- SM0VPO 簡約版本,移除了按鍵菜單的設置,配上精簡化的原始碼.
- SQ3NQJ 在DL4YHF的代碼之上,增加外部二進制預分頻器(PreScaler)的選單設置,適配不同前置預分頻器,擴展至更高頻率的測量。
建基於PIC芯片的頻率計事實上很多,也有以普及的LCD1602來作顯示的。其中 OM3CPH 在他網頁介紹使用 PIC16F84 的DIY,同樣是參照 James Hutchby, MadLab Ltd. 1996 的設計,或可以認為這才是真正的元祖吧。OM3CPH的原始碼年份標註為更早的2000年了,但還是DL4YHF版本較多模仿和版本改進,或因硬件相對複雜吧。
中國製造及販售的廉價仿製品,理所當然採用 DL4YHF 設計,取其低成本。這款賣點是加上晶振測量,似乎好實用。它算是最忠於原著吧,固件想必直接拿用,但沒有交代何處取材。ZL2PD的網頁有詳盡分析,並整理出仿品的原理圖。用做晶振測量有其局限,陽春的振蕩電路不太可靠。因此參考 TheHWcave 的視頻,將該部份改成簡單前置放大,他同時有代碼修改建議。
這類單片機計頻工具,以代碼生成的固件是它的靈魂,那時候研習PIC的編程,正好利用這台仿品作練習。代碼都以組合語言寫成,試過在 MPLAB IDE 8.92 透過 MPASM 直接編繹成功。可能因為先學習 C/C++,組合語言又要由零起步,故一直閒置沒去研究了。最近計劃將玩過的都滙入 GitHub 上保存記錄,因此製作這個倉庫。
經典的舊單片機代碼似乎都愛用上組合語言,相信是基於效率吧,原作也不例外。它採用 MPASM 來編譯,但 MicroChip 已將它淡出,要求轉用內建 pic-as 的 XC8,支援 MPASM 語法的最後版本是 MPLAB X IDE 5.35。若要用上新版本,必須將代碼做調整。
感覺 MicroChip 處理 assembly compiler 的過渡搞得十分混亂,網絡上片言隻字的說法,都不盡相同,令人迷惑。參照 IU8NQI 的方法,成功移植可以編繹的 DL4YHL 版本。但能夠編繹不等於能用,初試失敗,經排查發現一行輸入錯誤,竟導致實際無法運行。固件雖然最終完成了,但亦說明組合語言在某程度上的艱難,修改源碼不易。
IU8NQI 採用的是這個由 Ho-Ro 改良的版本,看罷 Ho-Ro GitHub 介紹,因為他仍用「舊」語法來做開發,才知使用 gputils 也能夠讓這些舊組合語言的代碼進行編繹,無需移植到 pic-as。同時也有好用的燒錄工具 pk2cmd,在 Linux 環境下輕鬆完事。對元祖的代碼進行編繹,順利生成固件,令我這個小白變得自信滿滿。
雖然 gpasm 好用,但現時目標是做迭代更新實驗,新的 pic-as 會繼續發展,是有必要認識的。事實上進行舊代碼的移植,也是不錯的學習。能夠找到的資料,比較碎片化,以下是部份。
- https://www.circuitbread.com/tutorials/mpasm-to-mplab-xc8-pic-assembler
- https://www.circuitbread.com/tutorials/series/microcontroller-basics (這是教學,對初學PIC組合語很有幫助。)
- https://github.com/thetrung/ASM_BLINK_PIC18F45k50
- https://github.com/dsoze1138/MPLABX_pic-as_examples
- https://github.com/rorticus/mpasm-picas (自動化轉換,但不知如何入手。)
以下筆記是這次移植主要修改之處:
- #include <xc.inc> 取代 list P=16F628, #include <p16F628.inc>
- #define, #if, #ifdef, #else, #endif 尾後不可加備註,必需移走。
- 所有 label 都要加上冒號,例如 label:
- 程式尾末 END 要加上 reset vector 的進入點 label,例如 END resetVec,往後的行不允許其他內容,包括備註行,否則編繹報錯。IDE設定 -Wl,-PresetVec=0x0" in pic-as global options (Additional Options) of Project Properties。
- __CONFIG __XT_OSC 改成 CONFIG FOSC = XT,如此類推。
- __IDLOCS H'XXXX' 改成 CONFIG IDLOC[0..3] = 0xXX
- b'10110011' 改成 10110011B
- 10進位數目字前刪去 dot
- de 改為 db
- (value>>.16)&0xFF 改成 (value>>16) and 0xFF
- ORG 設定區段要改用 PSECT,具體表述及參數看 official guide,要驗証。
- skpnc, skpc, skpnz, skpz, tstf, clrc, setc, bc, bnc, bz, bnz, 要改以其他語法去實現相同效果。設計成對應的 marco,就不用每行去修改。這昰 IU8NQI 採用的方法,相當好用。
- movfw XXX 語法不再使用,要改為 movf XXX, w
- errorlevel 語句不再使用,直接刪除。
- bsf STATUS, RP0 改為「長寫法」bsf STATUS, STATUS_RP0_POSITION,如此類推。
- 使用 MPLAB X IDE, 加上 PROCESSOR 16F628 似乎不是必需。
- 加上 RADIX DEC 似乎也不是必需,因為預設應該就是10進數系。
單片機跟組合語言有密切的關係,事實亦十分好玩。要學習當然要有教材,程式語言句法無論怎樣演變,都是累積而成,有它的基礎原理存在。這兩冊 基礎篇和提高篇 已經有二十多年歷史,在中國算是官方教材吧,仍有參考價值,但確實費時去看,暫寄存在此,留待日後吧。
中國電子科技的發展,人才在這幾十年確實有很大進步,這些教材功不可抹。
使用 pk2cmd 及 gpdasm 做了以下驗証,放到這目錄下。 首先讀取仿品的固件內容,保存為 counter_clone.hex。對照 DL4YHF counter2.hex,結果與芯片上代碼袛有一處不同。然後直接燒寫counter2.hex,正常運行。用 diff 比較兩個hex,差異很大。初時認為屬正常,因為按intel hex的格式本質(問AI的),明白機械碼的一點差別,會造成hex檔內的每行記錄的檢查碼變化,直接比較變得沒意義。及後才察覺是行末的 CR/LF 作怪,轉換之後,差異變得合理了。最後嘗試反組繹,兩者生成的asm,基本上相同,跟 pk2cmd 作比較的結果吻合。分析hex檔,原因是 IF_TABLE 改了,eep_dw 4433619 變成 4433421,顯示變成這樣。為何這樣,原因不詳,相信是源碼被無故改動,而固件生成後一直在複製翻用。
pk2cmd -PPIC16F628A -GFcounter_clone.hex
pk2cmd -PPIC16F628A -Fcounter2.hex -Y
file counter2.hex
dos2unix counter2.hex
diff -u counter_clone.hex counter2.hex
gpdasm -p PIC16F628A counter2.hex > counter2.asm
gpdasm -p PIC16F628A counter_clone.hex > counter_clone.asm
diff -u counter_clone.asm counter2.asm進一步試驗,把 IU8NQI 的原始碼編繹成固件,另下載他提供的hex,以上述相同的驗証方法,結果兩者的hex及反組繹asm都吻合,並成功燒寫運行。
燒錄器採用了 PICKIT2 clone,配以 MPLAB X IDE v6.15,XC8 v3.00,PIC16Fxxx_DFP/1.7.162,初時將芯片離板進行燒寫,插拔比較麻煩,於是由板子直接引線出來,進行在板燒寫,暫時未發現有異常情況。在 Linux 使用,要加 60-pickit.rules 到 /etc/udev/rules.d/。選項的使用,參照 CLI 顯示的說明。
pk2cmd -PPIC16F628A -Fcounter_clone.hex -E -M -Y
pk2cmd -PPIC16F628A -R事實上 DL4YHF 版本存在幾點問題,這裏是修改的代碼及生成的固件,兩者分別在於此。當然關於 EEPROM 部份,因為採用了 gpasm。順便修改其他幾個代碼,並且燒寫驗証。及收進 HO_RO 的一個版本,亦一並修正IF_TABLE掉失的那一行。唯有 SQ3NQJ 版本有補回這一行,相信他在增加選單上 PreScaler 設定時,才發現這 bug。至於這倉庫的版本,不修改了,當成一個曆史記錄就好。
gpasm -D DISPLAY_VARIANT_2 -p pic16f628 -o counter_mod.hex counter_mod.asm
pk2cmd -PPIC16F628A -Fcounter_mod.hex -E -M -Y
pk2cmd -PPIC16F628A -R在之後的無聊實驗中,意外地發現了一個較嚴重的bug,於是修改了這兩處。這個新的代碼,算是完滿地按原始版本的修正了,其生成的固件,亦驗証成功。
手上有一塊PIC16F877A學習板HJ-5G,嘗試修改代碼來配合生成固件,借用仿品頻率計的放大部份,導入1KHz來驗証,勉強算成功了。袛為實驗,沒有實用性。
硬件上的差異,利用代碼修改來配合,大致內容如下:
- HJ-5G用4MHz晶振,直接以DISPLAY_VARIANT_1來修改。
- 段碼改由PORTD來驅動,並且更改對應的顯示腳位。
- 原來是以RA5為設置按鍵,改為使用RB1。
- EEPROM操作要選 bank 2 及 bank 3。
- LSB位直接用RA0來選管作顯示,其餘使用RA5,RA3,RA2,RA1。
- 由於HJ-5G硬件連接是 RA4(TMR0) 作為數碼管的驅動,令無法直接套用,袛能棄用該管作顯示。HJ-5G的選管經過ULN2003A反相,GPIO高位時顯示,RA4位亦有上拉電阻,所以要改為下沿觸發計頻。因此,連接的那個數碼管無法完全熄掉。
再來最後一個實驗,使用MAX7219的數碼管又如何呢?首先試驗使用模組化的代碼,套進上述代碼中,這是初次試運行的結果。事實上,滙編用模組化,似乎不化算,亦不是必需。
之後再做調整,完成現時的版本,目的是令HJ-5G內建的數碼管不顯示,生成的固件順利地正確運行。修改的地方記錄在這文檔中說明,主要是配對數碼段的位元及安放在何處取得顯示資料。這是dirty方法,硬套進去,其實應該重寫,將原來的顯示驅動邏緝刪去,換成以MAX7219來顯示,袛需3個GPIO,還可以修改為全8位的顯示。不過,就是又得花時間。還是搞其它去吧,這倉庫應該到此為止了。
- 既然其他PIC型號能夠套用,近似的又如何?偶然見到淘寶有平宜的PIC16F716,也是18PIN,腳位定義基本上相同,估計可以直接替代。因為它沒有EEPROM,Program Mode功能無法應用,相關代碼需要刪除。省電模式雖然可以保留,但事實用處不大,也就一並抹去。調整適合的芯片配置字,就完成今次代碼修改,順利生成固件,正常地運行。
- 這塊【仿製品】一直沒有用於日常,經過令次的深入研究後,或者加個外盒和電池,令它成為真正的簡便計頻工具吧。雖然數碼管已開始出現狀況,需要更換或是將就使用。無論結果如何,研究的過程是寶貴的經驗,也是樂趣所在。
- 增補的無聊實驗都以 gpasm 完成,因為不需花費時間將代碼重新適配到 XC8 PIC-AS,這樣較為方便。感覺對於小型代碼的研發,它仍舊十分方便好用。
1-50Mhz_freq_counter_clone.X/
├── assets/ 圖片展示,PDF文件,代碼,等等資料。
├── nbproject/ 専案資料
├── Makefile IDE的自動化文件
├── counter_pic-as.s 展示的移植代碼
└── README.md 本說明文件