Печать

Управление бесколлекторным двигателем постоянного тока

Автор: AntonChip Опубликовано . Опубликовано в Программирование на Си

Рейтинг:   / 30
ПлохоОтлично 

Управление бесколлекторным двигателем постоянного токаКак известно в коллекторных двигателях постоянного тока коммутация обмоток в нужный момент времени осуществляется с помощью коллекторного узла(якоря). В беcколлекторных двигателях коммутацией управляет электроника. Для определения момента коммутации контроллер может использовать или датчики положения(Датчики Холла) или обратную ЭДС, генерируемую неподключенными обмотками. Датчики положения наиболее часто используются в низкооборотистых (таговых)двигателях, где пусковой момент существенно варьируется или где требуется его высокое значение, а также где двигатель используется для позиционирования. Управление бесколлекторными двигателями без датчиков используется в тех случаях, когда пусковой момент существенно не изменяется и когда отсутствует необходимость в управлении позиционированием, как, например, в вентиляторах.

На каждой ступени коммутации, обмотка одной фазы подключается к положительному напряжению питания, другая - к отрицательному, а третья - остается неподключенной. Обратная ЭДС неподключенной фазы в результате пересекает ноль при пересечении среднего значения положительного и отрицательного напряжений. Пересечение ноля возникает всегда в центре между двумя коммутациями. На постоянной скорости или медленно изменяющейся скорости период времени от одной коммутации до пересечения нуля и время от пересечения нуля до следующей коммутации равны. Это используется в качестве основы в данной реализации устройства управления без использования датчиков.

Для определения сигналов обратной ЭДС будем использовать метод виртуальной средней точки, для этого меряем напряжение на свободной фазе и сравниваем его со средней точкой. При использовании АЦП требуется некоторое время для преобразования, что снижает производительность, поэтому логичнее использовать аналоговые компараторы, нам ведь не нужно знать точное значение АЦП этого сигнала. Компаратор может генерировать прерывание в момент перехода напряжения через среднюю точку, а также выдавать логический сигнал своего состояния, что нам и будет нужно.

Три ШИМ-канала, OC1A, OC2 и OC1B, управляют верхними ключами(P-канальные MOSFET) мостовой схемы. Это дает возможность управления электрическим током с помощью аппаратных возможностей генерации ШИМ-сигналов при минимальном использовании программных ресурсов. В этом случае управление скоростью выполняется за счет изменения скважности ШИМ-сигнала.

Нижние ключи управляются логическими сигналами, и в нужный момент N-канальные MOSFET подключают обмотку к минусу питания или к линии обратной ЭДС.

Код программы с подробными комментариями:

// Подключение бесколлекторного двигателя к AVR(без датчиков)
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>

// Фаза U(Верхнее плечо)
#define UH_ON	TCCR1A |= (1 << COM1A1);
#define UH_OFF	TCCR1A &= ~(1 << COM1A1);

// Фаза U(Нижнее плечо)
#define UL_ON	PORTB |= (1 << PB5);
#define UL_OFF	PORTB &= ~(1 << PB5);

// Фаза V(Верхнее плечо)
#define VH_ON	TCCR2 |= (1 << COM21);
#define VH_OFF	TCCR2 &= ~(1 << COM21);

// Фаза V(Нижнее плечо)
#define VL_ON	PORTB |= (1 << PB0);
#define VL_OFF	PORTB &= ~(1 << PB0);

// Фаза W(Верхнее плечо)
#define WH_ON	TCCR1A |= (1 << COM1B1);
#define WH_OFF	TCCR1A &= ~(1 << COM1B1);

// Фаза W(Нижнее плечо)
#define WL_ON	PORTB |= (1 << PB4);
#define WL_OFF	PORTB &= ~(1 << PB4);

#define PHASE_ALL_OFF	UH_OFF;UL_OFF;VH_OFF;VL_OFF;WH_OFF;WL_OFF;

#define SENSE_U		ADMUX = 0; // Вход обратной ЭДС фазы U 
#define SENSE_V		ADMUX = 1; // Вход обратной ЭДС фазы V
#define SENSE_W		ADMUX = 2; // Вход обратной ЭДС фазы W

