无传感器 BLDC 电机控制 BEMF 部分
Sensorless BLDC motor control BEMF section
我正在尝试制作无传感器 bldc 电机控制驱动器。我找到了一个 Arduino 代码,我想将它转换为 ARM Stm32。但我完全不明白 ISR 中断部分发生了什么。谁能尽快给我解释一下?为什么使用 bldc_step&1
以及何时减少 i
.
byte bldc_step = 0, motor_speed, pin_state;
void setup()
{
DDRD |= 0xE0; // configure pins 5, 6 and 7 as outputs
PORTD = 0x00;
DDRB |= 0x0E; // configure pins 9, 10 and 11 as outputs
PORTB = 0x31;
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
}
// pin change interrupt 2 (PCINT2) ISR
ISR (PCINT2_vect)
{
if( (PIND & PCMSK2) != pin_state )
return;
// BEMF debounce
for(byte i = 0; i < 20; i++)
{
if(bldc_step & 1){
if(PIND & PCMSK2) i -= 1;
}
else {
if(!(PIND & PCMSK2)) i -= 1;
}
}
bldc_move();
bldc_step++;
bldc_step %= 6;
}
// BLDC motor commutation function
void bldc_move()
{
switch(bldc_step)
{
case 0:
AH_BL();
BEMF_C_FALLING();
break;
case 1:
AH_CL();
BEMF_B_RISING();
break;
case 2:
BH_CL();
BEMF_A_FALLING();
break;
case 3:
BH_AL();
BEMF_C_RISING();
break;
case 4:
CH_AL();
BEMF_B_FALLING();
break;
case 5:
CH_BL();
BEMF_A_RISING();
}
}
PCICR = 4; // enable pin change interrupt for pins PCINT23..16 (Arduino 0 to 7)
void BEMF_A_RISING()
{
PCMSK2 = 0x04; // enable Arduino pin 2 (PCINT18) interrupt, others are disabled
pin_state = 0x04;
}
void BEMF_A_FALLING()
{
PCMSK2 = 0x04; // enable Arduino pin 2 (PCINT18) interrupt, others are disabled
pin_state = 0;
}
void BEMF_B_RISING()
{
PCMSK2 = 0x08; // enable Arduino pin 3 (PCINT19) interrupt, others are disabled
pin_state = 0x08;
}
void BEMF_B_FALLING()
{
PCMSK2 = 0x08; // enable Arduino pin 3 (PCINT19) interrupt, others are disabled
pin_state = 0;
}
void BEMF_C_RISING()
{
PCMSK2 = 0x10; // enable Arduino pin 4 (PCINT20) interrupt, others are disabled
pin_state = 0x10;
}
void BEMF_C_FALLING()
{
PCMSK2 = 0x10; // enable Arduino pin 4 (PCINT20) interrupt, others are disabled
pin_state = 0;
}
void AH_BL()
{
PORTD &= ~0xA0;
PORTD |= 0x40;
TCCR1A = 0; // turn pin 11 (OC2A) PWM ON (pin 9 & pin 10 OFF)
TCCR2A = 0x81; //
}
void AH_CL()
{
PORTD &= ~0xC0;
PORTD |= 0x20;
TCCR1A = 0; // turn pin 11 (OC2A) PWM ON (pin 9 & pin 10 OFF)
TCCR2A = 0x81; //
}
void BH_CL()
{
PORTD &= ~0xC0;
PORTD |= 0x20;
TCCR2A = 0; // turn pin 10 (OC1B) PWM ON (pin 9 & pin 11 OFF)
TCCR1A = 0x21; //
}
void BH_AL()
{
PORTD &= ~0x60;
PORTD |= 0x80;
TCCR2A = 0; // turn pin 10 (OC1B) PWM ON (pin 9 & pin 11 OFF)
TCCR1A = 0x21; //
}
void CH_AL()
{
PORTD &= ~0x60;
PORTD |= 0x80;
TCCR2A = 0; // turn pin 9 (OC1A) PWM ON (pin 10 & pin 11 OFF)
TCCR1A = 0x81; //
}
void CH_BL()
{
PORTD &= ~0xA0;
PORTD |= 0x40;
TCCR2A = 0; // turn pin 9 (OC1A) PWM ON (pin 10 & pin 11 OFF)
TCCR1A = 0x81; //
}
void SET_PWM_DUTY(byte duty)
{
OCR1A = duty; // set pin 9 PWM duty cycle
OCR1B = duty; // set pin 10 PWM duty cycle
OCR2A = duty; // set pin 11 PWM duty cycle
}
此代码用于去抖反电磁力 (BEMF) 信号,等效代码在 https://github.com/esden/open-bldc-mk/blob/master/bldc.c
ISR(ANA_COMP_vect){
unsigned char i;
/* debounce the bemf signal */
for(i=0; i<BEMF_DEBOUNCE_COUNT; i++){
if(bldc_phase & 1){
if(BEMF_L) i -= BEMF_DEBOUNCE_DEC;
}else{
if(BEMF_H) i -= BEMF_DEBOUNCE_DEC;
}
}
关于 去抖动 以及为什么完成,请参阅 https://en.wikipedia.org/wiki/Switch#Contact_bounce
这里实现的确切算法是带垂直计数器的去抖动开关,cf https://www.compuphase.com/electronics/debouncing.htm - 带垂直计数器的去抖动开关
在 bldc_step & 1
中,&
运算符是 按位与 即二进制中的 45 & 35 = 33
或 00101101 & 00100011 = 00100001
bldc_step
是一个字节,将其与 1
按位与运算等同于 测试 bldc_step
的最后一位是否已设置 。使用 PIND & PCMSK2
检查 PIND
是高还是低
这段代码和其余的去抖动循环实现了https://www.compuphase.com/electronics/debouncing.htm
中描述的垂直计数器
电机的速度取决于施加的电压D.V,其中 D 是占空比。
Fm = D.VP.KV.poles/120 = D.Vp/M
Tm = M/(D.Vp)
bemf 检测后的理想延迟为 30 度:
delay = Tm/12 = M/(12.D.Vp) = M'/(D.Vp) : M'=M/12
M' – 过零检测后 30° 延迟的伏特*秒。
比较器 ISR 仅在导通期间向上计数。 PWM 脉冲越宽,计数越快。
循环最长时间:
m = N.ticks.Cycles
周期是每条指令的滴答声。
环路仅在 BEMF 上升或下降时计数(向上)到 N。计数的 PWM 脉冲将为:
Pc = m/ton or Pc = m/(D.Ts)
估计循环时间为:
dt = Pc.Ts = m.Ts/(D.Ts) = m/D
要求的延迟和循环的时间必须相等:delay = dt
M'/(Vp.D) = m/D or m = M'/Vp
这种方法也称为“反电动势积分法”。
M' = D.Vp.Tm'
是从 ZCP 到下一次换向的积分 bemf 电压。你可以阅读更多
在这里简要介绍一下:
https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3231115/
调整 N 和 PWM 频率 (Fs=1/Ts) 可以在 bemf 检测后为您提供近乎完美的 30 度延迟。应知道电机的极数和 Kv。未经调整,此代码不适用于任何电机。
干杯
我正在尝试制作无传感器 bldc 电机控制驱动器。我找到了一个 Arduino 代码,我想将它转换为 ARM Stm32。但我完全不明白 ISR 中断部分发生了什么。谁能尽快给我解释一下?为什么使用 bldc_step&1
以及何时减少 i
.
byte bldc_step = 0, motor_speed, pin_state;
void setup()
{
DDRD |= 0xE0; // configure pins 5, 6 and 7 as outputs
PORTD = 0x00;
DDRB |= 0x0E; // configure pins 9, 10 and 11 as outputs
PORTB = 0x31;
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
}
// pin change interrupt 2 (PCINT2) ISR
ISR (PCINT2_vect)
{
if( (PIND & PCMSK2) != pin_state )
return;
// BEMF debounce
for(byte i = 0; i < 20; i++)
{
if(bldc_step & 1){
if(PIND & PCMSK2) i -= 1;
}
else {
if(!(PIND & PCMSK2)) i -= 1;
}
}
bldc_move();
bldc_step++;
bldc_step %= 6;
}
// BLDC motor commutation function
void bldc_move()
{
switch(bldc_step)
{
case 0:
AH_BL();
BEMF_C_FALLING();
break;
case 1:
AH_CL();
BEMF_B_RISING();
break;
case 2:
BH_CL();
BEMF_A_FALLING();
break;
case 3:
BH_AL();
BEMF_C_RISING();
break;
case 4:
CH_AL();
BEMF_B_FALLING();
break;
case 5:
CH_BL();
BEMF_A_RISING();
}
}
PCICR = 4; // enable pin change interrupt for pins PCINT23..16 (Arduino 0 to 7)
void BEMF_A_RISING()
{
PCMSK2 = 0x04; // enable Arduino pin 2 (PCINT18) interrupt, others are disabled
pin_state = 0x04;
}
void BEMF_A_FALLING()
{
PCMSK2 = 0x04; // enable Arduino pin 2 (PCINT18) interrupt, others are disabled
pin_state = 0;
}
void BEMF_B_RISING()
{
PCMSK2 = 0x08; // enable Arduino pin 3 (PCINT19) interrupt, others are disabled
pin_state = 0x08;
}
void BEMF_B_FALLING()
{
PCMSK2 = 0x08; // enable Arduino pin 3 (PCINT19) interrupt, others are disabled
pin_state = 0;
}
void BEMF_C_RISING()
{
PCMSK2 = 0x10; // enable Arduino pin 4 (PCINT20) interrupt, others are disabled
pin_state = 0x10;
}
void BEMF_C_FALLING()
{
PCMSK2 = 0x10; // enable Arduino pin 4 (PCINT20) interrupt, others are disabled
pin_state = 0;
}
void AH_BL()
{
PORTD &= ~0xA0;
PORTD |= 0x40;
TCCR1A = 0; // turn pin 11 (OC2A) PWM ON (pin 9 & pin 10 OFF)
TCCR2A = 0x81; //
}
void AH_CL()
{
PORTD &= ~0xC0;
PORTD |= 0x20;
TCCR1A = 0; // turn pin 11 (OC2A) PWM ON (pin 9 & pin 10 OFF)
TCCR2A = 0x81; //
}
void BH_CL()
{
PORTD &= ~0xC0;
PORTD |= 0x20;
TCCR2A = 0; // turn pin 10 (OC1B) PWM ON (pin 9 & pin 11 OFF)
TCCR1A = 0x21; //
}
void BH_AL()
{
PORTD &= ~0x60;
PORTD |= 0x80;
TCCR2A = 0; // turn pin 10 (OC1B) PWM ON (pin 9 & pin 11 OFF)
TCCR1A = 0x21; //
}
void CH_AL()
{
PORTD &= ~0x60;
PORTD |= 0x80;
TCCR2A = 0; // turn pin 9 (OC1A) PWM ON (pin 10 & pin 11 OFF)
TCCR1A = 0x81; //
}
void CH_BL()
{
PORTD &= ~0xA0;
PORTD |= 0x40;
TCCR2A = 0; // turn pin 9 (OC1A) PWM ON (pin 10 & pin 11 OFF)
TCCR1A = 0x81; //
}
void SET_PWM_DUTY(byte duty)
{
OCR1A = duty; // set pin 9 PWM duty cycle
OCR1B = duty; // set pin 10 PWM duty cycle
OCR2A = duty; // set pin 11 PWM duty cycle
}
此代码用于去抖反电磁力 (BEMF) 信号,等效代码在 https://github.com/esden/open-bldc-mk/blob/master/bldc.c
ISR(ANA_COMP_vect){
unsigned char i;
/* debounce the bemf signal */
for(i=0; i<BEMF_DEBOUNCE_COUNT; i++){
if(bldc_phase & 1){
if(BEMF_L) i -= BEMF_DEBOUNCE_DEC;
}else{
if(BEMF_H) i -= BEMF_DEBOUNCE_DEC;
}
}
关于 去抖动 以及为什么完成,请参阅 https://en.wikipedia.org/wiki/Switch#Contact_bounce
这里实现的确切算法是带垂直计数器的去抖动开关,cf https://www.compuphase.com/electronics/debouncing.htm - 带垂直计数器的去抖动开关
在 bldc_step & 1
中,&
运算符是 按位与 即二进制中的 45 & 35 = 33
或 00101101 & 00100011 = 00100001
bldc_step
是一个字节,将其与 1
按位与运算等同于 测试 bldc_step
的最后一位是否已设置 。使用 PIND & PCMSK2
检查 PIND
是高还是低
这段代码和其余的去抖动循环实现了https://www.compuphase.com/electronics/debouncing.htm
中描述的垂直计数器电机的速度取决于施加的电压D.V,其中 D 是占空比。
Fm = D.VP.KV.poles/120 = D.Vp/M
Tm = M/(D.Vp)
bemf 检测后的理想延迟为 30 度:
delay = Tm/12 = M/(12.D.Vp) = M'/(D.Vp) : M'=M/12
M' – 过零检测后 30° 延迟的伏特*秒。
比较器 ISR 仅在导通期间向上计数。 PWM 脉冲越宽,计数越快。
循环最长时间:
m = N.ticks.Cycles
周期是每条指令的滴答声。 环路仅在 BEMF 上升或下降时计数(向上)到 N。计数的 PWM 脉冲将为:
Pc = m/ton or Pc = m/(D.Ts)
估计循环时间为:
dt = Pc.Ts = m.Ts/(D.Ts) = m/D
要求的延迟和循环的时间必须相等:delay = dt
M'/(Vp.D) = m/D or m = M'/Vp
这种方法也称为“反电动势积分法”。 M' = D.Vp.Tm' 是从 ZCP 到下一次换向的积分 bemf 电压。你可以阅读更多 在这里简要介绍一下: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3231115/
调整 N 和 PWM 频率 (Fs=1/Ts) 可以在 bemf 检测后为您提供近乎完美的 30 度延迟。应知道电机的极数和 Kv。未经调整,此代码不适用于任何电机。 干杯