久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 168642|回復(fù): 554
收起左側(cè)

請(qǐng)工程化,定制化你的單片機(jī)代碼

    [復(fù)制鏈接]
回帖獎(jiǎng)勵(lì) 40 黑幣 回復(fù)本帖可獲得 2 黑幣獎(jiǎng)勵(lì)! 每人限 1 次
ID:476527 發(fā)表于 2019-6-6 11:48 | 顯示全部樓層 |閱讀模式
  • - 前言 -
    • 時(shí)至今日,依舊看到很多小伙伴們放著單片機(jī)里的定時(shí)器不用,動(dòng)輒delay1s(); delay500ms();雖然簡(jiǎn)單粗暴,但是其實(shí)是很不妥當(dāng)?shù)摹?/font>
    • 還有很多需要按鍵的程序,動(dòng)不動(dòng)就“while(k1==0);”的等按鍵松開(kāi),這樣的代碼只是“為了滿(mǎn)足某個(gè)功能“而設(shè)計(jì)的代碼,而非”為了保證產(chǎn)品的質(zhì)量“而設(shè)計(jì)的代碼。
    • 我們應(yīng)該時(shí)刻考慮“如果這傻逼用戶(hù)不按我的標(biāo)準(zhǔn)操作來(lái)搞我的產(chǎn)品,我該怎么寫(xiě)程序?”,而不是”只要客戶(hù)乖乖聽(tīng)我的,這樣做是沒(méi)問(wèn)題的,就行了;出了問(wèn)題都是他亂搞,跟我有個(gè)毛關(guān)系”,后面的思維是典型的只顧自己爽的思維,我們應(yīng)當(dāng)想方設(shè)法的提高產(chǎn)品的可靠度。
    • OK,扯遠(yuǎn)了,現(xiàn)在只是想提出一些設(shè)計(jì)的思路。
  • part1 . 系統(tǒng)的時(shí)基 & 依托于時(shí)基去設(shè)計(jì)函數(shù)
- 系統(tǒng)的時(shí)鐘基線 -
  • 關(guān)鍵詞,是“時(shí)鐘基線”。
  • 我們需要設(shè)置一個(gè)定時(shí)器,這個(gè)定時(shí)器會(huì)告訴單片機(jī):“好的,現(xiàn)在已經(jīng)過(guò)了1ms了(或者100ms?這都沒(méi)關(guān)系)”單片機(jī)一拍腦袋:“啊,已經(jīng)到了1ms了么,那我就把某一件事情做一下吧”。
  • 大致像這樣:
  • 主函數(shù)與定時(shí)器

    主函數(shù)與定時(shí)器
  • 這個(gè)程序的意思就是,讓單片機(jī)每隔1ms就do_sth()一次(定時(shí)器的初始化函數(shù)省略了沒(méi)畫(huà));
  • 這樣寫(xiě)還可以讓中斷函數(shù)非常的簡(jiǎn)潔,幾乎一進(jìn)去就出來(lái),基本不會(huì)影響到被中斷打斷的函數(shù)的工作;
  • 以傳遞關(guān)鍵參數(shù)的形式,大循環(huán)里只要查一查這個(gè)flag1ms值,知道什么時(shí)間要做什么事情就對(duì)了。
- 按鍵函數(shù)舉例 -
  • 上圖中這個(gè)do_sth()可以是任意函數(shù),以按鍵函數(shù)keyPress()為例,可以這樣寫(xiě):
  1. void keyPress(){
  2.     static unsigned int key_press_time = 0;  // ……請(qǐng)記得標(biāo)為靜態(tài)變量
  3.     if(K1==0){
  4.         if(++key_press_time <=0 ) --key_press_time;//計(jì)量按鍵時(shí)間,并避免數(shù)據(jù)溢出
  5.         if(key_press_time==3000){
  6.             //在此寫(xiě)下按鍵長(zhǎng)按3s時(shí)要做的事情;
  7.         }
  8.     }else{
  9.         if(20<=key_press_time && key_press_time < 3000){
  10.             //大于20ms小于3s,視為短按,在此寫(xiě)下寫(xiě)短按的處理代碼
  11.         }
  12.         key_press_time=0;
  13.     }
  14. }
復(fù)制代碼

  • 這里有很多可以研究的地方:
    • ①“if(++key_press_time <=0 ) --key_press_time;”這一句,看起來(lái)用“++key_press_time”就能搞定,但是,誰(shuí)也不能保證某些用戶(hù)真的不會(huì)按按鍵超過(guò)65秒的啊;萬(wàn)一他真的按了65576ms;單片機(jī)還就真的以為用戶(hù)“短按”了一次呢(65576-65536=40ms,屬于短按范疇),這下那個(gè)短按程序段也會(huì)被執(zhí)行一次;現(xiàn)在這樣寫(xiě),哪怕你按100年也沒(méi)關(guān)系了,反正我的單片機(jī)就每隔1ms進(jìn)來(lái)看一次,K1這個(gè)按鈕你想按多久就按多久,掉在我的范圍內(nèi)我就處理你,超出我的范圍我就無(wú)視你。
    • ②“if(key_press_time==3000){ ; }”這里的3000只是隨便設(shè)置的的一個(gè)時(shí)間(3s),如果你需要做按鍵長(zhǎng)短按功能,這里就是你的長(zhǎng)按程序所放的位置;你也可以不用3000;用2000,50000都沒(méi)事,別超過(guò)65534就行(提問(wèn):為什么這里又是65534呢?);
    • ③“if(20<=key_press_time && key_press_time < 3000)”這里,前面的>=20是個(gè)消抖的設(shè)計(jì),客戶(hù)再?gòu)?qiáng)也是人類(lèi),再?gòu)?qiáng)的人類(lèi)也不可能1秒按一個(gè)按鍵超過(guò)20次;也就是不可能短于50ms的時(shí)間;這里用了20ms相當(dāng)于兼容 男上加男的快男 也來(lái)按按鍵了。后面<3000是不能和長(zhǎng)按的時(shí)間沖突,因?yàn)?s我們已經(jīng)人為的設(shè)置成長(zhǎng)按時(shí)間節(jié)點(diǎn)了。
  • 好,現(xiàn)在知道相關(guān)的程序該怎么寫(xiě)了,我們回到剛剛討論的時(shí)鐘基線處。

