В этом варианте контроллера бесколлекторного двигателя для управления силовыми ключами используется специальный драйвер IR2101, который позволяет избавиться от дорогих и дифицитных P-канальных полевых транзисторов. Также с небольшим изменением схемы можно использовать драйвера ключей нижнего и верхнего уровней IR2110 или IR2113. В исходный код внес некоторые изменения, в частности плавный пуск и изменение вращения вала двигателя. При первом запуске двигатель плавно разгоняется, от уровня ШИМ 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)" | |
Описание: Проект AVRStudio4, схема, макет печатной платы DipTrace | |
Размер файла: 38.76 KB Количество загрузок: 3 211 | Скачать |
Комментарии
Сравнивайте и изменяйте имена регистров в соответствие с этим примером radioparty.ru/.../...
Здравствуйте. Схема и прошивка разработаны для работы без датчиков Холла
Ток будет слишком мал чтобы повредить МК
Да, лучше пересчитать