0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

基于CW32的無刷直流空心杯電機(jī)有感控制驅(qū)動(dòng)方案

CW32生態(tài)社區(qū) ? 來源:CW32生態(tài)社區(qū) ? 作者:CW32生態(tài)社區(qū) ? 2024-04-24 15:28 ? 次閱讀

一、概述

空心杯電機(jī)(Hollow-Cup Motor)是一種特殊類型的微型無刷直流電機(jī),具有空心的旋轉(zhuǎn)部分。它通常由外部固定的外殼和內(nèi)部旋轉(zhuǎn)的空心杯組成。空心杯電機(jī)具有較高的功率密度和扭矩輸出,適用于一些特定的應(yīng)用場景,如精密儀器、機(jī)器人、醫(yī)療設(shè)備等。

空心杯電機(jī)的工作原理是基于無刷直流電機(jī)的原理。它采用無刷電機(jī)的結(jié)構(gòu),包括定子(固定部分)和轉(zhuǎn)子(旋轉(zhuǎn)部分)。定子包含一組永磁體,而轉(zhuǎn)子則包含一組線圈。通過電流在線圈中的流動(dòng)和永磁體之間的相互作用,產(chǎn)生電磁力,從而使轉(zhuǎn)子旋轉(zhuǎn)。

圖1-1 空心杯電機(jī)結(jié)構(gòu)

空心杯電機(jī)的特點(diǎn)和優(yōu)勢包括:

  1. 空心結(jié)構(gòu):空心杯設(shè)計(jì)使得電機(jī)的旋轉(zhuǎn)部分中心為空,可以通過空心軸傳遞其他信號(hào)、光線或氣體,并且由于繞組無鐵芯,轉(zhuǎn)矩分布均勻。
  2. 高功率密度:由于其緊湊的設(shè)計(jì)和高效的電機(jī)結(jié)構(gòu),空心杯電機(jī)具有較高的功率密度,可以在有限的空間內(nèi)提供更大的扭矩輸出。
  3. 平滑運(yùn)行:空心杯電機(jī)通常具有平滑的運(yùn)行特性,可以提供穩(wěn)定的轉(zhuǎn)速和低噪音。
  4. 高精度和可控性:空心杯電機(jī)的設(shè)計(jì)使得其具有較高的精度和可控性,適用于需要精確位置控制的應(yīng)用。
  5. 快速響應(yīng):由于其轉(zhuǎn)動(dòng)慣量小,空心杯電機(jī)能夠快速響應(yīng)控制信號(hào),機(jī)械時(shí)間常數(shù)可以達(dá)到ms級(jí),適用于需要高速動(dòng)態(tài)響應(yīng)的應(yīng)用場景。

需要注意的是,空心杯電機(jī)由于結(jié)構(gòu)緊湊的設(shè)計(jì)導(dǎo)致散熱困難,并且其要實(shí)現(xiàn)高速和高精度的響應(yīng),因此空心杯電機(jī)的功率和扭矩都有一定的限制,需要根據(jù)具體工程問題選擇合適的電機(jī)類型和配套的控制系統(tǒng)。

應(yīng)用場景:

  1. 機(jī)器人技術(shù):空心杯電機(jī)廣泛應(yīng)用于機(jī)器人的關(guān)節(jié)驅(qū)動(dòng)器中,能夠提供高精度的運(yùn)動(dòng)控制和力矩輸出。機(jī)器人的關(guān)節(jié)通常需要快速而準(zhǔn)確地執(zhí)行各種動(dòng)作,而空心杯電機(jī)可以滿足這些要求。
  2. 自動(dòng)化設(shè)備:在自動(dòng)化設(shè)備中,如自動(dòng)裝配線、自動(dòng)化儀器等,空心杯電機(jī)可用于驅(qū)動(dòng)各種傳送帶、傳送裝置和旋轉(zhuǎn)平臺(tái),以實(shí)現(xiàn)工件的快速、精確定位和搬運(yùn)。
  3. 醫(yī)療器械:空心杯電機(jī)在醫(yī)療器械中的應(yīng)用廣泛,例如手術(shù)機(jī)器人、醫(yī)療影像裝置、藥物輸送系統(tǒng)等。這些應(yīng)用需要高度精確的運(yùn)動(dòng)控制和定位,而空心杯電機(jī)能夠提供穩(wěn)定的力矩輸出和高精度的位置控制。
  4. 光學(xué)設(shè)備:在需要進(jìn)行旋轉(zhuǎn)、調(diào)焦、變焦等精密光學(xué)操作的設(shè)備中,如攝像機(jī)、望遠(yuǎn)鏡、激光器等,空心杯電機(jī)可用于驅(qū)動(dòng)相應(yīng)的部件,實(shí)現(xiàn)精確的光路控制和圖像穩(wěn)定。
  5. 回轉(zhuǎn)平臺(tái):空心杯電機(jī)常被用于回轉(zhuǎn)平臺(tái)或轉(zhuǎn)臺(tái),例如航天器的天線轉(zhuǎn)動(dòng)、攝影設(shè)備的平穩(wěn)旋轉(zhuǎn)等。通過空心杯電機(jī)的驅(qū)動(dòng),可以實(shí)現(xiàn)平穩(wěn)、高速的旋轉(zhuǎn),并且減小了傳動(dòng)裝置的尺寸和重量。

二、控制原理

2.1 霍爾傳感器

霍爾傳感器是一種基于霍爾效應(yīng)原理的傳感器,用于檢測磁場的存在和變化。它通常由霍爾元件、信號(hào)調(diào)理電路和輸出接口組成?;魻栐且环N半導(dǎo)體材料,當(dāng)其受到外部磁場的作用時(shí),會(huì)產(chǎn)生一個(gè)電壓信號(hào)。這個(gè)電壓信號(hào)經(jīng)過信號(hào)調(diào)理電路處理后,就可以輸出給控制系統(tǒng)進(jìn)行相應(yīng)的處理。

霍爾傳感器的工作原理基于霍爾效應(yīng),即當(dāng)電流通過某些材料時(shí),受到垂直于電流方向的磁場的影響,會(huì)在材料兩側(cè)產(chǎn)生一種電勢差。這個(gè)電勢差被稱為霍爾電壓,其大小與外部磁場的強(qiáng)度成正比。

霍爾傳感器具有以下特點(diǎn)和優(yōu)勢:

  1. 非接觸式檢測:霍爾傳感器通過檢測磁場,而無需與被檢測物直接接觸,從而避免了物理接觸可能帶來的摩擦和磨損。
  2. 快速響應(yīng):由于霍爾傳感器是基于半導(dǎo)體材料的電子器件,其響應(yīng)速度非??欤梢詫?shí)時(shí)檢測和響應(yīng)磁場變化。
  3. 高精度:霍爾傳感器能夠提供精確的磁場測量和檢測,可用于測量磁場的強(qiáng)度、方向和變化。
  4. 寬工作溫度范圍:霍爾傳感器具有較寬的工作溫度范圍,可以在高溫或低溫環(huán)境下正常工作。
  5. 可靠性和耐用性:霍爾傳感器不受機(jī)械磨損的影響,具有較長的使用壽命和可靠性。
  6. 低功耗:霍爾傳感器通常具有低功耗特性,適用于電池供電或?qū)δ茉聪拿舾械膽?yīng)用。
    在本次實(shí)驗(yàn)中,我們使用霍爾傳感器對轉(zhuǎn)子位置進(jìn)行檢測。通過將三個(gè)霍爾傳感器相隔120°安裝在電機(jī)定子的不同位置,即可根據(jù)霍爾傳感器的電平信號(hào)確定電機(jī)轉(zhuǎn)子的位置。下圖是本次實(shí)驗(yàn)用到的霍爾真值表,理解真值表后對程序的編寫有著重要作用:


圖2-1 120°霍爾真值表

上圖左為正轉(zhuǎn),右為反轉(zhuǎn)。從上圖可以看出,A、B、C三相霍爾傳感器分別在空間上間隔120°放置,當(dāng)轉(zhuǎn)子的磁極運(yùn)動(dòng)到對應(yīng)的霍爾傳感器位置時(shí),對應(yīng)的相產(chǎn)生高電平,高電平的持續(xù)角度為180°(電角度,當(dāng)電機(jī)極對數(shù)為1時(shí)也等于機(jī)械角度)。所以我們根據(jù)上面的真值表可以寫出電機(jī)運(yùn)行時(shí)的六種狀態(tài),以C相為高位:101、001、011、010、110、100;用十六進(jìn)制的表示方式為:5、1、3、2、6、4,也就是說電機(jī)在正轉(zhuǎn)時(shí),霍爾傳感器的信號(hào)只會(huì)按照513264的大小依次出現(xiàn),在程序里讀取對應(yīng)霍爾引腳的電平狀態(tài)即可判斷此時(shí)電機(jī)轉(zhuǎn)子的位置,這對于后續(xù)的方波控制尤為重要。

