User Tools

Site Tools


study:motor-paper:2024-12-20-01:index

基於CW32的無刷直流空心杯馬達有感控制驅動方案 (2024-12-20)

Local Backup

01、概述

  • 空心杯電機(Hollow-Cup Motor)是一種特殊類型的微型無刷直流電機,具有空心的旋轉部分。它通常由外部固定的外殼和內部旋轉的空心杯組成。空心杯馬達具有較高的功率密度和扭矩輸出,適用於一些特定的應用場景,如精密儀器、機器人、醫療設備等。
  • 空心杯馬達的工作原理是基於無刷直流馬達的原理。它採用無刷馬達的結構,包括定子(固定部分)和轉子(旋轉部分)。定子包含一組永久磁鐵,而轉子則包含一組線圈。透過電流在線圈中的流動和永久磁鐵之間的相互作用,產生電磁力,使轉子旋轉。

  • 圖1-1 空心杯馬達結構

1.1空心杯馬達的特性與優勢

  • 空心結構:空心杯設計使得馬達的旋轉部分中心為空,可以透過空心軸傳遞其他訊號、光線或氣體,並且由於繞組無鐵芯,因此轉矩分佈均勻。
  • 高功率密度:由於其緊湊的設計和高效的馬達結構,空心杯馬達具有較高的功率密度,可在有限的空間內提供更大的扭力輸出。
  • 平滑運轉:空心杯馬達通常具有平滑的運轉特性,可以提供穩定的轉速和低雜訊。
  • 高精度和可控性:空心杯馬達的設計使得其具有較高的精度和可控性,適用於需要精確位置控制的應用。
  • 快速響應:由於其轉動慣量小,空心杯馬達能夠快速響應控制訊號,機械時間常數可以達到ms級,適用於需要高速動態響應的應用場景。
  • 需要注意的是,空心杯馬達由於結構緊湊的設計導致散熱困難,並且其要實現高速和高精度的響應,因此空心杯電機的功率和扭矩都有一定的限制,需要根據具體工程問題選擇合適的馬達類型和配套的控制系統。

1.2應用場景

  • 機器人技術:空心杯馬達廣泛應用於機器人的關節驅動器中,能夠提供高精度的運動控制和力矩輸出。機器人的關節通常需要快速且準確地執行各種動作,而空心杯馬達可以滿足這些要求。
  • 自動化設備:在自動化設備中,如自動裝配線、自動化儀器等,空心杯馬達可用於驅動各種傳送帶、傳送裝置和旋轉平台,以實現工件的快速、精確定位和搬運。
  • 醫療器械:空心杯馬達在醫療器械的應用廣泛,例如手術機器人、醫療影像裝置、藥物傳輸系統等。這些應用需要高度精確的運動控制和定位,而空心杯馬達能夠提供穩定的力矩輸出和高精度的位置控制。
  • 光學設備:在需要進行旋轉、調焦、變焦等精密光學操作的設備中,如攝影機、望遠鏡、雷射等,空心杯馬達可用於驅動相應的零件,實現精確的光路控制和影像穩定性。
  • 迴轉平台:空心杯馬達常被用於迴轉平台或轉台,例如太空船的天線轉動、攝影設備的平穩旋轉等。透過空心杯馬達的驅動,可以實現平穩、高速的旋轉,並且減少了傳動裝置的尺寸和重量。

02、控制原理

