欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

標題: 請優(yōu)化你的MCU代碼 Ver2.0 [打印本頁]

作者: Similarv    時間: 2025-10-30 17:41
標題: 請優(yōu)化你的MCU代碼 Ver2.0
- 前言 -
⼤家,好久不⻅。
此⽂旨在于對2019年我發(fā)表在51黑論壇的貼⼦《請⼯程化,定制化你的單⽚機代碼http://www.raoushi.com/bbs/dpj-162218-1.html 進⾏更新,升級和完善。
雖說現(xiàn)在回頭⼀看,那篇貼⼦在⼀些細節(jié)確實有⼀些問題,不過最⼤的問題是——它不是⼀個完整的⽂章,我匆忙的把⼀些編程要點塞進了帖⼦⾥,然后就⼀直沒有更新了。
[attach]338394[/attach]

如今⼀晃就是6年,機緣巧合下,我突然⼜找到了那篇貼⼦。在不知不覺之間,帖⼦已經(jīng)被置頂,有了這么多的評論和閱讀量,這令我甚是慚愧。
感謝⼤家的⽀持。
我近期剛好有時間,那就把帖⼦重寫⼀下,并更完⽂章吧。

- 第⼀章:設(shè)計⼀個時鐘基線 -
在⼀些初級MCU編程⼊⻔書中,經(jīng)常能夠⻅到類似
  1. delay1s();  //延時1秒
復(fù)制代碼
或者
  1. while(K1 == 0); //等待⽤戶釋放鍵盤上的K1按鍵
復(fù)制代碼
這樣的代碼,表⾯上看沒有什么問題,但是本質(zhì)上跟下⾯的邏輯差不多:
“已知⼩明同學(xué)從教室跑去⼩賣部買糖再回來,⼤概需要1分鐘,所以,當(dāng)我們需要計時12⼩時的時候,讓⼩明同學(xué)這樣來回往返個720次,應(yīng)該就差不多了。”
“你戳⼩明⼀下,他就會叫⼀聲但是如果你⼀直戳著不松開,他就會由于腦⼦不夠⽤,不但叫不出來,就算你跟他說話他也沒法聽進去。”


在這樣的代碼中,MCU的PC指針(這東⻄代表著程序當(dāng)前在哪個代碼⾥運⾏)就如同悲催的⼩明同學(xué),被困在那兩⾏代碼中。也許是巨⼤的資源浪費,也許是⽆法對外部的信息變化做出反應(yīng),都是很糟糕的事情。
那么,要怎么樣來編寫單⽚機程序,才可以⼜實現(xiàn)這些邏輯功能,⼜釋放PC指針呢這就是我們接下來要討論的內(nèi)容。

1.1 帶有時基的主程序架構(gòu)

正如“ 每個不得不跑去⼩賣部的⼩明,其實他去年買了個表,根本不⽤跑 ”的道理()。
即使是普通的51單⽚機,他也是有定時器的。
我們需要設(shè)置⼀個定時器,讓定時器會告訴單⽚機:“好的,現(xiàn)在已經(jīng)過了1ms了(或者10ms這都沒關(guān)系)”單⽚機⼀拍腦袋:“啊,已經(jīng)到了1ms了么,那我就把⼀些事情做⼀下吧”。就像下面這樣子:


在這個框架下,我們的代碼看起來會像下⾯這個樣⼦:
  1. unsigned char flag1ms; //全局變量

  2. void main()
  3. {
  4.     flag1ms = 0;
  5.     mcuConfig(); //MCU的⼀些其他初始化,此處略過
  6.     timer0Init(); //定時器0初始化,略過,需設(shè)置1ms定時周期

  7.     while(1)
  8.     {
  9.         if(flag1ms)
  10.         {
  11.             flag1ms = 0;
  12.             doAnything(); //單片機可以做任意事情
  13.         }
  14.     }
  15. }

  16. void timer0XINT() interrupt 1 //定時器T0中斷
  17. {
  18.     flag1ms = 1;
  19. }
復(fù)制代碼
為了⽅便理解,這⾥的“⼀系列⼯作”在代碼中只⽤了⼀個doAnything()來表⽰,實際應(yīng)⽤中,往往會放好⼏個⼦程序,沒什么問題。
在本程序中,單⽚機每隔1ms會將⼀系列⼯作執(zhí)⾏⼀遍。從現(xiàn)在開始,你的⼦程序必須要摒棄那些“傻等⾏為”,重新設(shè)計你的程序邏輯。