-  多個(gè)時(shí)鐘基線的方案  -
  • 剛剛的例子中我們只展示了1ms的時(shí)基,對(duì)于單片機(jī)來(lái)說(shuō),1ms已經(jīng)很慢了,但對(duì)于人和某些設(shè)備來(lái)說(shuō)來(lái)說(shuō)還是快的不行,比如一些本就需要10ms間隔的通信設(shè)置,需要隔100ms才能刷一次的顯示,需要50ms才能重新采的某些傳感器等等,這些東西放進(jìn)1ms的do_sth()里面肯定是不行的(其實(shí)也行,但不方便管理來(lái)著)——怎么辦呢?
  • ——好辦,放進(jìn)10ms 或50ms 或100ms 的do_sth() 里就OK了
  • ——但是我們只有1個(gè)定時(shí)器啊,怎么弄幾個(gè)時(shí)基呢?
  • ——1個(gè)定時(shí)器就夠了,其他的時(shí)基都基于那個(gè)1ms的時(shí)基來(lái)就好。我們已經(jīng)有了flag1ms,當(dāng)然可以弄幾個(gè)flag10ms乃至flag1000ms,只要你需要,就能設(shè)置。
  • 如下圖,我們通過(guò)參數(shù)控制參數(shù)的形式,將flag1ms擴(kuò)展為多個(gè)時(shí)基,使得程序漸漸的趨于模塊化,精準(zhǔn)化
  • 增大時(shí)基的設(shè)置

    增大時(shí)基的設(shè)置
  • 這里有個(gè)要注意的地方,就是函數(shù)從宏觀上來(lái)看,確實(shí)是“每隔1ms就do_sth();每隔10ms就do_sth1();每隔100ms就do_sth2()"。
  • 但是,從微觀上看,單片機(jī)是沒(méi)法在同一時(shí)刻做2件事情的!所以,每到10ms的時(shí)候,單片機(jī)會(huì)”先把1ms的事情做完再做10ms的事“;每到100ms的時(shí)候,單片機(jī)會(huì)”先把1ms的事情做完再做10ms的事,再做100ms的事“。
  • 現(xiàn)在,我們的系統(tǒng)已經(jīng)趨于成型了,不過(guò)要注意一點(diǎn),這些做事情的子函數(shù)里萬(wàn)萬(wàn)不得有delay函數(shù)了(放幾個(gè)nop倒是無(wú)傷大雅),好不容易劃分好了時(shí)鐘基線,你在1ms的時(shí)基里塞上幾個(gè)delay2ms是要鬧怎樣。
  • 還有一個(gè)問(wèn)題,那就是子函數(shù)不要拖泥帶水,寫(xiě)得越簡(jiǎn)潔越好,趕緊把事情做完,把控制權(quán)還給單片機(jī),由它來(lái)決定接下來(lái)要做什么。