#define SENSE_UVW	(ACSR&(1 << ACO)) // Выход компаратора

#define START_PWM   10 // Минимальный ШИМ при запуске
#define WORK_PWM   100 // Рабочий уровень ШИМ

unsigned char start_stop = 0;
volatile unsigned char motor_pwm = WORK_PWM;
volatile unsigned char commutation_step = 0;
volatile unsigned char rotor_run = 0; // Счетчик импульсов обратной ЭДС

// Крутим по часовой стрелке
void commutation(unsigned char startup)
{
	switch (commutation_step)
	{
		case (0):
			if(!SENSE_UVW || startup) 
			{
				UH_ON; // На фазе U - ШИМ
				WH_OFF; // Фаза W отключена
				SENSE_W; // Активируем вход фазы W
				commutation_step = 1; // Следующий шаг
				TCNT0 = 0; // Обнуляем счетчик T0
			}
			break;

		case (1):
			if(SENSE_UVW || startup)
			{
				VL_OFF; // На фазе V - лог. 0
				WL_ON;  // На Фазе W - лог. 1
				SENSE_V; // Активируем вход фазы V
				commutation_step = 2;
				TCNT0 = 0; // Обнуляем счетчик T0
			}
			break;

		case (2):
			if(!SENSE_UVW || startup)
			{
				UH_OFF; // Фаза U отключена
				VH_ON;  // На фазе V - ШИМ
				SENSE_U; // Активируем вход фазы U
				commutation_step = 3;
				TCNT0 = 0; // Обнуляем счетчик T0
			}
			break;
	
		case (3):
			if(SENSE_UVW || startup)
			{
				UL_ON;  // На фазе U - лог. 1
				WL_OFF; // На Фаза W - лог. 0
				SENSE_W; // Активируем вход фазы W
				commutation_step = 4;
				TCNT0 = 0; // Обнуляем счетчик T0
			}
			break;

		case (4):
			if(!SENSE_UVW || startup)
			{
				VH_OFF;  // Фаза V отключена
				WH_ON;   // На фазе W - ШИМ
				SENSE_V; // Активируем вход фазы V
				commutation_step = 5;
				TCNT0 = 0; // Обнуляем счетчик T0
			}
			break;

		case (5):
			if(SENSE_UVW || startup)
			{
				UL_OFF; // На фазе U - лог. 0
				VL_ON;  // На Фазе V - лог. 1
				SENSE_U; // Активируем вход фазы U
				commutation_step = 0;
				TCNT0 = 0; // Обнуляем счетчик T0
			}
			break;
	}
}
// Обработчик прерывания по компаратору. Детектор обратной ЭДС
ISR(ANA_COMP_vect) 
{
rotor_run++; // инкрементируем импульсы
if(rotor_run > 200) rotor_run = 200;
if(rotor_run == 200) // Если импульсы обратной ЭДС присутствуют, крутим наполную 
commutation(0);
}
// Обработчик прерывания по переполнению Т0. Работа двигателя без сигналов обратной ЭДС
ISR(TIMER0_OVF_vect)
{	
commutation(1); // Если сработало прерывание, есть пропуски импульсов обратной ЭДС
rotor_run = 0;  // Сбрасываем счетчик импульсов
OCR1A = START_PWM; // ШИМ минимум
OCR1B = START_PWM;
OCR2 = START_PWM;
}
// Обработчик внешнего прерывания INT0. Энкодер
ISR(INT0_vect){
    _delay_us(100);
    if ((PIND & ( 1 << PD2)) == 0){
        _delay_us(100);
// Крутим против часовой стрелки
		if ((PIND & ( 1 << PD1)) == 0)
	    { 
		  if(motor_pwm != START_PWM) motor_pwm -= 5; // Уменьшаем ШИМ
		}
// Крутим по часовой стрелке
		else
    	{
		  if(motor_pwm != 255) motor_pwm += 5; // Увеличиваем ШИМ
		}
	}
    GIFR = (1 << INTF0); // Сбрасываем флаг внешнего прерывания
    return;
}