2.1 霍爾感測器

  • 霍爾感測器是一種基於霍爾效應原理的感測器,用於檢測磁場的存在和變化。它通常由霍爾元件、訊號調理電路和輸出介面組成。霍爾元件是一種半導體材料,當其受到外部磁場的作用時,會產生電壓訊號。這個電壓訊號經過訊號調理電路處理後,就可以輸出給控制系統做對應的處理。
  • 霍爾感測器的工作原理基於霍爾效應,即當電流通過某些材料時,受到垂直於電流方向的磁場的影響,會在材料兩側產生一種電位差。這個電位差被稱為霍爾電壓,其大小與外部磁場的強度成正比。
  • 霍爾感測器具有以下特點和優勢:
    • 非接觸式偵測:霍爾感測器透過偵測磁場,而無需與被偵測物直接接觸,從而避免了物理接觸可能帶來的摩擦和磨損。
    • 快速響應:由於霍爾感測器是基於半導體材料的電子裝置,其響應速度非常快,可以即時檢測和響應磁場變化。
    • 高精度:霍爾感測器能夠提供精確的磁場測量和檢測,可用於測量磁場的強度、方向和變化。
    • 寬工作溫度範圍:霍爾感測器具有較寬的工作溫度範圍,可以在高溫或低溫環境下正常工作。
    • 可靠性和耐用性:霍爾感測器不受機械磨損的影響,具有較長的使用壽命和可靠性。
    • 低功耗:霍爾感測器通常具有低功耗特性,適用於電池供電或對能源消耗敏感的應用。
  • 在本次實驗中,我們使用霍爾感測器對轉子位置進行偵測。將三個霍爾感測器相隔120°安裝在馬達定子的不同位置,即可根據霍爾感測器的電平訊號確定馬達轉子的位置。下圖是本次實驗用到的霍爾真值表,理解真值表後對程式的編寫有重要作用:

  • 圖2-1 120°霍爾真值表
  • 上圖左為正轉,右為反轉。從上圖可以看出,A、B、C三相霍爾感測器分別在空間上間隔120°放置,當轉子的磁極移動到對應的霍爾感測器位置時,對應的相產生高電平,高電平的持續角度為180°(電角度,當馬達極對數為1時也等於機械角度)。所以我們根據上面的真值表可以寫出馬達運轉時的六種狀態,以C相為高位:101、001、011、010、110、100;用十六進位的表示方式為:5、1 、3、2、6、4,也就是說馬達在正轉時,霍爾感測器的訊號只會按照513264的大小依序出現,在程式裡讀取對應霍爾引腳的電平狀態即可判斷此時馬達轉子的位置,這對於後續的方波控制尤為重要。

2.2 方波控制

  • 方波控制是透過改變馬達的輸入電壓訊號來控制馬達的轉速和方向,這裡的方波是指在馬達運轉過程中定子電流的波形近似方波。

  • 圖2-1 120°霍爾真值表
  • 如果我們採用二二導通的方式,即同一時刻電機的繞組只有兩相導通,本次實驗的空心杯電機的內部為三角形連接,極對數為1。在一個電週期(360°)內,由上面提到的霍爾六種不同的狀態來切換控制MOSFET的開通關斷,使得定子電流也有六種狀態,即定子繞組的合成磁動勢有六種態-所以,方波控制又被稱為六步換相。
  • 以上文的霍爾狀態舉例,當霍爾感測器傳出訊號為5時,控制VT1和VT6開通,其餘關斷,所以A相電流為正,B相電流為負;馬達旋轉至霍爾訊號為1時,控制VT1和VT2開通,其餘關斷;以此類推,完整地經歷過六個狀態後,電機也就旋轉完了一圈,再次進行上述步驟就可以使得電機連續運轉。
  • 那麼電機為什麼會這樣運作呢,我們在這裡用較為通俗的語言解釋,如果讀者有興趣可以自行查閱相關資料。馬達的定子通電後也具有磁性,根據“異性相吸”的原理,電機轉子會向著通電的定子相運動直至二者“吸住”,如果在轉子運動到對應“相吸”定子前的一瞬間,斷掉該定子的供電而對順著轉子運動方向相隔120°的下一相定子供電,則轉子又會與下一相定子“相吸”,如此往復即可使轉子不斷轉動,上文的電路等效圖對應相關定子相的供電。

  • 圖2-3 直流無刷馬達定轉子運動示意圖
  • 一個完整系統的方波控制步驟如下:
    • 01)設定控制系統
      • 確定控制系統的輸入和輸出接口,選擇適當的控制器(如微控制器)和驅動電路。
    • 02)確定轉子位置
      • 根據霍爾感測器訊號的真值表,確定馬達轉子此時的位置。
    • 03)確定換相順序
      • 根據轉子的位置情況,決定馬達定子的換相順序,即圖2-2中VT1-6的通斷順序。
    • 04)控制馬達轉速
      • 透過對MOS管VT輸入PWM訊號,此變佔空比來控制平均電壓的大小即可控制馬達的轉速。
    • 05)控制馬達方向
      • 透過改變換相順序的運轉方向,可以控制馬達的運動方向。
    • 06)回授控制(可選)
      • 如果需要更精確的控制,可以使用更靈敏的感測器,如編碼器,來進一步監控馬達的位置,在程式中使用對應演算法(如PID)精確控制馬達的位置和速度。
  • 注意事項:
    • 控制器的選擇應考慮到方波控制的要求,如頻率範圍、引腳取樣速度和解析度等。驅動電路的設計應與馬達的額定電壓和電流相匹配,並具備過電流、過壓等保護功能。在實際應用中,應注意馬達的負載特性、慣性等因素對控制的影響,可能需要參數調整和系統最佳化。