2.2 方波控制

方波控制是通過改變電機(jī)的輸入電壓信號(hào)來控制電機(jī)的轉(zhuǎn)速和方向,這里的方波是指在電機(jī)運(yùn)行過程中定子電流的波形近似方波。
image.png

圖2-2 無刷直流電機(jī)的電路等效圖

如果我們采用二二導(dǎo)通的方式,即同一時(shí)刻電機(jī)的繞組只有兩相導(dǎo)通,本次實(shí)驗(yàn)的空心杯電機(jī)的內(nèi)部為三角形連接,極對數(shù)為1。在一個(gè)電周期(360°)內(nèi),由上面提到的霍爾六種不同的狀態(tài)來切換控制MOSFET的開通關(guān)斷,使得定子電流也有六種狀態(tài),即定子繞組的合成磁動(dòng)勢有六種狀態(tài)——所以,方波控制又被稱為六步換相。

以上文的霍爾狀態(tài)舉例,當(dāng)霍爾傳感器傳出信號(hào)為5時(shí),控制VT1和VT6開通,其余關(guān)斷,所以A相電流為正,B相電流為負(fù);電機(jī)旋轉(zhuǎn)至霍爾信號(hào)為1時(shí),控制VT1和VT2開通,其余關(guān)斷;以此類推,完整地經(jīng)歷過六個(gè)狀態(tài)后,電機(jī)也就旋轉(zhuǎn)完了一圈,再次進(jìn)行上述步驟就可以使得電機(jī)連續(xù)運(yùn)行。

那么電機(jī)為什么會(huì)這樣運(yùn)行呢,我們在這里用較為通俗的語言解釋,如果讀者有興趣可以自行查閱相關(guān)資料。電機(jī)的定子通電后也具有磁性,根據(jù)“異性相吸”的原理,電機(jī)轉(zhuǎn)子會(huì)向著通電的定子相運(yùn)動(dòng)直至二者“吸住”,如果在轉(zhuǎn)子運(yùn)動(dòng)到對應(yīng)“相吸”定子前的一瞬間,斷掉該定子的供電而對順著轉(zhuǎn)子運(yùn)動(dòng)方向相隔120°的下一相定子供電,則轉(zhuǎn)子又會(huì)與下一相定子“相吸”,如此往復(fù)即可使轉(zhuǎn)子不斷轉(zhuǎn)動(dòng),上文的電路等效圖對應(yīng)相關(guān)定子相的供電。

圖2-3 直流無刷電機(jī)定轉(zhuǎn)子運(yùn)動(dòng)示意圖

一個(gè)完整系統(tǒng)的方波控制步驟如下:

  1. 設(shè)置控制系統(tǒng):確定控制系統(tǒng)的輸入和輸出接口,選擇適當(dāng)?shù)?a target="_blank">控制器(如微控制器)和驅(qū)動(dòng)電路
  2. 確定轉(zhuǎn)子位置:根據(jù)霍爾傳感器信號(hào)的真值表,確定電機(jī)轉(zhuǎn)子此時(shí)的位置。
  3. 確定換相順序:根據(jù)轉(zhuǎn)子的位置情況,確定電機(jī)定子的換相順序,即圖2-2中VT1-6的通斷順序。
  4. 控制電機(jī)轉(zhuǎn)速:通過對MOS管VT輸入PWM信號(hào),該變占空比來控制平均電壓的大小即可控制電機(jī)的轉(zhuǎn)速。
  5. 控制電機(jī)方向:通過改變換相順序的運(yùn)行方向,可以控制電機(jī)的運(yùn)動(dòng)方向。
  6. 反饋控制(可選):如果需要更精確的控制,可以使用更加靈敏的傳感器,如編碼器,來進(jìn)一步監(jiān)測電機(jī)的位置,在程序里使用對應(yīng)算法(如PID)精確控制電機(jī)的位置和速度。

注意事項(xiàng):

  1. 控制器的選擇應(yīng)考慮到方波控制的要求,如頻率范圍、引腳采樣速度和分辨率等。
  2. 驅(qū)動(dòng)電路的設(shè)計(jì)應(yīng)與電機(jī)的額定電壓和電流匹配,并具備過流、過壓等保護(hù)功能。
  3. 在實(shí)際應(yīng)用中,應(yīng)注意電機(jī)的負(fù)載特性、慣性等因素對控制的影響,可能需要進(jìn)行參數(shù)調(diào)整和系統(tǒng)優(yōu)化。

三、CW32性能特點(diǎn)

本次實(shí)驗(yàn)采用的MCU為CW32F030C8T6,其性能特點(diǎn)如下:

  1. 架構(gòu)和處理能力:CW32F030C8T6采用了ARM Cortex-M0+處理器核心,具有高性能和低功耗的特點(diǎn)。Cortex-M0+是ARM架構(gòu)中的一種32位處理器核心,適用于對功耗要求較高的應(yīng)用場景。
  2. 主頻和存儲(chǔ)器:CW32F030C8T6的主頻可以高達(dá)48MHz,提供了較高的處理速度。它具有8KB的SRAM(靜態(tài)隨機(jī)存儲(chǔ)器)和32KB的閃存(用于存儲(chǔ)程序代碼和數(shù)據(jù)),可用于存儲(chǔ)應(yīng)用程序和數(shù)據(jù)。
  3. 低功耗特性:CW32F030C8T6在低功耗方面表現(xiàn)出色,具有多種省電模式和功耗管理功能,可實(shí)現(xiàn)對系統(tǒng)功耗的有效控制。這對于需要長時(shí)間運(yùn)行的電池供電設(shè)備或?qū)拿舾械膽?yīng)用非常重要。
  4. 外設(shè)和接口:CW32F030C8T6提供了豐富的外設(shè)和接口,包括多個(gè)通用輸入輸出引腳(GPIO)、SPI(串行外設(shè)接口)、I2C(串行通信接口)、UART(通用異步收發(fā)器)等。這些接口可用于與外部傳感器、存儲(chǔ)器、通信模塊等設(shè)備進(jìn)行通信和連接。
  5. 定時(shí)器和中斷控制:CW32F030C8T6配備了多個(gè)定時(shí)器和中斷控制功能,可用于實(shí)現(xiàn)精確的定時(shí)和事件觸發(fā)。定時(shí)器可以用于生成精確的時(shí)間延遲、PWM(脈沖寬度調(diào)制)輸出等應(yīng)用,而中斷控制則可以實(shí)現(xiàn)對外部事件的快速響應(yīng)。
  6. 安全性和保護(hù)機(jī)制:CW32F030C8T6提供了多種安全性和保護(hù)機(jī)制,包括存儲(chǔ)器保護(hù)單元、訪問控制等。這些機(jī)制可以幫助保護(hù)系統(tǒng)免受潛在的安全威脅和未授權(quán)訪問。
    本次實(shí)驗(yàn)我們使用了CW32的ATIM、GTIM、BTIM、ADCDMA外設(shè),下面分別簡要介紹這五種外設(shè)。

3.1 高級(jí)定時(shí)器(ATIM)

高級(jí)定時(shí)器 (ATIM) 由一個(gè) 16 位的自動(dòng)重載計(jì)數(shù)器和 7 個(gè)比較單元組成,并由一個(gè)可編程的預(yù)分頻器驅(qū)動(dòng)。ATIM 支持 6 個(gè)獨(dú)立的捕獲 / 比較通道,可實(shí)現(xiàn) 6 路獨(dú)立 PWM 輸出或 3 對互補(bǔ) PWM 輸出或?qū)?6 路輸入進(jìn)行捕獲???用于基本的定時(shí) / 計(jì)數(shù)、測量輸入信號(hào)的脈沖寬度和周期、產(chǎn)生輸出波形(PWM、單脈沖、插入死區(qū)時(shí)間的互補(bǔ) PWM 等)。 在本次實(shí)驗(yàn)中,我們使用 ATIM 來產(chǎn)生PWM波驅(qū)動(dòng)上橋。


圖3-1 ATIM 功能框圖

3.2 通用定時(shí)器(GTIM)