1.2 ⼀個按鍵程序的例⼦
我們先拿⼀個⾮常惡⼼的按鍵函數(shù)來開⼑,如果沒有時基,我們可能會寫出這樣的⼀個按鍵程序:
  1. /* 在沒有時基的時候,代碼是這樣寫的 */
  2. #define K1_PRESSING() ((P1&0x01)==0) //按鍵位于P1^0引腳
  3. void keyPress()
  4. {
  5.     unsigned int key_press_time = 0;
  6.     while(K1_PRESSING()) //等待松開
  7.     {
  8.         ++key_press_time;
  9.         if(key_press_time==300) //300*10ms = 3s
  10.         {
  11.             //⻓按3s時要做的事情
  12.         }
  13.         delay10ms(); //delay計時
  14.     }
  15.     if((key_press_time < 300) && (key_press_time >= 2))
  16.     {
  17.         //短按的處理
  18.     }
  19. }
復(fù)制代碼
這個函數(shù)兼具delay()語句和while(KEY==0)語句,可以說是⼆毒俱全了。
如果是在新的代碼架構(gòu)中,它可以修改成這樣的形式
  1. /* 本程序?qū)⒃诿總1ms時基中被調(diào)⽤ */
  2. #define JUST_INC(x) if(++x<=0) --x //x在不能溢出的前提下++
  3. #define K1_PRESSING() ((P1&0x01)==0) //按鍵位于P1^0引腳
  4. void keyPress()
  5. {
  6.     static unsigned int key_press_time = 0;  // ……請標為靜態(tài)變量
  7.     if(K1_PRESSING())
  8.     {
  9.         JUST_INC(key_press_time);//計量按鍵時間,并避免數(shù)據(jù)溢出
  10.         if(key_press_time==3000)
  11.         {
  12.             //在此寫下按鍵⻓按3s時要做的事情
  13.         }
  14.     }
  15.     else
  16.     {
  17.         if((20<=key_press_time) && (key_press_time < 3000))
  18.         {
  19.             //20ms ~ 3s之間,視為短按,在此寫下寫短按的處理代碼
  20.         }
  21.         key_press_time=0;
  22.     }
  23. }
復(fù)制代碼
功能是⼀樣的,但實際⽤起來區(qū)別很⼤——舊程序跑1次⻓按功能,新程序已經(jīng)跑了3000次,且后者不會⼀直占⽤PC指針。
新的程序有些細節(jié),可以展開說⼀說:
①key_press_time現(xiàn)在是⼀個靜態(tài)變量,static關(guān)鍵字可以讓該變量在每次重新進⼊函數(shù)的時候不會重新賦值為0,⽽是保留上次退出函數(shù)時的值。
②“JUST_INC(key_press_time)”這⼀句,看起來⽤“++key_press_time”就能搞定,但是,誰也不能保證⽤戶真的不會按按鍵超過65秒的啊萬⼀他真的按了65576ms單⽚機還就真的以為⽤戶“短按”了⼀次呢(65576-65536=40ms,屬于短按范疇),下⾯那個短按程序段也會被執(zhí)⾏現(xiàn)在這樣寫,哪怕你按100年也沒關(guān)系了,反正單⽚機就每隔1ms進來看⼀次,K1這個按鈕你想按多久就按多久,掉在范圍內(nèi)就處理,超出范圍就⽆視
③“if(key_press_time==3000)”這⾥的3000只是隨便設(shè)置的⼀個3秒⻓按時間,如果需要做按鍵⻓短按功能,這⾥就是⻓按程序所放的位置也可以不⽤3000,⽤2000、50000都沒事,別超過65534就⾏。
④“if((20<=key_press_time) && (key_press_time < 3000))”這⾥,前⾯的>=20是短按的消抖設(shè)計——再強的⼈類也不可能1秒按⼀個按鍵超過20次,也就是不可能⼩于50ms的時間——這⾥⽤了20ms相當(dāng)于兼容“超級快男”來按按鍵了。后⾯<3000是不能和⻓按的時間沖突,因為3s我們已經(jīng)⼈為的設(shè)置成⻓按時間節(jié)點了。
⑤這⾥的參數(shù)遵循乘法原則。舉個例⼦,如果時基是10ms,那么這⾥的if(key_press_time==3000)就會代表30秒,如果想設(shè)置⻓按3秒的話,得把3000改成300。