03、CW32性能特點

  • 本次實驗所採用的MCU為CW32F030C8T6,其性能特性如下:
    • 架構與處理能力:CW32F030C8T6採用了ARM Cortex-M0+處理器核心,具有高效能和低功耗的特性。 Cortex-M0+是ARM架構中的一種32位元處理器核心,適用於對功耗需求較高的應用場景。
    • 主頻和記憶體:CW32F030C8T6的主頻可以高達48MHz,提供了較高的處理速度。它具有8KB的SRAM(靜態隨機記憶體)和32KB的快閃記憶體(用於儲存程式碼和資料),可用於儲存應用程式和資料。
    • 低功耗特性:CW32F030C8T6在低功耗方面表現出色,具有多種省電模式和功耗管理功能,可實現對系統功耗的有效控制。這對於需要長時間運行的電池供電設備或對功耗敏感的應用非常重要。
    • 週邊和介面:CW32F030C8T6提供了豐富的周邊和接口,包括多個通用輸入輸出引腳(GPIO)、SPI(串行外設接口)、I2C(串行通訊接口)、UART(通用非同步收發器)等。這些介面可用於與外部感測器、記憶體、通訊模組等設備進行通訊和連接。
    • 定時器和中斷控制:CW32F030C8T6配備了多個定時器和中斷控制功能,可用於實現精確的定時和事件觸發。定時器可用於產生精確的時間延遲、PWM(脈衝寬度調變)輸出等應用,而中斷控制則可實現對外部事件的快速回應。
    • 安全性和保護機制:CW32F030C8T6提供了多種安全性和保護機制,包括記憶體保護單元、存取控制等。這些機制可以幫助保護系統免受潛在的安全威脅和未授權存取。
    • 本次實驗我們使用了CW32的ATIM、GTIM、BTIM、ADC和DMA外設,以下分別簡單介紹這五種週邊。

3.1 高級定時器(ATIM)

  • 高級定時器(ATIM) 由一個16 位元的自動重載計數器和7 個比較單元組成,並由一個可編程的預分頻器驅動。 ATIM 支援6 個獨立的擷取/ 比較通道,可實現6 路獨立PWM 輸出或3 對互補PWM 輸出或對6 路輸入進行擷取。可用於基本的定時/ 計數、測量輸入訊號的脈衝寬度和週期、產生輸出波形(PWM、單脈衝、插入死區時間的互補PWM 等)。在本次實驗中,我們使用ATIM 來產生PWM波驅動上橋。

  • 圖3-1 ATIM 功能框圖

3.2 通用定時器(GTIM)

  • CW32F030 內部整合4 個通用定時器(GTIM),每個GTIM 完全獨立且功能完全相同,各包含一個16bit 自動重裝載計數器並由一個可編程預分頻器驅動。 GTIM 支援定時器模式、計數器模式、觸發啟動模式和閘控模式4 種基本工作模式,每組帶4 路獨立的捕獲/ 比較通道,可以測量輸入訊號的脈衝寬度(輸入捕獲)或產生輸出波形(輸出比較和PWM)。本次實驗使用GTIM 的輸入擷取功能來觸發獲取霍爾感測器的資料。

  • 圖3-2 GTIM功能框圖

