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

Рейтинг:  5 / 5

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

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

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

// Подключение бесколлекторного двигателя к 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)" HOT
Проект AVRStudio4, схема, макет печатной платы DipTrace
File Size 38.76 KB Download 378 Download

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

Печать E-mail

Комментарии  

0 #1 bashsat 22.03.2017 22:42
Поделитесь пожалуйста, схемой в DipTrace.
Сообщить модератору
0 #2 AntonChip 29.03.2017 23:00
Цитирую bashsat:
Поделитесь пожалуйста, схемой в DipTrace.

Добавил в архив
Сообщить модератору
0 #3 bashsat 10.04.2017 20:25
Спасибо за схему. Возможно ли переделать код для управления двигателем радиоуправляемо й модели (квадрокоптера) ?
Сообщить модератору
0 #4 AntonChip 12.04.2017 11:25
Цитирую bashsat:
Спасибо за схему. Возможно ли переделать код для управления двигателем радиоуправляемой модели (квадрокоптера)?

Возможно, необходимо добавить код для управления по шине I2C, линии SDA и SCL свободны.
Сообщить модератору
0 #5 bashsat 12.04.2017 21:05
Посмотрел сигналы с выхода моего приёмника. Там сигнал PWM с длительностью от 1000мкс(мин. скорость) до 2000мкс(макс.ск орость). Нашёл схемы регуляторов, сигнал PWM подается на выводы прерывания INT0 и захвата ICP1.
Сообщить модератору
0 #6 AntonChip 13.04.2017 12:42
В таком случае нужно использовать микроконтроллер Atmega48/168, возможно будет измерять ширину импульса 16 битным таймером и одновременно генерировать ШИМ
Сообщить модератору
0 #7 Макс 19.07.2017 11:20
Здравствуйте! У меня двигатель на 24 вольта 70 ватт. Нужно собрать схему чтобы при подаче питания она сама разгонялась так как он находится на грузовике для охлаждения. Подскажите пожалуйста какие изменения надо внести? Очень срочно нужно собрать так как без охлаждение скипит.
Сообщить модератору
+2 #8 AntonChip 19.07.2017 23:32
Цитирую Макс:
Здравствуйте! У меня двигатель на 24 вольта 70 ватт. Нужно собрать схему чтобы при подаче питания она сама разгонялась так как он находится на грузовике для охлаждения. Подскажите пожалуйста какие изменения надо внести? Очень срочно нужно собрать так как без охлаждение скипит.

Для плавного авотзапуска в main оставить только этот кусок кода Код:
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;
}

объявить переменную direction ноль или один, также если уберете энкодер WORK_PWM сделать равным 255
Сообщить модератору
0 #9 Макс 20.07.2017 10:12
Уважаемый Антон.хотел попросить Вас написать готовую программу и отправить на email. Так как у меня компьютер сильно тормозит и навыков переписать программу к меня не достаточно. Так как я умею заливать прошивку через программаторы (файлы hex и eeprom) Очень замучился. Уже как неделю капаю интернет. И нашёл ваш проект. Буду признателен. Выручайте пожалуйста
Сообщить модератору
0 #10 Макс 20.07.2017 13:24
Пробовал самостоятельно изменить как вы написали но у меня при компиляции выскакивает failed. Можете пожалуйста помочь? Нужно убрать энкодер и кнопку. Нужно сделать так чтобы при подключении питания двигатель начинал работать. заранее благодарен
Сообщить модератору
0 #11 Макс 01.08.2017 19:41
Уважаемый Антон! Огромное Вам спасибо! Собрал обе варианта и оба рабочие! В настоящее время установил в грузовик и всё работает как часы! Желаю счастья, удачи и успехов!
Сообщить модератору
0 #12 AntonChip 04.08.2017 23:29
Спасибо!
Сообщить модератору
0 #13 MegaVT 08.08.2017 09:41
Доброго времени суток. Вопрос: каковы максимальные обороты двигателя с данной схемой? Есть пара движков от принтеров HP, интересует, насколько их можно "разогнать"? Хотя бы теоретически.
Сообщить модератору
0 #14 Kamal123 12.08.2017 22:09
Уважаемый Антон,если можно помогите мне,что бы можно было без энкодера и кнопки управлять плавно двигателем,по пробовал сам добавить но но не хочет работать,не могли бы вы сами написать код,тоже самое вас просил Макс пост #9,если можете помогите,почта спасибо.
Сообщить модератору
0 #15 Kamal123 12.08.2017 22:11
Уважаемый Антон скиньте свою почту,спасибо.
Сообщить модератору
0 #16 Yarik 04.10.2017 21:03
здравствуйте, подскажите пожалуйста в программе реализована стабилизация оборотов(поддер жка оборотов независимо от нагрузки на вал) ?
Сообщить модератору
0 #17 Berg 12.10.2017 17:13
Здравствуйте. Проект замечательный, особенно для тех кто осваивает МК. В двигателях не силен и поэтому вопрос. Есть мотор из древнего HDD 4 вывода, прозвонив его понел, что он имеет 3 обмотки ABC (5.7 Ом каждая), которые соединяются в одной точке D (это у нас 4-ый вывод). Т.е. как я понимаю соединение у нас звезда. Так вопрос, заработает ли он у меня с вашей схемой, если я его подключу: выводы ABC к UVW, а 4-ый вывод мотора D подключу на GND?
Сообщить модератору
0 #18 AntonChip 12.10.2017 18:38
Цитирую Berg:
Так вопрос, заработает ли он у меня с вашей схемой, если я его подключу: выводы ABC к UVW, а 4-ый вывод мотора D подключу на GND?
Среднюю точку подключать не надо
Сообщить модератору
0 #19 IvanS 26.10.2017 10:03
Здравствуйте! Не могли бы вы подсказать для чего нужны переключатели S1 S2? А так же, по скольку я новичок в этих вопросах, как и через какой софт прошить контроллер? А так же что для этого понадобится? И еще один не мало важный вопрос как задается скорость вращения вала двигателя, только ручкой потенциометра или же программно можно реализовать? связаться со мной можно по адресу
Сообщить модератору
0 #20 AntonChip 26.10.2017 11:26
Кнопка S1 пуск/стоп двигателя.
Переключатель S2 служит для изменения направления вращения двигателя.
Прошить можно любым программатором для AVR и через любой софт. Скорость регулируется ручкой энкодера, также скорость можно поменять в исходнике.
Сообщить модератору

Авторизация