1.3 關(guān)于時基的進階設(shè)置
回到剛剛討論的時鐘基線處,這⾥有⼏個⼩問題。
(1)假如,1ms的周期不夠把事情做完怎么辦
——那就把時基設(shè)置⼤⼀些,⽐如5ms,10ms,20ms,還不夠就該換芯⽚了,要不就是代碼還有很⼤的其他問題,需要好好排查。
(2)我該怎么⼤致估算代碼跑完“⼀系列⼯作”需要的時間,好讓我設(shè)置更合適的時基
——好問題這⾥有⼀個簡單且準確的⽅案任意找個閑置端⼝,⽐如P0^0,在⼲活之前先把這個端⼝拉⾼,⼲完活之后⻢上把它拉低,通過外接⽰波器或者邏輯分析儀,就能直觀的測量出耗時了。



(3)只有1個時基不⽅便,我的按鍵只需要10ms采集1次,但是LCD顯⽰我需要100ms才刷新⼀次。
——時基是可以擴展的!在1個時基的基礎(chǔ)上,只要你有需要,完全可以擴展出N多個時基匹配你的N個⼦程序。
⽐如下⾯的代碼,就在1ms的時基上分別擴展出了10ms和100ms的時基:
(4)我的各個函數(shù)應(yīng)該放在哪個時基⾥⾯呢
——這要求我們要對⾃⼰的程序要有清楚的把握,以及⼀定的產(chǎn)品思維,以下是⼀⼰之⻅。
①⾸先,所有的函數(shù)都要寫得簡潔⼲凈,不要有任何模塊的delay()加起來超過0.2ms,⼦程序⾥⾯放⼏個nop倒是⽆傷⼤雅。
按鍵,檢測,通信這類的⼦程序放到10ms時基⾥。輸出,顯⽰這類的放100ms時基就OK了。
③1ms時基⾥⾯應(yīng)該放什么呢可以什么也別放,空著就好。或者把主程序的基礎(chǔ)時基換成10ms也可以,其實很少有東⻄需要刷新得這么快的。如果基礎(chǔ)時基打算⽤10ms的話,可以將定時器的中斷設(shè)置為每10ms觸發(fā)(這樣可以刪掉flag1ms變量,此處不展開)也可以偷個懶,原本的程序框架改成這樣即可


④如果有特別需要關(guān)照的部分,⽐如說步進電機的驅(qū)動啥的,請放到另⼀個定時器中斷⾥(單⽚機基本都⾄少有倆定時器的,不⽤⽩不⽤),按你需要的來設(shè)置。
⑤定時器的中斷觸發(fā)時間建議不要少于0.5ms,不然進中斷就太頻繁了。
現(xiàn)在,我們的代碼已經(jīng)初具雛形,⼤家可以⾃⼰搭⼀下這個框架來體驗⼀下。
(當(dāng)當(dāng)當(dāng),現(xiàn)在是中場休息時間,喝杯⽔吧)







- 第⼆章: 程序之間的解耦 -
通俗點說,耦合度就是表⽰兩個東⻄“你中有我,我中有你”的程度,代碼間的耦合度越⾼,修改代碼就會越費勁
去耦合,或者說解耦,就是把各個功能從代碼層⾯盡可能的分隔開,當(dāng)代碼邏輯因為各種原因需要變化的時候,就可以簡單的修改⼀⼩部分,⽽不需要⼤改動。

2.1 從⼀個⻛扇的案例說起
為了⽅便說明,這⾥舉⼀個例⼦,假設(shè)我們有個⻛扇項⽬,MCU有這些IO端⼝要連接:
輸入 輸出 顯示
K1開關(guān)鍵 風(fēng)扇電機的開關(guān) 1個LED,開機時打開
K2擺頭鍵 擺頭電機 1個LED,擺頭時打開
K3檔位鍵 風(fēng)扇電機的強弱切換 1個LED,高檔風(fēng)速時打開