3.3 基本定時器(BTIM)

  • CW32F030 內部整合3 個基本定時器(BTIM),每個BTIM 完全獨立且功能完全相同,各包含一個16bit 自動重裝載計數器並由一個可編程預分頻器驅動。 BTIM 支援定時器模式、計數器模式、觸發啟動模式和閘控模式4 種工作模式,支援溢位事件觸發中斷請求和DMA 請求。由於採用對觸發訊號的精細處理設計,使得BTIM 可以由硬體自動執行觸發訊號的濾波操作,也能令觸發事件產生中斷和DMA 要求。本實驗使用BTIM的定時器中斷功能,10ms進入一次定時器中斷,在中斷中修改相關功能的標誌位,在主函數的while 循環裡根據標誌位判斷相關功能本次是否執行。

  • 圖3-3 BTIM功能框圖

3.4 類比數位轉換器(ADC)

  • CW32F030 內部整合一個12 位元精度、最高1M SPS 轉換速度的逐次逼近型類比數位轉換器(SAR ADC),最多可將16 路類比訊號轉換為數位訊號。現實世界中的絕大多數訊號都是類比量,如光、電、聲音、影像訊號等,都要由ADC 轉換成數位訊號,才能由MCU 進行數位化處理。本實驗使用ADC 擷取電位器的電壓值,根據電位器的電壓大小控制目標值的設定。

  • 圖3-4 ADC 功能框圖

3.5 直接記憶體存取(DMA)

  • CW32F030 支援直接記憶體存取(DMA),無需CPU 幹預,即可實現週邊裝置和記憶體之間、週邊裝置和周邊裝置之間、記憶體和記憶體之間的高速資料傳輸。 DMA 控制器內部的優先權仲裁器,可實現DMA 和CPU 對週邊總線控制權的仲裁,以及多DMA 通道之間的調度執行。本次實驗使用DMA 將ADC 擷取的資料寫入內存,DMA 傳輸由ADC 轉換完成訊號觸發。

  • 圖3-5 DMA 功能框圖

04、實驗設備

4.1 CW32-BLDC馬達驅動板

  • 本次實驗我們使用的無刷馬達驅動板為CW32_BLDC_EVA V5開發板,其配置如下:

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

4.2 空心杯馬達與連接

  • 本次實驗所使用的空心杯馬達如下圖:

  • 圖4-2 空心杯馬達實體圖
  • 連接示意圖如下:

  • 圖4-3 馬達與驅動板連接示意圖
  • 下面展示馬達驅動板的原理圖:

  • 圖4-4 馬達驅動板原理圖1

  • 圖4-5 馬達驅動板原理圖2

  • 圖4-6 馬達驅動板原理圖3

05、程式編寫