CW32F030 內(nèi)部集成 4 個(gè)通用定時(shí)器 (GTIM),每個(gè) GTIM 完全獨(dú)立且功能完全相同,各包含一個(gè) 16bit 自動(dòng)重裝載計(jì)數(shù)器并由一個(gè)可編程預(yù)分頻器驅(qū)動(dòng)。GTIM 支持定時(shí)器模式、計(jì)數(shù)器模式、觸發(fā)啟動(dòng)模式和門控模式 4 種基本工作模式,每組帶 4 路獨(dú)立的捕獲 / 比較通道,可以測量輸入信號(hào)的脈沖寬度(輸入捕獲)或者產(chǎn)生輸出波形(輸出比較和 PWM)。本次實(shí)驗(yàn)使用 GTIM 的輸入捕獲功能來觸發(fā)獲取霍爾傳感器的數(shù)據(jù)。

圖3-2 GTIM功能框圖

3.3 基本定時(shí)器(BTIM)

CW32F030 內(nèi)部集成 3 個(gè)基本定時(shí)器 (BTIM),每個(gè) BTIM 完全獨(dú)立且功能完全相同,各包含一個(gè) 16bit 自動(dòng)重裝載計(jì)數(shù)器并由一個(gè)可編程預(yù)分頻器驅(qū)動(dòng)。BTIM 支持定時(shí)器模式、計(jì)數(shù)器模式、觸發(fā)啟動(dòng)模式和門控模式 4 種工作模式,支持溢出事件觸發(fā)中斷請求和 DMA 請求。得益于對觸發(fā)信號(hào)的精細(xì)處理設(shè)計(jì),使得 BTIM 可以由硬件自動(dòng)執(zhí)行觸發(fā)信號(hào)的濾波操作,還能令觸發(fā)事件產(chǎn)生中斷和 DMA 請求。 本次實(shí)驗(yàn)使用BTIM的定時(shí)器中斷功能,10ms進(jìn)入一次定時(shí)器中斷,在中斷中修改相關(guān)功能的標(biāo)志位,在主函數(shù)的 while 循環(huán)里根據(jù)標(biāo)志位判斷相關(guān)功能本次是否執(zhí)行。

圖3-3 BTIM功能框圖

3.4 模數(shù)轉(zhuǎn)換器ADC)

CW32F030 內(nèi)部集成一個(gè) 12 位精度、最高 1M SPS 轉(zhuǎn)換速度的逐次逼近型模數(shù)轉(zhuǎn)換器 (SAR ADC),最多可將 16 路模擬信號(hào)轉(zhuǎn)換為數(shù)字信號(hào)。現(xiàn)實(shí)世界中的絕大多數(shù)信號(hào)都是模擬量,如光、電、聲、圖像信號(hào)等,都要由 ADC 轉(zhuǎn)換成數(shù)字信號(hào),才能由 MCU 進(jìn)行數(shù)字化處理。本次實(shí)驗(yàn)使用 ADC 采集電位器的電壓值,根據(jù)電位器的電壓大小控制目標(biāo)值的設(shè)定。

圖3-4 ADC 功能框圖

3.5 直接內(nèi)存訪問(DMA)

CW32F030 支持直接內(nèi)存訪問(DMA),無需 CPU 干預(yù),即可實(shí)現(xiàn)外設(shè)和存儲(chǔ)器之間、外設(shè)和外設(shè)之間、存儲(chǔ)器和存儲(chǔ)器之間的高速數(shù)據(jù)傳輸。DMA 控制器內(nèi)部的優(yōu)先級(jí)仲裁器,可實(shí)現(xiàn) DMA 和 CPU 對外設(shè)總線控制權(quán)的仲裁,以及多 DMA 通道之間的調(diào)度執(zhí)行。本次實(shí)驗(yàn)使用 DMA 將 ADC 采集的數(shù)據(jù)寫入內(nèi)存,DMA 傳輸由 ADC 轉(zhuǎn)換完成信號(hào)觸發(fā)。


圖3-5 DMA 功能框圖

四、實(shí)驗(yàn)設(shè)備

4.1 CW32-BLDC電機(jī)驅(qū)動(dòng)板

本次實(shí)驗(yàn)我們使用的無刷電機(jī)驅(qū)動(dòng)板為CW32_BLDC_EVA V5開發(fā)板,其配置如下:


圖4-1 CW32_BLCD_EVA 評(píng)估板資源配置圖

4.2 空心杯電機(jī)與連接

本次實(shí)驗(yàn)使用的空心杯電機(jī)參考圖如下:
02f626f62f9b74ee6767528c5f23397f.jpg

圖4-2 空心杯電機(jī)實(shí)物圖

連接示意圖如下:


圖4-3 電機(jī)與驅(qū)動(dòng)板連接示意圖

下面展示電機(jī)驅(qū)動(dòng)板的原理圖:


圖4-4 電機(jī)驅(qū)動(dòng)板原理圖1


圖4-5 電機(jī)驅(qū)動(dòng)板原理圖2


圖4-6 電機(jī)驅(qū)動(dòng)板原理圖3

五、程序編寫

5.1 有霍爾方波開環(huán)控制程序

下面會(huì)將控制程序按照不同的功能模塊向讀者展示。

首先是與霍爾傳感器相關(guān)的模塊,存放在HALL.c文件中,先展示HALL.h文件的內(nèi)容:

#ifndef _HALL_H_
#define _HALL_H_

#include "cw32f030_rcc.h"
#include "cw32f030_gpio.h"
#include "cw32f030_gtim.h"

#define HALLA_PORT         (CW_GPIOA)
#define HALLB_PORT         (CW_GPIOB)
#define HALLC_PORT         (CW_GPIOA)
#define HALLA_PIN          (GPIO_PIN_15)
#define HALLB_PIN          (GPIO_PIN_3)
#define HALLC_PIN          (GPIO_PIN_2)

extern void Commutation(unsigned int step,unsigned int OutPwmValue,unsigned int PWM_ON_flag);
extern void GTIM2_IRQHandler(void);
        
void HALL_Init(void);
unsigned char  HALL_Check(void);

#endif

HALL.c文件

#include "HALL.h"

uint8_t ErrorCode;                                           //電機(jī)運(yùn)行錯(cuò)誤代碼
extern uint8_t Motor_Start_F;                                //電機(jī)啟動(dòng)運(yùn)行標(biāo)志
extern uint8_t Cur_Step;                                     //當(dāng)前HALL狀態(tài)
extern uint8_t Direction;                                    //電機(jī)方向,0為正轉(zhuǎn),1為反轉(zhuǎn)
const uint8_t STEP_TAB[2][6] = {{4,0,5,2,3,1},{1,3,2,5,0,4}};//電機(jī)換相序號(hào)
extern uint32_t HALLcount;                                   //霍爾脈沖計(jì)數(shù)
extern uint32_t OutPwm;                                      //輸出PWM值