項⽬需求:
產(chǎn)品具有開機和關(guān)機2個狀態(tài),關(guān)機時所有負載和LED關(guān)閉,開機時恢復(fù)上⼀次的⼯作狀態(tài),第⼀次開機時默認為低轉(zhuǎn)速,不開擺頭。斷電后⽆記憶。以下為按鍵功能
開關(guān)鍵——切換產(chǎn)品的開關(guān)機狀態(tài)
擺頭鍵——開機狀態(tài)下,可切換擺頭電機開關(guān)
檔位鍵——開機狀態(tài)下,可切換⻛扇電機的輸出⻛⼒強弱。
基于此需求,我們?nèi)绻麤]有去耦合的概念,可能就會寫出這樣的代碼——






Tip⽆需逐⾏去理解這些代碼,很快它就會被推翻重寫,但請體會⼀下代碼⾼耦合的感覺。
這樣的代碼雖然實現(xiàn)了功能,但耦合度很⾼,它的按鍵、顯⽰、負載程序像蜜糖⼀樣黏糊糊的。呈現(xiàn)這樣的狀態(tài)

不過,反正我們都實現(xiàn)了項⽬的功能,測試也統(tǒng)統(tǒng)Pass,如果功能不再改來改去,作為研發(fā)你當(dāng)然可以到點下班,回家打⿇將去。

2.2 完了,需求要改啦
實際上到了⼯作上,你就會發(fā)現(xiàn),功能的改動是很平常且頻繁的事情



在陽光燦爛的⼀個上午,產(chǎn)品經(jīng)理向你提出了新的需求,并且改動的理由⼗分的充分
①開機之后如果不按開關(guān)機鍵,就會⼀直開機,這太危險了——所以,現(xiàn)在我們要把開機分成⽆限⼯作和限時
⼯作兩種模式限時⼯作模式下,LED1是0.5s亮0.5s滅的閃爍狀態(tài),連續(xù)⼯作8⼩時都⽆新按鍵按下的話,就⾃
動關(guān)機,如果有新按鍵就重新計時⽆限⼯作模式下,LED1是常亮狀態(tài),這個模式下不會⾃動關(guān)機,只能⼿動
關(guān)機。
②開關(guān)機鍵現(xiàn)在修改為兼容⻓短按的功能,1s之內(nèi)的按鍵視為短按,3s以上視為⻓按。開機時,短按為關(guān)機
關(guān)機時,短按則進⼊限時⼯作模式,⻓按則進⼊⽆限⼯作模式,兩⼯作模式之間⽆法直接切換。其他按鍵功能
不變。
雖然你還想反問他,⻛扇⼀直開著怎么就危險了,連續(xù)⼯作8⼩時怎么就安全了但根據(jù)⽃爭經(jīng)驗,這樣的爭辯
之后,往往會因你⼝技不如⼈⽽失敗(業(yè)內(nèi)常態(tài)),還不如省下吵架的功夫來考慮軟件怎么改。
那么,該怎么下⼿呢

2.3 按各個功能來劃分程序
舊代碼太臃腫且耦合了,光是LED閃爍這個功能都夠我們頭疼的,重寫吧
⾸先,把粘連的模塊分開,按鍵歸按鍵,顯⽰歸顯⽰,輸出歸輸出,就像這樣⼦:

這樣的話,keyPress( ),display( )和output( )三個函數(shù)各做各的事情,互不⼲擾,需要共享的信息通過關(guān)鍵的變量來傳遞。這⾥我們設(shè)置了3個全局變量system_status, swing, speed; 在keyPress( )函數(shù)和timeCount( )⾥可以修改這3個變量的值,然后在display( )和output( )函數(shù)⾥查詢這3個變量的值來控制顯⽰和輸出。
這時候的代碼結(jié)構(gòu),就是這樣⼦的——各個模塊分開,⽤關(guān)鍵參數(shù)傳遞信息

所謂的“解耦”⼤致就是這種感覺,現(xiàn)在你需要在哪⾥改動,就單獨改動哪個部分的,不⾄于瞻前顧后、束⼿束腳了。
現(xiàn)在的display( )和output( )程序彼此之間已經(jīng)沒有關(guān)聯(lián),⼏乎可以不費吹灰之⼒寫出來