5.1 有霍爾方波開環控製程序

  • 下面會將控製程式依照不同的功能模組向讀者展示。
  • 首先是與霍爾感測器相關的模組,存放在HALL.c檔案中,先展示HALL.h檔案的內容:
    #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; //馬達運行錯誤碼
    extern uint8_t Motor_Start_F; //馬達啟動運作標誌
    extern uint8_t Cur_Step; //當前HALL狀態
    extern uint8_t Direction; //馬達方向,0為正轉,1為反轉
    const uint8_t STEP_TAB[2][6] = {{4,0,5,2,3,1},{1,3,2,5,0,4}};//電機換相序號
    extern uint32_t HALLcount; //霍爾脈衝計數
    extern uint32_t OutPwm; //輸出PWM值
    //初始化霍爾感測器要用到的GPIO和定時器
    void HALL_Init(void)
    {  
        __RCC_GTIM2_CLK_ENABLE(); //先開啟對應時鐘  
        __RCC_GPIOA_CLK_ENABLE();  
        __RCC_GPIOB_CLK_ENABLE();   
        
        GPIO_InitTypeDef GPIO_InitStruct; //再配置對應接口  
        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) //讀取霍爾狀態,決定換相順序
    {  
        static unsigned char hallerrnum=0;   
        unsigned char Hall_State=0;   
        
        if(PA15_GETVALUE()!=0)Hall_State=0x1; //對每個腳位狀態分別判斷,所以三個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都是異常狀態    
        {      
            hallerrnum++;      
            if(hallerrnum>=10)      
            {
                hallerrnum=10;
                ErrorCode=2;
            } //持續異常狀態說明霍爾感應器有問題    
        }  
        else hallerrnum=0;  
        return Hall_State;
    }
    void GTIM2_IRQHandler(void) //在GTIM2的中斷服務程式裡對霍爾脈衝計數、霍爾狀態確定、換相確定
    {          
        uint32_t Hall_State;         
        /* USER CODE BEGIN */  
        if (GTIM_GetITStatus(CW_GTIM2, GTIM_IT_CC1)) //擷取輸入變化就產生中斷標誌  
        {    
            GTIM_ClearITPendingBit(CW_GTIM2, GTIM_IT_CC1); //清除中斷標誌  
        }  
        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++; //霍爾脈衝計數           
        Hall_State=HALL_Check(); //讀取霍爾狀態   
        Cur_Step=STEP_TAB[Direction][Hall_State-1]; //取得換相序位,例如霍爾變化為513264,則Cur_Step變化為345012   
        if(Motor_Start_F==1&&ErrorCode==0) //依啟動停止狀態 換相     
         Commutation(Cur_Step,OutPwm,Motor_Start_F);             
        /* USER CODE END */
    }
  • 與馬達相關的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調變控制,下管GPIO開關控制, 上管高電平開關管導通,下管反相
      #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];//馬達換相序號
      uint8_t Cur_Step; //目前HALL狀態
      uint8_t STEP_last; //上次HALL狀態
      extern uint8_t Direction; //馬達方向,0為正轉,1為反轉
      extern uint8_t Motor_Start_F; //馬達啟動運作標誌
      uint32_t OutPwm; //PWM佔空比//初始化馬達要用到的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; G
          PIO_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; //初始化先關閉下管   
          
          //初始化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); //初始化先關閉上管  
          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,為目前換相序號,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) //不啟動則關閉輸出   
          {     
              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; //先關閉輸出,避免意外     
          //輸出上橋     
          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下橋導通     
          else if(step==1||step==2){PWM_AL_OFF;PWM_BL_OFF;PWM_CL_ON;}//AC BC; C下橋導通     
          else if(step==3||step==4){PWM_BL_OFF;PWM_CL_OFF;PWM_AL_ON;}//BA CA; A下橋導通      
          
          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) //啟動電機
      {           
          uint32_t x;     
          
          x=HALL_Check();  
          if(x==0||x==7) {x=1;} //如果霍爾異常,輸出一項,使馬達先轉起來  
          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) //停止電機
      {  
          Motor_Start_F = 0;  
          Commutation(Cur_Step,OutPwm,Motor_Start_F);;
      }
  • 與測速(BTIM1)相關的檔案: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; //霍爾脈衝計數
    extern uint16_t ADC_TimeCount; //電位器ADC取樣計算計數
    extern uint16_t Hall_TimeCount; //計數,進了2次BTIM1中斷,即20ms對轉速計算一次
    extern uint16_t OLED_FRESH_TimeCount;//計數,500ms刷新一次OLED顯示
    void Speed_Measure_Init(void) //BTIM1 10ms進一次中斷,在中斷裡改變標誌位           
    {  
        __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++; //計數,進了2次BTIM1中斷,即20ms對轉速計算一次    
            ADC_TimeCount++; //計數,100ms檢查一次電位器的電壓大小,決定目標速度    
            OLED_FRESH_TimeCount++; //計數,500ms刷新一次OLED顯示  
        }  
        /* USER CODE END */
    }
  • 與電位器輸入相關的檔案: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; //內建溫度感測器停用  
        ADC_InitStruct.ADC_DMAEn = ADC_DmaEnable; //ADC轉換完成觸發DMA傳輸  
        ADC_InitStruct.ADC_Align = ADC_AlignRight; //ADC轉換結果右邊對齊  
        ADC_InitStruct.ADC_AccEn = ADC_AccDisable; //轉換結果累積不使能  
        ADC_Init(&ADC_InitStruct); //初始化ADC配置  
        CW_ADC->CR1_f.DISCARD = FALSE; //配置資料更新策略,覆蓋未被讀取的舊數據,保留新數據  
        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; //此模式在傳輸過程中會被更進階的回應打斷  
        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; //硬體觸發  
        DMA_InitStruct.HardTrigSource = DMA_HardTrig_ADC_TRANSCOMPLETE; //ADC擷取完成觸發  
        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;
    }
  • 與顯示有關的驅動函數由於篇幅原因不在此展示,下面展示main.c的內容:
    #include "main.h"
    uint8_t Direction; //馬達方向,0為正轉,1為反轉
    uint8_t Motor_Start_F=0; //馬達啟動運作標誌
    uint16_t ADC_TimeCount=0; //電位器ADC取樣計時計數
    uint16_t Hall_TimeCount=0; //霍爾計時計數
    uint16_t OLED_FRESH_TimeCount=0; //OLED刷新顯示計時計數
    uint32_t HALLcount=0; //霍爾脈衝計數
    uint32_t Motor_Speed = 0; //馬達實際轉速,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(); //馬達初始化  
        HALL_Init(); //霍爾感應器初始化  
        Speed_Measure_Init(); //BTIM1初始化  
        ADC_Configuration(); //ADC初始化  
        I2C_OLED_Clear(1);      
                //清螢幕   
        Direction = 1; //馬達方向   
        
        sprintf(Buffer1,"Speed:%d rpm ",Motor_Speed); //顯示馬達轉速  
        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檢查一次目標速度    
            {      
                ADC_TimeCount = 0;      
                OutPwm = ADC_SampleTarget() / 5; //設定佔空比      
                if(OutPwm > 0 && Motor_Start_F == 0)BLDC_Motor_Start(Direction);//轉速大於1000rpm才啟動電機      
                else if(OutPwm > 0 && Motor_Start_F == 1)UPPWM(); //更新佔空比      
                else BLDC_Motor_Stop(); //停止電機    
            }     
            if(Hall_TimeCount > 1) //20ms測一次速    
            {      
                Hall_TimeCount = 0;      
                Motor_Speed = HALLcount * 500 / MotorPoles; //轉速計算,rpm      
                HALLcount = 0;    
            }     
            
            if(OLED_FRESH_TimeCount > 50) //500ms OLED顯示刷新一次    
            {      
                OLED_FRESH_TimeCount = 0;      
                sprintf(Buffer1,"Speed:%d rpm ",Motor_Speed); //顯示馬達轉速      
                I2C_OLED_ShowString(0,0,Buffer1);       
                
                Pwm_Buffer = OutPwm/32; //最大25%對應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. 設定HCLK和PCLK的分頻係數 */  
        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  
        /*< 當使用的時脈來源HCLK大於24M,小於等於48MHz:設定FLASH 讀取等待週期為2 cycle  
        < 當使用的時脈來源HCLK大於48M,小於等於72MHz:設定FLASH 讀取等待週期為3 cycle */      
        __RCC_FLASH_CLK_ENABLE();  
        FLASH_SetLatency(FLASH_Latency_3);  
        /* 3. 時脈切換到PLL */  
        RCC_SysClk_Switch(RCC_SYSCLKSRC_PLL);  
        RCC_SystemCoreClockUpdate(64000000);
    }
  • 最終的實驗結果如下:

    • 圖5-1 有霍爾方波開環控制無刷直流空心杯電機