-  函數(shù)應(yīng)該放在哪個(gè)時(shí)基里?  -
  • 這也是關(guān)鍵的地方,這要求我們要對(duì)自己的程序要有清楚的把握。以及一定的產(chǎn)品思維。
  • 總的原則還是沒(méi)變:所有的函數(shù)都要寫(xiě)得簡(jiǎn)潔干凈,不要有任何模塊的delay()加起來(lái)超過(guò)200us!
  • 一般來(lái)說(shuō),按鍵按一次不會(huì)超過(guò)50ms,放到flag10ms或者flag20ms的時(shí)間段里是沒(méi)什么關(guān)系的(注意,這時(shí)候函數(shù)里的3000表示的就不是3s了,而是30s或者60s!這是遵循乘法原則的!);
  • LCD顯示之類(lèi)的,控制某個(gè)LED之類(lèi)的,100ms一次就行了,人眼視覺(jué)暫留之類(lèi)的看不出問(wèn)題的。
  • 一般:檢測(cè),通信這類(lèi)的子程序都能放到flag10ms或者flag20ms里。輸出,顯示這類(lèi)的放flag100ms就OK了。
  • flag1ms里面應(yīng)該放什么呢?我的意見(jiàn)是盡量什么也別放,空著都OK,因?yàn)槠鋵?shí)沒(méi)什么東西需要刷新得這么快的。
  • 如果有特別需要關(guān)照的部分,比如說(shuō)步進(jìn)電機(jī)的驅(qū)動(dòng)啥的,請(qǐng)放到另一個(gè)定時(shí)器中斷里(單片機(jī)有倆定時(shí)器的,不用白不用),按你需要的來(lái)設(shè)置。
  • 定時(shí)器的中斷觸發(fā)時(shí)間建議不要低于0.5ms,不然進(jìn)中斷就太頻繁了,誰(shuí)也不會(huì)希望自己正看著小電影的時(shí)候,爸媽過(guò)來(lái)拍你的房門(mén)吧?
  • —— 2019年6月10日更新 ——
  • Part2.將代碼模塊化,降低耦合度
  • - 降低代碼間的耦合度 -
    • 通俗點(diǎn)說(shuō),耦合度就是表示兩個(gè)東西“你中有我,我中有你”的程度,代碼間的耦合度越高,你修改起來(lái)就越費(fèi)勁,有時(shí)候看到代碼黏糊糊的像一大坨蜜糖,難免會(huì)讓人不知從何處下口。
    • 還是用個(gè)例子來(lái)說(shuō)明一下吧——《電風(fēng)扇系統(tǒng)設(shè)計(jì)1》
      • 假設(shè)我們要寫(xiě)個(gè)電風(fēng)扇的控制程序 —— 按鍵方面:風(fēng)扇有開(kāi)關(guān)鍵,強(qiáng)風(fēng)弱風(fēng)切換,擺頭控制3個(gè)按鍵(注意,這里的按鍵是那種大開(kāi)大合的開(kāi)關(guān)按鍵,不是那種輕觸按鍵); 顯示方面:每個(gè)按鍵旁邊各有1個(gè)小led燈,共3個(gè)燈; 輸出方面:有個(gè)控制風(fēng)扇擺頭的負(fù)載,有個(gè)控制風(fēng)扇轉(zhuǎn)不轉(zhuǎn)的負(fù)載,有個(gè)控制風(fēng)扇轉(zhuǎn)得快或者慢的負(fù)載。
      • 或許有人三下兩下就畫(huà)了個(gè)這樣的流程圖(一般風(fēng)扇沒(méi)開(kāi)的時(shí)候是不能擺頭的,這里就先不管了):
      • 51hei2.jpg
      • 然后就隨手寫(xiě)出了這樣的代碼:
      • 51hei3.jpg
      • 老實(shí)說(shuō),這沒(méi)啥問(wèn)題,因?yàn)槲覀兊念}目要求是那么的簡(jiǎn)單,簡(jiǎn)單的要求那就簡(jiǎn)單的實(shí)現(xiàn)吧。雖然這里的按鍵、顯示、負(fù)載的程序代碼像蜜糖一樣黏糊糊的,但是代碼也才十幾行,誰(shuí)會(huì)在意呢?也大致畫(huà)一下如上代碼的結(jié)構(gòu)吧:
      • 51hei4.jpg
      • 但是,別忘了2點(diǎn)!①是客戶(hù)的需求隨時(shí)都會(huì)改動(dòng);是這么簡(jiǎn)單的項(xiàng)目還用不到你做。所以,我們稍微,加點(diǎn)難度上來(lái)看看?
    • 《電風(fēng)扇系統(tǒng)設(shè)計(jì)2》
      • 在《風(fēng)扇1》的基礎(chǔ)上,①風(fēng)扇沒(méi)開(kāi)時(shí)不能擺頭;②風(fēng)扇沒(méi)開(kāi)時(shí),為了與沒(méi)電作區(qū)分,要讓3個(gè)LED燈同時(shí)以1s為周期閃爍;③開(kāi)風(fēng)扇后若是5小時(shí)內(nèi)按鍵都沒(méi)有變化過(guò),則自動(dòng)關(guān)掉風(fēng)扇(避免久開(kāi),當(dāng)然此后LED也要閃爍),若想重開(kāi)風(fēng)扇必須把“風(fēng)扇開(kāi)關(guān)按鍵”先關(guān)掉再打開(kāi)才行。
      • 說(shuō)句實(shí)話,先前的那份代碼也到此為止了,如果有人還想在原來(lái)的代碼上改出滿(mǎn)足現(xiàn)在的需求的代碼,我只能祝他好運(yùn)。雖然也不是不能改,但是若是想用你那delay500ms來(lái)滿(mǎn)足我的閃爍要求;或者硬是嵌入一些繞來(lái)繞去的東西在里面,那肯定沒(méi)有從頭再來(lái)要省事。
      • 那么——現(xiàn)在該怎么做呢?
        • 首先,把粘連的模塊分開(kāi),按鍵歸按鍵,顯示歸顯示,輸出歸輸出。就像這樣子: 51hei5.jpg
          • 這樣的話,大家各做各的事情,互不干擾,需要共享的信息則通過(guò)關(guān)鍵參數(shù)來(lái)傳遞。這里我們?cè)O(shè)置了3個(gè)全局變量:key_on_flag, key_strong_flag, key_sheak_flag; 在keyPress()函數(shù)里可以修改這3個(gè)變量的值,然后在display()和output()函數(shù)里查詢(xún)這3個(gè)變量的值來(lái)控制顯示和輸出。這時(shí)候的代碼結(jié)構(gòu)就是這種樣子的了——各個(gè)模塊分開(kāi),用關(guān)鍵參數(shù)傳遞信息

          • 51hei6.jpg
          • 所謂的“模塊化,降低耦合度”大致就是這種感覺(jué),現(xiàn)在你需要在哪里改動(dòng)就單獨(dú)改動(dòng)哪個(gè)部分的,不至于瞻前顧后、束手束腳了。
        • 還沒(méi)完呢,第二步,把我們的“時(shí)基”弄進(jìn)來(lái)(不然上一堂課就白講了),如圖所示: 51hei7.jpg
          • 如此一來(lái),關(guān)于那些指定時(shí)間的、指定頻率的要求,我們也能輕松的應(yīng)對(duì)了。比如這時(shí)候的display()函數(shù),可以這樣寫(xiě)(這個(gè)其實(shí)還有缺陷,不過(guò)先湊合一下)——
          • 51hei8.jpg

      • 相信通過(guò)這樣一個(gè)例子,大家應(yīng)該能看到模塊化對(duì)你的軟件系統(tǒng)有多大的改善了。模塊間的耦合度降低之后,自有一種九陽(yáng)神功中的“他強(qiáng)由他強(qiáng),清風(fēng)拂山崗。它弱由他弱,明月照大江。”的感覺(jué)。你那邊愛(ài)怎么變就怎么變,我這邊有必要就改動(dòng),沒(méi)必要就不改動(dòng),將彼此間的影響減到最低。
      • 時(shí)間有限,模塊化的解說(shuō)先到這里,后續(xù)有時(shí)間會(huì)將狀態(tài)機(jī)等知識(shí)盡可能的講解給大家。同時(shí)還得把這個(gè)需求變更后的《電風(fēng)扇系統(tǒng)設(shè)計(jì)2》的軟件給寫(xiě)完。
      • ——2019年6月11日 ,今天沒(méi)空更貼,暫時(shí)先優(yōu)化一下排版——
      • ——2019年6月14日,修復(fù)了教程中的keyPress()和display()函數(shù)中的兩個(gè)靜態(tài)變量忘了加static關(guān)鍵字的bug——
      • ——2019年6月16日,更新,狀態(tài)機(jī)上篇 ——
      • part3.使用狀態(tài)機(jī),幫助你管理系統(tǒng)狀態(tài)(上篇)
      • (本章較為復(fù)雜,需要讀者有較好的數(shù)電和C語(yǔ)言功底,方能融匯貫通)
      • - 狀態(tài)機(jī)入門(mén)(有基礎(chǔ)的可以跳過(guò)本小節(jié)) -
        • 直白的說(shuō),狀態(tài)機(jī)就是若干個(gè)“當(dāng)前狀態(tài) + 觸發(fā)條件 = 新?tīng)顟B(tài)( + 附加動(dòng)作)”的公式。
        • 狀態(tài)機(jī)可以畫(huà)成圖的形式(《狀態(tài)遷移圖》),也可以做成表格的形式(《狀態(tài)分析表》),如果大家還有數(shù)字電子技術(shù)的功底的話,應(yīng)該對(duì)下圖還不至于太陌生。
          • 51hei9.jpg
          • ↑此為某狀態(tài)遷移圖舉例(與下表同義) 51hei10.jpg
          • ↑此為某狀態(tài)分析表舉例(與上圖同義)
        • 如果上述圖表使用公式來(lái)表達(dá)的話那就是4個(gè)公式(取決于圖的箭頭數(shù),或者表的跳轉(zhuǎn)數(shù)),用公式的話,公式的數(shù)量不但多,看起來(lái)也很麻煩,所以我們一般用《圖》或者《表》來(lái)描述你的狀態(tài)機(jī)。
        • 注意,一般的狀態(tài)機(jī)是包含“動(dòng)作”的,這里為了教學(xué)方便,略過(guò)了“動(dòng)作”(后面會(huì)加回來(lái)的)。
        • 狀態(tài)機(jī)的使用有助于我們更直接,更便捷的管理我們的系統(tǒng)工作。尤其是在系統(tǒng)比較復(fù)雜的時(shí)候。
      • - 用程序來(lái)表現(xiàn)狀態(tài)機(jī) -
        • 狀態(tài)用枚舉量為佳,因?yàn)槲覀儜?yīng)當(dāng)保證系統(tǒng)的狀態(tài)處于可控范圍內(nèi),枚舉量是我們工程師自定義的一個(gè)量,可以使系統(tǒng)處處受我們控制。
        • 觸發(fā)條件用bit變量即可,觸發(fā)了就是1,沒(méi)觸發(fā)就是0;當(dāng)然char之類(lèi)也可以,但沒(méi)必要。
          • 有基礎(chǔ)的同學(xué)可以使用"位結(jié)構(gòu)體"來(lái)優(yōu)化這些觸發(fā)條件的內(nèi)存,這里不提,請(qǐng)自行百度。
        • ok,那現(xiàn)在可以先定義我們的狀態(tài)機(jī)變量了(以上述圖表為例)。
            1. typedef enum{
            2.     STATE1,
            3.     STATE2,
            4.     STATE3
            5. }ENUM_STATE;     //定義ENUM_STATE枚舉類(lèi)型,表狀態(tài)
            6. ENUM_STATE system_state = STATE1;    //定義上述枚舉類(lèi)型的枚舉變量system_state, 初始化為STATE1
            7. bit test_flag_a,  test_flag_b, test_flag_c;   //定義3個(gè)觸發(fā)條件的bit變量。
            復(fù)制代碼

        • 那么,狀態(tài)機(jī)的程序要怎么寫(xiě)呢?其實(shí)我們觀察《狀態(tài)分析表》的時(shí)候,有人會(huì)喜歡根據(jù)當(dāng)前狀態(tài),分析觸發(fā)條件,來(lái)決定下一刻的狀態(tài);有人會(huì)喜歡從觸發(fā)條件開(kāi)始,看看現(xiàn)在的狀態(tài)是否受這種觸發(fā)條件影響,而進(jìn)入新的狀態(tài)
        • ——好吧,有兩種觀察方法,就有2種寫(xiě)法,讀者可以自由選擇自己喜歡的寫(xiě)法。
          • 寫(xiě)法1(根據(jù)當(dāng)前狀態(tài),看觸發(fā)條件是否有效):
            1. void systemStateCtrl(){
            2.     switch(system_state){
            3.         case STATE1:
            4.             if(test_flag_b) system_state = STATE2;
            5.         break;
            6.         case STATE2:
            7.             if(test_flag_a) system_state = STATE1;
            8.             else if(test_flag_c) system_state = STATE3;//條件a比條件c優(yōu)先
            9.         break;
            10.         case STATE3:
            11.             if(test_flag_a) system_state = STATE1;
            12.         break;
            13.         default:
            14.         break;
            15.     }
            16. }
            復(fù)制代碼


          • 寫(xiě)法2(根據(jù)觸發(fā)條件,看當(dāng)前狀態(tài)是否需要改變):
            1. void systemStateCtrl(){
            2.     if(test_flag_a){
            3.         if(system_state==STATE2 || system_state==STATE3)
            4.             system_state = STATE1;
            5.     }
            6.     else if(test_flag_b){
            7.         if(system_state==STATE1)
            8.             system_state = STATE2;
            9.     }
            10.     else if(test_flag_c){
            11.         if(system_state==STATE2)
            12.             system_state = STATE3;
            13.     }
            14.     else{
            15.         ;
            16.     }
            17. }
            復(fù)制代碼

        • 這2種寫(xiě)法各有特點(diǎn),并沒(méi)有優(yōu)劣之分,各位可以自取所需。非要比較的話,我個(gè)人認(rèn)為:第一種寫(xiě)法"好讀一些",第二種寫(xiě)法"好寫(xiě)一些"。
      • - 根據(jù)狀態(tài)的值,控制系統(tǒng)的工作流 -
        • “系統(tǒng)的工作”很好理解,就是系統(tǒng)現(xiàn)在在干什么的意思,那么“系統(tǒng)的工作流”是什么意思?
        • ——系統(tǒng)的工作流,表示系統(tǒng)在某段時(shí)間內(nèi)的工作流程。
        • ——為什么要普及“工作流”這個(gè)東西呢?
        • ——因?yàn)椋芏嗲闆r下,某個(gè)狀態(tài)的工作不是寫(xiě)死的,而是可變的。比如:冰箱在制冷時(shí),制冷器并不是一直開(kāi)著的,而是一段時(shí)間開(kāi),一段時(shí)間關(guān);洗衣機(jī)在洗衣服時(shí),滾筒不是一直開(kāi)著的,而是先等注水完成之后,正著轉(zhuǎn)一段時(shí)間,然后反著轉(zhuǎn)一段時(shí)間,然后又正著轉(zhuǎn)……就是有一系列的工作步驟,這些工作的步驟其實(shí)就是我們所說(shuō)的工作流。
        • 如果你非要把洗衣機(jī)在洗衣服時(shí),滾筒正著轉(zhuǎn)和反著轉(zhuǎn)分成2種新的狀態(tài)的話……一路走好。
        • 總之,為了給狀態(tài)下的動(dòng)作有一定的預(yù)留空間(因?yàn)?/font>天知道,需求會(huì)不會(huì)發(fā)生變化),我們需要給每個(gè)狀態(tài)都做一套關(guān)于此狀態(tài)下的動(dòng)作的設(shè)計(jì)
        • 這個(gè)程序?qū)懫饋?lái)也很簡(jiǎn)單,嵌入位置上,直接塞進(jìn)狀態(tài)機(jī)的屁股后面就行。如下:
          1. /* 狀態(tài)機(jī)程序 */
          2. void systemStateCtrl(){
          3.     //你的狀態(tài)機(jī)程序
          4.     systemStateWork();//把狀態(tài)工作程序放這里
          5. }
          6. /* 狀態(tài)工作程序 */
          7. void systemStateWork(){ //設(shè)計(jì)你各個(gè)狀態(tài)下的工作
          8.     switch(system_state){
          9.         case STATE1:
          10.             do_sth1();break;
          11.         case STATE2:
          12.             do_sth2();break;
          13.         case STATE3:
          14.             do_sth3();break;
          15.         default:
          16.             break;
          17.     }
          18. }
          復(fù)制代碼

      • - 例程:《電風(fēng)扇系統(tǒng)設(shè)計(jì)2》的狀態(tài)機(jī)初版 -
        • 狀態(tài)機(jī)真的是一個(gè)很龐大的知識(shí)點(diǎn)啊,好不容易把理論說(shuō)完了,接下來(lái)諸位看看我的實(shí)例吧。
        • 這個(gè)系統(tǒng)設(shè)計(jì)的需求我就不再重復(fù)了,各位往回看一看就能找到,關(guān)鍵在于,需求③我們還未處理【③開(kāi)風(fēng)扇后若是5小時(shí)內(nèi)按鍵都沒(méi)有變化過(guò),則自動(dòng)關(guān)掉風(fēng)扇(避免久開(kāi),當(dāng)然此后LED也要閃爍),若想重開(kāi)風(fēng)扇必須把“風(fēng)扇開(kāi)關(guān)按鍵”先關(guān)掉再打開(kāi)才行。】。
        • 那么開(kāi)始吧,我們?cè)谝婚_(kāi)始,會(huì)將系統(tǒng)的狀態(tài)分成“風(fēng)扇開(kāi)”和“風(fēng)扇關(guān)”兩種,直接由風(fēng)扇的開(kāi)機(jī)鍵控制切換。但是,多了新的需求之后,開(kāi)機(jī)鍵就不好使了——因?yàn)橛蟹N“風(fēng)扇關(guān)”的狀態(tài),這時(shí)候的開(kāi)機(jī)鍵也是按下的!經(jīng)過(guò)一番思索,為了和真正的“風(fēng)扇關(guān)”作區(qū)別,我們可以再創(chuàng)造一種新的狀態(tài)——“停機(jī)”!也就是開(kāi)機(jī)太久了,需要停機(jī)休息。停機(jī)時(shí)候的搖頭鍵,強(qiáng)弱風(fēng)鍵都無(wú)效,只有開(kāi)機(jī)鍵松開(kāi),才能讓你退出“停機(jī)”,進(jìn)入"關(guān)機(jī)"。
        • 根據(jù)我們的分析,可以畫(huà)出系統(tǒng)的狀態(tài)遷移圖:
        • 51hei11.jpg
        • 同樣的,狀態(tài)分析表。
        • 51hei12.jpg
        • 相關(guān)程序如下
        • typedef enum{
              STATE_OFF,
              STATE_ON,
              STATE_STOP
          }ENUM_STATE;     //定義ENUM_STATE枚舉類(lèi)型
          ENUM_STATE system_state = STATE_OFF; //定義枚舉變量system_state, 初始化為STATE_OFF
          bit key_on_flag, key_off_flag, work_too_long_flag; //定義3個(gè)觸發(fā)條件的bit變量(其實(shí)用2個(gè)就行)
          void systemStateCtrl(){
              if(key_on_flag){
                  if(system_state==STATE_ON || system_state==STATE_STOP)
                      system_state = STATE_OFF;
              }
              else if(key_off_flag){
                  if(system_state==STATE_OFF)
                      system_state = STATE_ON;
              }
              else if(work_too_long_flag){
                  if(system_state==STATE_ON)
                      system_state = STATE_STOP;
              }
              else{
                  ;
              }
              systemStateWork();//把狀態(tài)工作程序放這里
          }
          void systemStateWork(){ //設(shè)計(jì)你各個(gè)狀態(tài)下的工作
              switch( system_state ){
                  case STATE_OFF:
                      do_sth1();    //關(guān)機(jī)時(shí)的工作
                  break;
                  case STATE_ON:
                      do_sth2();    //開(kāi)機(jī)時(shí)的工作
                  break;
                  case STATE_STOP:
                      do_sth3();    //超時(shí)停機(jī)時(shí)的工作
                  break;
                  default:
                  break;
              }
          }


          • 現(xiàn)在,我們從《電風(fēng)扇系統(tǒng)設(shè)計(jì)2》的需求出發(fā),解析系統(tǒng)的狀態(tài);再作圖表(其實(shí)圖和表做一個(gè)就行,這里為了解讀需要,都做了出來(lái)),將狀態(tài)機(jī)的大體結(jié)構(gòu)都描述出來(lái);這時(shí)候?qū)懜鱾(gè)狀態(tài)下的工作程序,就是水到渠成的事情了。

      • - 狀態(tài)機(jī)小結(jié) -
        • 狀態(tài)機(jī)確實(shí)是個(gè)比較長(zhǎng)的教程,所以我將之分成了2部分來(lái)解說(shuō),第一部分只強(qiáng)調(diào)“狀態(tài)+條件=新?tīng)顟B(tài)”這一部分,目的是讓大家先對(duì)狀態(tài)機(jī)有個(gè)初步的認(rèn)知;第二部分再來(lái)描述“狀態(tài)+條件=新?tīng)顟B(tài)+動(dòng)作”的完整的狀態(tài)機(jī)。
        • 眼尖的貼友應(yīng)該也發(fā)現(xiàn)了,這里為了解說(shuō)方便,還沒(méi)有將“強(qiáng)弱風(fēng)”,“是否擺頭”等動(dòng)作做進(jìn)狀態(tài)機(jī)里。不過(guò)他們其實(shí)只是一些“動(dòng)作”而已,在開(kāi)始分析系統(tǒng)的狀態(tài)時(shí),我們要分清楚系統(tǒng)的“主要?jiǎng)幼鳌焙汀按我獎(jiǎng)幼鳌保瑢?duì)于電風(fēng)扇而言,開(kāi)和關(guān)是主要的動(dòng)作,擺頭和強(qiáng)弱風(fēng)只是一些次要的附加動(dòng)作罷了。
        • 關(guān)于如何劃分系統(tǒng)的主要狀態(tài)?
        • ——這也是一個(gè)值得拿來(lái)長(zhǎng)篇大論的話題,但我這里不想深入探討,也無(wú)力深入探討。因?yàn)椤皩⒅付ㄎ锲贩诸?lèi)”,或者“請(qǐng)給蘋(píng)果,梨,水果,蔬菜,白菜,豆腐,白板筆這幾個(gè)詞進(jìn)行排序”這類(lèi)問(wèn)題本就有無(wú)數(shù)解法,是很看重解答者的主觀意識(shí)的。
        • 熟練掌握狀態(tài)機(jī)的用法,可以使你能夠更準(zhǔn)確的把握系統(tǒng)的狀態(tài)
        • 本章未完,此外,由于我的個(gè)人原因,狀態(tài)機(jī)的下篇只能保證在今年7月15日前更新,還請(qǐng)各位諒解。屆時(shí)會(huì)將本教程劃上一個(gè)完美的句號(hào),同時(shí)各種源碼等也會(huì)打包上傳。