//初始化霍爾傳感器要用到的GPIO和定時(shí)器
void HALL_Init(void)
{
  __RCC_GTIM2_CLK_ENABLE();                    //先打開對應(yīng)時(shí)鐘
  __RCC_GPIOA_CLK_ENABLE();
  __RCC_GPIOB_CLK_ENABLE();
        
  GPIO_InitTypeDef GPIO_InitStruct;            //再配置對應(yīng)接口
  GPIO_InitStruct.IT = GPIO_IT_NONE;
  GPIO_InitStruct.Mode =GPIO_MODE_INPUT_PULLUP;//霍爾輸入配置;
  GPIO_InitStruct.Pins = HALLA_PIN | HALLC_PIN;//PA15和PA2
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  GPIO_Init(HALLA_PORT, &GPIO_InitStruct);
        
  GPIO_InitStruct.IT = GPIO_IT_NONE;
  GPIO_InitStruct.Mode =GPIO_MODE_INPUT_PULLUP;// 霍爾輸入配置;
  GPIO_InitStruct.Pins = HALLB_PIN;            //PB3
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  GPIO_Init(HALLB_PORT, &GPIO_InitStruct);
        
  PA15_AFx_GTIM2CH1();                         //GTIM2CH1();
  PB03_AFx_GTIM2CH2();                         //GTIM2CH2();
  PA02_AFx_GTIM2CH3();                         //GTIM2CH3();
                
  __disable_irq(); 
  NVIC_EnableIRQ(GTIM2_IRQn);                  //配置GTIM2輸入捕獲中斷
  __enable_irq();
        
  GTIM_InitTypeDef GTIM_InitStruct;            //這里使用GTIM2的輸入捕獲功能
  GTIM_ICInitTypeDef GTIM_ICInitStruct;
        
  GTIM_InitStruct.Mode = GTIM_MODE_TIME;
  GTIM_InitStruct.OneShotMode = GTIM_COUNT_CONTINUE;
  GTIM_InitStruct.Prescaler = GTIM_PRESCALER_DIV1;
  GTIM_InitStruct.ReloadValue = 0xFFFF;
  GTIM_InitStruct.ToggleOutState = DISABLE;
  GTIM_TimeBaseInit(CW_GTIM2, >IM_InitStruct);

  GTIM_ICInitStruct.CHx = GTIM_CHANNEL1;       //GTIM2捕獲通道配置
  GTIM_ICInitStruct.ICFilter = GTIM_CHx_FILTER_PCLK_N2;
  GTIM_ICInitStruct.ICInvert = GTIM_CHx_INVERT_OFF;
  GTIM_ICInitStruct.ICPolarity = GTIM_ICPolarity_BothEdge;
  GTIM_ICInit(CW_GTIM2, >IM_ICInitStruct);

  GTIM_ICInitStruct.CHx = GTIM_CHANNEL2;
  GTIM_ICInit(CW_GTIM2, >IM_ICInitStruct);
        
  GTIM_ICInitStruct.CHx = GTIM_CHANNEL3;
  GTIM_ICInit(CW_GTIM2, >IM_ICInitStruct);
        
  GTIM_ITConfig(CW_GTIM2, GTIM_IT_CC1 | GTIM_IT_CC2 | GTIM_IT_CC3, ENABLE);
  GTIM_Cmd(CW_GTIM2, ENABLE);
}

unsigned char  HALL_Check(void)                 //讀取霍爾狀態(tài),確定換相順序
{
  static unsigned char hallerrnum=0; 
  unsigned char Hall_State=0;
  
  if(PA15_GETVALUE()!=0)Hall_State=0x1;         //對每個(gè)引腳狀態(tài)分別判斷,所以三個(gè)if而不是else if
  if(PB03_GETVALUE()!=0)Hall_State|=0x2;        //或運(yùn)算 010
  if(PA02_GETVALUE()!=0)Hall_State|=0x4;        //或運(yùn)算 100
  if(Hall_State==0||Hall_State==7)              //000或者111都是異常狀態(tài)
    {
      hallerrnum++;
      if(hallerrnum >=10)
      {hallerrnum=10;ErrorCode=2;}              //持續(xù)異常狀態(tài)說明霍爾傳感器有問題
    }
  else hallerrnum=0;
  return Hall_State;
}

void GTIM2_IRQHandler(void)   //在GTIM2的中斷服務(wù)程序里對霍爾脈沖計(jì)數(shù)、霍爾狀態(tài)確定、換相確定
{        
  uint32_t Hall_State;       
  /* USER CODE BEGIN */
  if (GTIM_GetITStatus(CW_GTIM2, GTIM_IT_CC1))        //捕獲輸入變化就產(chǎn)生中斷標(biāo)志
  {
    GTIM_ClearITPendingBit(CW_GTIM2, GTIM_IT_CC1);    //清除中斷標(biāo)志
  }

  else if (GTIM_GetITStatus(CW_GTIM2, GTIM_IT_CC2))
  {    
    GTIM_ClearITPendingBit(CW_GTIM2, GTIM_IT_CC2);
  }
  
  else if (GTIM_GetITStatus(CW_GTIM2, GTIM_IT_CC3))
  {    
    GTIM_ClearITPendingBit(CW_GTIM2, GTIM_IT_CC3);
  }
        
   HALLcount++;                                       //霍爾脈沖計(jì)數(shù)        
   Hall_State=HALL_Check();                           //讀取霍爾狀態(tài)
   Cur_Step=STEP_TAB[Direction][Hall_State-1];        //獲取換相序位,例如霍爾變化為513264,則Cur_Step變化為345012
   if(Motor_Start_F==1&&ErrorCode==0)                 //根據(jù)啟停狀態(tài) 換相
     Commutation(Cur_Step,OutPwm,Motor_Start_F);           
  /* USER CODE END */
}

與電機(jī)相關(guān)的BLDC模塊:
BLDC.h

#include "main.h"

/***********************                PWM        definition   *************************/

#define PWM_HN_PORT                 (CW_GPIOA)      //上管引腳
#define PWM_LN_PORT                 (CW_GPIOB)      //下管引腳
#define PWM_AH_PIN                  (GPIO_PIN_8)
#define PWM_BH_PIN                  (GPIO_PIN_9)
#define PWM_CH_PIN                  (GPIO_PIN_10)
#define PWM_AL_PIN                  (GPIO_PIN_13)
#define PWM_BL_PIN                  (GPIO_PIN_14)
#define PWM_CL_PIN                  (GPIO_PIN_15)

//上管PWM調(diào)制控制,下管GPIO開關(guān)控制, 上管高電平開關(guān)管導(dǎo)通,下管反相
#define PWM_AL_OFF GPIO_WritePin(PWM_LN_PORT,PWM_AL_PIN,GPIO_Pin_SET)
#define PWM_BL_OFF GPIO_WritePin(PWM_LN_PORT,PWM_BL_PIN,GPIO_Pin_SET)
#define PWM_CL_OFF GPIO_WritePin(PWM_LN_PORT,PWM_CL_PIN,GPIO_Pin_SET)

#define PWM_AL_ON GPIO_WritePin(PWM_LN_PORT,PWM_AL_PIN,GPIO_Pin_RESET)
#define PWM_BL_ON GPIO_WritePin(PWM_LN_PORT,PWM_BL_PIN,GPIO_Pin_RESET)
#define PWM_CL_ON GPIO_WritePin(PWM_LN_PORT,PWM_CL_PIN,GPIO_Pin_RESET)

#define PWM_FRQ                        (20000)       //PWM頻率(HZ)
#define PWM_TS                          3200
//20K
        
#define OUTMAXPWM  PWM_TS*0.25
#define OUTMINPWM  PWM_TS*0.005 

void BLDC_Init(void);
void BLDC_Motor_Start(uint8_t Dir);
void BLDC_Motor_Stop(void);
void Commutation(unsigned int step,unsigned int OutPwmValue,unsigned int PWM_ON_flag);
void UPPWM(void);         //更新PWM占空比

/////////////////////////

BLDC.c

#include "BLDC.h"

extern const uint8_t STEP_TAB[2][6];//電機(jī)換相序號(hào)

uint8_t Cur_Step;                   //當(dāng)前HALL狀態(tài)
uint8_t STEP_last;                  //上次HALL狀態(tài)
extern uint8_t Direction;           //電機(jī)方向,0為正轉(zhuǎn),1為反轉(zhuǎn)
extern uint8_t Motor_Start_F;       //電機(jī)啟動(dòng)運(yùn)行標(biāo)志
uint32_t OutPwm;                    //PWM占空比

