AVR單片機教程——第三期導語

背景(一)

寒假裏做了一個燈帶控制器:

理想情況下我應該在一個星期內完成這個項目,但實際上它耗費了我幾乎一整個寒假,因為涉及到很多未曾嘗試的方案。在這種不是很趕時間的、可以自定目標、自由發揮的項目中,我喜歡這麼做。

簡要介紹一下這個項目。硬件部分:

  • 12V直流電源供電,開關降壓到4V,LDO降壓到3.3V,三路供電;

  • 使用STM32G030KBT6單片機,基於Cortex-M0+;

  • 12V燈帶用異步降壓驅動;

  • WS2812B燈帶的數據用SPI信號加上一定的邏輯運算生成;

  • OLED屏通過I²C連接單片機;

  • 無定位旋轉編碼器連接定時器的兩個通道。

軟件部分:

  • 用多項式擬合把ADC讀到的值轉換成溫度;

  • 指令與數據調度、兩級流水線式OLED更新策略;

  • 完全自主設計的簡單GUI,包括繪圖與控制邏輯。

大約一半時間花在兩種燈帶的方案驗證上,我製作了兩塊PCB才最終確定以上硬件方案;另有一部分時間花在STM32和HAL的調試上,但這本來就在我的STM32學習計劃中;剩下的主要是OLED和GUI,以及寫不出來時的摸魚行為。

我趕在去學校當天的上午完成了項目,在砍掉一點完成度的前提下。有那麼幾個小時,我很後悔把整個寒假都花在了這個項目上,沒有學該學的數學、寫該寫的博客。但是現在回想起來,這個項目讓我對單片機開發有了新的認識。

背景(二)

曾經AVR單片機教程唯一的讀者要開始獨立做項目了,這是對我文章質量的一次考驗。從我們之間的交流來看,我沒有通過這次考驗——

  • 我說從供電開始思考:通常USB可以提供5V1A,如果需要5V2A,就應該考慮從12V1A轉換。她問如何轉換,於是我給她介紹了降壓轉換器。那麼如何確定電流呢?主要耗電器件是32個LED。按我的思路,也可以說是絕大多數業內人士的思路,每個燈不會超過20mA,加起來640mA,其餘器件耗電忽略,1A肯定是夠的。而她的思路是,算出每個LED的等效電阻,並聯起來,再計算電流。她又問,如果電源是5V2A,但負載只有5V1A,會燒壞嗎?

  • 然後決定用什麼燈。兩年半以前我送給她一個禮物,用32個LED組成一顆心,燈是紅藍交錯的。她想做得比這個高級一點,用32個RGB燈,但這麼多燈的連接是個問題,以及RGB三種顏色之間的亮度匹配。又想到WS2812B,它在功能上很強,但是控制稍微麻煩一點。我提示她可以用PWM來生成控制信號,她又搞不清這裡的PWM和PWM呼吸燈的區別。

  • 可能是因為在第二期里學過OLED屏和u8g2,在電賽中又用過一遍,又收到了帶OLED屏的禮物,她覺得OLED屏很簡單,想在項目中也放一塊。

暫時不作評價,繼續說事。後來又有兩人從博客園後台聯繫我,以成本價拿到了開發板,成為了教程的讀者(至此我已經沒有多餘的開發板了)。一位讀者剛開始學C,他常常問我兩類我不希望他問的問題(請這位讀者不要生氣):一類是與單片機無關的純C語言問題,另一類是與教程進度不符的、我想隱藏的實現細節問題。

他們讓我開始反思教程的內容是否充足、順序編排是否合理。

回顧(一)

他們問我的這些問題,很多也是我曾經困惑的。

預初的那個暑假,我正式學習了C語言。此後,我想寫一個C程序來加密文件,把若干位元組作為一組處理一下,寫進新的文件,就算是加密了。文件長度不一定是整組的,最後一組可能要加入幾個空的位元組,這種現在看來很基礎的控制邏輯,我當時想了很久都寫不出來。

