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

Рейтинг:  4 / 5

Звезда активнаЗвезда активнаЗвезда активнаЗвезда активнаЗвезда не активна
 

В этом варианте контроллера бесколлекторного двигателя для управления силовыми ключами используется специальный драйвер IR2101, который позволяет избавиться от дорогих и дифицитных P-канальных полевых транзисторов. В исходный код внес некоторые изменения, в частности плавный пуск и изменение вращения вала двигателя. При первом запуске двигатель плавно разгоняется, от уровня ШИМ  START_PWM, до уровня WORK_PWM, задержку можно поменять. При повторном запуске двигатель разгонится уже до уровня, который будет в переменной motor_pwm. Эта переменная меняется при помощи ручки энкодера. Переключатель направления вращения работает только когда двигатель находится в выключенном состоянии.

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

 Исходный код программы:

// Подключение бесколлекторного двигателя к 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 = 0, start_stop = 0, start_pwm;
unsigned char direction = 1; // 0 - против часовой, 1 - по часовой
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) 
			{
				if(direction)
				{
				UH_ON; WH_OFF; SENSE_W;
				}
				else
				{
				UH_OFF; WH_ON; SENSE_U; 
				}
				commutation_step = 1; // Следующий шаг
				TCNT0 = 0; // Обнуляем счетчик T0
			}
			break;

		case (1):
			if(SENSE_UVW || startup)
			{
				if(direction)
				{
				VL_OFF;	WL_ON; SENSE_V;
				}
				else
				{
				VL_OFF;	UL_ON; SENSE_V;
				}
				commutation_step = 2;
				TCNT0 = 0; // Обнуляем счетчик T0
			}
			break;

		case (2):
			if(!SENSE_UVW || startup)
			{
				if(direction)
				{
				UH_OFF; VH_ON; SENSE_U;
				}
				else
				{
				VH_ON; WH_OFF; SENSE_W;				
				}
				commutation_step = 3;
				TCNT0 = 0; // Обнуляем счетчик T0
			}
			break;
	
		case (3):
			if(SENSE_UVW || startup)
			{
				if(direction)
				{
				UL_ON; WL_OFF; SENSE_W;
				}
				else
				{
				UL_OFF; WL_ON; SENSE_U;
				}
				commutation_step = 4;
				TCNT0 = 0; // Обнуляем счетчик T0
			}
			break;

		case (4):
			if(!SENSE_UVW || startup)
			{
				if(direction)
				{
				VH_OFF; WH_ON; SENSE_V;
				}
				else
				{
				VH_OFF;	UH_ON; SENSE_V;
				}
				commutation_step = 5;
				TCNT0 = 0; // Обнуляем счетчик T0
			}
			break;

		case (5):
			if(SENSE_UVW || startup)
			{
				if(direction)
				{
				UL_OFF;	VL_ON; SENSE_U;
				}
				else
				{
				VL_ON; WL_OFF; SENSE_W;
				}
				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)
{	
rotor_run = 0; // Сбрасываем счетчик импульсов
OCR1A = START_PWM; // ШИМ минимум
OCR1B = START_PWM;
OCR2 = START_PWM;
commutation(1); // Переключаем обмотки безусловно
}
// Обработчик внешнего прерывания 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 << PD7);
DDRD &= ~(1 << PD6)|(1 << PD3)|(1 << PD2)|(1 << PD1)|(1 << PD0);
PORTD |= (1 << PD3)|(1 << PD2)|(1 << PD1)|(1 << PD0);	
PORTD &= ~(1 << PD7)|(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 && start == 0) // Если импульсы обратной ЭДС присутствуют и двигатель не был запущен
  { 
    for(start_pwm = START_PWM; start_pwm < motor_pwm; start_pwm++)
    {
	  _delay_ms(10); // Задержка
	  OCR1A = start_pwm;
      OCR1B = start_pwm;
      OCR2 = start_pwm;
	}
  start = 1; // Запуск произошел	 
  PORTD |= (1 << PD7); // Включаем светодиод
  }

  if(rotor_run == 200) // Если импульсы обратной ЭДС присутствуют, можем менять ШИМ
  {
  OCR1A = motor_pwm;
  OCR1B = motor_pwm;
  OCR2 = motor_pwm;
  }
}
else
{

if(PIND&(1 << PD3)) direction = 1; // Выбор направления вращения вала
else direction = 0;

start = 0; // Двигатель остановлен
PORTD &= ~(1 << PD7); // Выключаем светодиод
PHASE_ALL_OFF; // Все фазы выключены
ACSR &= ~(1 << ACIE); // Запрещаем прерывание от компаратора
TIMSK &= ~(1 << TOIE0); // Запрещаем прерывание по переполнению T0
GICR &= ~(1 << INT0); // Запрещаем внешние прерывания INT0
}

}
}

 