//初始化電機(jī)要用到的GPIO和定時(shí)器,上橋?yàn)镻WM,下橋?yàn)橐_電平控制
void BLDC_Init(void)
{
  __RCC_ATIM_CLK_ENABLE();          
  __RCC_GPIOA_CLK_ENABLE();
  __RCC_GPIOB_CLK_ENABLE();
          
  //初始化下管GPIO
  GPIO_InitTypeDef GPIO_InitStruct;
  GPIO_InitStruct.IT = GPIO_IT_NONE;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pins = PWM_AL_PIN | PWM_BL_PIN | PWM_CL_PIN;
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  GPIO_Init(PWM_LN_PORT,&GPIO_InitStruct);
  //初始化上管GPIO
  GPIO_InitStruct.Pins = PWM_AH_PIN | PWM_BH_PIN | PWM_CH_PIN;
  GPIO_Init(PWM_HN_PORT,&GPIO_InitStruct);
        
  PWM_AL_OFF;PWM_BL_OFF;PWM_CL_OFF;   //初始化先關(guān)閉下管
        
  //初始化ATIM的PWM通道
  ATIM_InitTypeDef ATIM_InitStruct;
  ATIM_OCInitTypeDef ATIM_OCInitStruct;
        
  PA08_AFx_ATIMCH1A();               //上管ABC三相
  PA09_AFx_ATIMCH2A();
  PA10_AFx_ATIMCH3A();
        
  ATIM_InitStruct.BufferState = DISABLE;
  ATIM_InitStruct.ClockSelect = ATIM_CLOCK_PCLK;
  ATIM_InitStruct.CounterAlignedMode = ATIM_COUNT_MODE_EDGE_ALIGN;
  ATIM_InitStruct.CounterDirection = ATIM_COUNTING_UP;
  ATIM_InitStruct.CounterOPMode = ATIM_OP_MODE_REPETITIVE;
  ATIM_InitStruct.OverFlowMask = DISABLE;
  ATIM_InitStruct.Prescaler = ATIM_Prescaler_DIV1;    // 計(jì)算時(shí)鐘1MHz
  ATIM_InitStruct.ReloadValue = PWM_TS - 1;           // 20K 
  ATIM_InitStruct.RepetitionCounter = 0;
  ATIM_InitStruct.UnderFlowMask = DISABLE;
  ATIM_Init(&ATIM_InitStruct);

  //初始化PWM通道
  ATIM_OCInitStruct.BufferState = DISABLE;
  ATIM_OCInitStruct.OCDMAState = DISABLE;
  ATIM_OCInitStruct.OCInterruptSelect = ATIM_OC_IT_UP_COUNTER;
  ATIM_OCInitStruct.OCInterruptState = ENABLE;
  ATIM_OCInitStruct.OCMode = ATIM_OCMODE_PWM1;
  ATIM_OCInitStruct.OCPolarity = ATIM_OCPOLARITY_NONINVERT;
  ATIM_OC1AInit(&ATIM_OCInitStruct);
  ATIM_OC2AInit(&ATIM_OCInitStruct);
  ATIM_OC3AInit(&ATIM_OCInitStruct);

  ATIM_SetCompare1A(0);        //初始化先關(guān)閉上管
  ATIM_SetCompare2A(0);
  ATIM_SetCompare3A(0);
  ATIM_PWMOutputConfig(OCREFA_TYPE_SINGLE, OUTPUT_TYPE_COMP, 0);
  ATIM_CtrlPWMOutputs(ENABLE);
  ATIM_Cmd(ENABLE);
}

void ATIM_IRQHandler(void)
{
  if (ATIM_GetITStatus(ATIM_IT_OVF))
  {
    ATIM_ClearITPendingBit(ATIM_IT_OVF);                
  }
}

//step,為當(dāng)前換相序號(hào),OutPwmValue 輸出PWM值,PWM_ON_flag=1時(shí)啟動(dòng)PWM輸出
void Commutation(unsigned int step,unsigned int OutPwmValue,unsigned int PWM_ON_flag)
{
 if(PWM_ON_flag==0) //不啟動(dòng)則關(guān)閉輸出
   {
     CW_ATIM- >CH1CCRA=0;CW_ATIM- >CH2CCRA=0;CW_ATIM- >CH3CCRA=0;        
     ATIM_CtrlPWMOutputs(DISABLE);
     PWM_AL_OFF;PWM_BL_OFF;PWM_CL_OFF;
     return;
   }
     PWM_AL_OFF;PWM_BL_OFF;PWM_CL_OFF;           //先關(guān)閉輸出,避免意外

     //輸出上橋
     if(step==0||step==1){         CW_ATIM- >CH1CCRA=OutPwmValue;CW_ATIM- >CH2CCRA=0;CW_ATIM- >CH3CCRA=0;        } //0:AB; 1:AC
     if(step==2||step==3){         CW_ATIM- >CH1CCRA=0;CW_ATIM- >CH2CCRA=OutPwmValue;CW_ATIM- >CH3CCRA=0;        } //2:BC; 3:BA
     if(step==4||step==5){         CW_ATIM- >CH1CCRA=0;CW_ATIM- >CH2CCRA=0;CW_ATIM- >CH3CCRA=OutPwmValue;        } //4:CA; 5:CB
        
     //輸出下橋
     if(step==0||step==5){PWM_AL_OFF;PWM_CL_OFF;PWM_BL_ON;}       //AB CB ; B下橋?qū)?/span>
     else if(step==1||step==2){PWM_AL_OFF;PWM_BL_OFF;PWM_CL_ON;}//AC BC; C下橋?qū)?/span>
     else if(step==3||step==4){PWM_BL_OFF;PWM_CL_OFF;PWM_AL_ON;}//BA CA; A下橋?qū)?/span>
                
     ATIM_CtrlPWMOutputs(ENABLE);         //輸出有效
     STEP_last = step;
}

void UPPWM(void)         //更新PWM占空比
{        
  if(STEP_last==0||STEP_last==1){         CW_ATIM- >CH2CCRA=0;CW_ATIM- >CH3CCRA=0; CW_ATIM- >CH1CCRA=OutPwm;        }
  if(STEP_last==2||STEP_last==3){         CW_ATIM- >CH1CCRA=0;CW_ATIM- >CH3CCRA=0;CW_ATIM- >CH2CCRA=OutPwm;        }
  if(STEP_last==4||STEP_last==5){         CW_ATIM- >CH1CCRA=0;CW_ATIM- >CH2CCRA=0;CW_ATIM- >CH3CCRA=OutPwm;        }
}

void BLDC_Motor_Start(uint8_t Dir)  //啟動(dòng)電機(jī)
{         
  uint32_t x;  
        
  x=HALL_Check();
  if(x==0||x==7) {x=1;}           //如果霍爾異常,輸出一項(xiàng),使電機(jī)先轉(zhuǎn)起來
  Cur_Step=STEP_TAB[Direction][x-1];
  Motor_Start_F = 1;
  OutPwm = OUTMINPWM;
  Commutation(Cur_Step,OutPwm,Motor_Start_F);
}

void BLDC_Motor_Stop(void)         //停止電機(jī)
{
  Motor_Start_F = 0;
  Commutation(Cur_Step,OutPwm,Motor_Start_F);;
}

與測速(BTIM1)相關(guān)的文件:

Speed_Measure.h

#ifndef _SPEED_MEASURE_H_
#define _SPEED_MEASURE_H_

#include "cw32f030_btim.h"
#include "cw32f030_rcc.h"

void Speed_Measure_Init(void);

#endif

Speed_Measure.c

#include "Speed_Measure.h"

extern uint32_t HALLcount;           //霍爾脈沖計(jì)數(shù)
extern uint16_t ADC_TimeCount;       //電位器ADC采樣計(jì)算計(jì)數(shù)
extern uint16_t Hall_TimeCount;      //計(jì)數(shù),進(jìn)了2次BTIM1中斷,即20ms對轉(zhuǎn)速計(jì)算一次
extern uint16_t OLED_FRESH_TimeCount;//計(jì)數(shù),500ms刷新一次OLED顯示

void Speed_Measure_Init(void)        //BTIM1 10ms進(jìn)一次中斷,在中斷里改變標(biāo)志位           
{
  __RCC_BTIM_CLK_ENABLE();
  __disable_irq(); 
  NVIC_EnableIRQ(BTIM1_IRQn); 
  __enable_irq();
        
  BTIM_TimeBaseInitTypeDef BTIM_InitStruct;
  BTIM_InitStruct.BTIM_Mode = BTIM_Mode_TIMER;
  BTIM_InitStruct.BTIM_OPMode = BTIM_OPMode_Repetitive;
  BTIM_InitStruct.BTIM_Prescaler = BTIM_PRS_DIV64;
  BTIM_InitStruct.BTIM_Period = 10000;           
  BTIM_TimeBaseInit(CW_BTIM1, &BTIM_InitStruct);
  BTIM_ITConfig(CW_BTIM1, BTIM_IT_OV, ENABLE);
  BTIM_Cmd(CW_BTIM1, ENABLE);
}        

void BTIM1_IRQHandler(void)
{
  /* USER CODE BEGIN */
  if(BTIM_GetITStatus(CW_BTIM1, BTIM_IT_OV))
  {  
    BTIM_ClearITPendingBit(CW_BTIM1, BTIM_IT_OV);

    Hall_TimeCount++;        //計(jì)數(shù),進(jìn)了2次BTIM1中斷,即20ms對轉(zhuǎn)速計(jì)算一次
    ADC_TimeCount++;         //計(jì)數(shù),100ms檢查一次電位器的電壓大小,確定目標(biāo)速度
    OLED_FRESH_TimeCount++;  //計(jì)數(shù),500ms刷新一次OLED顯示
  }
  /* USER CODE END */
}

與電位器輸入有關(guān)的文件:

ADC_BLDC_Ctrl.h

#ifndef _ADC_BLDC_CTRL_H_
#define _ADC_BLDC_CTRL_H_