剩下的⼯作也簡單,只需要將在keyPress( )和timeCount( )程序⾥,正確的設(shè)置好3個關(guān)鍵變量的值,我們就
成功的完成了代碼的變動,準點下班也不再是幻想。
⼤家不妨⾃⼰試著寫⼀下(你或許會需要⼀個新的全局變量)。
希望通過這樣⼀個例⼦,⼤家能夠?qū)Τ绦蚪怦畹暮锰幠苡星逦庇^的認識。
(當(dāng)當(dāng)當(dāng),現(xiàn)在是中場休息時間,起來伸個懶腰吧)






- 第三章:⽤狀態(tài)機管理系統(tǒng) -
其實,輕量級的⼩項⽬都可以不上狀態(tài)機,直接⼀⼝⽓擼完代碼流程也OK。
不過,這并不代表狀態(tài)機不好⽤,只是顯得有點⼤材⼩⽤了,這篇⽂章既然是個教程,所以⽤上狀態(tài)機也并⽆不可,那咱們現(xiàn)在就端上⼲貨。



3.1 狀態(tài)機是什么
狀態(tài)機,其實就是若⼲個“舊狀態(tài) + 觸發(fā)條件 = 新狀態(tài) + 額外動作”的公式,⽐如針對我們的新⻛扇需求,我們就可以寫出這些公式
① 關(guān)機狀態(tài) + 開關(guān)機鍵短按 = 限時⼯作模式 (⽆額外動作,下略)
② 關(guān)機狀態(tài) + 開關(guān)機鍵⻓按 = 不限時⼯作模式
③ 限時⼯作模式 + 開關(guān)機鍵短按 = 關(guān)機狀態(tài)
……
狀態(tài)機就是這些公式的集合
我個⼈并不喜歡寫公式,更喜歡作圖,如下,是不是更⼀⽬了然⼀些

這個圖直觀展⽰了系統(tǒng)的各個狀態(tài)之間是如何跳轉(zhuǎn)的,各個觸發(fā)條件⼜是如何對系統(tǒng)狀態(tài)產(chǎn)⽣影響的。
圖⾥畫了多少箭頭,你就能寫出多少個公式。
《狀態(tài)遷移》雖然在梳理邏輯的時候很好⽤,但是寫代碼需要參考時,《狀態(tài)遷移》⼜更勝⼀籌,如下所
⽰(⽤ - 表⽰⽆作⽤)

狀態(tài)0:關(guān)機 狀態(tài)1:限時工作狀態(tài)2:不限時工作
⽆操作 - 計時8⼩時后,轉(zhuǎn)⼊狀態(tài)0 -
K1短按 轉(zhuǎn)⼊狀態(tài)1 轉(zhuǎn)⼊狀態(tài)0   轉(zhuǎn)⼊狀態(tài)0
K1長按 轉(zhuǎn)⼊狀態(tài)2 - -
K2短按 - 切換擺頭開關(guān),且重新計時 切換擺頭開關(guān)
K3短按 - 切換檔位⾼低,且重新計時 切換檔位⾼低
左邊第⼀列,表⽰觸發(fā)條件;上⾯第⼀⾏,表⽰當(dāng)前狀態(tài)。
⾏與列的交叉點,則表⽰“這個狀態(tài)下,假如有這個觸發(fā)動作,則會發(fā)⽣什么事情”


3.2 對狀態(tài)機需要使⽤的變量進⾏⾃定義
狀態(tài)——建議⽤枚舉量表⽰,這是你⾃定義的⼀個變量
觸發(fā)條件——建議⽤布爾變量,觸發(fā)就是True,沒有觸發(fā)就是False
動作——則可以⾃由的根據(jù)你的項⽬來設(shè)置。
在本項⽬中,狀態(tài)機的所使⽤到的變量可以這樣定義

3.3 撰寫狀態(tài)機程序
完成了變量定義,接下來就可以寫出真正的狀態(tài)機程序。
⾸先,將系統(tǒng)狀態(tài)填⼊程序中


然后,根據(jù)《狀態(tài)遷移表》,⼀點點的填⼊你的狀態(tài)遷移公式,最終程序如下



這樣的話,我們的狀態(tài)機程序就寫完了
附帶⼀提,狀態(tài)機還有第⼆種寫法,這⾥也展⽰⼀下


