本著授人以漁的原則,既提供我一直在用的程序架構(gòu),也講程序架構(gòu)的設(shè)計(jì)思路。
如果本文內(nèi)容,你都能領(lǐng)悟并做到,不管項(xiàng)目多復(fù)雜,都將游刃有余。
我研發(fā)的那幾年,接觸大多數(shù)工程師,都沒(méi)有程序架構(gòu)的概念,基本一個(gè)while死循環(huán)干到底。
模塊之間也沒(méi)有封裝好,導(dǎo)致代碼寫(xiě)好以后,擴(kuò)展性和維護(hù)性太差,類似的功能代碼,也很難移植到新項(xiàng)目去復(fù)用。
早期我也是這樣寫(xiě)的,反正實(shí)現(xiàn)功能就行了,代碼好不好,功能上又看不出區(qū)別。
不過(guò),等你接觸到復(fù)雜的項(xiàng)目時(shí),這招就行不通了,沒(méi)設(shè)計(jì)好程序架構(gòu),根本做不穩(wěn)定。
我意識(shí)到這個(gè)問(wèn)題,是碰到兩種需求的時(shí)候:
1.是做一個(gè)基于STM32的網(wǎng)關(guān)項(xiàng)目,項(xiàng)目做完以后,客戶老是要改功能,客戶不懂技術(shù),在客戶眼里,覺(jué)得改一個(gè)LED閃爍效果很簡(jiǎn)單,但對(duì)于程序架構(gòu)沒(méi)設(shè)計(jì)好的工程師來(lái)說(shuō),就是一個(gè)噩夢(mèng),比如每隔5秒快閃2次這種惡心的需求,搞不好很多代碼都要重新組織。
我經(jīng)常會(huì)被這種問(wèn)題搞到頭痛,特別是客戶又催得急的時(shí)候,經(jīng)常加班加到焦頭爛耳,越急又越搞不出來(lái)。
2.我做過(guò)的很多項(xiàng)目,其實(shí)很多功能都有重復(fù)的,比如很多產(chǎn)品都有LED、都有按鍵、都有掉電參數(shù)存儲(chǔ)、都有串口協(xié)議解析等等。
但是程序架構(gòu)沒(méi)寫(xiě)好,導(dǎo)致想移植代碼,過(guò)來(lái)新項(xiàng)目復(fù)用時(shí),不太好改,比如老項(xiàng)目才1個(gè)LED,新項(xiàng)目有6個(gè)LED,類似的還有按鍵等等。
后面為了有更多的時(shí)間摸魚(yú),我開(kāi)始思考,怎么把程序?qū)懙?,改起功能?lái)很方便,代碼復(fù)用性又很強(qiáng)那種,當(dāng)時(shí)還不知道這個(gè)叫程序架構(gòu)設(shè)計(jì)。
程序架構(gòu),我覺(jué)得是一個(gè)系統(tǒng)的學(xué)問(wèn),貫穿著整個(gè)項(xiàng)目,而不是具體某些細(xì)節(jié)。
就是各種功能模塊,比如LED特效功能,按鍵檢測(cè)功能,菜單功能,系統(tǒng)參數(shù)存儲(chǔ)功能、語(yǔ)音功能、OTA升級(jí)功能等等。
這些功能模塊的設(shè)計(jì),我通常是采用硬件驅(qū)動(dòng)代碼和功能邏輯代碼分離的方式,用大白話來(lái)說(shuō),就是一個(gè)功能模塊,我可能會(huì)分2個(gè).c文件來(lái)寫(xiě),硬件驅(qū)動(dòng)代碼我以hal_xxx.c命名,功能邏輯代碼我以mt_xxx.c命名。
硬件驅(qū)動(dòng)代碼主要是和單片機(jī)外設(shè)的配置代碼,比如設(shè)置GPIO、Timer、串口、SPI這些,然后提供硬件接口給mt_xxx.c調(diào)用。
拿無(wú)際項(xiàng)目特訓(xùn)營(yíng)的項(xiàng)目6來(lái)舉例,這個(gè)項(xiàng)目可以實(shí)現(xiàn)遠(yuǎn)程控制,因?yàn)榧恿薟iFi和4G模塊。
如果你接觸過(guò)類似項(xiàng)目,單片機(jī)和云平臺(tái)之間,其實(shí)還有個(gè)串口通訊協(xié)議的,類似于下圖這種。