#include "cw32f030_rcc.h"
#include "cw32f030_gpio.h"
#include "cw32f030_adc.h"
#include "cw32f030_dma.h"

void ADC_Configuration(void);
void ADC_DMA_Trans(void);
uint32_t ADC_SampleTarget(void);

#endif

ADC_BLDC_Ctrl.c

#include "ADC_BLDC_Ctrl.h"

uint32_t ADC_Result_Array;

//ADC采集電位器的值,使用了DMA傳輸
void ADC_Configuration(void)
{
  RCC_AHBPeriphClk_Enable(RCC_AHB_PERIPH_DMA | RCC_AHB_PERIPH_GPIOB, ENABLE);  //開啟DMA和ADC使用GPIO引腳的時(shí)鐘
  RCC_APBPeriphClk_Enable2(RCC_APB2_PERIPH_ADC, ENABLE);    //開啟ADC時(shí)鐘

  PB00_ANALOG_ENABLE();  //配置ADC測試IO口  電位器接口
        
  //ADC初始化
  ADC_InitTypeDef   ADC_InitStruct;         
  ADC_InitStruct.ADC_OpMode = ADC_SingleChContinuousMode; 
  ADC_InitStruct.ADC_ClkDiv = ADC_Clk_Div8;          //PCLK 8MHz
  ADC_InitStruct.ADC_SampleTime = ADC_SampTime10Clk; //10個(gè)ADC時(shí)鐘周期
  ADC_InitStruct.ADC_VrefSel = ADC_Vref_VDDA;        //外部3.3V參考電壓
  ADC_InitStruct.ADC_InBufEn = ADC_BufDisable;       //開啟跟隨器
  ADC_InitStruct.ADC_TsEn = ADC_TsDisable;           //內(nèi)置溫度傳感器禁用
  ADC_InitStruct.ADC_DMAEn = ADC_DmaEnable;          //ADC轉(zhuǎn)換完成觸發(fā)DMA傳輸
  ADC_InitStruct.ADC_Align = ADC_AlignRight;         //ADC轉(zhuǎn)換結(jié)果右對齊
  ADC_InitStruct.ADC_AccEn = ADC_AccDisable;         //轉(zhuǎn)換結(jié)果累加不使能
  ADC_Init(&ADC_InitStruct);                         //初始化ADC配置
  CW_ADC- >CR1_f.DISCARD = FALSE;                     //配置數(shù)據(jù)更新策略,覆蓋未被讀取的舊數(shù)據(jù),保留新數(shù)據(jù)
  CW_ADC- >CR1_f.CHMUX = ADC_ExInputCH8;              //配置ADC輸入通道
        
  //ADC使能
  ADC_Enable();    
  ADC_SoftwareStartConvCmd(ENABLE);
    
  //配置DMA
  DMA_InitTypeDef   DMA_InitStruct;
  DMA_StructInit( &DMA_InitStruct );
  DMA_InitStruct.DMA_Mode = DMA_MODE_BLOCK;        //該模式在傳輸過程中會(huì)被更高級(jí)的響應(yīng)打斷
  DMA_InitStruct.DMA_TransferWidth = DMA_TRANSFER_WIDTH_32BIT;//傳輸32位
  DMA_InitStruct.DMA_SrcInc = DMA_SrcAddress_Fix;  //源地址增量方式固定
  DMA_InitStruct.DMA_DstInc = DMA_DstAddress_Fix;  //目的地址增量方式固定
  DMA_InitStruct.DMA_TransferCnt =60000;           
  DMA_InitStruct.DMA_SrcAddress = (uint32_t) &(CW_ADC- >RESULT0);//(0x00000020) RESULT0
  DMA_InitStruct.DMA_DstAddress = (uint32_t)&ADC_Result_Array;
  DMA_InitStruct.TrigMode = DMA_HardTrig;          //硬件觸發(fā)
  DMA_InitStruct.HardTrigSource = DMA_HardTrig_ADC_TRANSCOMPLETE; //ADC采集完成觸發(fā)
  DMA_Init(CW_DMACHANNEL3,&DMA_InitStruct);
  DMA_ClearITPendingBit(DMA_IT_ALL);
  DMA_ITConfig(CW_DMACHANNEL3, DMA_IT_TC|DMA_IT_TE , ENABLE);     //使能DMA_CHANNEL3中斷
  DMA_Cmd(CW_DMACHANNEL3, ENABLE);                 //使能DMA
}

void ADC_DMA_Trans(void)
{
  if (CW_DMA- >ISR_f.TC3)
  { //AD DMA 啟動(dòng)
    CW_DMA- >ICR_f.TC3 = 0;        
    CW_DMACHANNEL3- >CNT=bv16|60000;         //MUST RET AGAIN BEFORE CW_DMACHANNEL1- >CNT=0
    CW_DMACHANNEL3- >CSR_f.EN = 1;                 
  }
}

uint32_t ADC_SampleTarget(void)            //采集電壓
{
  uint32_t Target = 0;
        
  if(ADC_Result_Array >= 4000)Target = 4000;//限制大小,12位ADC采集值為:0-4096
  else if(ADC_Result_Array < 3)Target = 0;
  else Target = ADC_Result_Array;

  return Target;
}

與顯示有關(guān)的驅(qū)動(dòng)函數(shù)由于篇幅原因不在此展示 ,下面展示main.c的內(nèi)容:

#include "main.h"

uint8_t Direction;                //電機(jī)方向,0為正轉(zhuǎn),1為反轉(zhuǎn)
uint8_t Motor_Start_F=0;          //電機(jī)啟動(dòng)運(yùn)行標(biāo)志

uint16_t ADC_TimeCount=0;         //電位器ADC采樣計(jì)時(shí)計(jì)數(shù)
uint16_t Hall_TimeCount=0;        //霍爾計(jì)時(shí)計(jì)數(shù)
uint16_t OLED_FRESH_TimeCount=0;  //OLED刷新顯示計(jì)時(shí)計(jì)數(shù)
uint32_t HALLcount=0;             //霍爾脈沖計(jì)數(shù)

uint32_t Motor_Speed = 0;         //電機(jī)實(shí)際轉(zhuǎn)速,rpm 

extern uint32_t OutPwm;

char Buffer1[48],Buffer2[48];
uint32_t Pwm_Buffer;

int main()
{
  RCC_Configuration();            //時(shí)鐘樹初始化
  I2C_init();                                        //OLED初始化
  I2C_OLED_Init();                //I2C初始化
  BLDC_Init();                    //電機(jī)初始化
  HALL_Init();                    //霍爾傳感器初始化
  Speed_Measure_Init();           //BTIM1初始化
  ADC_Configuration();            //ADC初始化
  I2C_OLED_Clear(1);              //清屏
        
  Direction = 1;     //電機(jī)方向
        
  sprintf(Buffer1,"Speed:%d rpm   ",Motor_Speed); //顯示電機(jī)轉(zhuǎn)速
  sprintf(Buffer2,"PWM:%d %%   ",Pwm_Buffer);     //顯示PWM占空比
  I2C_OLED_ShowString(0,0,Buffer1);        
  I2C_OLED_ShowString(0,15,Buffer2);
  I2C_OLED_UPdata(); 
        
  while(1)
  {
    ADC_DMA_Trans();          //DMA傳輸完畢則允許下一次傳輸
                
    if(ADC_TimeCount > 10)    //100ms檢查一次目標(biāo)速度
    {
      ADC_TimeCount = 0;

      OutPwm = ADC_SampleTarget() / 5;                   //設(shè)置占空比
      if(OutPwm > 0 && Motor_Start_F == 0)BLDC_Motor_Start(Direction);//轉(zhuǎn)速大于1000rpm才啟動(dòng)電機(jī)
      else if(OutPwm > 0 && Motor_Start_F == 1)UPPWM();  //更新占空比
      else BLDC_Motor_Stop(); //停止電機(jī)
    }
                
    if(Hall_TimeCount > 1)   //20ms測一次速
    {
      Hall_TimeCount = 0;
      Motor_Speed = HALLcount * 500 / MotorPoles;  //轉(zhuǎn)速計(jì)算,rpm
      HALLcount = 0;
    }
                
    if(OLED_FRESH_TimeCount > 50)  //500ms OLED顯示刷新一次
    {
      OLED_FRESH_TimeCount = 0;
      sprintf(Buffer1,"Speed:%d rpm   ",Motor_Speed);    //顯示電機(jī)轉(zhuǎn)速
      I2C_OLED_ShowString(0,0,Buffer1);
                        
      Pwm_Buffer = OutPwm/32;     //最大25%對應(yīng)OutPwm的值:800
      sprintf(Buffer2,"PWM:%d %%   ",Pwm_Buffer);        //顯示占空比
      I2C_OLED_ShowString(0,15,Buffer2);
      I2C_OLED_UPdata();
    }
  }
}