評(píng)分

參與人數(shù) 32黑幣 +476 收起 理由
kusp + 30 絕世好帖!
June_aa + 5 很給力!
Fance9988 + 5
youziwb + 20
hqh8001 + 10 很給力!
130boby + 5 絕世好帖!
gqzjl + 15 絕世好帖!
stone2018 + 5
ko44 + 11 很給力!
wjl520oo + 12 很給力!
ag26259 + 6 絕世好帖!
leooo + 30 絕世好帖!
13487086265 + 12 絕世好帖!
hxszrb + 10 很給力!
大膽1 + 10 很給力!
digger + 15 絕世好帖!
菜鳥(niǎo)yc + 5 贊一個(gè)!
cheng95 + 30
wfqxgw + 5
1255230 + 5 共享資料的黑幣獎(jiǎng)勵(lì)!
fl1983 + 30 很給力!
莫燁 + 10 贊一個(gè)!
梁廷明 + 4 淡定
5083 + 5 贊一個(gè)!
wps10025 + 9 好貼子

查看全部評(píng)分

回復(fù)

使用道具 舉報(bào)

ID:476527 發(fā)表于 2019-6-6 16:41 | 顯示全部樓層
如果有需要,我可以把相關(guān)的主程序和架構(gòu)打包上傳……不過(guò)說(shuō)實(shí)話這些代碼隨便敲敲就有了,需要鍛煉的是一種“精準(zhǔn)控制”軟件的邏輯的思維。
跑快了的東西我們把它放慢些,跑慢了的東西給它放快些。
對(duì)于一個(gè)系統(tǒng)來(lái)說(shuō),“平衡”是很重要的事情。

