使用 BLDC 霍爾感測器當作位置編碼器 - 第 3 篇
使用 Teensy 3.5 微控制器計算位置、方向和距離
以下資訊旨在協助解讀霍爾效應感測器的邏輯輸出,用以確定位置、方向與速度。雖然此輸出可用於馬達換向,但這個 BLDC 馬達操作層面並非本文探討範圍。
請參見本部落格系列的第 1 篇和第 2 篇,回顧此專案到目前為止的內容。
概覽
當 BLDC 中的三個霍爾效應感測器輸出饋送到微控制器時,訊號可以像三通道編碼器一樣接受處理。資料可進行顯示,或用於確定脈衝數、轉動方向和平均每分鐘轉數 (RPM)。對 RPM 進行平均是為了讓顯示的值平順地遞進。
PJRC Teensy 3.5 開發板
SparkFun 的 PJRC Teensy 3.5 開發板 (1568-1464-ND) 具有足夠的數位中斷,能處理來自霍爾感測器的三個訊號輸入,同時還配有焊入式排針座。由於具有足夠的額外 I/O 通道,Teensy 3.5 功能十分強大,能夠執行許多額外的任務,並可搭配內建的 SD 卡,實現資料記錄功能。
圖 1:SparkFun Electronics 的 Teensy 3.5 評估板。(圖片來源:SparkFun Electronics)
使用試驗電路板測試感測器輸出和 PJRC Teensy 3.5
使用試驗電路板 (438-1045-ND 或類似產品),將 Teensy 3.5 的 USB 連接器放在右側,將上方排針座引腳插入隔板上方的第一排試驗電路板孔洞 (圖 2)。這樣就可以留出空間,將感測器輸出連接到 Teensy I/O。
圖 2:連有 Teensy 3.5 開發板及跳接線的試驗電路板。(圖片來源:DigiKey)
使用實心跳接線 (BKWK-3-ND) 完成所有的試驗電路板連接。將 5 V、1 A 電源供應器的正極 (+) 引線連接到試驗電路板的上方或下方正電軌,隨後將負極 (-) 電源引線連接到上方或下方負電軌。將霍爾感測器連接器的正極 (紅色) 和負極 (黑色) 引線,分別連接到試驗電路板的正負軌,然後以任意順序將連接器的三條感測器引線,連接到 Teensy 3.5 的引腳 2、3 和 4。
感測器輸出為低態動作,因此觸發時,此輸出會連接到負電軌。未觸發時,需要將感測器輸出向上拉至正電軌,以建立兩個定義的邏輯狀態。在試驗電路板中插入三個 4 KΩ 至 8 KΩ 的電阻,即可用作感測器輸出的上拉電阻 (圖 2)。
使用 micro B 轉標準 A 型 USB 纜線,將 Teensy 3.5 連接至電腦。
軟體
Teensy 3.5 與 Arduino 整合式開發環境 (IDE) 相容,可實現編程用途。IDE 和 Teensyduino 附加組件均可從網路上取得。請遵循 https://www.pjrc.com/teensy/td_download.html 的安裝步驟繼續操作。
下面提供的編程範例程式碼使用三個硬體中斷,來監測霍爾感測器輸出的任何變化 (上升緣和下降緣)。一旦發生中斷,即會讀取 Teensy 3.5 的歷時時脈,以及三個輸入引腳中的兩個引腳。接著比較感測器的值以確定轉動方向,然後進行其他計算,以確定脈衝數和平均 RPM。透過將當前時脈值與先前儲存的前一個中斷時脈值進行比較,計算出兩個中斷之間的時間。
在 void loop 中,有四個值可用於進行序列列印。註解或取消註解程式碼行,可停用或啟用序列列印功能,然後將程式碼下載到 Teensy 並啟動序列監視器,可查看即時資料。旋轉 BLDC 馬達,在列印監視器中觀察數值的變化。
註:序列列印功能會降低微控制器的速度。I/O 中斷會導致顯示值暫停和跳轉,因為根據定義,每當輸入引腳改變狀態時,序列列印過程就會中斷。如果不使用顯示功能,請確保從程式碼中註解排除掉所有序列列印功能。
複製/* BLDC Hall Sensor read and calculation program for Teensy 3.5 in the Arduino IDE (Ver.1).DigiKey*/
/***************************** Variables *********************************/
#define CW 1 // Assign a value to represent clock wise rotation
#define CCW -1 // Assign a value to represent counter-clock wise rotation
bool HSU_Val = digitalRead(2); // Set the U sensor value as boolean and read initial state
bool HSV_Val = digitalRead(3); // Set the V sensor value as boolean and read initial state
bool HSW_Val = digitalRead(4); // Set the W sensor value as boolean and read initial state
int direct = 1; // Integer variable to store BLDC rotation direction
int pulseCount; // Integer variable to store the pulse count
float startTime; // Float variable to store the start time of the current interrupt
float prevTime; // Float variable to store the start time of the previous interrupt
float pulseTimeW; // Float variable to store the elapsed time between interrupts for hall sensor W
float pulseTimeU; // Float variable to store the elapsed time between interrupts for hall sensor U
float pulseTimeV; // Float variable to store the elapsed time between interrupts for hall sensor V
float AvPulseTime; // Float variable to store the average elapsed time between all interrupts
float PPM; // Float variable to store calculated pulses per minute
float RPM; // Float variable to store calculated revolutions per minute
/***************************** Setup *********************************/
void setup()
{
// Set digital pins 2, 3 and 4 as inputs
pinMode(2, INPUT);
pinMode(3, INPUT);
pinMode(4, INPUT);
// Set digital pins 2, 3 and 4 as interrupts that trigger on rising and falling edge changes.Call a function (i.e.HallSensorU) on change
attachInterrupt(digitalPinToInterrupt(2), HallSensorU, CHANGE);
attachInterrupt(digitalPinToInterrupt(3), HallSensorV, CHANGE);
attachInterrupt(digitalPinToInterrupt(4), HallSensorW, CHANGE);
// Initialize the print monitor and set baud rate to 9600
Serial.begin(9600);
}
/*************************** Main Loop ******************************/
void loop()
{
if ((millis() - prevTime) > 600) RPM = 0; // Zero out RPM variable if wheel is stopped
//Serial.print(HSU_Val); Serial.print(HSV_Val); Serial.println(HSW_Val); // Display Hall Sensor Values
//Serial.println(direct); // Display direction of rotation
//Serial.println(pulseCount); // Display the pulse count
Serial.println(RPM); // Display revolutions per minute
}
/************************ Interrupt Functions ***************************/
void HallSensorW()
{
startTime = millis(); // Set startTime to current microcontroller elapsed time value
HSW_Val = digitalRead(4); // Read the current W hall sensor value
HSV_Val = digitalRead(3); // Read the current V (or U) hall sensor value
direct = (HSW_Val == HSV_Val) ?CW : CCW; // Determine rotation direction (ternary if statement)
pulseCount = pulseCount + (1 * direct); // Add 1 to the pulse count
pulseTimeW = startTime - prevTime; // Calculate the current time between pulses
AvPulseTime = ((pulseTimeW + pulseTimeU + pulseTimeV)/3); // Calculate the average time time between pulses
PPM = (1000 / AvPulseTime) * 60; // Calculate the pulses per min (1000 millis in 1 second)
RPM = PPM / 90; // Calculate revs per minute based on 90 pulses per rev
prevTime = startTime; // Remember the start time for the next interrupt
}
void HallSensorV()
{
startTime = millis();
HSV_Val = digitalRead(3);
HSU_Val = digitalRead(2); // Read the current U (or W) hall sensor value
direct = (HSV_Val == HSU_Val) ?CW : CCW;
pulseCount = pulseCount + (1 * direct);
pulseTimeV = startTime - prevTime;
AvPulseTime = ((pulseTimeW + pulseTimeU + pulseTimeV)/3);
PPM = (1000 / AvPulseTime) * 60;
RPM = PPM / 90;
prevTime = startTime;
}
void HallSensorU()
{
startTime = millis();
HSU_Val = digitalRead(2);
HSW_Val = digitalRead(4); // Read the current W (or V) hall sensor value
direct = (HSU_Val == HSW_Val) ?CW : CCW;
pulseCount = pulseCount + (1 * direct);
pulseTimeU = startTime - prevTime;
AvPulseTime = ((pulseTimeW + pulseTimeU + pulseTimeV)/3);
PPM = (1000 / AvPulseTime) * 60;
RPM = PPM / 90;
prevTime = startTime;
}
註:編程人員也許想將重複的中斷函數程式碼分解成額外的函數,以簡化整個編程。但這麼做可能會導致額外的函數中斷,並導致數值在不同的計算之間發生更改,進而產生資料錯誤。如試驗電路板測試步驟和程式碼中所述,感測器輸入的順序只會影響對轉動方向的確定。取消註解與變數「direct」有關的序列列印行,即可在顯示監視器中查看值。確認這個值是否保持為 1 或 -1,這取決於您轉動轉輪的方式。如果偏離,在相應的中斷函數中,反轉三進制程式碼的「CW」和「CCW」,以修正輸出。
總結
BLDC 霍爾感測器現設定為低解析度的三通道編碼器,能夠提供準確的資料來輔助導航及轉輪位置感測,而不會妨礙其主要的馬達控制功能。有些 BLDC 控制器則只使用反電動勢來確定線圈和磁鐵的位置,造成霍爾感測器輸出僅用於導航和位置感測。但無論是哪種方式,感測器給使用者帶來的價值都遠不止是馬達控制。
其他資源:
Arduino IDE:http://www.arduino.cc/en/Main/Software
Teensyduino:https://www.pjrc.com/teensy/td_145/TeensyduinoInstall.exe

Have questions or comments? Continue the conversation on TechForum, Digi-Key's online community and technical resource.
Visit TechForum