void RCC_Configuration(void)
{
  RCC_HSI_Enable(RCC_HSIOSC_DIV6);

  /* 1. 設(shè)置HCLK和PCLK的分頻系數(shù) */
  RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
  RCC_PCLKPRS_Config(RCC_PCLK_DIV1);

  /* 2. 使能PLL,通過HSI倍頻到64MHz */
  RCC_PLL_Enable(RCC_PLLSOURCE_HSI, 8000000, 8);     
  // PLL輸出頻率64MHz

  /*< 當(dāng)使用的時(shí)鐘源HCLK大于24M,小于等于48MHz:設(shè)置FLASH 讀等待周期為2 cycle
  < 當(dāng)使用的時(shí)鐘源HCLK大于48M,小于等于72MHz:設(shè)置FLASH 讀等待周期為3 cycle */    
  __RCC_FLASH_CLK_ENABLE();
  FLASH_SetLatency(FLASH_Latency_3);

  /* 3. 時(shí)鐘切換到PLL */
  RCC_SysClk_Switch(RCC_SYSCLKSRC_PLL);
  RCC_SystemCoreClockUpdate(64000000);
}

最終的實(shí)驗(yàn)結(jié)果如下:


圖5-1 有霍爾方波開環(huán)控制無刷直流空心杯電機(jī)

5.2 有霍爾方波閉環(huán)控制程序

閉環(huán)程序與開環(huán)程序相比,分別在main.c、Speed_Measure.c、ADC_BLDC_Ctrl.c文件中略有變化,同時(shí)新增了PID.c文件用于控制。

首先是main.c文件中的變化,新增了變量Flag_PID_TimeCount、Target_Speed,函數(shù)修改如下:

int main()
{
  RCC_Configuration();            //時(shí)鐘樹初始化
  I2C_init();                     //OLED初始化
  I2C_OLED_Init();                //I2C初始化
  BLDC_Init();                    //電機(jī)初始化
  HALL_Init();                    //霍爾傳感器初始化
  Speed_Measure_Init();           //BTIM1初始化
  PID_Init();                     //PID初始化
  ADC_Configuration();            //ADC初始化
  I2C_OLED_Clear(1);              //清屏
        
  Direction = 1;     //電機(jī)方向
        
  sprintf(Buffer1,"Target:%d rpm",Target_Speed);  //顯示目標(biāo)速度
  sprintf(Buffer2,"Speed:%d rpm   ",Motor_Speed); //顯示電機(jī)轉(zhuǎn)速
  I2C_OLED_ShowString(0,0,Buffer1);
  I2C_OLED_ShowString(0,15,Buffer2);        
  I2C_OLED_UPdata(); 
        
  while(1)
  {
    ADC_DMA_Trans();          //DMA傳輸完畢則允許下一次傳輸
    if(ADC_TimeCount > 10)    //100ms檢查一次目標(biāo)速度
    {
      ADC_TimeCount = 0;
                        
      Target_Speed = ADC_SampleTarget();  //采集目標(biāo)速度
      if(Target_Speed > 1000 && Motor_Start_F == 0)BLDC_Motor_Start(Direction);//轉(zhuǎn)速大于1000rpm才啟動(dòng)電機(jī)
      else if(Target_Speed > 1000 && Motor_Start_F == 1);  //沒有操作,避免重復(fù)啟動(dòng)
      else BLDC_Motor_Stop(); //停止電機(jī)
    }
                
    if(Hall_TimeCount > 1)   //20ms測一次速
    {
      Hall_TimeCount = 0;
      Motor_Speed = HALLcount * 500 / MotorPoles;  //轉(zhuǎn)速計(jì)算,HALLcount * 50 * 60 / 6 ,單位rpm
      HALLcount = 0;
    }
                
    if(Flag_PID_TimeCount > 1) //20ms PID控制一次
    {
      Flag_PID_TimeCount = 0;
      PID_Ctrl(Target_Speed);
    }
                
    if(OLED_FRESH_TimeCount > 50)  //500ms OLED顯示刷新一次
    {
      OLED_FRESH_TimeCount = 0;
      sprintf(Buffer1,"Target:%d rpm   ",Target_Speed);  //顯示目標(biāo)速度
      sprintf(Buffer2,"Speed:%d rpm   ",Motor_Speed);    //顯示電機(jī)轉(zhuǎn)速
      I2C_OLED_ShowString(0,0,Buffer1);
      I2C_OLED_ShowString(0,15,Buffer2);        
      I2C_OLED_UPdata();
    }
  }      
}

Speed_Measure.c中對BTIM1的中斷服務(wù)程序修改:

void BTIM1_IRQHandler(void)
{
  /* USER CODE BEGIN */
  if(BTIM_GetITStatus(CW_BTIM1, BTIM_IT_OV))
  {  
    BTIM_ClearITPendingBit(CW_BTIM1, BTIM_IT_OV);
  
    Hall_TimeCount++;        //計(jì)數(shù),進(jìn)了2次BTIM1中斷,即20ms對轉(zhuǎn)速計(jì)算一次
    Flag_PID_TimeCount++;    //計(jì)數(shù),進(jìn)了2次BTIM1中斷,即20ms對PID計(jì)算一次
    ADC_TimeCount++;         //計(jì)數(shù),100ms檢查一次電位器的電壓大小,確定目標(biāo)速度
    OLED_FRESH_TimeCount++;  //計(jì)數(shù),500ms刷新一次OLED顯示
  }
  /* USER CODE END */
}

ADC_BLDC_Ctrl.c中對電壓采集函數(shù)作修改:

uint32_t ADC_SampleTarget(void)        //采集電壓
{
  uint32_t Target = 0;
        
  if(ADC_Result_Array >= 4000)Target = 4000;//限制大小,12位ADC采集值為:0-4096
  else if(ADC_Result_Array < 3)Target = 0;
  else Target = ADC_Result_Array;
        
  Target = Target * 5;                 //目標(biāo)速度為采集值的5被則設(shè)置最大速度20000rpm,可自行修改
        
  return Target;
}

新增PID文件如下:

#include "PID.h"

extern uint8_t Motor_Start_F;  //電機(jī)啟動(dòng)運(yùn)行標(biāo)志
extern uint32_t OutPwm;        //輸出PWM值,PID最終計(jì)算要得到一個(gè)確定的PWM占空比輸出值
extern uint32_t Motor_Speed;   //電機(jī)實(shí)際轉(zhuǎn)速,rpm 

float V_Kp,V_Ki,V_Kd;

void PID_Init(void)
{
  V_Kp = 25;
  V_Ki = 5;
  V_Kd = 0;
}

void PID_Ctrl(uint32_t Target)
{
  static int Error,LastError;
  int PID=0;
        
  Error = Target - Motor_Speed;
        
  PID = (V_Kp/1000) * (Error - LastError) + (V_Ki/1000) * Error;
        
  if(PID >10)PID=10;         //犧牲響應(yīng)速度換取穩(wěn)定性,避免占空比從0突增到25 
  else if(PID< -10)PID=-10;
        
  OutPwm += PID;
        
  if(OutPwm > OUTMAXPWM)OutPwm = OUTMAXPWM;  //占空比輸出限制
  else if(OutPwm < OUTMINPWM)
  {
    if(Target > 100)OutPwm = OUTMINPWM;
    else OutPwm = 0;
  }
        
  if(Motor_Start_F == 0)OutPwm = 0;         //啟停判斷
  else if(Motor_Start_F == 1);
  else OutPwm = 0;
        
  UPPWM();                                  //更新占空比
  LastError = Error;
}

最終實(shí)驗(yàn)結(jié)果如下:


圖5-2 有霍爾方波閉環(huán)控制無刷直流空心杯電機(jī)

六、調(diào)試過程中的問題與小提示