第⼀種寫法給⼈的感覺是——“當(dāng)前正在關(guān)機,由于按了開關(guān)機鍵,所以現(xiàn)在要開機”。
⽽第⼆種寫法給⼈的感覺就是——“開關(guān)機鍵被按下了該怎么辦,查⼀查,嗯現(xiàn)在是關(guān)機狀態(tài),所以得開機”。
我個⼈是⽐較喜歡第⼀種寫法的,因為⽐較符合⼈的常規(guī)思維當(dāng)然也有⼀些⼯程師更喜歡后⾯那種,它有時可以節(jié)省代碼量。各有所好嘛,這⾥沒必要爭個⾼低了,反正功能都是⼀樣的



3.4 編寫系統(tǒng)⼯作程序的⼀些要點
確定了系統(tǒng)的狀態(tài),就到了系統(tǒng)該真正處理⼯作流程的時候了,不過有些要點。需要提前說明。
(1)建議各位將功能定義與具體的功能實現(xiàn)區(qū)分開來
——這句話是什么意思呢還是舉個例⼦,我們都知道LED燈要么亮,要么滅。也就是在“功能實現(xiàn)”上,它其實只有“亮”和“滅”,兩個值。但是,我們其實在設(shè)計⼯作流程的時候,卻可以⾃由設(shè)計出常亮,常滅,0.5秒亮1秒滅,2秒亮0.5秒滅,甚⾄是5秒周期的呼吸燈這樣的⼯作流程。后者就屬于⼀個“功能定義”,是可以多種多樣的。
我們的狀態(tài)機,只需要關(guān)注功能定義就好,具體的⼯作實現(xiàn),則“外包”給負載的驅(qū)動,讓他⾃⼰去控制輸出邏輯變化就好。
也就是說,狀態(tài)機不關(guān)⼼驅(qū)動模塊的⼯作細節(jié),但他需要知道這些模塊有哪些能耐。
基于這樣的思維,程序會出呈現(xiàn)這樣的框架


(2)模塊的變量和狀態(tài)機⾃⼰的變量不宜混⽤
⽐如說,b_swing這個變量,是狀態(tài)機⾃⼰⽤來記住擺頭的開關(guān)狀態(tài)的,output()程序最好另外有個屬于他⾃⼰的輸出變量,⽐如這⾥定義⼀個b_out_swing;
為什么因為項⽬需求要我們對開機的狀態(tài)進⾏記憶,只有b_swing的情況下,關(guān)機的時候到底是清空還是不清空有了b_out_swing,那就簡單得多關(guān)機時,b_out_swing為關(guān),開機時,b_out_swing = b_swing,完美。
(3)有關(guān)計時的程序可以放進對應(yīng)的⼦狀態(tài)中,⾃⼰慢慢跑。
在《狀態(tài)遷移表》中還有⼀⾏“⽆操作”時也要切換狀態(tài)的邏輯,屬于計時邏輯,這個邏輯可以放進這個程序中。
關(guān)于要點的提⽰就到這⾥,以下是程序。


最后,把systemStateSet()程序和systemStateWork()合并⼀下,就是完整的狀態(tài)機模塊了




3.5 使⽤狀態(tài)機后,其他函數(shù)需要做些調(diào)整
如果要⽤狀態(tài)機,那么先前在2.3中編寫的display()和output()程序需要重寫keyPress( )函數(shù)則是需要刪除⼀些處理邏輯,只保留對b_key1_short, b_key2這類的觸發(fā)變量的改值。
為什么因為先前的代碼,是從底層追朔到頂層的編寫模式
這些驅(qū)動要需要怎么樣來控制這些LED和負載呢——取決于系統(tǒng)有哪些狀態(tài),所以display()和output()做了什么事情呢他去訪問了system_status這個變量
⼀個驅(qū)動,居然去訪問系統(tǒng)狀態(tài)


這相當(dāng)于⼀個⽼板的專屬司機,⽆時⽆刻追著⽼板問領(lǐng)導(dǎo)要不要出⻔,要出⻔他就去準備⻋,不出⻔司機就balabala……
正確的邏輯,應(yīng)該是這個司機等⽼板給他發(fā)命令。他⾃⼰知道⾃⼰能做那些事,⽼板也知道。但是司機不能去打探⽼板在⼲嘛,畢竟他只是個driver
既然決定了要⽤狀態(tài)機,要讓程序變得進⼀步的層次分明,就得快⼑斬亂⿇的放棄原本為了偷懶⽽⾛的捷徑。
output程序現(xiàn)在要這樣寫:


類似的,display( )程序