按照我的思維,我會(huì)這樣去設(shè)計(jì)程序:
單片機(jī)外設(shè)驅(qū)動(dòng)的配置、串口發(fā)送數(shù)據(jù)、接收數(shù)據(jù)代碼,我都放在hal_uart.c里。

串口協(xié)議數(shù)據(jù)發(fā)送和解析的代碼,我會(huì)放在mt_protocol.c文件里。

這樣就能實(shí)現(xiàn)硬件驅(qū)動(dòng)代碼和功能邏輯代碼徹底分離。
那這樣的好處是什么?
1.萬(wàn)一要換單片機(jī)了,如果通訊協(xié)議不變的情況下,mt_protocol.c文件代碼可以不用改,只要改hal_uart.c硬件驅(qū)動(dòng)程序,就能對(duì)接起來(lái)。
2.如果通訊協(xié)議格式變了,單片機(jī)不變,那只需要改mt_protocol.c文件代碼就可以了。
3.調(diào)試方便,比如mt_protocol.c的功能,可以在PC上搭建一個(gè)開(kāi)發(fā)環(huán)境先調(diào)試好,再對(duì)接硬件驅(qū)動(dòng)接口,對(duì)于復(fù)雜的功能,這招還是很有用的,畢竟keil仿真調(diào)試沒(méi)那么方便靈活。
這種設(shè)計(jì),就是一種架構(gòu)思維,解決了代碼擴(kuò)展性和移植性的問(wèn)題。
如果每個(gè)功能模塊都采用這種思維去設(shè)計(jì),最終從整體看,你的程序架構(gòu)就非常好了,就像組裝汽車一樣靈活了。
所以,要設(shè)計(jì)好程序架構(gòu),真的不是靠一個(gè)課程能搞定的,需要完整地做幾個(gè)復(fù)雜的項(xiàng)目,并且有資深工程師的思路和代碼,可以參考和借鑒,這樣才能高效,系統(tǒng)地掌握。
每個(gè)功能模塊都設(shè)計(jì)好以后,最后還需要有一個(gè)協(xié)調(diào)者。
類似于人的大腦,去協(xié)調(diào)手、腳、眼睛、耳朵、嘴巴。
這個(gè)大腦,一般就是程序的"地基",類似于RTOS,就是"協(xié)調(diào)者"身份,負(fù)責(zé)調(diào)度協(xié)調(diào)整個(gè)項(xiàng)目的各個(gè)功能模塊。
RTOS本質(zhì)也是一種程序架構(gòu),但是我很少用,因?yàn)樗奶幘常鋵?shí)很尷尬。
沒(méi)那么復(fù)雜的項(xiàng)目,上RTOS并沒(méi)有優(yōu)勢(shì),反而為后期調(diào)試帶來(lái)不必要的麻煩,如果對(duì)系統(tǒng)不熟悉,就像埋了一個(gè)定時(shí)炸彈,可能會(huì)跑一段時(shí)間后死機(jī)的現(xiàn)象。
復(fù)雜的項(xiàng)目,有些直接上Linux了,現(xiàn)在很多***,成本也能做得很低。
所以,現(xiàn)在rtos的應(yīng)用,我覺(jué)得主要集中在中等復(fù)雜的項(xiàng)目,要求實(shí)時(shí)性很高,同時(shí)工程師,又不具備設(shè)計(jì)程序架構(gòu)的能力時(shí)。
不過(guò),至今為止,我基本是用自己設(shè)計(jì)的架構(gòu)去替代RTOS,目前大多數(shù)產(chǎn)品都?jí)蛴谩?/p>


這個(gè)架構(gòu),我也錄了套系統(tǒng)的教程,粉絲可以找我拿去參考學(xué)習(xí)。

寫(xiě)了3個(gè)多小時(shí),腦子和手都麻了(我的意思是,可以開(kāi)始點(diǎn)贊了^ ^)
編輯:黃飛
?
電子發(fā)燒友App











評(píng)論