5.2 有霍爾方波閉環控製程序

  • 閉環程式與開環程式相比,分別在main.c、Speed_Measure.c、ADC_BLDC_Ctrl.c檔案中略有變化,同時新增了PID.c檔案用於控制。
  • 首先是main.c檔案中的變化,新增了變數Flag_PID_TimeCount、Target_Speed,函數修改如下:
  • int main()
    {  
        RCC_Configuration(); //時鐘樹初始化  
        I2C_init(); //OLED初始化  
        I2C_OLED_Init(); //I2C初始化  
        BLDC_Init(); //馬達初始化  
        HALL_Init(); //霍爾感應器初始化  
        Speed_Measure_Init(); //BTIM1初始化  
        PID_Init(); //PID初始化  
        ADC_Configuration(); //ADC初始化  
        I2C_OLED_Clear(1); //清屏  
         
        Direction = 1; //馬達方向   
        
        sprintf(Buffer1,"Target:%d rpm",Target_Speed); //顯示目標速度  
        sprintf(Buffer2,"Speed:%d rpm ",Motor_Speed); //顯示馬達轉速  
        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檢查一次目標速度    
            {      
                ADC_TimeCount = 0;       
                Target_Speed = ADC_SampleTarget(); //擷取目標速度  
                    
                if(Target_Speed > 1000 && Motor_Start_F == 0)BLDC_Motor_Start(Direction);//轉速大於1000rpm才啟動電機      
                else if(Target_Speed > 1000 && Motor_Start_F == 1); //沒有操作,避免重複啟動      
                else BLDC_Motor_Stop(); //停止電機    
            }     
            
            if(Hall_TimeCount > 1) //20ms測一次速    
            {      
                Hall_TimeCount = 0;      
                Motor_Speed = HALLcount * 500 / MotorPoles; //轉速計算,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); //顯示目標速度      
                sprintf(Buffer2,"Speed:%d rpm ",Motor_Speed); //顯示馬達轉速      
                I2C_OLED_ShowString(0,0,Buffer1);      
                I2C_OLED_ShowString(0,15,Buffer2);              
                I2C_OLED_UPdata();    
            }  
        }      
    }
  • Speed_Measure.c中BTIM1的中斷服務程序修改:
  • void BTIM1_IRQHandler(void)
    {  
        /* USER CODE BEGIN */  
        if(BTIM_GetITStatus(CW_BTIM1, BTIM_IT_OV))  
        {      
            BTIM_ClearITPendingBit(CW_BTIM1, BTIM_IT_OV);     
            Hall_TimeCount++; //計數,進了2次BTIM1中斷,即20ms對轉速計算一次    
            Flag_PID_TimeCount++; //計數,進了2次BTIM1中斷,即20ms對PID計算一次    
            ADC_TimeCount++; //計數,100ms檢查一次電位器的電壓大小,決定目標速度    
            OLED_FRESH_TimeCount++; //計數,500ms刷新一次OLED顯示  
        }  
        /* USER CODE END */
    }
  • ADC_BLDC_Ctrl.c中對電壓擷取函數作修改:
  • 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; //目標速度為採集值的5被則設定最大速度20000rpm,可自行修改   
        
        return Target;
    }
  • 新增PID檔案如下:
  • #include "PID.h"
    extern uint8_t Motor_Start_F; //馬達啟動運作標誌
    extern uint32_t OutPwm; //輸出PWM值,PID最終計算要得到一個確定的PWM佔空比輸出值
    extern uint32_t Motor_Speed; //馬達實際轉速,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; //犧牲反應速度換取穩定性,避免佔空比從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;
    }
  • 最終實驗結果如下:

    • 圖5-2 有霍爾方波閉環控制無刷直流空心杯電機

