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

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

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

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

武漢芯源半導(dǎo)體 ? 來源:CW32生態(tài)社區(qū) ? 2024-05-21 10:39 ? 次閱讀

01

概述

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

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

d3c7b58c-1710-11ef-b74b-92fbcf53809c.jpg

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

1.1空心杯電機(jī)的特點和優(yōu)勢

空心結(jié)構(gòu):空心杯設(shè)計使得電機(jī)的旋轉(zhuǎn)部分中心為空,可以通過空心軸傳遞其他信號、光線或氣體,并且由于繞組無鐵芯,轉(zhuǎn)矩分布均勻。

高功率密度:由于其緊湊的設(shè)計和高效的電機(jī)結(jié)構(gòu),空心杯電機(jī)具有較高的功率密度,可以在有限的空間內(nèi)提供更大的扭矩輸出。

平滑運行:空心杯電機(jī)通常具有平滑的運行特性,可以提供穩(wěn)定的轉(zhuǎn)速和低噪音。

高精度和可控性:空心杯電機(jī)的設(shè)計使得其具有較高的精度和可控性,適用于需要精確位置控制的應(yīng)用。

快速響應(yīng):由于其轉(zhuǎn)動慣量小,空心杯電機(jī)能夠快速響應(yīng)控制信號,機(jī)械時間常數(shù)可以達(dá)到ms級,適用于需要高速動態(tài)響應(yīng)的應(yīng)用場景。

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

機(jī)器人技術(shù):空心杯電機(jī)廣泛應(yīng)用于機(jī)器人的關(guān)節(jié)驅(qū)動器中,能夠提供高精度的運動控制和力矩輸出。機(jī)器人的關(guān)節(jié)通常需要快速而準(zhǔn)確地執(zhí)行各種動作,而空心杯電機(jī)可以滿足這些要求。

自動化設(shè)備:在自動化設(shè)備中,如自動裝配線、自動化儀器等,空心杯電機(jī)可用于驅(qū)動各種傳送帶、傳送裝置和旋轉(zhuǎn)平臺,以實現(xiàn)工件的快速、精確定位和搬運。

醫(yī)療器械:空心杯電機(jī)在醫(yī)療器械中的應(yīng)用廣泛,例如手術(shù)機(jī)器人、醫(yī)療影像裝置、藥物輸送系統(tǒng)等。這些應(yīng)用需要高度精確的運動控制和定位,而空心杯電機(jī)能夠提供穩(wěn)定的力矩輸出和高精度的位置控制。

光學(xué)設(shè)備:在需要進(jìn)行旋轉(zhuǎn)、調(diào)焦、變焦等精密光學(xué)操作的設(shè)備中,如攝像機(jī)、望遠(yuǎn)鏡、激光器等,空心杯電機(jī)可用于驅(qū)動相應(yīng)的部件,實現(xiàn)精確的光路控制和圖像穩(wěn)定。

回轉(zhuǎn)平臺:空心杯電機(jī)常被用于回轉(zhuǎn)平臺或轉(zhuǎn)臺,例如航天器的天線轉(zhuǎn)動、攝影設(shè)備的平穩(wěn)旋轉(zhuǎn)等。通過空心杯電機(jī)的驅(qū)動,可以實現(xiàn)平穩(wěn)、高速的旋轉(zhuǎn),并且減小了傳動裝置的尺寸和重量。

02

控制原理

2.1 霍爾傳感器

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

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

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

非接觸式檢測:霍爾傳感器通過檢測磁場,而無需與被檢測物直接接觸,從而避免了物理接觸可能帶來的摩擦和磨損。

快速響應(yīng):由于霍爾傳感器是基于半導(dǎo)體材料的電子器件,其響應(yīng)速度非???,可以實時檢測和響應(yīng)磁場變化。

高精度:霍爾傳感器能夠提供精確的磁場測量和檢測,可用于測量磁場的強(qiáng)度、方向和變化。

寬工作溫度范圍:霍爾傳感器具有較寬的工作溫度范圍,可以在高溫或低溫環(huán)境下正常工作。

可靠性和耐用性:霍爾傳感器不受機(jī)械磨損的影響,具有較長的使用壽命和可靠性。

低功耗:霍爾傳感器通常具有低功耗特性,適用于電池供電或?qū)δ茉聪拿舾械膽?yīng)用。

在本次實驗中,我們使用霍爾傳感器對轉(zhuǎn)子位置進(jìn)行檢測。通過將三個霍爾傳感器相隔120°安裝在電機(jī)定子的不同位置,即可根據(jù)霍爾傳感器的電平信號確定電機(jī)轉(zhuǎn)子的位置。下圖是本次實驗用到的霍爾真值表,理解真值表后對程序的編寫有著重要作用:

d3de3f14-1710-11ef-b74b-92fbcf53809c.png

圖2-1 120°霍爾真值表

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

2.2 方波控制

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

d4099772-1710-11ef-b74b-92fbcf53809c.png

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

如果我們采用二二導(dǎo)通的方式,即同一時刻電機(jī)的繞組只有兩相導(dǎo)通,本次實驗的空心杯電機(jī)的內(nèi)部為三角形連接,極對數(shù)為1。在一個電周期(360°)內(nèi),由上面提到的霍爾六種不同的狀態(tài)來切換控制MOSFET的開通關(guān)斷,使得定子電流也有六種狀態(tài),即定子繞組的合成磁動勢有六種狀態(tài)——所以,方波控制又被稱為六步換相。 以上文的霍爾狀態(tài)舉例,當(dāng)霍爾傳感器傳出信號為5時,控制VT1和VT6開通,其余關(guān)斷,所以A相電流為正,B相電流為負(fù);電機(jī)旋轉(zhuǎn)至霍爾信號為1時,控制VT1和VT2開通,其余關(guān)斷;以此類推,完整地經(jīng)歷過六個狀態(tài)后,電機(jī)也就旋轉(zhuǎn)完了一圈,再次進(jìn)行上述步驟就可以使得電機(jī)連續(xù)運行。

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

d425ba60-1710-11ef-b74b-92fbcf53809c.png

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

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

01 設(shè)置控制系統(tǒng)

確定控制系統(tǒng)的輸入和輸出接口,選擇適當(dāng)?shù)?a target="_blank">控制器(如微控制器)和驅(qū)動電路。

02 確定轉(zhuǎn)子位置

根據(jù)霍爾傳感器信號的真值表,確定電機(jī)轉(zhuǎn)子此時的位置。

03 確定換相順序

根據(jù)轉(zhuǎn)子的位置情況,確定電機(jī)定子的換相順序,即圖2-2中VT1-6的通斷順序。

04 控制電機(jī)轉(zhuǎn)速

通過對MOS管VT輸入PWM信號,該變占空比來控制平均電壓的大小即可控制電機(jī)的轉(zhuǎn)速。

05 控制電機(jī)方向

通過改變換相順序的運行方向,可以控制電機(jī)的運動方向。

06 反饋控制(可選)

如果需要更精確的控制,可以使用更加靈敏的傳感器,如編碼器,來進(jìn)一步監(jiān)測電機(jī)的位置,在程序里使用對應(yīng)算法(如PID)精確控制電機(jī)的位置和速度。

注意事項:

控制器的選擇應(yīng)考慮到方波控制的要求,如頻率范圍、引腳采樣速度和分辨率等。

驅(qū)動電路的設(shè)計應(yīng)與電機(jī)的額定電壓和電流匹配,并具備過流、過壓等保護(hù)功能。

在實際應(yīng)用中,應(yīng)注意電機(jī)的負(fù)載特性、慣性等因素對控制的影響,可能需要進(jìn)行參數(shù)調(diào)整和系統(tǒng)優(yōu)化。

04

CW32性能特點

本次實驗采用的MCU為CW32F030C8T6,其性能特點如下:

架構(gòu)和處理能力:CW32F030C8T6采用了ARM Cortex-M0+處理器核心,具有高性能和低功耗的特點。Cortex-M0+是ARM架構(gòu)中的一種32位處理器核心,適用于對功耗要求較高的應(yīng)用場景。

主頻和存儲器:CW32F030C8T6的主頻可以高達(dá)48MHz,提供了較高的處理速度。它具有8KB的SRAM(靜態(tài)隨機(jī)存儲器)和32KB的閃存(用于存儲程序代碼和數(shù)據(jù)),可用于存儲應(yīng)用程序和數(shù)據(jù)。

低功耗特性:CW32F030C8T6在低功耗方面表現(xiàn)出色,具有多種省電模式和功耗管理功能,可實現(xiàn)對系統(tǒng)功耗的有效控制。這對于需要長時間運行的電池供電設(shè)備或?qū)拿舾械膽?yīng)用非常重要。

外設(shè)和接口:CW32F030C8T6提供了豐富的外設(shè)和接口,包括多個通用輸入輸出引腳(GPIO)、SPI(串行外設(shè)接口)、I2C(串行通信接口)、UART(通用異步收發(fā)器)等。這些接口可用于與外部傳感器、存儲器、通信模塊等設(shè)備進(jìn)行通信和連接。

定時器和中斷控制:CW32F030C8T6配備了多個定時器和中斷控制功能,可用于實現(xiàn)精確的定時和事件觸發(fā)。定時器可以用于生成精確的時間延遲、PWM(脈沖寬度調(diào)制)輸出等應(yīng)用,而中斷控制則可以實現(xiàn)對外部事件的快速響應(yīng)。

安全性和保護(hù)機(jī)制:CW32F030C8T6提供了多種安全性和保護(hù)機(jī)制,包括存儲器保護(hù)單元、訪問控制等。這些機(jī)制可以幫助保護(hù)系統(tǒng)免受潛在的安全威脅和未授權(quán)訪問。

本次實驗我們使用了CW32的ATIM、GTIM、BTIM、ADCDMA外設(shè),下面分別簡要介紹這五種外設(shè)。

3.1 高級定時器(ATIM)

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

d44a747c-1710-11ef-b74b-92fbcf53809c.png

圖3-1 ATIM 功能框圖

3.2 通用定時器(GTIM)

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

d47a3266-1710-11ef-b74b-92fbcf53809c.png

圖3-2 GTIM功能框圖

3.3 基本定時器(BTIM)

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

d49262f0-1710-11ef-b74b-92fbcf53809c.png

圖3-3 BTIM功能框圖

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

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

d4bb5264-1710-11ef-b74b-92fbcf53809c.png

圖3-4 ADC 功能框圖

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

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

d4e0b8b0-1710-11ef-b74b-92fbcf53809c.png

圖3-5 DMA 功能框圖

04

實驗設(shè)備

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

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

d5046b48-1710-11ef-b74b-92fbcf53809c.png

圖4-1 CW32_BLCD_EVA 評估板資源配置圖

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

本次實驗使用的空心杯電機(jī)(參考圖)如下:

d534796e-1710-11ef-b74b-92fbcf53809c.jpg

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

連接示意圖如下:

d56038ce-1710-11ef-b74b-92fbcf53809c.jpg

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

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

d58524e0-1710-11ef-b74b-92fbcf53809c.png

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

d5ad9916-1710-11ef-b74b-92fbcf53809c.png

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

d65168fc-1710-11ef-b74b-92fbcf53809c.png

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

05

程序編寫

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

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

首先是與霍爾傳感器相關(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ī)運行錯誤代碼
extern uint8_t Motor_Start_F;                //電機(jī)啟動運行標(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ī)換相序號
extern uint32_t HALLcount;                  //霍爾脈沖計數(shù)
extern uint32_t OutPwm;                   //輸出PWM值
//初始化霍爾傳感器要用到的GPIO和定時器
void HALL_Init(void)
{
 __RCC_GTIM2_CLK_ENABLE();          //先打開對應(yīng)時鐘
 __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;     //對每個引腳狀態(tài)分別判斷,所以三個if而不是else if
 if(PB03_GETVALUE()!=0)Hall_State|=0x2;    //或運算 010
 if(PA02_GETVALUE()!=0)Hall_State|=0x4;    //或運算 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ù)程序里對霍爾脈沖計數(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++;                    //霍爾脈沖計數(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ī)換相序號
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ī)啟動運行標(biāo)志
uint32_t OutPwm;          //PWM占空比
//初始化電機(jī)要用到的GPIO和定時器,上橋為PWM,下橋為引腳電平控制
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;  // 計算時鐘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)前換相序號,OutPwmValue 輸出PWM值,PWM_ON_flag=1時啟動PWM輸出
void Commutation(unsigned int step,unsigned int OutPwmValue,unsigned int PWM_ON_flag)
{
 if(PWM_ON_flag==0) //不啟動則關(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ū)?   else if(step==1||step==2){PWM_AL_OFF;PWM_BL_OFF;PWM_CL_ON;}//AC BC; C下橋?qū)?   else if(step==3||step==4){PWM_BL_OFF;PWM_CL_OFF;PWM_AL_ON;}//BA CA; A下橋?qū)? 
   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) //啟動電機(jī)
{     
 uint32_t x; 
 
 x=HALL_Check();
 if(x==0||x==7) {x=1;}      //如果霍爾異常,輸出一項,使電機(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;      //霍爾脈沖計數(shù)
extern uint16_t ADC_TimeCount;    //電位器ADC采樣計算計數(shù)
extern uint16_t Hall_TimeCount;   //計數(shù),進(jìn)了2次BTIM1中斷,即20ms對轉(zhuǎn)速計算一次
extern uint16_t OLED_FRESH_TimeCount;//計數(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++;    //計數(shù),進(jìn)了2次BTIM1中斷,即20ms對轉(zhuǎn)速計算一次
  ADC_TimeCount++;     //計數(shù),100ms檢查一次電位器的電壓大小,確定目標(biāo)速度
  OLED_FRESH_TimeCount++; //計數(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引腳的時鐘
 RCC_APBPeriphClk_Enable2(RCC_APB2_PERIPH_ADC, ENABLE);  //開啟ADC時鐘
 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個ADC時鐘周期
 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;    //該模式在傳輸過程中會被更高級的響應(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 啟動
  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ū)動函數(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ī)啟動運行標(biāo)志
uint16_t ADC_TimeCount=0;     //電位器ADC采樣計時計數(shù)
uint16_t Hall_TimeCount=0;    //霍爾計時計數(shù)
uint16_t OLED_FRESH_TimeCount=0; //OLED刷新顯示計時計數(shù)
uint32_t HALLcount=0;       //霍爾脈沖計數(shù)
uint32_t Motor_Speed = 0;     //電機(jī)實際轉(zhuǎn)速,rpm 
extern uint32_t OutPwm;
char Buffer1[48],Buffer2[48];
uint32_t Pwm_Buffer;
int main()
{
 RCC_Configuration();      //時鐘樹初始化
 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才啟動電機(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)速計算,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)使用的時鐘源HCLK大于24M,小于等于48MHz:設(shè)置FLASH 讀等待周期為2 cycle
 ?< 當(dāng)使用的時鐘源HCLK大于48M,小于等于72MHz:設(shè)置FLASH 讀等待周期為3 cycle */ ? ?
 ?__RCC_FLASH_CLK_ENABLE();
 ?FLASH_SetLatency(FLASH_Latency_3);
 ?/* 3. 時鐘切換到PLL */
 ?RCC_SysClk_Switch(RCC_SYSCLKSRC_PLL);
 ?RCC_SystemCoreClockUpdate(64000000);
}

最終的實驗結(jié)果如下:

d673787a-1710-11ef-b74b-92fbcf53809c.jpg

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

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

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

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

int main()
{
 RCC_Configuration();      //時鐘樹初始化
 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才啟動電機(jī)
   else if(Target_Speed > 1000 && Motor_Start_F == 1); //沒有操作,避免重復(fù)啟動
   else BLDC_Motor_Stop(); //停止電機(jī)
  }
 
  if(Hall_TimeCount > 1)  //20ms測一次速
  {
   Hall_TimeCount = 0;
   Motor_Speed = HALLcount * 500 / MotorPoles; //轉(zhuǎn)速計算,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++;    //計數(shù),進(jìn)了2次BTIM1中斷,即20ms對轉(zhuǎn)速計算一次
  Flag_PID_TimeCount++;  //計數(shù),進(jìn)了2次BTIM1中斷,即20ms對PID計算一次
  ADC_TimeCount++;     //計數(shù),100ms檢查一次電位器的電壓大小,確定目標(biāo)速度
  OLED_FRESH_TimeCount++; //計數(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ī)啟動運行標(biāo)志
extern uint32_t OutPwm;    //輸出PWM值,PID最終計算要得到一個確定的PWM占空比輸出值
extern uint32_t Motor_Speed;  //電機(jī)實際轉(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;
}

最終實驗結(jié)果如下:

d6a35842-1710-11ef-b74b-92fbcf53809c.jpg

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

06

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

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

程序在KEIL5在進(jìn)入和退出調(diào)試窗口的過程中存在未知的運行情況,所有燒毀都在進(jìn)入和退出調(diào)試窗口時發(fā)生,推薦使用性能較好的線性電源限流0.2A進(jìn)行供電,開關(guān)電源限流響應(yīng)較慢,也會導(dǎo)致板子或電機(jī)燒毀。

如果缺乏對應(yīng)電源,可以在進(jìn)入和退出調(diào)試窗口前斷掉PCB供電,待進(jìn)入調(diào)試后再對PCB上電。

如果發(fā)生燒毀情況,首先檢查PCB供電的芯片XL7005是否損壞,如若正常則依次檢查EG3013的15V供電,板上的5V和3.3V供電。如果電機(jī)仍然無法轉(zhuǎn)動,再使用萬用表測量MOS管是否燒毀。

小提示

對于BLDC.c文件中的程序,需要確認(rèn)邏輯是否嚴(yán)密,切記不可發(fā)生上下橋同時導(dǎo)通的情況。

在 ADC_SampleTarget 函數(shù)可以自行修改 Target 的值來規(guī)定目標(biāo)速度上限。

本程序的方向切換在程序里手動設(shè)置,如果讀者想要通過按鍵等控制方向,需要在方向改變前先停止電機(jī),再切換方向,不可在電機(jī)運行時直接改變方向和換相順序。

對于轉(zhuǎn)速的測量要及時,雖然由于硬件原因,測量轉(zhuǎn)速時間間隔越小,轉(zhuǎn)速變化的梯度越大,但是未獲得實時速度會導(dǎo)致PID控制效果不佳。先測速再進(jìn)行PID運算。



審核編輯:劉清

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

    關(guān)注

    142

    文章

    7001

    瀏覽量

    212240
  • 激光器
    +關(guān)注

    關(guān)注

    17

    文章

    2455

    瀏覽量

    60092
  • 霍爾傳感器
    +關(guān)注

    關(guān)注

    26

    文章

    696

    瀏覽量

    62938
  • 無刷直流電機(jī)
    +關(guān)注

    關(guān)注

    60

    文章

    682

    瀏覽量

    45885
  • 永磁體
    +關(guān)注

    關(guān)注

    0

    文章

    116

    瀏覽量

    5429

原文標(biāo)題:【產(chǎn)品方案】基于CW32的無刷直流空心杯電機(jī)有感控制驅(qū)動方案

文章出處:【微信號:武漢芯源半導(dǎo)體,微信公眾號:武漢芯源半導(dǎo)體】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

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

    適合用于電機(jī)控制感方波控制算法是一種簡單有效的電機(jī)控制算法,不需要使用霍爾傳感器,可以降低硬
    的頭像 發(fā)表于 04-24 15:38 ?1711次閱讀
    基于<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ū)動</b><b class='flag-5'>方案</b>

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

    一、概述 空心電機(jī)(Hollow-Cup Motor)是一種特殊類型的微型直流電機(jī),具有
    的頭像 發(fā)表于 04-24 15:28 ?2006次閱讀
    基于<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ū)動</b><b class='flag-5'>方案</b>

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

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

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

    空心電機(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ī)特性

    空心電動機(jī)在結(jié)構(gòu)上突破了傳統(tǒng)電機(jī)的轉(zhuǎn)子結(jié)構(gòu)形式,采用的是鐵芯轉(zhuǎn)子,也叫空心型轉(zhuǎn)子。這種轉(zhuǎn)子
    發(fā)表于 09-20 11:18 ?9410次閱讀
    <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ī)具有體積小效率高的特點,由于空心電機(jī)沒有鐵芯大大的減小的
    發(fā)表于 08-16 09:33 ?2275次閱讀

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

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

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

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

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

    該工程項目采用CW32F030C8T6+EG3013+WSF40N10A組成的BLDC驅(qū)動電路,分別實現(xiàn):BLDC的有感開環(huán)、有感閉環(huán)、
    的頭像 發(fā)表于 07-02 14:06 ?5657次閱讀
    基于<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ū)動</b>系統(tǒng)

    基于CW32水泵方案

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

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

    方案采用CW32F030C8T6作為主控芯片,采用感方波控制算法控制
    的頭像 發(fā)表于 05-28 10:47 ?690次閱讀
    求一種基于<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ū)動</b><b class='flag-5'>方案</b>

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

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

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

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

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

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