最后再說(shuō)一句,while(1)大循環(huán)里面不要放“delay();”或者“while(按鍵被按下);”了……
回復(fù)

使用道具 舉報(bào)

ID:476527 發(fā)表于 2019-7-7 19:26 | 顯示全部樓層
很抱歉的告訴大家,之前的想法還是太樂(lè)觀,現(xiàn)在每天忙成狗,完全不確定啥時(shí)候能抽時(shí)間寫(xiě)完,7月15日要是沒(méi)有更新的話還請(qǐng)大家諒解。

不過(guò)我是不會(huì)就這么停筆的,只是不知道啥時(shí)候有時(shí)間寫(xiě)而已。作為打工仔,真的身不由己。
為了不辜負(fù)大家的期待,下次更新時(shí)我會(huì)把文檔做成pdf,附帶源碼,流程圖,表格一并上傳。

其實(shí)還有很多可以寫(xiě)的地方,但是現(xiàn)在這篇帖子就寫(xiě)這3點(diǎn)——時(shí)基,模塊化,狀態(tài)機(jī)——已經(jīng)夠大家消化一陣子了。而且,如果帖子的篇幅太長(zhǎng)了,其實(shí)不利于閱讀的。
以后如果還有別的分享,我會(huì)另開(kāi)帖子的,多蹭點(diǎn)管理員的黑幣,哈哈。
回復(fù)

