Подключение бесколлекторного двигателя с датчиками Холла к AVR

Модератор: boogyman

Ответить
Аватара пользователя
AntonChip
Администратор
Сообщения: 211
Зарегистрирован: 24 дек 2011, 22:11
Откуда: Киров
Контактная информация:

Подключение бесколлекторного двигателя с датчиками Холла к AVR

#1

Сообщение AntonChip » 28 ноя 2018, 19:19

Здравствуйте. По просьбам читателей решил дополнить управляющую программу драйвера бесколлекторного двигателя с датчиками Холла. Изменил источник опорного напряжения на внутренний (1,1V), лучше подходит для измерения тока, поэтому потенциометр подключил через делитель напряжения. Так как в дальнейшем планируется измерение тока каналы измерения меняются в обработчике прерывания от АЦП, а само прерывание происходит от переполнения таймера. Переменная start_speed содержит значение при котором начинается запуск двигателя.
Реверс двигателя осуществляется переключателем S1 при полной остановке двигателя.
Выходы на светодиоды "Реверс" и "Макс. ток" в коде пока не использовал, а также переменную current.

Код: Выделить всё

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

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

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

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

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

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

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

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

#define start_speed 2

volatile uint16_t current;
char start = 0;
volatile uint8_t speed;
volatile char direction, channel = 3;

// Обработчик внешнего прерывания
ISR(PCINT0_vect)
{
uint8_t position;
// Считываем значения датчиков
position = (PINB & ((1 << PB2)|(1 << PB1)|(1 << PB0)));
  if(direction) // Если по часовой
  {
    switch(position) // Переключаем обмотки
    {
    case 0b101: UH_OFF; UL_ON; VH_ON; VL_OFF; WH_OFF; WL_OFF; break;
    case 0b001: UH_OFF; UL_ON; VH_OFF; VL_OFF; WH_ON; WL_OFF; break;
    case 0b011: UH_OFF; UL_OFF; VH_OFF; VL_ON; WH_ON; WL_OFF; break;
    case 0b010: UH_ON; UL_OFF; VH_OFF; VL_ON; WH_OFF; WL_OFF; break;
    case 0b110: UH_ON; UL_OFF; VH_OFF; VL_OFF; WH_OFF; WL_ON; break;
    case 0b100: UH_OFF; UL_OFF; VH_ON; VL_OFF; WH_OFF; WL_ON; break;
    }
  }
  else // иначе против часовой
  {
    switch(position) // Переключаем обмотки
    {
    case 0b101: UH_ON; UL_OFF; VH_OFF; VL_ON; WH_OFF; WL_OFF; break;
    case 0b001: UH_ON; UL_OFF; VH_OFF; VL_OFF; WH_OFF; WL_ON; break;
    case 0b011: UH_OFF; UL_OFF; VH_ON; VL_OFF; WH_OFF; WL_ON; break;
    case 0b010: UH_OFF; UL_ON; VH_ON; VL_OFF; WH_OFF; WL_OFF; break;
    case 0b110: UH_OFF; UL_ON; VH_OFF; VL_OFF; WH_ON; WL_OFF; break;
    case 0b100: UH_OFF; UL_OFF; VH_OFF; VL_ON; WH_ON; WL_OFF; break;
    }
  }
}
// Обработчик прерывания от АЦП
ISR(ADC_vect)
{
  switch(channel)
  {
  case 3:
    ADMUX = (1 << REFS1)|(1 << REFS0)|(1 << MUX2);
    speed = ADC/4;
	channel = 4;
	break;
  case 4:
    ADMUX = (1 << REFS1)|(1 << REFS0)|(1 << MUX1)|(1 << MUX0);
    current = ADC;
	channel = 3;
    break;
  }
  TIFR0 = (1 << TOV0);
}

// Функция изменения скорости
static void set_speed(uint8_t speed)
{
TIFR0 = TIFR0;    // Очищаем флаг прерывания TC0
while(!(TIFR0 & (1<<TOV0)));  // Ждем переполнения таймера
cli();
OCR0A = speed; // Изменяем ШИМ
OCR0B = speed;
OCR2B = speed;
sei();
}

int main(void)
{
TCCR0A |= //(1 << COM0A1)|(0 << COM0A0)| // Сброс вывода OC0A при совпадении
          //(1 << COM0B1)|(0 << COM0B0)| // Сброс вывода OC0B при совпадении
          (1 << WGM01)|(1 << WGM00); // Режим Fast PWM
TCCR0B |= (1 << CS00); // Предделитель CLK/1

TCCR2A |= //(1 << COM2B1)|(0 << COM2B0)| // Сброс вывода OC2B при совпадении
          (1 << WGM01)|(1 << WGM00);   // Режим Fast PWM
TCCR2B |= (1 << CS20); // // Предделитель CLK/1

PCMSK0 |= (1 << PCINT2)|(1 << PCINT1)|(1 << PCINT0); // Активируем входы внешних прерываний
PCICR |= (1 << PCIE0);    // Разрешаем прерывание по изменению состояния порта B

ADMUX = (1 << REFS1)|(1 << REFS0)|(1 << MUX1)|(1 << MUX0);
ADCSRA = (1 << ADEN)|(1 << ADSC)|(1 << ADATE)|(1 << ADIF)|(1 << ADIE)|(1 << ADPS1);
ADCSRB = (1 << ADTS2); // Запуск измерения по переполнению Т0

DDRC &= ~(1 << PC5); // Переключатель направления вращения
PORTC |= (1 << PC5);

sei(); // Глобально разрешаем прерывания

DDRD = 0xFF; // Порт D - выход 

while(1)
{
  if(speed > start_speed) // Если значение скорости больше скорости запуска 
  {
	// Режим запуска
	if(start == 0) // Если пуск разрешен, запускаем двигатель
	{
	  if(PINC&(1 << PC5))        direction = 1; // По часовой
	  if((PINC&(1 << PC5)) == 0) direction = 0; // Против часовой
    PCICR |= (1 << PCIE0);    // Разрешаем прерывание по изменению состояния порта B
	DDRB |=  (1 << PB2)|(1 << PB1)|(1 << PB0); // Кратковреммено подаем лог.1 на входы датчиков 
    PORTB |= (1 << PB2)|(1 << PB1)|(1 << PB0); // для первоначального запуска двигателя
    PORTB &= ~(1 << PB2)|(1 << PB1)|(1 << PB0);
	DDRB = 0x00; // Порт B - вход
    start = 1; // Запрещаем запуск
	}
    // Рабочий режим
	set_speed(speed); // Изменяем скорость
  }
  else
  {
  start = 0; // Разрешаем запуск
  PCICR &= ~(1 << PCIE0); // Запрещаем прерывание по изменению состояния порта B
  PHASE_ALL_OFF; // Выключем выход на двигатель
  }

}
}
Схема с датчиками Холла.gif
Вложения
bldc_holl_atmega48.rar
Проект AVRStudio4
(30.62 КБ) 10 скачиваний

Аватара пользователя
AntonChip
Администратор
Сообщения: 211
Зарегистрирован: 24 дек 2011, 22:11
Откуда: Киров
Контактная информация:

Re: Подключение бесколлекторного двигателя с датчиками Холла к AVR

#2

Сообщение AntonChip » 29 ноя 2018, 19:34

Для использования регулятора на основе датчика Холла вместо потенциометра можно поменять строчку

Код: Выделить всё

speed = ADC/4;
на

Код: Выделить всё

if(ADC <= 164) speed = 0;
else speed = (ADC - 164)/3.3;
тогда двигатель начнет запуск от 0,9 Вольт на входе делителя напряжения

Ответить