int main (void) 
{
// Порты ввода/вывода
DDRB  = 0xFF;
PORTB = 0x00;
DDRD &= ~(1 << PD6)|(1 << PD2)|(1 << PD1)|(1 << PD0);
PORTD |= (1 << PD2)|(1 << PD1)|(1 << PD0);	
PORTD &= ~(1 << PD6);

// T0 - для старта и работы двигателя без сигналов обратной ЭДС
TCCR0 |= (1 << CS02)|(1 << CS00); // Предделитель на 1024
TIMSK |= (1 << TOIE0); // Разрешаем прерывание по переполнению T0
// T1 и T2 ШИМ
TCCR1A |= (1 << COM1A1)|(1 << COM1B1)| // Clear OC1A/OC1B, set OC1A/OC1B at BOTTOM
          (1 << WGM10);  // Режим Fast PWM, 8-bit
TCCR1B |= (1 << CS10)|(1 << WGM12); // Без предделителя 
TCCR2 |= (1 << COM21)| // Clear OC2, set OC2 at BOTTOM
         (1 << WGM21)|(1 << WGM20)| // Режим Fast PWM
		 (1 << CS20); // Без предделителя

PHASE_ALL_OFF; // Выключаем все фазы 
	
// Аналаговый компаратор
ADCSRA &= ~(1 << ADEN); // Выключаем АЦП
SFIOR |= (1 << ACME); // Отрицательный вход компаратора подключаем к выходу мультиплексора АЦП
ACSR |= (1 << ACIE); // Разрешаем прерывания от компаратора

// Внешнее прерывание(Энкодер)
MCUCR |= (1 << ISC01); // Прерывание по заднему фронту INT0(по спаду импульса)
GIFR |= (1 << INTF0); // Очищаем флаг внешнего прерывания
GICR |= (1 << INT0); // Разрешаем внешние прерывания INT0
	    
sei(); // Глобально разрешаем прерывания

while(1)
{	
if((PIND&(1 << PD0)) == 0) // Старт/Стоп 
{
_delay_ms(20);
start_stop ^= 1; // Переключаем состояние
while((PIND&(1 << PD0)) == 0){}
}

if(start_stop)
{
ACSR |= (1 << ACIE); // Разрешаем прерывание от компаратора
TIMSK |= (1 << TOIE0); // Разрешаем прерывание по переполнению T0
GICR |= (1 << INT0); // Разрешаем внешние прерывания INT0  
 
  if(rotor_run == 200) // Если импульсы обратной ЭДС присутствуют, можем менять ШИМ
  {
  OCR1A = motor_pwm;
  OCR1B = motor_pwm;
  OCR2 = motor_pwm;
  }
}
else
{
PHASE_ALL_OFF; // Все фазы выключены
ACSR &= ~(1 << ACIE); // Запрещаем прерывание от компаратора
TIMSK &= ~(1 << TOIE0); // Запрещаем прерывание по переполнению T0
GICR &= ~(1 << INT0); // Запрещаем внешние прерывания INT0
}

}
}

 

Файлы:
Проект AVRStudio4, макет печатной платы Diptrace
Дата 08.12.2015 Размер файла 36.31 KB Закачек 696

Комментарии  

0 #1 Сержант 28.11.2015 16:49
Повторил твою схему - работает!!! Потом собрал силовую часть на ir2101 + irf630 и работает чёрти как. Понял что ir2101 инвертирует сигнал. Что изменить в программе что-бы
с ir2101 работало? СПАСИБО!!!
Сообщить модератору
0 #2 AntonChip 28.11.2015 21:47
В дефайне UL_ON и UL_OFF и т.п. поменять местами
Сообщить модератору
0 #3 Strelok1986 08.12.2015 13:59
А платку не могли бы скинуть?
Сообщить модератору
0 #4 Strelok1986 10.12.2015 20:08
Спасибо огромное!
Сообщить модератору
0 #5 BORIS102 09.02.2016 20:48
В дефайне UL_ON и UL_OFF и т.п. поменять местами-----
если можно поподробней
Сообщить модератору
0 #6 Romario 03.06.2016 19:08
А какие обороты можно выжать на этом девайсе?
Сообщить модератору

Рекомендуем посмотреть