使用道具 舉報(bào)

ID:476527 發(fā)表于 2019-8-2 20:36 | 顯示全部樓層
ccdmcu 發(fā)表于 2019-8-2 16:22
按鍵的松手檢測(cè)呢?怎么用定時(shí)器寫(xiě)?

我不是給了個(gè)keyPress()程序么,你再好好看看。
簡(jiǎn)單來(lái)說(shuō),有鍵按下時(shí),時(shí)間就會(huì)++;
無(wú)鍵按下時(shí),時(shí)間就會(huì)清零。
但在清零之前會(huì)先檢查,時(shí)間是否大于0,時(shí)間值大于0(或者消抖值)說(shuō)明曾經(jīng)有鍵按下過(guò),并且剛剛松開(kāi)。這時(shí)候處理“這次按鍵”不就好了。
回復(fù)

使用道具 舉報(bào)

ID:385637 發(fā)表于 2019-8-10 10:38 | 顯示全部樓層
樓主這文章比那些所謂的教科書(shū)好多了,那些教科書(shū)按鍵消抖動(dòng)不動(dòng)就是delay(20ms),真是誤人子弟,真正出來(lái)做到大型項(xiàng)目才知道 DELAY是多么不實(shí)際。希望樓主繼續(xù)更新,最好轉(zhuǎn)成PDF,多點(diǎn)例程,尤其是一些按鍵的,短按,長(zhǎng)按,雙擊組合鍵例程。現(xiàn)在絕大部份寫(xiě)按鍵程序都喜歡delay消抖,while松手檢測(cè)。郭天詳?shù)臅?shū)也是這么教的,一點(diǎn)不實(shí)用
回復(fù)

使用道具 舉報(bào)

ID:476527 發(fā)表于 2019-8-12 11:46 | 顯示全部樓層

確實(shí)不會(huì)“小于”0,但“等于”0是有可能的喔,所以這樣寫(xiě)是沒(méi)問(wèn)題的。
至于為什么我寫(xiě)了“<=",而不是”==“呢?
理由是 —— 容錯(cuò)機(jī)制:
萬(wàn)一手殘了,在定義key_press_time的時(shí)候忘記加了unsigned,我們的按鍵程序照樣可以正常工作(只是計(jì)數(shù)最大值只有原來(lái)的一半了)
回復(fù)

使用道具 舉報(bào)

ID:476527 發(fā)表于 2019-8-14 14:12 | 顯示全部樓層
本帖最后由 Similarv 于 2019-8-15 10:40 編輯
IdeaMing 發(fā)表于 2019-8-14 10:27
我想問(wèn),怎么把DS18B20的加入到你這種機(jī)制里?一次通訊時(shí)間都要好幾毫秒

這個(gè)好說(shuō),把基礎(chǔ)時(shí)基變成10ms(或者20ms),也就是定時(shí)器中斷10ms(或者20ms)產(chǎn)生一次。
然后就是……
  1. unsigned char flag10ms=0,flag100ms=0;
  2. void t0Init()
  3. { /*略*/}
  4. void t0Xint() Interrupt n
  5. {
  6.     flag10ms = 1;//10ms產(chǎn)生一次中斷
  7. }
復(fù)制代碼



回復(fù)

使用道具 舉報(bào)

ID:476527 發(fā)表于 2019-8-19 01:00 來(lái)自手機(jī) | 顯示全部樓層
IdeaMing 發(fā)表于 2019-8-16 16:25
如果同時(shí)存在數(shù)碼管的刷新呢,比如一秒讀一次18B20,讀的時(shí)候數(shù)碼管的刷新就被卡了一下

我剛剛特意去查了一下,這玩意僅僅是個(gè)溫度傳感器,而且還特么是數(shù)字的,讀一次溫度居然至少要5Ms?!(還不確定是否會(huì)更久)
這樣,如果你有示波器的話,請(qǐng)你做這么一個(gè)實(shí)驗(yàn),把單片機(jī)某個(gè)端口設(shè)為輸出,這個(gè)端口平時(shí)是低電平,然后用18b20讀取溫度之前拉高它,讀取結(jié)束的時(shí)候又拉低它,然后用示波器好好的看看這個(gè)端口被拉高的時(shí)間,你就知道它每次采溫需要多長(zhǎng)時(shí)間了。再結(jié)合其他子程序的工作時(shí)長(zhǎng),設(shè)計(jì)你的時(shí)基。
其實(shí),這種數(shù)字型溫度傳感器在我們實(shí)際做項(xiàng)目的人的眼里,只有華而不實(shí)四個(gè)字可以評(píng)價(jià)。如果我們的項(xiàng)目里需要測(cè)溫,我們一般會(huì)采用內(nèi)部自帶adc模塊的單片機(jī),測(cè)溫只要一個(gè)熱敏電阻就可以搞定。整個(gè)測(cè)溫的時(shí)間只需大約10us。不但更便宜,精度更好,效率還是你那個(gè)測(cè)溫模塊的500倍!具體方案這里就不贅述了。
回復(fù)

使用道具 舉報(bào)

ID:476527 發(fā)表于 2020-1-13 16:52 | 顯示全部樓層
本帖最后由 Similarv 于 2020-1-13 18:07 編輯
13303022280 發(fā)表于 2020-1-7 14:29
如果我只需要執(zhí)行一次按鍵之后的程序,為了避免按鍵長(zhǎng)按導(dǎo)致的重復(fù)運(yùn)行,就用一個(gè)變量,在每次進(jìn)入中斷檢 ...

你的做法當(dāng)然也沒(méi)有問(wèn)題,不過(guò)我是這么做的:
按鍵就只是做按鍵檢測(cè),并且設(shè)置相應(yīng)的“按鍵已觸發(fā)”標(biāo)志(bit變量);至于按鍵的功能則是在別處比如狀態(tài)機(jī)中去執(zhí)行。
例子:當(dāng)按鍵按下之后開(kāi)/關(guān)燈

key.c 文件:
bit key_flag_light;  //當(dāng)按鍵觸發(fā)時(shí)為1,否則為0, 此變量是給狀態(tài)機(jī)使用的
static bit key_press_light; //當(dāng)按鍵按下時(shí)為1,未按下為0,此變量?jī)H在key.c內(nèi)使用。
函數(shù)1-keyScan()  -- 功能:檢測(cè)按鍵是否按下,若按鍵按下則將key_press_light置一,否則清零。
函數(shù)2-keyDeal()   -- 功能:使用某靜態(tài)變量統(tǒng)計(jì)key_press_light的時(shí)間;當(dāng)key_press_light從1變?yōu)?的時(shí)候,檢查靜態(tài)變量的值是否大于消抖值,若大于消抖時(shí)間則將key_flag_light設(shè)置為1;

state.c文件
函數(shù)1-StateMachine() -- 功能:當(dāng)key_flag_light==1時(shí),取反led_flag_out的值,隨后將key_flag_light設(shè)置為0.

