Перейти к содержимому
Форум журнала практической электроники «Датагор»
Набор для вскрытия электроники WOSAI 11 In 1
Сумка для инструментов 12"-14"-16", очень прочная 600D
Магнитный браслет мастера. Биты, гайки, саморезы, гвозди перестали теряться
Набор резаков, метал. ручка, цанга
Увлажнитель и очиститель воздуха. Когда шпарят батареи
Беспроводной звонок, 32 мелодии!
Набор термоусадок разного калибра, 385шт.
AAM2302 (DHT22) цифровой датчик влажности и температуры
Касса резисторов 0.25Вт, 64 номинала, всего 1280шт.
Водозащищённые навороченные мужские часы SANDA-G
Детские/стариковские GPS-часы-антипотеряшки и телефон
600шт., 3 цвета, 15 типов терминалов под обжим 22~12AWG

Wishmaster

Помогите модифицировать программу управления бесколлекторным двигателем постоянного тока.

Рекомендованные сообщения

Здравствуйте товарищи!

Прошу Вас помочь советом о модификации программы управления бесколлекторным двигателем постоянного тока.

Повторил следующую схему:

post-32116-0-41061500-1500409447_thumb.gif

Всё запустилось и отлично работает. Хочу теперь миниатюризировать плату и убрать лишний функционал в виде кнопки запуска и выбора стороны вращения. Опыта в программировании явно не достаёт.

Исходный код:

 

// Подключение бесколлекторного двигателя к 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

}

 

}

}

 

 

Хочу, чтобы при подачи питания движок вращался сразу по часовой стрелке, без внешнего прерывания от кнопки. И даже примерно понимаю, что нужно изменить код где-то в этом блоке:

 

 

// Обработчик внешнего прерывания 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;

}

 

 

 

Но, что именно и как понять не могу.

Изменено пользователем Wishmaster

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Добрый день, Дмитрий.

 

Попробуйте из этого куска

 

if((PIND&(1 << PD0)) == 0) // Старт/Стоп

{

_delay_ms(20);

start_stop ^= 1; // Переключаем состояние

while((PIND&(1 << PD0)) == 0){}

}

 

оставить только

 

start_stop = 1;

Изменено пользователем erbol

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

+

... Хочу, чтобы при подачи питания движок вращался сразу по часовой стрелке, без внешнего прерывания от кнопки. ...

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

Если вам не нужна регулировка вращения, то в регистры PWM нужно будет забить какое то конкретное значение, в зависимости от необходимой скорости.

Изменено пользователем Sergiy_83

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Спасибо за ответы. Завтра опробую Ваши вариаты.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Здравствуйте товарищи!

Прошу Вас помочь советом о модификации программы управления бесколлекторным двигателем постоянного тока.

 

 

Дмитрий, добрый день!

А можно попросить ссылку на первоисточник данной схемы. интересно посмотреть для каких целей и с какими движками она там применялась.

Для своих целей попробовать использовать.

Спасибо!

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Возможно вот оно:

_http://radioparty.ru/prog-avr/program-c/611-lesson-bldc-sensorless

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

︽ Наверх страницы ︽
×