電機(jī):從接線到加減速的工程實(shí)戰(zhàn))
簡(jiǎn)介本資源是一套基于STM32F103C8T6微控制器驅(qū)動(dòng)28BYJ-48五線四相步進(jìn)電機(jī)的完整嵌入式開(kāi)發(fā)工程面向嵌入式初學(xué)者與機(jī)電控制實(shí)踐者解決步進(jìn)電機(jī)精準(zhǔn)啟停、正反轉(zhuǎn)及速度調(diào)節(jié)等核心控制問(wèn)題適用于智能小車(chē)、3D打印定位模塊、自動(dòng)化演示裝置等教學(xué)與原型開(kāi)發(fā)場(chǎng)景。壓縮包共261個(gè)文件含114個(gè)頭文件.h定義外設(shè)與電機(jī)接口、69個(gè)源文件.c實(shí)現(xiàn)HAL庫(kù)驅(qū)動(dòng)邏輯、定時(shí)器PWM脈沖生成及ULN2003達(dá)林頓陣列控制時(shí)序另有編譯中間文件.o/.d、鏈接腳本.sct、可執(zhí)行鏡像.hex/.axf及Keil工程配置.uvprojx整體大小7.04MB。已有2515人學(xué)習(xí)下載提供從電路連接、步進(jìn)序列查表法實(shí)現(xiàn)、細(xì)分邏輯預(yù)留到中斷式速度閉環(huán)的完整代碼結(jié)構(gòu)特別包含多外設(shè)HAL驅(qū)動(dòng)TIM/UART/I2C/SPI/ADC等共存適配便于理解資源協(xié)同與實(shí)時(shí)性約束下的電機(jī)控制工程實(shí)踐。 如果你剛拿到一塊28BYJ-48步進(jìn)電機(jī)手頭又正好有一塊STM32開(kāi)發(fā)板大概率你會(huì)去搜“STM32控制步進(jìn)電機(jī)28BYJ-48”下載一個(gè)工程包燒錄看它轉(zhuǎn)起來(lái)。我當(dāng)年就是這么入門(mén)的。但轉(zhuǎn)起來(lái)之后真正的問(wèn)題才開(kāi)始為什么它轉(zhuǎn)得比蝸牛還慢為什么正反轉(zhuǎn)切換時(shí)經(jīng)常卡一下甚至停擺為什么同樣的代碼在別人那兒順滑到我這兒電機(jī)抖兩下就罷工這篇文章把我調(diào)這塊電機(jī)從入門(mén)到踩坑再到沉淀出一套工程做法的過(guò)程整理出來(lái)涉及硬件連接、換相時(shí)序、定時(shí)器驅(qū)動(dòng)、加減速和常見(jiàn)故障排查。壓縮包里的工程建議邊看邊對(duì)照很多坑文字里說(shuō)再多不如你在調(diào)試時(shí)親手復(fù)現(xiàn)一遍來(lái)得深刻。1. 先搞懂28BYJ-48的真實(shí)身份四相五線減速電機(jī)1.1 四相五線到底是什么28BYJ-48這個(gè)名字拆開(kāi)看28是機(jī)座直徑28mmBYJ是永磁步進(jìn)電機(jī)的類(lèi)型代號(hào)48這個(gè)數(shù)字在很多資料里被解釋成減速比1:48但實(shí)際驅(qū)動(dòng)時(shí)芯片資料上標(biāo)得更貼近現(xiàn)實(shí)的參數(shù)是“步距角5.625°/64”。也就是說(shuō)電機(jī)本體和輸出軸之間有一組塑料減速齒輪最終輸出軸的動(dòng)作遠(yuǎn)比轉(zhuǎn)子本身慢。電機(jī)引出5根線紅色是公共端接電源正極橙色、黃色、粉色、藍(lán)色分別對(duì)應(yīng)A、B、C、D四相線圈所以叫四相五線。很多人第一次看到“四相五線”會(huì)以為五根線都要給脈沖實(shí)際上公共端是電源真正需要控制的是四根相線。通過(guò)給四相線圈按不同順序通電轉(zhuǎn)子會(huì)一步步追趕旋轉(zhuǎn)磁場(chǎng)。1.2 減速比和4096步背后的數(shù)學(xué)賬輸出軸轉(zhuǎn)一圈需要多少個(gè)脈沖這是這類(lèi)項(xiàng)目里第一個(gè)必須算明白的賬。電機(jī)本體的步距角是5.625度經(jīng)過(guò)1:64的齒輪箱后輸出軸每收到一拍脈沖轉(zhuǎn)過(guò)5.625/64度。那么一圈就是360 ÷ (5.625 ÷ 64) 4096拍所以“4096步轉(zhuǎn)一圈”不是拍腦袋定的是這么算出來(lái)的。后面寫(xiě)定位程序時(shí)這個(gè)數(shù)字會(huì)反復(fù)用到轉(zhuǎn)90度就是1024拍轉(zhuǎn)45度就是512拍。如果你對(duì)精度有更高要求還要知道一個(gè)細(xì)節(jié)28BYJ-48內(nèi)部齒輪的實(shí)際減速比約是1:63.68395而不是精確的1:64。廠商標(biāo)稱(chēng)64是為了好記普通演示無(wú)所謂但長(zhǎng)時(shí)間反復(fù)累計(jì)步數(shù)后角度誤差會(huì)慢慢變大。真正要求位置長(zhǎng)期可信的項(xiàng)目需要靠限位開(kāi)關(guān)或編碼器做校準(zhǔn)不能只靠開(kāi)環(huán)數(shù)脈沖。它還天生跑不快因?yàn)樵O(shè)計(jì)目標(biāo)就是低轉(zhuǎn)速大扭矩空調(diào)掃風(fēng)葉片、洗衣機(jī)排水閥、智能馬桶翻蓋、自動(dòng)澆灌閥門(mén)全是這種場(chǎng)景。所以別拿它去和42步進(jìn)電機(jī)比轉(zhuǎn)速。我實(shí)測(cè)下來(lái)它的實(shí)用轉(zhuǎn)速大概在15到25RPM之間超過(guò)這個(gè)區(qū)間失步概率明顯上升這也是后面為什么必須考慮加減速的物理前提。2. 硬件連接ULN2003驅(qū)動(dòng)板是如何把“信號(hào)”變“動(dòng)力”的2.1 為什么不能把電機(jī)直接接到STM32的GPIO上28BYJ-48單個(gè)線圈的額定電流在100mA級(jí)別四相全部通電時(shí)峰值可以到200mA以上。而STM32的GPIO輸出能力通常只有幾毫安到二十毫安直接帶電機(jī)輕則帶不動(dòng)重則燒引腳。所以中間必須加驅(qū)動(dòng)板。最常見(jiàn)的驅(qū)動(dòng)板是藍(lán)色或綠色的ULN2003模塊核心芯片是ULN2003達(dá)林頓管陣列本質(zhì)是7路大電流開(kāi)關(guān)每路最大灌電流500mA內(nèi)部自帶續(xù)流二極管可以吸收線圈關(guān)斷瞬間的反向電動(dòng)勢(shì)。沒(méi)有這個(gè)續(xù)流保護(hù)感性負(fù)載的尖峰電壓很容易把單片機(jī)或者電源打壞。驅(qū)動(dòng)板上一般有6個(gè)輸入相關(guān)引腳IN1到IN4接STM32的GPIOGND接電源負(fù)極VCC接電機(jī)電源正極。注意這個(gè)VCC是給電機(jī)用的不是給STM32邏輯用的。有的驅(qū)動(dòng)板還額外引出電源指示燈接線時(shí)不要被指示燈誤導(dǎo)重點(diǎn)確認(rèn)IN1到IN4、VCC、GND這六個(gè)點(diǎn)。2.2 供電和共地程序沒(méi)問(wèn)題卻不動(dòng)的大概率原因我最開(kāi)始調(diào)這塊電機(jī)時(shí)圖省事直接從開(kāi)發(fā)板的5V引腳取電結(jié)果電機(jī)抖兩下就停。后來(lái)?yè)QST-Link的3.3V去試直接帶不動(dòng)。原因很簡(jiǎn)單開(kāi)發(fā)板上的LDO穩(wěn)壓芯片輸出能力有限28BYJ-48啟動(dòng)瞬間的電流尖峰很容易把板載電壓拉低。電壓一低STM32自己先復(fù)位或死機(jī)。正確的做法是給電機(jī)單獨(dú)一路5V供電用USB-TTL模塊、電池盒或5V電源適配器都行。關(guān)鍵是三件事驅(qū)動(dòng)板的GND必須和STM32的GND用導(dǎo)線連通這叫共地。不共地GPIO輸出的高電平參考地不一致驅(qū)動(dòng)板收到的信號(hào)就是亂的。電機(jī)電源端并一個(gè)100uF電解電容和一個(gè)104陶瓷電容用來(lái)吸收啟動(dòng)和換相時(shí)的電流尖峰。不要把電機(jī)電源從板載3.3V取哪怕你覺(jué)得只是試一下。共地這件事看著基礎(chǔ)但新手翻車(chē)比例非常高。排查“程序看起來(lái)對(duì)了但電機(jī)不動(dòng)”時(shí)第一件事就是用萬(wàn)用表量GND通不通而不是反復(fù)改代碼。2.3 GPIO引腳分配建議GPIO選型盡量避開(kāi)JTAG/SWD復(fù)用腳。PA13、PA14、PA15、PB3、PB4這些引腳在芯片默認(rèn)狀態(tài)下有調(diào)試功能直接當(dāng)普通GPIO用要么需要額外配置禁用JTAG要么程序燒錄后行為怪怪的。網(wǎng)絡(luò)熱詞里“stm32禁用jtag”這條熱搜就是因?yàn)楹枚嗳税央姍C(jī)接在這些腳上怎么配都不動(dòng)。我個(gè)人的習(xí)慣是四相接到PC0到PC3或者PA0到PA3這種干凈引腳。工程初始化時(shí)把四個(gè)引腳都配置為推挽輸出默認(rèn)輸出低電平。這樣上電瞬間電機(jī)不會(huì)出現(xiàn)誤動(dòng)作也避免驅(qū)動(dòng)板輸入端懸空導(dǎo)致的不確定狀態(tài)。3. 讓電機(jī)轉(zhuǎn)起來(lái)的核心相位換相順序和八拍時(shí)序3.1 為什么必須有固定的換相順序步進(jìn)電機(jī)的原理可以簡(jiǎn)化成“旋轉(zhuǎn)磁場(chǎng)追著轉(zhuǎn)子跑”。每次改變四相線圈的通電組合磁場(chǎng)方向就變一點(diǎn)轉(zhuǎn)子就追著轉(zhuǎn)一點(diǎn)。通電組合的變化順序也就是換相順序決定了電機(jī)正轉(zhuǎn)還是反轉(zhuǎn)。如果順序亂轉(zhuǎn)子就會(huì)抖、卡、嘯叫。四相線圈的驅(qū)動(dòng)方式常見(jiàn)三種單四拍A、B、C、D分別單獨(dú)通電力矩最小而且每一步跨度大容易丟步。雙四拍AB、BC、CD、DA兩相同時(shí)通電力矩大但每步角度和單四拍一樣偏粗。八拍A、AB、B、BC、C、CD、D、DA單相和雙相交替相當(dāng)于把一步切成兩個(gè)半步運(yùn)行最平滑力矩也穩(wěn)定是我在這個(gè)項(xiàng)目里推薦的方式。八拍驅(qū)動(dòng)時(shí)一張典型的相位表如下。表里的GPIO值按IN4到IN1的順序排列方便和代碼對(duì)應(yīng)拍數(shù)A(IN1)B(IN2)C(IN3)D(IN4)GPIO值110000x01211000x03301000x02401100x06500100x04600110x0C700010x08810010x09每次向后走一格轉(zhuǎn)子就追一點(diǎn)走滿8格電機(jī)的電角度完成一個(gè)周期輸出軸轉(zhuǎn)過(guò)約0.703度。要反轉(zhuǎn)就把這張表倒著查。3.2 用定時(shí)器中斷驅(qū)動(dòng)而不是delay很多網(wǎng)上例程喜歡在主循環(huán)里翻轉(zhuǎn)GPIO然后delay看起來(lái)簡(jiǎn)單但實(shí)際項(xiàng)目里CPU被占死速度控制也不精確。延時(shí)稍微抖一下電機(jī)就一個(gè)卡頓一個(gè)脈沖時(shí)間長(zhǎng)了還容易出現(xiàn)未知的丟步。比較工程化的做法是用定時(shí)器產(chǎn)生固定頻率的更新中斷在中斷服務(wù)函數(shù)里切換相位表主循環(huán)只負(fù)責(zé)改方向標(biāo)志和速度參數(shù)。這樣做的好處是脈沖間隔由硬件定時(shí)器保證誤差在微秒級(jí)轉(zhuǎn)速穩(wěn)定。用HAL庫(kù)舉例基本定時(shí)器TIM6可以承擔(dān)這個(gè)任務(wù)。初始化時(shí)配置預(yù)分頻和自動(dòng)重載值讓更新中斷頻率等于目標(biāo)脈沖頻率。中斷回調(diào)里寫(xiě)這樣的邏輯volatile uint8_t step_index 0; volatile uint32_t step_count 0; volatile int8_t direction 1; const uint8_t phase_table[8] {0x01, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x09}; void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim-Instance TIM6) { step_index (step_index direction 8) % 8; HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, (phase_table[step_index] 0) 0x01); HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, (phase_table[step_index] 1) 0x01); HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, (phase_table[step_index] 2) 0x01); HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, (phase_table[step_index] 3) 0x01); if (step_count 0xFFFFFFFF) step_count; } }注意這里用了一個(gè)環(huán)形索引(step_index direction 8) % 8。direction為1時(shí)正轉(zhuǎn)為-1時(shí)反轉(zhuǎn)。后面講方向切換時(shí)這個(gè)索引的寫(xiě)法是關(guān)鍵。如果你用的是標(biāo)準(zhǔn)庫(kù)邏輯完全一樣只是GPIO操作改成BSRR或ODR中斷回調(diào)換成對(duì)應(yīng)定時(shí)器的中斷函數(shù)。3.3 轉(zhuǎn)速怎么算、調(diào)到多少合適脈沖頻率和轉(zhuǎn)速的關(guān)系是輸出軸一圈要4096拍所以轉(zhuǎn)速RPM 脈沖頻率 ÷ 4096 × 60。幾個(gè)典型值脈沖頻率輸出軸轉(zhuǎn)速100Hz1.46 RPM500Hz7.32 RPM1000Hz14.65 RPM2000Hz29.30 RPM我實(shí)測(cè)下來(lái)1500Hz到2500Hz這個(gè)區(qū)間能用超過(guò)2500Hz負(fù)載稍大就會(huì)聽(tīng)到齒輪“咔咔”打滑聲這就是失步。程序里改轉(zhuǎn)速很簡(jiǎn)單直接改定時(shí)器的自動(dòng)重載值A(chǔ)RR或者調(diào)用__HAL_TIM_SET_AUTORELOAD。但不要在主循環(huán)里每毫秒都改中斷頻率被不斷打亂反而容易出問(wèn)題。4. 一個(gè)讓我反復(fù)折騰了很久的現(xiàn)象高速正反轉(zhuǎn)切換時(shí)電機(jī)卡死4.1 癥狀和初步判斷我第一次寫(xiě)正反轉(zhuǎn)切換時(shí)在main循環(huán)里檢測(cè)到按鍵后直接把direction改成-1。結(jié)果轉(zhuǎn)速低時(shí)沒(méi)事轉(zhuǎn)速一高電機(jī)要么“嗡”一聲卡住要么發(fā)出刺耳的嘯叫同時(shí)驅(qū)動(dòng)板上的ULN2003明顯升溫。一開(kāi)始我以為是換相時(shí)序?qū)戝e(cuò)了反復(fù)對(duì)照相位表又用示波器看GPIO波形發(fā)現(xiàn)每一步都是按表走的時(shí)序完全正確。那問(wèn)題就不在換相邏輯而是出在“切換”這個(gè)動(dòng)作本身??ㄋ赖臅r(shí)候電機(jī)線圈一直通電電流比正常運(yùn)行時(shí)大不少時(shí)間一長(zhǎng)芯片發(fā)燙。這也是我后來(lái)堅(jiān)持在工程里寫(xiě)加減速和換向保護(hù)的原因——直接翻轉(zhuǎn)方向標(biāo)志這種操作真的會(huì)在極限情況下把驅(qū)動(dòng)芯片拖垮。4.2 根因轉(zhuǎn)子慣性追不上磁場(chǎng)突變28BYJ-48內(nèi)部是減速齒輪輸出軸轉(zhuǎn)速看著不高但轉(zhuǎn)子在齒輪箱之前其實(shí)轉(zhuǎn)得很快。輸出軸轉(zhuǎn)一圈內(nèi)部轉(zhuǎn)子要轉(zhuǎn)大約64圈。也就是說(shuō)當(dāng)輸出軸以15RPM轉(zhuǎn)動(dòng)時(shí)內(nèi)部轉(zhuǎn)子的轉(zhuǎn)速已經(jīng)接近1000RPM級(jí)別。高速轉(zhuǎn)子瞬間收到反向磁場(chǎng)時(shí)慣性會(huì)帶著它繼續(xù)往前沖而驅(qū)動(dòng)脈沖已經(jīng)按反方向給兩個(gè)磁場(chǎng)方向在電機(jī)內(nèi)部打架轉(zhuǎn)子就被“憋”在中間表現(xiàn)就是卡死和嘯叫。我把脈沖頻率從1000Hz往上提到1500Hz后正反轉(zhuǎn)切換幾乎必卡就是因?yàn)檫@個(gè)慣性撞上了太高的頻率切換。4.3 正確的切換姿勢(shì)先減速再反向解決方案不算復(fù)雜但要從狀態(tài)機(jī)的角度考慮不能只是把direction翻轉(zhuǎn)。我現(xiàn)在的做法是在main里維護(hù)目標(biāo)方向、當(dāng)前方向、目標(biāo)速度、當(dāng)前速度四個(gè)變量。檢測(cè)到需要換向時(shí)先把當(dāng)前速度降到低速比如把中斷頻率降到100Hz以下保持一小段穩(wěn)定時(shí)間再把direction反向最后恢復(fù)目標(biāo)轉(zhuǎn)速。偽代碼思路如下void set_target_direction(int8_t dir) { if (dir current_direction) return; target_direction dir; set_speed(80); // 先降到低速 direction_change_pending 1; } // 在低速輪詢(xún)或中斷中處理 if (direction_change_pending) { direction target_direction; // 穩(wěn)定后再改方向 direction_change_pending 0; ramp_up_speed(); // 再逐步提速 }提速也用梯形加減速不要從1000Hz直接跳上去而是每幾十拍增加一點(diǎn)頻率直到目標(biāo)值。對(duì)于28BYJ-48這種齒輪減速電機(jī)我建議起步頻率設(shè)在100到200Hz加速斜率不要超過(guò)每秒300Hz否則很容易在啟動(dòng)瞬間丟掉前幾步。減速也一樣先降頻再停不能讓電機(jī)從15RPM瞬間剎停。5. 工程實(shí)現(xiàn)里的細(xì)節(jié)定位、限位和速度曲線5.1 步數(shù)計(jì)數(shù)與角度定位開(kāi)環(huán)步進(jìn)電機(jī)的定位核心是“數(shù)脈沖”。我習(xí)慣維護(hù)一個(gè)累計(jì)步數(shù)變量step_count每進(jìn)一次中斷加1方向?yàn)榉磿r(shí)就減1程序隨時(shí)知道當(dāng)前位置相對(duì)上電位置走過(guò)了多少拍。前面算過(guò)4096拍一圈。想讓輸出軸轉(zhuǎn)90度就往前走1024拍轉(zhuǎn)180度就是2048拍。這是個(gè)線性關(guān)系非常好用。但必須清醒認(rèn)識(shí)到開(kāi)環(huán)定位的前提是電機(jī)一直沒(méi)丟步。如果中途失步過(guò)step_count就不再代表真實(shí)位置。所以實(shí)際項(xiàng)目里我會(huì)在起始位置加一個(gè)光電限位開(kāi)關(guān)或微動(dòng)開(kāi)關(guān)。每次上電先回原點(diǎn)讓電機(jī)朝限位方向轉(zhuǎn)碰到開(kāi)關(guān)后記錄當(dāng)前位置為0。這樣即使中途出現(xiàn)過(guò)失步下次上電能重新校準(zhǔn)。這也是我后來(lái)看到有人在討論AS5600磁編碼器閉環(huán)方案時(shí)覺(jué)得確實(shí)有必要的原因開(kāi)環(huán)系統(tǒng)跑得越久越需要一個(gè)“錨點(diǎn)”。5.2 不用硬算的梯形加減速實(shí)現(xiàn)梯形加減速有很多實(shí)現(xiàn)方式最笨但可靠的是查表法。提前準(zhǔn)備一個(gè)頻率數(shù)組從低頻起步每走N拍換一檔到目標(biāo)轉(zhuǎn)速后保持停車(chē)前再倒序降檔。代碼簡(jiǎn)單調(diào)試時(shí)還能直接改表看效果。對(duì)于28BYJ-48我一般這樣設(shè)計(jì)const uint16_t ramp_up[] {120, 180, 240, 320, 420, 550, 700, 900, 1200, 1600}; const uint16_t ramp_down[] {1600, 1200, 900, 700, 550, 420, 320, 240, 180, 120};定時(shí)器中斷里每次換擋時(shí)修改ARR速度曲線就自然出來(lái)了。我測(cè)試過(guò)從零速到1600Hz大約耗時(shí)0.5秒正轉(zhuǎn)反轉(zhuǎn)都平穩(wěn)沒(méi)有失步。如果負(fù)載比較重起步頻率再壓低一檔前幾拍別追求速度。這個(gè)查表法的優(yōu)點(diǎn)在于不依賴(lài)浮點(diǎn)運(yùn)算嵌入式單片機(jī)跑起來(lái)沒(méi)有任何壓力。如果你需要更平滑的S型曲線可以在查表基礎(chǔ)上再對(duì)每檔內(nèi)部做插值但對(duì)28BYJ-48這種減速電機(jī)梯形曲線已經(jīng)足夠了。5.3 停穩(wěn)再操作關(guān)斷與保持力矩28BYJ-48在通電時(shí)即使不發(fā)脈沖只要最后一個(gè)相位保持勵(lì)磁轉(zhuǎn)子也有一定保持力矩輸出軸不容易被外力撥動(dòng)。但代價(jià)是線圈長(zhǎng)期通電驅(qū)動(dòng)板和電機(jī)都會(huì)有溫?zé)帷H绻?xiàng)目對(duì)功耗有要求電機(jī)到位后可以把四個(gè)GPIO全部置低切斷勵(lì)磁。這時(shí)候輸出軸雖然還能被手?jǐn)Q動(dòng)但由于減速齒輪在前面擋著阻力還是有的比完全自由的狀態(tài)強(qiáng)很多。我在做電池供電的自動(dòng)澆灌閥時(shí)就是到位后立即斷電實(shí)測(cè)靜態(tài)功耗幾乎降到零一節(jié)18650電池能撐很久。6. 調(diào)試中踩過(guò)的坑和最終工程結(jié)構(gòu)建議6.1 幾個(gè)高頻故障和對(duì)應(yīng)的排查順序在實(shí)際調(diào)試和幫朋友看代碼的過(guò)程中我總結(jié)了幾類(lèi)高頻故障按出現(xiàn)概率排序電機(jī)完全不動(dòng)先測(cè)驅(qū)動(dòng)板VCC和GND之間的電壓再測(cè)STM32的GPIO電平是否按八拍表變化最后查共地線是不是虛接。很多時(shí)候不是程序問(wèn)題是接觸不良。電機(jī)抖動(dòng)但不轉(zhuǎn)第一嫌疑是相位順序不對(duì)A、B、C、D和GPIO的對(duì)應(yīng)關(guān)系搞混了第二嫌疑是脈沖頻率太低單四拍在低頻下尤其明顯。轉(zhuǎn)著轉(zhuǎn)著停住且發(fā)燙負(fù)載卡死或供電能力不足。先換獨(dú)立電源再查減速齒輪是不是打滑了。程序燒錄后一運(yùn)行開(kāi)發(fā)板就復(fù)位供電被拉垮。加電容、換獨(dú)立電源基本能解決。輸出軸轉(zhuǎn)向和預(yù)期相反把direction反一下就行。硬件上也可以對(duì)調(diào)A和C、B和D這兩對(duì)線但改代碼更省事。下載程序時(shí)如果遇到IDE燒錄不穩(wěn)定或芯片疑似鎖死的情況可以用STM32 ST-LINK Utility這類(lèi)工具直接寫(xiě)Flash必要時(shí)整片擦除再重新燒錄。這塊電機(jī)項(xiàng)目本身不大但養(yǎng)成檢查Flash和Option Bytes的習(xí)慣后面做復(fù)雜項(xiàng)目時(shí)能少踩很多坑。6.2 模塊化驅(qū)動(dòng)文件怎么組織源碼壓縮包里我把驅(qū)動(dòng)拆成了幾個(gè)文件模塊化是為了后續(xù)換平臺(tái)或少改動(dòng)motor.c和motor.h提供motor_init()、motor_set_speed()、motor_set_direction()、motor_move_steps()、motor_stop()這幾個(gè)接口。phase_table.c八拍表單獨(dú)放以后換其他電機(jī)或改驅(qū)動(dòng)方式時(shí)只動(dòng)這個(gè)文件。main.c里只放業(yè)務(wù)邏輯比如按鍵、屏幕或串口交互。這樣分層的理由很簡(jiǎn)單驅(qū)動(dòng)邏輯和業(yè)務(wù)邏輯分離。我后來(lái)把這套代碼從HAL庫(kù)移植到標(biāo)準(zhǔn)庫(kù)改動(dòng)量其實(shí)只有GPIO寫(xiě)法和定時(shí)器中斷入口核心的八拍表和加減速邏輯一行都沒(méi)動(dòng)。6.3 后續(xù)還能怎么擴(kuò)展如果項(xiàng)目要繼續(xù)深入我建議按優(yōu)先級(jí)來(lái)第一步加限位開(kāi)關(guān)和原點(diǎn)回零解決累計(jì)誤差。第二步用光電傳感器或編碼器做簡(jiǎn)單閉環(huán)檢測(cè)比如在輸出軸加碼盤(pán)比較實(shí)際轉(zhuǎn)速和脈沖數(shù)是否一致不一致就報(bào)錯(cuò)或自動(dòng)校正。第三步如果確實(shí)需要更大扭矩和更高轉(zhuǎn)速可以考慮換42步進(jìn)電機(jī)加A4988驅(qū)動(dòng)??刂扑悸窌?huì)從GPIO順序換相變成“方向脈沖加細(xì)分脈沖”本質(zhì)上是同一個(gè)邏輯只是八拍表從軟件里的數(shù)組變成了驅(qū)動(dòng)器芯片自己處理。我在實(shí)際項(xiàng)目中體會(huì)最深的一點(diǎn)是28BYJ-48雖然看起來(lái)簡(jiǎn)單但它身上暴露出來(lái)的換相順序、減速比、電流沖擊、加減速這些問(wèn)題幾乎覆蓋了步進(jìn)電機(jī)控制所有的基礎(chǔ)知識(shí)點(diǎn)。把這塊玩透了后面再碰其他類(lèi)型的電機(jī)思路基本是平移的。壓縮包里的工程別只當(dāng)成品用建議把相位表、定時(shí)器配置、換向保護(hù)這些關(guān)鍵代碼都自己敲一遍踩一次坑比讀十遍資料都管用。本文還有配套的精品資源點(diǎn)擊獲取