led.c文件
bit led_flag_out; //當(dāng)該值==1,開(kāi)燈;當(dāng)該值==0;關(guān)燈
函數(shù)1-ledOutput() -- 功能:根據(jù)led_flag_out的取值開(kāi)燈或者關(guān)燈

main.c文件
在10ms或者20ms的時(shí)基中依次調(diào)用
keyScan();
keyDeal();
StateMachine();
在100ms的時(shí)基中調(diào)用
ledOutput();

/******/
稍微修改一下,剛剛沒(méi)有認(rèn)真審題,你需要做長(zhǎng)按的判定,我這個(gè)架構(gòu)是基于短按的。
修改的地方位于keyDeal()部分,
短按 —— 是等待按鍵松開(kāi)時(shí)裁決靜態(tài)變量的計(jì)時(shí)值。
長(zhǎng)按 —— 則是直接在靜態(tài)變量等于‘長(zhǎng)按時(shí)間點(diǎn)’的時(shí)刻將key_flag_light置一即可。key_flag_light==1的時(shí)候,狀態(tài)機(jī)自然會(huì)處理長(zhǎng)按事件,此后keyDeal()里的靜態(tài)變量會(huì)在按鍵繼續(xù)按著的時(shí)候繼續(xù)加,但其值已經(jīng)‘大于’‘長(zhǎng)按時(shí)間點(diǎn)’了,所以key_flag_light不會(huì)被重復(fù)置一,當(dāng)按鍵釋放之后,此靜態(tài)變量清零,一切重新開(kāi)始。


回復(fù)

使用道具 舉報(bào)

ID:476527 發(fā)表于 2020-1-13 17:46 | 顯示全部樓層
hubj627 發(fā)表于 2020-1-13 09:20
這種針對(duì)代碼量小的項(xiàng)目實(shí)時(shí)性沒(méi)有問(wèn)題。但代碼量大的整個(gè)程序架構(gòu)就會(huì)顯得臃腫,也需針對(duì)同一個(gè)事情,在主 ...

進(jìn)階教程尚待壇友們自己修行,鄙人不才,只能帶路到這了
回復(fù)

使用道具 舉報(bào)

ID:521890 發(fā)表于 2019-6-6 20:53 | 顯示全部樓層
很好的文章,請(qǐng)繼續(xù)。感謝!
回復(fù)

使用道具 舉報(bào)

ID:464755 發(fā)表于 2019-6-7 00:36 | 顯示全部樓層
我對(duì)delay1s(); delay500ms()這樣的延時(shí)函數(shù)就很不爽,當(dāng)然程序流程很簡(jiǎn)單的,用用也沒(méi)什么,如果是一個(gè)還算比較長(zhǎng)的程序,使用delay1s(); delay500ms()這種就是在人為遲滯片子的運(yùn)行,響應(yīng)不過(guò)來(lái)又要罵,完全不會(huì)看自己做的程序?qū)懙氖鞘裁垂?p。你可以發(fā)現(xiàn),凡是這樣搞的,里面的變量,定義亂七八糟,想怎么寫(xiě)就怎么寫(xiě)。只要編譯的過(guò),不求后面優(yōu)化。
以前的專(zhuān)業(yè)程序員,可是對(duì)單片機(jī)了如指掌,每一點(diǎn)一滴的性能,一個(gè)字節(jié)都很珍惜,寫(xiě)的程序兼職就是藝術(shù)品。
之前我們這也有個(gè)做機(jī)構(gòu)設(shè)計(jì)的,畫(huà)的加工件,完全不考慮加工難度,想怎么畫(huà)就怎么畫(huà),機(jī)構(gòu)極度粗 暴yu 蠢,我看不下去了,問(wèn)他還就一句話,加工不管我的事,一個(gè)月不到就讓他滾 蛋了。
回復(fù)

使用道具 舉報(bào)

ID:435708 發(fā)表于 2019-6-7 00:42 | 顯示全部樓層
真的是好文章,對(duì)51定時(shí)器的理解更深了,原來(lái)程序還能這么寫(xiě)
回復(fù)

使用道具 舉報(bào)

ID:476527 發(fā)表于 2019-6-10 10:04 | 顯示全部樓層
nsush 發(fā)表于 2019-6-7 00:36
我對(duì)delay1s(); delay500ms()這樣的延時(shí)函數(shù)就很不爽,當(dāng)然程序流程很簡(jiǎn)單的,用用也沒(méi)什么,如果是一個(gè)還 ...

哈哈哈,做技術(shù)的可不能只管自己那小小的一畝三分地啊,不去學(xué)習(xí)和進(jìn)步終究要被淘汰的。
還有些人在步入一個(gè)新領(lǐng)域的時(shí)候總是抱著玩一下的心態(tài),勉強(qiáng)能用就行,卻不想把事情做到更好,其實(shí)也是自己限制住了自己的成長(zhǎng)。
回復(fù)

使用道具 舉報(bào)

ID:476527 發(fā)表于 2019-6-10 17:25 | 顯示全部樓層
@admin 這應(yīng)該是個(gè)比較長(zhǎng)的教程,預(yù)計(jì)下下次更新才能寫(xiě)完,屆時(shí)再發(fā)些源碼和參考例程
回復(fù)

使用道具 舉報(bào)

ID:58925 發(fā)表于 2019-6-10 21:08 | 顯示全部樓層
不錯(cuò)的文章,希望有后續(xù)
回復(fù)

使用道具 舉報(bào)

ID:557774 發(fā)表于 2019-6-11 10:13 來(lái)自手機(jī) | 顯示全部樓層
很好,學(xué)習(xí)了,現(xiàn)在實(shí)踐一下
回復(fù)

使用道具 舉報(bào)

ID:342911 發(fā)表于 2019-6-12 11:56 來(lái)自手機(jī) | 顯示全部樓層
學(xué)習(xí)了  很受用  會(huì)慢慢去嘗試應(yīng)用  期待后續(xù)
回復(fù)

使用道具 舉報(bào)

ID:56665 發(fā)表于 2019-6-13 09:04 | 顯示全部樓層
謝謝分享,多發(fā)一些類(lèi)似文章。
回復(fù)

使用道具 舉報(bào)

ID:557550 發(fā)表于 2019-6-13 10:53 | 顯示全部樓層
他們寫(xiě)程序粗的不行,可能自己覺(jué)的學(xué)個(gè)框架就算是學(xué)到了整個(gè)語(yǔ)言的精華,殊不知差得遠(yuǎn)呢。
回復(fù)

使用道具 舉報(bào)

ID:25481 發(fā)表于 2019-6-13 11:30 | 顯示全部樓層
支持持續(xù)更新,很好的東西。
回復(fù)

使用道具 舉報(bào)

ID:104825 發(fā)表于 2019-6-13 12:24 來(lái)自手機(jī) | 顯示全部樓層
好文章,好理論,!通熟易懂!
回復(fù)

使用道具 舉報(bào)

ID:235691 發(fā)表于 2019-6-13 13:46 | 顯示全部樓層
期待樓主的新文章
回復(fù)

使用道具 舉報(bào)