經(jīng)過調(diào)整之后,我們的軟件代碼變得主次分明。未來如果再有其他的變動,我們都可以輕松的劃分責(zé)任,來僅對有必要的部分進⾏修改。

(當(dāng)當(dāng)當(dāng),正⽂已經(jīng)結(jié)束了,起來上個廁所吧)


附文:從零使用STM32F103C8T6,構(gòu)建文章中的風(fēng)扇項目
帖子寫不下了,大家自己下載文檔來看這個附文吧。

感謝你的閱讀。
祝⼤家萬圣節(jié)快樂。
—— 【51黑】 Similarv ,Oct 30. 2025
(全⽂完。如需轉(zhuǎn)載,請標明出處。)




1.截至2025年10月的點擊量.png (39.4 KB, 下載次數(shù): 0)

1

1

請優(yōu)化你的代碼-附件程序F103.7z

684.3 KB, 下載次數(shù): 0, 下載積分: 黑幣 -5

請優(yōu)化你的單片機代碼.pdf

3.22 MB, 下載次數(shù): 0, 下載積分: 黑幣 -5


作者: Similarv    時間: 2025-10-30 20:43
本帖最后由 Similarv 于 2025-11-3 08:57 編輯

全文共有3頁,請手動翻頁。
另外,附件的排版應(yīng)該比網(wǎng)頁的排版干凈。
由于不可抗力,從第5個代碼塊開始,網(wǎng)頁端po出的代碼就開始出現(xiàn)亂碼,我重復(fù)編輯了很多次,都無法解決。因此后面很多代碼塊都變成了圖片格式,影響了大家的閱讀,望諒解。

作者: Similarv    時間: 2025-10-30 20:47
終于整完了,這次特意在換工作的空窗期,抽出時間完成了這個主題。大家萬圣節(jié)快樂。


祝我明天面試順利,嘻嘻。