06、調試過程中的問題與小提示

  • 在調試過程中,作者曾燒板四次,前面兩次燒毀MOS管,後兩次燒毀PCB供電,針對此種問題有三條注意事項:
    • 程式在KEIL5在進入和退出調試視窗的過程中存在未知的運行情況,所有燒毀都在進入和退出調試窗口時發生,建議使用性能較好的線性電源限流0.2A進行供電,開關電源限流響應較慢,也會導致板子或馬達燒毀。
    • 如果缺乏對應電源,可以在進入和退出調試視窗前斷掉PCB供電,待進入調試後再對PCB上電。
    • 若發生燒毀情況,先檢查PCB供電的晶片XL7005是否損壞,如若正常則依序檢查EG3013的15V供電,板上的5V和3.3V供電。如果馬達仍然無法轉動,再使用萬用電表測量MOS管是否燒毀。

小提示

  • 對於BLDC.c檔案中的程序,需要確認邏輯是否嚴密,切記不可發生上下橋同時導通的情況。
  • 在ADC_SampleTarget 函數可以自行修改Target 的值來規定目標速度上限。
  • 本程式的方向切換在程式裡手動設置,如果讀者想要透過按鍵等控制方向,需要在方向改變前先停止電機,再切換方向,不可在電機運轉時直接改變方向和換相順序。
  • 對於轉速的測量要及時,雖然由於硬體原因,測量轉速時間間隔越小,轉速變化的梯度越大,但是未獲得實時速度會導致PID控制效果不佳。先測速再進行PID運算。

study/motor-paper/2024-12-20-01/index.txt · Last modified: 2024/12/20 08:56 (external edit)