在調(diào)試過程中作者曾燒板四次,前面兩次燒毀MOS管,后兩次燒毀PCB供電,針對此種問題有三條注意事項(xiàng):

  1. 程序在KEIL5在進(jìn)入和退出調(diào)試窗口的過程中存在未知的運(yùn)行情況,所有燒毀都在進(jìn)入和退出調(diào)試窗口時(shí)發(fā)生,推薦使用類似學(xué)校教學(xué)使用的線性電源限流0.2A進(jìn)行供電,開關(guān)電源限流速度較慢也會(huì)發(fā)生燒毀。
  2. 如果缺乏對應(yīng)電源,可以在進(jìn)入和退出調(diào)試窗口前斷掉PCB供電,待進(jìn)入調(diào)試后再對PCB上電。
  3. 如果發(fā)生燒毀情況,首先檢查PCB供電的芯片XL7005是否損壞,如若正常則依次檢查EG3013的15V供電,板上的5V和3.3V供電。如果電機(jī)仍然無法轉(zhuǎn)動(dòng),再使用萬用表通斷檔測量MOS管是否燒毀。

小提示

  1. 對于BLDC.c文件中的程序,需要確認(rèn)邏輯是否嚴(yán)密,切記不可發(fā)生上下橋同時(shí)導(dǎo)通的情況。
  2. 在 ADC_SampleTarget 函數(shù)可以自行修改 Target 的值來規(guī)定目標(biāo)速度上限。
  3. 本程序的方向切換在程序里手動(dòng)設(shè)置,如果讀者想要通過按鍵等控制方向,需要在方向改變前先停止電機(jī),再切換方向,不可在電機(jī)運(yùn)行時(shí)直接改變方向和換相順序。
  4. 對于轉(zhuǎn)速的測量要及時(shí),雖然由于硬件原因,測量轉(zhuǎn)速時(shí)間間隔越小,轉(zhuǎn)速變化的梯度越大,但是未獲得實(shí)時(shí)速度會(huì)導(dǎo)致PID控制效果不佳。先測速再進(jìn)行PID運(yùn)算。

審核編輯 黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 電機(jī)
    +關(guān)注

    關(guān)注

    141

    文章

    8769

    瀏覽量

    143759
  • PID
    PID
    +關(guān)注

    關(guān)注

    35

    文章

    1466

    瀏覽量

    84834
  • 無刷電機(jī)
    +關(guān)注

    關(guān)注

    57

    文章

    800

    瀏覽量

    45473
  • CW32
    +關(guān)注

    關(guān)注

    1

    文章

    168

    瀏覽量

    502
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    基于CW32直流空心電機(jī)感方波控制驅(qū)動(dòng)方案

    適合用于電機(jī)控制。感方波控制算法是一種簡單有效的電機(jī)控制算法,不需要使用霍爾傳感器,可以降低硬
    的頭像 發(fā)表于 04-24 15:38 ?1587次閱讀
    基于<b class='flag-5'>CW32</b>的<b class='flag-5'>無</b><b class='flag-5'>刷</b><b class='flag-5'>直流</b><b class='flag-5'>空心</b><b class='flag-5'>杯</b><b class='flag-5'>電機(jī)</b><b class='flag-5'>無</b>感方波<b class='flag-5'>控制</b><b class='flag-5'>驅(qū)動(dòng)</b><b class='flag-5'>方案</b>

    淺析基于CW32直流空心電機(jī)有感控制驅(qū)動(dòng)方案

    空心電機(jī)(Hollow-Cup Motor)是一種特殊類型的微型直流電機(jī),具有
    的頭像 發(fā)表于 05-21 10:39 ?1251次閱讀
    淺析基于<b class='flag-5'>CW32</b>的<b class='flag-5'>無</b><b class='flag-5'>刷</b><b class='flag-5'>直流</b><b class='flag-5'>空心</b><b class='flag-5'>杯</b><b class='flag-5'>電機(jī)</b><b class='flag-5'>有感</b><b class='flag-5'>控制</b><b class='flag-5'>驅(qū)動(dòng)</b><b class='flag-5'>方案</b>

    基于ARM的空心電機(jī)控制設(shè)計(jì)

    本設(shè)計(jì)是基于μC/OS—III控制系統(tǒng),采用ARM處理器控制PWM驅(qū)動(dòng)空心電機(jī),來達(dá)到快速
    發(fā)表于 01-06 17:33

    空心電機(jī)的特點(diǎn)及分類

    空心電機(jī)(coreless motor)屬于直流、永磁、伺服微特電機(jī)。空心
    發(fā)表于 09-13 06:53

    什么是空心無刷電機(jī)

    常規(guī)磁體結(jié)構(gòu)的空心型定子高速永磁直流電機(jī)的氣隙磁通密度較低,采用新型磁體結(jié)構(gòu)能夠大幅度提高氣隙磁通密度。
    發(fā)表于 08-23 08:56 ?69次下載

    空心電機(jī)原理_空心電機(jī)特性

    空心電動(dòng)機(jī)在結(jié)構(gòu)上突破了傳統(tǒng)電機(jī)的轉(zhuǎn)子結(jié)構(gòu)形式,采用的是鐵芯轉(zhuǎn)子,也叫空心型轉(zhuǎn)子。這種轉(zhuǎn)子
    發(fā)表于 09-20 11:18 ?9305次閱讀
    <b class='flag-5'>空心</b><b class='flag-5'>杯</b><b class='flag-5'>電機(jī)</b>原理_<b class='flag-5'>空心</b><b class='flag-5'>杯</b><b class='flag-5'>電機(jī)</b>特性

    空心直流電機(jī)有哪些類型

    空心直流電機(jī)具有體積小效率高的特點(diǎn),由于空心電機(jī)沒有鐵芯大大的減小的
    發(fā)表于 08-16 09:33 ?2242次閱讀

    空心電機(jī)的結(jié)構(gòu)原理

    了由于鐵芯形成渦流而造成的電能損耗,大大地提高了電動(dòng)機(jī)的伺服特性。 ? 一、空心電機(jī)結(jié)構(gòu)原理 空心電動(dòng)機(jī)采用的是
    的頭像 發(fā)表于 08-09 23:53 ?8069次閱讀

    空心電機(jī)的工作原理

    了由于鐵芯形成渦流而造成的電能損耗,大大地提高了電動(dòng)機(jī)的伺服特性。 ? 一、空心電機(jī)結(jié)構(gòu)原理 空心電動(dòng)機(jī)采用的是
    的頭像 發(fā)表于 08-10 23:49 ?1.6w次閱讀

    基于CW32F030C8T6的直流電機(jī)驅(qū)動(dòng)系統(tǒng)

    該工程項(xiàng)目采用CW32F030C8T6+EG3013+WSF40N10A組成的BLDC驅(qū)動(dòng)電路,分別實(shí)現(xiàn):BLDC的有感開環(huán)、有感閉環(huán)、
    的頭像 發(fā)表于 07-02 14:06 ?5578次閱讀
    基于<b class='flag-5'>CW</b>32F030C8T6的<b class='flag-5'>無</b><b class='flag-5'>刷</b><b class='flag-5'>直流電機(jī)</b><b class='flag-5'>驅(qū)動(dòng)</b>系統(tǒng)

    基于CW32水泵方案

    基于CW32水泵方案
    的頭像 發(fā)表于 11-03 17:28 ?683次閱讀
    基于<b class='flag-5'>CW32</b>的<b class='flag-5'>無</b><b class='flag-5'>刷</b>水泵<b class='flag-5'>方案</b>

    求一種基于CW32直流空心電機(jī)感方波控制驅(qū)動(dòng)方案

    方案采用CW32F030C8T6作為主控芯片,采用感方波控制算法控制
    的頭像 發(fā)表于 05-28 10:47 ?644次閱讀
    求一種基于<b class='flag-5'>CW32</b>的<b class='flag-5'>無</b><b class='flag-5'>刷</b><b class='flag-5'>直流</b><b class='flag-5'>空心</b><b class='flag-5'>杯</b><b class='flag-5'>電機(jī)</b><b class='flag-5'>無</b>感方波<b class='flag-5'>控制</b><b class='flag-5'>驅(qū)動(dòng)</b><b class='flag-5'>方案</b>

    空心電機(jī)是有還是

    空心電機(jī)空心
    的頭像 發(fā)表于 06-12 15:00 ?1197次閱讀

    空心電機(jī)效率高嗎為什么

    探討其在不同應(yīng)用中的優(yōu)勢。 空心電機(jī)的工作原理 空心電機(jī)是一種
    的頭像 發(fā)表于 06-12 15:38 ?497次閱讀

    空心電機(jī)的結(jié)構(gòu)原理是什么

    、醫(yī)療設(shè)備等。本文將詳細(xì)介紹空心電機(jī)的結(jié)構(gòu)原理。 一、空心電機(jī)的基本概念 1.1
    的頭像 發(fā)表于 06-12 17:33 ?1261次閱讀