我也長期以來不知道電池充電的電流是如何控制的,在我看來把5V電壓加到3.7V鋰電池上根本不可控啊!後來才知道降壓、參考電流、反饋控制之類的。某些營銷號還說5V2A充電器給5V1A手機充電會造成損壞,也難怪非專業人士容易受誤導了。

高一的那個暑假,我完成了第一個像樣的項目,就是前面提到的那顆心。32個LED分別串聯470Ω排阻,接到4片級聯的74HC595上,用GPIO驅動。放到現在,如果不改變設計目標,我會選擇8*4動態掃描的連接方式,還可能用上一片TM16xx來驅動這個陣列。

按下按鍵切換模式,這個很簡單的功能在當時實現得非常亂:先定義一個宏,每次如果按下按鍵就return,然後在循環中多次調用它。現在我會在定時器中斷里處理按鍵,具體來講還有多種方法。

這些不懂的問題、不好的實現,都是經驗。有些不好的實現,比如上面這個按鍵,不值得嘗試,所以我會在回答相關問題時提供我認為合理的方法。類似的有很多,所以我一直儘力回答每個問題,幫人避雷,也好讓我審視一下自己的方法。

回顧(二)

AVR單片機教程的一期介紹了簡單外設的用法。我假設讀者有良好的C語言基礎,所以沒有把基礎單片機和基礎C語言結合起來講,而是在前幾講的作業題中對讀者的C功底提出了較高的要求。針對當時讀者的問題,我專門寫了一篇元教程,強調了要廣泛地了解相關知識。

從按鍵開始我加快了節奏,否則按照一個LED都能寫4篇的速度我現在大概剛剛講到LCD1602。原計劃一期結束後還有大量內容,但是我當時已經不大想寫了,所以挑了點必要的組成了第二期的6講。

現在有讀者反映第二期太難,其實不是太難而是兩期之間有明顯斷層。在與讀者交流的過程中,我還發現有很多我強調過的點還強調得不夠:有些是我沒講清楚,有些是讀者真的做不到,比如完成作業——我把很多關鍵的、實際應用中需要的問題放在了作業中,它們容易被忽略,至少沒有被足夠嚴肅地對待。

這些問題,以及上面帶有責怪情感的讀者提問,都是我的失職。

展望

我決定開始寫AVR單片機教程第三期。

首先是查漏補缺,這還得再細分幾類:

  • 外設。I²C和定時器輸入在前兩期的正文中沒有涉及到,會在第三期補上。

  • 語言。我不應假設讀者有良好的C基礎,但我真的沒法面對完完全全的新手,所以我將補充一些非單片機編程中不常用的特性,以及高級但實用的用法。

    第三期的很多內容用C++講起來會更加方便,所以我會簡單介紹那些需要用的C++語法,它們也是我在自己項目中常用的C++功能子集。

  • 作業。如前所述,很多重要的內容都在作業里,我將提供解題思路和優化建議。

然後是結構:

  • 與C++綁定起來的對象的概念,包括基於對象與面向對象;

  • 第二期最後提到的事件驅動範式,原本是單獨的一期,將成為第三期的一部分;

  • 有些硬件結構可以啟發設計(有的可能最初來自軟件),包括雙緩衝、FIFO、狀態機、流水線等;

  • 大型程序和庫的結構。

此外,單片機項目的共同問題,比如供電、制板、測試等,也會集中講解一下。

由此可見,這一期「AVR單片機教程」實際上可以把前三個字去掉,儘管我們還是基於AVR平台講解。

我設計了新的開發板,與第一版相比縮小了尺寸,去掉了部分擴展資源,使它更加核心。擴展資源被移動到了單獨的模塊上,多個模塊提供不同方向的器件。

原來的開發板仍然提供支持。新開發板有開放小批量訂購的計劃,目前還在原型設計階段。因此,我將從不依賴於AVR的C和C++開始。

希望第三期能為讀者建立完善的概念,能讓讀者學會必要的單片機編程方法,在例子中積累經驗,獨立設計並製作出與文首項目難度相當的單片機系統。

Tags: