01
概述
空心杯電機(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)
1.1空心杯電機(jī)的特點(diǎn)和優(yōu)勢(shì)
空心結(jié)構(gòu):空心杯設(shè)計(jì)使得電機(jī)的旋轉(zhuǎn)部分中心為空,可以通過空心軸傳遞其他信號(hào)、光線或氣體,并且由于繞組無鐵芯,轉(zhuǎn)矩分布均勻。
高功率密度:由于其緊湊的設(shè)計(jì)和高效的電機(jī)結(jié)構(gòu),空心杯電機(jī)具有較高的功率密度,可以在有限的空間內(nèi)提供更大的扭矩輸出。
平滑運(yùn)行:空心杯電機(jī)通常具有平滑的運(yùn)行特性,可以提供穩(wěn)定的轉(zhuǎn)速和低噪音。
高精度和可控性:空心杯電機(jī)的設(shè)計(jì)使得其具有較高的精度和可控性,適用于需要精確位置控制的應(yīng)用。
快速響應(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)。 1.2應(yīng)用場景
機(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ī)可以滿足這些要求。
自動(dòng)化設(shè)備:在自動(dòng)化設(shè)備中,如自動(dòng)裝配線、自動(dòng)化儀器等,空心杯電機(jī)可用于驅(qū)動(dòng)各種傳送帶、傳送裝置和旋轉(zhuǎn)平臺(tái),以實(shí)現(xiàn)工件的快速、精確定位和搬運(yùn)。
醫(yī)療器械:空心杯電機(jī)在醫(yī)療器械中的應(yīng)用廣泛,例如手術(shù)機(jī)器人、醫(yī)療影像裝置、藥物輸送系統(tǒng)等。這些應(yīng)用需要高度精確的運(yùn)動(dòng)控制和定位,而空心杯電機(jī)能夠提供穩(wěn)定的力矩輸出和高精度的位置控制。
光學(xué)設(shè)備:在需要進(jìn)行旋轉(zhuǎn)、調(diào)焦、變焦等精密光學(xué)操作的設(shè)備中,如攝像機(jī)、望遠(yuǎn)鏡、激光器等,空心杯電機(jī)可用于驅(qū)動(dòng)相應(yīng)的部件,實(shí)現(xiàn)精確的光路控制和圖像穩(wěn)定。
回轉(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)裝置的尺寸和重量。
02
控制原理
2.1 霍爾傳感器
霍爾傳感器是一種基于霍爾效應(yīng)原理的傳感器,用于檢測磁場的存在和變化。它通常由霍爾元件、信號(hào)調(diào)理電路和輸出接口組成。霍爾元件是一種半導(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)生一種電勢(shì)差。這個(gè)電勢(shì)差被稱為霍爾電壓,其大小與外部磁場的強(qiáng)度成正比。
霍爾傳感器具有以下特點(diǎn)和優(yōu)勢(shì):
非接觸式檢測:霍爾傳感器通過檢測磁場,而無需與被檢測物直接接觸,從而避免了物理接觸可能帶來的摩擦和磨損。
快速響應(yīng):由于霍爾傳感器是基于半導(dǎo)體材料的電子器件,其響應(yīng)速度非常快,可以實(shí)時(shí)檢測和響應(yīng)磁場變化。
高精度:霍爾傳感器能夠提供精確的磁場測量和檢測,可用于測量磁場的強(qiáng)度、方向和變化。
寬工作溫度范圍:霍爾傳感器具有較寬的工作溫度范圍,可以在高溫或低溫環(huán)境下正常工作。
可靠性和耐用性:霍爾傳感器不受機(jī)械磨損的影響,具有較長的使用壽命和可靠性。
低功耗:霍爾傳感器通常具有低功耗特性,適用于電池供電或?qū)δ茉聪拿舾械膽?yīng)用。
在本次實(shí)驗(yàn)中,我們使用霍爾傳感器對(duì)轉(zhuǎn)子位置進(jìn)行檢測。通過將三個(gè)霍爾傳感器相隔120°安裝在電機(jī)定子的不同位置,即可根據(jù)霍爾傳感器的電平信號(hào)確定電機(jī)轉(zhuǎn)子的位置。下圖是本次實(shí)驗(yàn)用到的霍爾真值表,理解真值表后對(duì)程序的編寫有著重要作用:
圖2-1 120°霍爾真值表
上圖左為正轉(zhuǎn),右為反轉(zhuǎn)。從上圖可以看出,A、B、C三相霍爾傳感器分別在空間上間隔120°放置,當(dāng)轉(zhuǎn)子的磁極運(yùn)動(dòng)到對(duì)應(yīng)的霍爾傳感器位置時(shí),對(duì)應(yīng)的相產(chǎn)生高電平,高電平的持續(xù)角度為180°(電角度,當(dāng)電機(jī)極對(duì)數(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),在程序里讀取對(duì)應(yīng)霍爾引腳的電平狀態(tài)即可判斷此時(shí)電機(jī)轉(zhuǎn)子的位置,這對(duì)于后續(xù)的方波控制尤為重要。
2.2 方波控制
方波控制是通過改變電機(jī)的輸入電壓信號(hào)來控制電機(jī)的轉(zhuǎn)速和方向,這里的方波是指在電機(jī)運(yùn)行過程中定子電流的波形近似方波。
圖2-2無刷直流電機(jī)的電路等效圖
如果我們采用二二導(dǎo)通的方式,即同一時(shí)刻電機(jī)的繞組只有兩相導(dǎo)通,本次實(shí)驗(yàn)的空心杯電機(jī)的內(nèi)部為三角形連接,極對(duì)數(shù)為1。在一個(gè)電周期(360°)內(nèi),由上面提到的霍爾六種不同的狀態(tài)來切換控制MOSFET的開通關(guān)斷,使得定子電流也有六種狀態(tài),即定子繞組的合成磁動(dòng)勢(shì)有六種狀態(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)行呢,我們?cè)谶@里用較為通俗的語言解釋,如果讀者有興趣可以自行查閱相關(guān)資料。電機(jī)的定子通電后也具有磁性,根據(jù)“異性相吸”的原理,電機(jī)轉(zhuǎn)子會(huì)向著通電的定子相運(yùn)動(dòng)直至二者“吸住”,如果在轉(zhuǎn)子運(yùn)動(dòng)到對(duì)應(yīng)“相吸”定子前的一瞬間,斷掉該定子的供電而對(duì)順著轉(zhuǎn)子運(yùn)動(dòng)方向相隔120°的下一相定子供電,則轉(zhuǎn)子又會(huì)與下一相定子“相吸”,如此往復(fù)即可使轉(zhuǎn)子不斷轉(zhuǎn)動(dòng),上文的電路等效圖對(duì)應(yīng)相關(guān)定子相的供電。
圖2-3 直流無刷電機(jī)定轉(zhuǎn)子運(yùn)動(dòng)示意圖
一個(gè)完整系統(tǒng)的方波控制步驟如下:
01 設(shè)置控制系統(tǒng)
確定控制系統(tǒng)的輸入和輸出接口,選擇適當(dāng)?shù)?a target="_blank">控制器(如微控制器)和驅(qū)動(dòng)電路。
02 確定轉(zhuǎn)子位置
根據(jù)霍爾傳感器信號(hào)的真值表,確定電機(jī)轉(zhuǎn)子此時(shí)的位置。
03 確定換相順序
根據(jù)轉(zhuǎn)子的位置情況,確定電機(jī)定子的換相順序,即圖2-2中VT1-6的通斷順序。
04 控制電機(jī)轉(zhuǎn)速
通過對(duì)MOS管VT輸入PWM信號(hào),該變占空比來控制平均電壓的大小即可控制電機(jī)的轉(zhuǎn)速。
05 控制電機(jī)方向
通過改變換相順序的運(yùn)行方向,可以控制電機(jī)的運(yùn)動(dòng)方向。
06 反饋控制(可選)
如果需要更精確的控制,可以使用更加靈敏的傳感器,如編碼器,來進(jìn)一步監(jiān)測電機(jī)的位置,在程序里使用對(duì)應(yīng)算法(如PID)精確控制電機(jī)的位置和速度。
注意事項(xiàng):
控制器的選擇應(yīng)考慮到方波控制的要求,如頻率范圍、引腳采樣速度和分辨率等。
驅(qū)動(dòng)電路的設(shè)計(jì)應(yīng)與電機(jī)的額定電壓和電流匹配,并具備過流、過壓等保護(hù)功能。
在實(shí)際應(yīng)用中,應(yīng)注意電機(jī)的負(fù)載特性、慣性等因素對(duì)控制的影響,可能需要進(jìn)行參數(shù)調(diào)整和系統(tǒng)優(yōu)化。
04
CW32性能特點(diǎn)
本次實(shí)驗(yàn)采用的MCU為CW32F030C8T6,其性能特點(diǎn)如下:
架構(gòu)和處理能力:CW32F030C8T6采用了ARM Cortex-M0+處理器核心,具有高性能和低功耗的特點(diǎn)。Cortex-M0+是ARM架構(gòu)中的一種32位處理器核心,適用于對(duì)功耗要求較高的應(yīng)用場景。
主頻和存儲(chǔ)器:CW32F030C8T6的主頻可以高達(dá)48MHz,提供了較高的處理速度。它具有8KB的SRAM(靜態(tài)隨機(jī)存儲(chǔ)器)和32KB的閃存(用于存儲(chǔ)程序代碼和數(shù)據(jù)),可用于存儲(chǔ)應(yīng)用程序和數(shù)據(jù)。
低功耗特性:CW32F030C8T6在低功耗方面表現(xiàn)出色,具有多種省電模式和功耗管理功能,可實(shí)現(xiàn)對(duì)系統(tǒng)功耗的有效控制。這對(duì)于需要長時(shí)間運(yùn)行的電池供電設(shè)備或?qū)拿舾械膽?yīng)用非常重要。
外設(shè)和接口:CW32F030C8T6提供了豐富的外設(shè)和接口,包括多個(gè)通用輸入輸出引腳(GPIO)、SPI(串行外設(shè)接口)、I2C(串行通信接口)、UART(通用異步收發(fā)器)等。這些接口可用于與外部傳感器、存儲(chǔ)器、通信模塊等設(shè)備進(jìn)行通信和連接。
定時(shí)器和中斷控制:CW32F030C8T6配備了多個(gè)定時(shí)器和中斷控制功能,可用于實(shí)現(xiàn)精確的定時(shí)和事件觸發(fā)。定時(shí)器可以用于生成精確的時(shí)間延遲、PWM(脈沖寬度調(diào)制)輸出等應(yīng)用,而中斷控制則可以實(shí)現(xiàn)對(duì)外部事件的快速響應(yīng)。
安全性和保護(hù)機(jī)制:CW32F030C8T6提供了多種安全性和保護(hù)機(jī)制,包括存儲(chǔ)器保護(hù)單元、訪問控制等。這些機(jī)制可以幫助保護(hù)系統(tǒng)免受潛在的安全威脅和未授權(quán)訪問。
本次實(shí)驗(yàn)我們使用了CW32的ATIM、GTIM、BTIM、ADC和DMA外設(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 對(duì)互補(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ā)中斷請(qǐng)求和 DMA 請(qǐng)求。得益于對(duì)觸發(fā)信號(hào)的精細(xì)處理設(shè)計(jì),使得 BTIM 可以由硬件自動(dòng)執(zhí)行觸發(fā)信號(hào)的濾波操作,還能令觸發(fā)事件產(chǎn)生中斷和 DMA 請(qǐng)求。本次實(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 對(duì)外設(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 功能框圖
04
實(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ī)(參考圖)如下:
圖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
05
程序編寫
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); #endifHALL.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(); //先打開對(duì)應(yīng)時(shí)鐘 __RCC_GPIOA_CLK_ENABLE(); __RCC_GPIOB_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct; //再配置對(duì)應(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; //對(duì)每個(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ù)程序里對(duì)霍爾脈沖計(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ū)? 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) //啟動(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對(duì)轉(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對(duì)轉(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é)果右對(duì)齊 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%對(duì)應(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中對(duì)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對(duì)轉(zhuǎn)速計(jì)算一次 Flag_PID_TimeCount++; //計(jì)數(shù),進(jìn)了2次BTIM1中斷,即20ms對(duì)PID計(jì)算一次 ADC_TimeCount++; //計(jì)數(shù),100ms檢查一次電位器的電壓大小,確定目標(biāo)速度 OLED_FRESH_TimeCount++; //計(jì)數(shù),500ms刷新一次OLED顯示 } /* USER CODE END */ }
ADC_BLDC_Ctrl.c中對(duì)電壓采集函數(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ī)
06
調(diào)試過程中的問題與小提示
在調(diào)試過程中,作者曾燒板四次,前面兩次燒毀MOS管,后兩次燒毀PCB供電,針對(duì)此種問題有三條注意事項(xiàng):
程序在KEIL5在進(jìn)入和退出調(diào)試窗口的過程中存在未知的運(yùn)行情況,所有燒毀都在進(jìn)入和退出調(diào)試窗口時(shí)發(fā)生,推薦使用性能較好的線性電源限流0.2A進(jìn)行供電,開關(guān)電源限流響應(yīng)較慢,也會(huì)導(dǎo)致板子或電機(jī)燒毀。
如果缺乏對(duì)應(yīng)電源,可以在進(jìn)入和退出調(diào)試窗口前斷掉PCB供電,待進(jìn)入調(diào)試后再對(duì)PCB上電。
如果發(fā)生燒毀情況,首先檢查PCB供電的芯片XL7005是否損壞,如若正常則依次檢查EG3013的15V供電,板上的5V和3.3V供電。如果電機(jī)仍然無法轉(zhuǎn)動(dòng),再使用萬用表測量MOS管是否燒毀。
小提示
對(duì)于BLDC.c文件中的程序,需要確認(rèn)邏輯是否嚴(yán)密,切記不可發(fā)生上下橋同時(shí)導(dǎo)通的情況。
在 ADC_SampleTarget 函數(shù)可以自行修改 Target 的值來規(guī)定目標(biāo)速度上限。
本程序的方向切換在程序里手動(dòng)設(shè)置,如果讀者想要通過按鍵等控制方向,需要在方向改變前先停止電機(jī),再切換方向,不可在電機(jī)運(yùn)行時(shí)直接改變方向和換相順序。
對(duì)于轉(zhuǎn)速的測量要及時(shí),雖然由于硬件原因,測量轉(zhuǎn)速時(shí)間間隔越小,轉(zhuǎn)速變化的梯度越大,但是未獲得實(shí)時(shí)速度會(huì)導(dǎo)致PID控制效果不佳。先測速再進(jìn)行PID運(yùn)算。
審核編輯:劉清
-
MOSFET
+關(guān)注
關(guān)注
147文章
7194瀏覽量
213591 -
激光器
+關(guān)注
關(guān)注
17文章
2524瀏覽量
60468 -
霍爾傳感器
+關(guān)注
關(guān)注
27文章
726瀏覽量
63255 -
無刷直流電機(jī)
+關(guān)注
關(guān)注
61文章
690瀏覽量
46210 -
永磁體
+關(guān)注
關(guān)注
0文章
124瀏覽量
5522
原文標(biāo)題:【產(chǎn)品方案】基于CW32的無刷直流空心杯電機(jī)有感控制驅(qū)動(dòng)方案
文章出處:【微信號(hào):武漢芯源半導(dǎo)體,微信公眾號(hào):武漢芯源半導(dǎo)體】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論