ID:382454 發(fā)表于 2019-6-13 21:19 來(lái)自手機(jī) | 顯示全部樓層
專(zhuān)家講解,學(xué)習(xí)了。
回復(fù)

使用道具 舉報(bào)

ID:557774 發(fā)表于 2019-6-14 02:25 來(lái)自手機(jī) | 顯示全部樓層
感謝樓主,學(xué)習(xí)到了
回復(fù)

使用道具 舉報(bào)

ID:562287 發(fā)表于 2019-6-14 06:48 來(lái)自手機(jī) | 顯示全部樓層
這個(gè)必須加精啊,新手不知道有沒(méi)有收藏功能
回復(fù)

使用道具 舉報(bào)

ID:143924 發(fā)表于 2019-6-14 08:38 | 顯示全部樓層
很不錯(cuò)的文章,啟迪匪淺。
回復(fù)

使用道具 舉報(bào)

ID:168971 發(fā)表于 2019-6-14 09:24 來(lái)自手機(jī) | 顯示全部樓層
好文章!
回復(fù)

使用道具 舉報(bào)

ID:516571 發(fā)表于 2019-6-14 10:18 | 顯示全部樓層
很不錯(cuò)的文章,請(qǐng)繼續(xù)
回復(fù)

使用道具 舉報(bào)

ID:111376 發(fā)表于 2019-6-14 11:31 | 顯示全部樓層
感謝樓主的文章!
回復(fù)

使用道具 舉報(bào)

ID:562693 發(fā)表于 2019-6-14 17:13 來(lái)自手機(jī) | 顯示全部樓層
怎么關(guān)注樓主啊?感覺(jué)寫(xiě)的很有意思
回復(fù)

使用道具 舉報(bào)

ID:461428 發(fā)表于 2019-6-16 11:24 來(lái)自手機(jī) | 顯示全部樓層
新手完全不曉得你說(shuō)的啥玩意
回復(fù)

使用道具 舉報(bào)

ID:476527 發(fā)表于 2019-6-16 12:05 | 顯示全部樓層
kissme 發(fā)表于 2019-6-16 11:24
新手完全不曉得你說(shuō)的啥玩意

那就請(qǐng)新手(自稱(chēng))們加油,這帖子本來(lái)就是進(jìn)階教程,希望他們先將基礎(chǔ)打牢
回復(fù)

使用道具 舉報(bào)

ID:564821 發(fā)表于 2019-6-17 18:05 | 顯示全部樓層
感謝樓主,學(xué)到了很多
回復(fù)

使用道具 舉報(bào)

ID:512205 發(fā)表于 2019-6-17 22:30 | 顯示全部樓層
很不錯(cuò)的文章
回復(fù)

使用道具 舉報(bào)

ID:517235 發(fā)表于 2019-6-18 09:05 | 顯示全部樓層
很好的編程思路,條理清晰,把復(fù)雜的事情簡(jiǎn)單化。
回復(fù)

使用道具 舉報(bào)

ID:509639 發(fā)表于 2019-6-18 12:55 | 顯示全部樓層
好貼!!!
回復(fù)

使用道具 舉報(bào)

ID:559308 發(fā)表于 2019-6-18 16:16 | 顯示全部樓層
送人玫瑰,手有余香
回復(fù)

使用道具 舉報(bào)

ID:307505 發(fā)表于 2019-6-19 15:30 | 顯示全部樓層
很好的技術(shù)貼
回復(fù)

使用道具 舉報(bào)

ID:282431 發(fā)表于 2019-6-20 08:39 | 顯示全部樓層
很好的文章,請(qǐng)繼續(xù)。感謝!
回復(fù)

使用道具 舉報(bào)

ID:467698 發(fā)表于 2019-6-20 10:48 | 顯示全部樓層
樓主經(jīng)驗(yàn)豐富,編程思想總結(jié)的很好,文章寫(xiě)得也很棒,希望可以繼續(xù)分享,感謝!
回復(fù)

使用道具 舉報(bào)

ID:499184 發(fā)表于 2019-6-20 12:01 | 顯示全部樓層
去除按鍵的抖動(dòng) 不用延時(shí)函數(shù)的話,怎么處理
回復(fù)

使用道具 舉報(bào)

ID:476527 發(fā)表于 2019-6-20 13:30 | 顯示全部樓層
tesrsm 發(fā)表于 2019-6-20 12:01
去除按鍵的抖動(dòng) 不用延時(shí)函數(shù)的話,怎么處理

用靜態(tài)變量去統(tǒng)計(jì)按鍵的時(shí)間,隨后對(duì)此時(shí)間進(jìn)行裁決。
延時(shí)只會(huì)讓你的程序卡在那里一段時(shí)間,動(dòng)彈不得。
回復(fù)

使用道具 舉報(bào)

ID:243491 發(fā)表于 2019-6-20 13:46 | 顯示全部樓層
好文章,不知樓主能否弄成pdf格式上傳呢,想保存起來(lái)
回復(fù)

使用道具 舉報(bào)

ID:476527 發(fā)表于 2019-6-20 14:29 | 顯示全部樓層
lianzai 發(fā)表于 2019-6-20 13:46
好文章,不知樓主能否弄成pdf格式上傳呢,想保存起來(lái)

等我抽空把狀態(tài)機(jī)的下半部分寫(xiě)完先再說(shuō)吧
回復(fù)

使用道具 舉報(bào)

ID:140275 發(fā)表于 2019-6-20 18:27 | 顯示全部樓層
這樣就是操作系統(tǒng)的雛形
回復(fù)

使用道具 舉報(bào)

ID:306475 發(fā)表于 2019-6-21 15:13 | 顯示全部樓層
高手,膜拜了。
回復(fù)

使用道具 舉報(bào)

ID:476274 發(fā)表于 2019-6-24 11:34 | 顯示全部樓層
不錯(cuò)學(xué)習(xí)了
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 日韩成人精品在线 | 午夜小电影 | 国产精品一区二区视频 | 操视频网站 | 欧美日本亚洲 | 午夜丰满寂寞少妇精品 | 久久视频免费看 | 国产一区二区三区色淫影院 | 久久久婷婷 | 久久艹免费视频 | 日本人做爰大片免费观看一老师 | 7777在线视频 | 免费成人在线网站 | 欧美国产视频 | 亚洲综合成人网 | 亚洲三区在线 | 成人免费在线观看 | 中文字幕视频在线观看免费 | 欧美一级艳情片免费观看 | 91精品久久久久久久久中文字幕 | 日本免费一区二区三区 | 国产午夜在线 | 久久综合一区二区三区 | 伊人网站 | 一区二区在线免费观看 | 久久成人一区 | 久久久免费毛片 | 亚洲一区中文字幕 | 欧美日韩亚洲一区 | 亚洲综合色婷婷 | 亚洲在线视频 | av网站免费| 国产精品一区二区三区久久 | 在线成人免费视频 | 日韩在线中文字幕 | 日日干夜夜操 | 欧美精品在线免费 | 91精品国产色综合久久 | 男人阁久久 | 91久久爽久久爽爽久久片 | 国产a级毛毛片 |