Архив для статьи "Управление бесколлекторным двигателем постоянного тока(IR2101)"
Описание: Проект AVRStudio4, схема, макет печатной платы DipTrace
Размер файла: 38.76 KB Количество загрузок: 1 138 Скачать

Метки: ATmega8, Бесколлекторный двигатель, IR2101, Датчик Холла

Печать Электронная почта

Комментарии  

0 #21 Сергей V 16.12.2017 18:38
Здраствуйте , а можете сказать до каких максимальных оборотах работает двигатель в вашей схеме. Давно искал такое решение для управления движком.
Сообщить модератору
0 #22 AntonChip 19.12.2017 08:16
Цитирую Сергей V:
Здраствуйте , а можете сказать до каких максимальных оборотах работает двигатель в вашей схеме. Давно искал такое решение для управления движком.

Все зависит от характеристик двигателя, подаваемого напряжения, мой двигатель крутит на максимальных 2500 об/мин, а например двигатель от HDD будет тоже вращаться на макс оборотах
Сообщить модератору
0 #23 Сергей V 21.12.2017 16:36
А у Вас случайно не найдется прошивка в формате hex ?
Сообщить модератору
0 #24 Wictor 05.11.2018 01:21
А можно ли с помощью этой схемы управлять обычным асинхронным двигателем 380 вольт? Много надо переделать? Спасибо.
Сообщить модератору
0 #25 AntonChip 05.11.2018 23:24
Цитирую Wictor:
А можно ли с помощью этой схемы управлять обычным асинхронным двигателем 380 вольт? Много надо переделать? Спасибо.

К этой схеме можно подключить двигатели только постоянного тока
Сообщить модератору
0 #26 Wictor 12.11.2018 23:06
:-* Но ведь, по сути. Частотные преобразователи как раз так и работают? Они же выпрямляют переменный ток в постоянный, а потом создают переменный но уже с другой частотой...
Сообщить модератору
0 #27 AntonChip 13.11.2018 17:45
В таком случае на выходе драйвера должна быть синусоида, ознакомьтесь с апноутом AVR447: Sinusoidal driving of three-phase
permanent magnet motor using
ATmega48/88/168 , вот ссылка на проект radioparty.ru/.../...
Сообщить модератору
0 #28 Ваня 18.07.2019 00:13
Переключение обмоток происходит сразу после обнаружения перехода через ноль или с задержкой ? Не заметил в коде какой либо задержки на переключение.
Измерение прохождения через ноль нужно делать обязательно в момент когда одна фаза на - а другая на + или можно даже между коммутациями шима ? У меня шим дает ложные переходы через ноль с частотой шима. Могли бы вы помочь с тем чтобы переделать прошивку для ESC на атмега8 , есть отличия в схемах. ESC регулируется по ШИМ сигналу а нужно сделать чтобы регулировался по входу АЦП.
Такие заводские ESC стоят копейки но в них много лишних функции , проверка напряжения , проверка входного сигнала и т.д. что не позволяет быстро запускать двигатель. Хотелось бы совместить дешевую качественную платформу с вашей программой , чтобы любой желающий купив и перепрошив контроллер получил сразу рабочий драйвер завадского качества. Могу немного помочь средствами , хотя еще студент.
Сообщить модератору
0 #29 AntonChip 20.07.2019 09:59
Переключение происходит с задержкой, с какой именно трудно посчитать, т.к. код написан на си.
Портировать эту программу на ESC Simonk 30A уже пытался, работает не стабильно, запуск через раз, зависит от типа двигателя.
Считаю что такой код нужно писать на ассемблере.
Сообщить модератору
0 #30 Ваня 01.08.2019 00:08
Не могли бы вы дать мне посмотреть на код программы который вы запускали на ESC Somonk 30A ?
Сообщить модератору
0 #31 Ваня 01.08.2019 00:10
В не поняли в чем была причина отказов ? Почему на ассемблере и кто смог бы это сделать за вознаграждение ?
Сообщить модератору

Авторизация