作者: hange_v    時間: 2025-10-30 22:40
這樣不好嗎void ledTask(void)
{
    static u32 usBck = 0, usNow = 0;
    static u8 sta = 0;

    usNow = mSysTimerGetUs();
    if((usNow - usBck) > 250000)
    {
      usBck = usNow;
      sta = (sta == 0) ? 1 : 0;
      if(sta == 0)
      {
        LED_RUN_OFF; LED_STOP_OFF;
      }
      else
      {
        LED_RUN_ON; LED_STOP_ON;
      }
}

作者: Similarv    時間: 2025-10-30 22:59
hange_v 發(fā)表于 2025-10-30 22:40
這樣不好嗎void ledTask(void)
{
    static u3 ...

你好,請問這是在?
作者: MCU2023    時間: 2025-10-31 04:49
非常不錯,謝謝小豬豬的指導(dǎo):D,收藏了!
作者: hange_v    時間: 2025-10-31 09:15
發(fā)表于 2025-10-30 22:59
你好,請問這是在?

閃爍LED  250ms
作者: Similarv    時間: 2025-10-31 16:48
hange_v 發(fā)表于 2025-10-31 09:15
閃爍LED  250ms

我推測,這段代碼只能保證“LED不會在250ms以內(nèi)就翻轉(zhuǎn)電平”,并不能確保剛好總是250ms的時候就立馬翻轉(zhuǎn)。
作者: hange_v    時間: 2025-10-31 20:46
Similarv 發(fā)表于 2025-10-31 16:48
我推測,這段代碼只能保證“LED不會在250ms以內(nèi)就翻轉(zhuǎn)電平”,并不能確保剛好總是250ms的時候就立馬翻轉(zhuǎn) ...

那得做到定時器中斷,且優(yōu)先級最高
作者: 莫燁    時間: 2025-10-31 22:16
感謝大師分享
作者: wbwcf13e    時間: 2025-11-1 07:21
這得好好學(xué)習(xí)一下!
作者: suixilpc    時間: 2025-11-1 15:24
謝謝分享
作者: suixilpc    時間: 2025-11-1 15:28
真的學(xué)到很多知識,再次謝謝
作者: lxh0508    時間: 2025-11-2 14:57
寫的真好
作者: lipen2008    時間: 2025-11-2 18:07
大神終于有更新了,受教了。
作者: jiangweich    時間: 2025-11-2 20:45
寫得很好
作者: jjwangxu2008    時間: 2025-11-2 23:33
[em05]
作者: maqykk    時間: 2025-11-3 07:44
好貼,學(xué)習(xí)了!
作者: dcc60    時間: 2025-11-3 09:51
樓主說的全部中招
作者: xuer0921    時間: 2025-11-3 18:53
感謝大佬的教程,已保存,慢慢研究!
作者: pxhxkij    時間: 2025-11-6 16:45
非常感謝樓主的付出。雖然我是小小小小白,只會復(fù)制別人的代碼
作者: mashuiyou    時間: 2025-11-7 08:19
非常不錯,謝謝指導(dǎo)!
作者: mashuiyou    時間: 2025-11-7 08:20
非常不錯,謝謝指導(dǎo)!
作者: zxq9781    時間: 2025-11-8 22:27
真的學(xué)到很多知識,再次謝謝
作者: zenghl    時間: 2025-11-9 20:24
大神終于有更新了,受教了。
作者: ldc2000    時間: 2025-11-13 02:22
菜鳥一枚,現(xiàn)在的能寫出的都是讓大神惡心的代碼
作者: hyzqq    時間: 2025-11-13 23:06

非常感謝樓主的付出。
作者: dyx811    時間: 2025-11-13 23:42
學(xué)習(xí)了大師的編程思維!真的受益良多!非常感謝!
作者: Similarv    時間: 2025-11-14 14:06
dyx811 發(fā)表于 2025-11-13 23:42
學(xué)習(xí)了大師的編程思維!真的受益良多!非常感謝!

大師不至于,這是一個面向新手的教程,目的是讓大伙起步的時候少走一些彎路。
至于怎么成為大師,我自己也在摸索前進。
作者: dcc60    時間: 2025-11-17 10:27
新手表示看不懂啊。
如果要設(shè)計一個短按與長按的函數(shù),是直接讓定時器計時嗎?
作者: Similarv    時間: 2025-11-17 11:46
dcc60 發(fā)表于 2025-11-17 10:27
新手表示看不懂啊。
如果要設(shè)計一個短按與長按的函數(shù),是直接讓定時器計時嗎?

你的主程序是每10ms才跑一次的,靜態(tài)變量的計數(shù)值就是計時值
作者: SHANWAZI    時間: 2025-11-17 11:49
又學(xué)習(xí)了
作者: kkfy888    時間: 2025-11-17 14:07
謝謝分享,學(xué)習(xí)優(yōu)化
作者: wdgao    時間: 2025-11-17 22:47
有個問題想請教:文中提到“不要有任何模塊的delay()加起來超過0.2ms”,但對于數(shù)碼管動態(tài)掃描如何控制每個數(shù)碼管點亮2ms?
作者: Similarv    時間: 2025-11-17 23:13
wdgao 發(fā)表于 2025-11-17 22:47
有個問題想請教:文中提到“不要有任何模塊的delay()加起來超過0.2ms”,但對于數(shù)碼管動態(tài)掃描如何控制每 ...

個人建議你用低優(yōu)先級的定時器中斷,2ms周期掃一下
作者: libin1009    時間: 2025-11-18 10:01
非常不錯,值得學(xué)習(xí)一下!
作者: wdgao    時間: 2025-11-19 07:07
發(fā)表于 2025-11-17 23:13
個人建議你用低優(yōu)先級的定時器中斷,2ms周期掃一下

謝謝指導(dǎo),是個好辦法。
作者: 亙古飛揚    時間: 2025-11-29 08:21
很好的編程思維,值得學(xué)習(xí)。
作者: 3wjkdhus    時間: 2025-11-30 12:13
能不用阻塞延時就不用
作者: ly_zhy    時間: 2025-12-2 18:43
真不錯,學(xué)習(xí)了!
作者: 三極管一樣的人    時間: 2025-12-3 14:13
想不到九年后還能看到更新版,上網(wǎng)這么多年,難得少見了。
作者: 手機刷機菜鳥    時間: 2025-12-9 12:15
這個真是厲害,又學(xué)習(xí)了

作者: xhbert    時間: 2025-12-16 09:52
只有我一個人看到的是方框嗎
作者: cqycqy666    時間: 2025-12-17 15:48

非常不錯,值得學(xué)習(xí)一下!




歡迎光臨 (http://www.raoushi.com/bbs/) Powered by Discuz! X3.1