сайт для палких паяльників

Управление бесколлекторным двигателем постоянного тока (BLDC) с помощью STM32

В качестве примера рассмотрим управления трехфазным бесколлекторным двигателем (BLDC Motor) с датчиками Холла. Об алгоритме управления бесколлекторным двигателем с датчиками Холла я ранее писал в статье Управление бесколлекторным двигателем с датчиками Холла (Sensored brushless motors). В этой статье мы рассмотрим только вопросы программирования микроконтроллера. Имеется в виду что вы знакомы с алгоритмом управления BLDC с датчиками Холла , имеете понятие о структуре регулятора, а силовая часть выбрана в соответствии с мощностью Вашего двигателя. Поэтому в статье не будет приведена принципиальная схема, будет рассматриваться только структурная схема с описанием назначения выводов микроконтроллера.

Общая информация

Этот простой пример показывает возможности микроконтроллера STM32, и основы управления BLDC двигателем с датчиками Холла. Этот пример не является готовым решением. В нем не реализованы системы контроля или стабилизации параметров. Не реализованные систем защиты. Это лишь базовый пример. Поэтому рассматривая этот пример Вы должны осознавать, что для использования в конечных изделиях Вам придется над ним основательно поработать.

Структурная схема подключения STM32

Силовая часть, то есть драйверы ключей и сами ключи, использовались с предыдущих проектов: http://www.avislab.com/blog/brushless08/. Подробнее о силовой части и ключах можно прочитать здесь: http://www.avislab.com/blog/brushless09_ru/. Описание силовой части выходит за рамки данной статьи. В этой статье рассматривается только структурная схема и программная реализация управления BLDC двигателями с датчиками Холла с помощью микроконтроллера STM32.

Генерация выходных сигналов

Первый таймер TIM1 микроконтроллера STM32 очень мощный инструмент и может выполнять различные интересные функции. Как я и обещал, когда писал о таймерах общего назначения, мы рассмотрим на практике некоторые возможности первого таймера. Первый таймер будет генерировать PWM сигналы для 6 ключей силовой части регулятора BLDC. Особенность таймера TIM1 заключается в том, что он имеет несколько пар комплементарных выходов. То есть выходов которые могут работать в паре. Мы будим использовать три пары, каждая пара будет формировать PWM сигналы для верхнего и нижнего ключей. Для верхних ключей это сигналы UH, VH, WH. Для нижних – UL, VL, WL. Каждая пара выходов таймера должна формировать сигналы таким образом, чтобы когда включен верхний ключ, нижний был выключен, когда верхний выключается, включается нижний. Кроме того, нам надо обеспечить Deadtime. То есть, промежуток времени для того чтобы ключ успел закрыться до того, как откроется комплементарный ключ. Иначе может возникнуть короткое замыкание. Этим также будет заниматься таймер TIM1.

Входные сигналы

Сигналы от трех датчиков Холла (H1, H2, H3) подаются на входы микроконтроллера. Коммутация ключей происходит в зависимости от состояния сигналов датчиков Холла. Когда происходит изменение состояния датчиков Холла, возникает прерывание. Обработчик прерывания изменяет состояние выходных сигналов. Скважность PWM задается потенциометром. Для считывания данных с потенциометра используется один из входных каналов ADC с использованием DMA. Для отключения выходных сигналов в случае перегрузки по току используется вход таймера TIM1_BKIN. Предполагается что на вход TIM1_BKIN будет подаваться дискретный сигнал от компаратора подключенного к датчику тока. Как видите для аварийного отключения выходных сигналов также используются ресурсы первого таймера. К тому же отключение происходит на аппаратном уровне. Это исключает возникновение даже малейших задержек которые могут быть в случаях, когда для этого используется программное решение, например используются прерывания.

Программное обеспечение

Описание настроек в файле bldc.h:

BLDC_CHOPPER_PERIOD – задает частоту PWM. Частота PWM в герцах = 72000000/BLDC_CHOPPER_PERIOD

Примеры:


#define BLDC_CHOPPER_PERIOD 9000 # - 8КГц
#define BLDC_CHOPPER_PERIOD 4500 # - 16КГц
#define BLDC_CHOPPER_PERIOD 3000 # - 24КГц
#define BLDC_CHOPPER_PERIOD 2250 # - 32КГц
#define BLDC_CHOPPER_PERIOD 1125 # - 64КГц

BLDC_NOL – задает Dead Time. Dead time = BLDC_NOL/72000000 (on 72MHz: 7 is 98ns)

Примеры:


#define BLDC_NOL 72

BLDC_PWMTOPKEYS – генерировать PWM только на верхних ключах
BLDC_PWMBOTTOMKEYS – генерировать PWM только на нижних ключах
BLDC_PWMTOPBOTTOMKEYS – генерировать PWM на верхних и нижних ключах
BLDC_PWMCOMPLEMENTARYMODE -генерировать PWM с использованием комплементарной работы ключей.

Только одна из этих опций должна быть включена.

Пример:


//#define BLDC_PWMTOPKEYS
//#define BLDC_PWMBOTTOMKEYS
//#define BLDC_PWMTOPBOTTOMKEYS
#define BLDC_PWMCOMPLEMENTARYMODE

Далее идут настройки ADC, то есть пороги срабатываний потенциометра. Напомню, показатели ADC лежат в пределах от 0 до 4096.

BLDC_ADC_START – задает нижний порог ниже которого считается мертвой зоной, двигатель не запускается.
BLDC_ADC_STOP – задает порог ниже которого происходит отключение двигателя. Обязательно должно быть меньше BLDC_ADC_START.
BLDC_ADC_MAX – максимальный порог ADC. Все значения выше этого порога задают максимальные обороты.

Пример:


#define BLDC_ADC_START 200
#define BLDC_ADC_STOP 50
#define BLDC_ADC_MAX 4000

Ниже график поясняющий как работают пороги для ADC.

main.c

Смотрим main.c:

#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_exti.h"
#include "stm32f10x_adc.h"
#include "stm32f10x_dma.h"
#include "misc.h"
#include "string.h"
#include "stdio.h"

#include "sysclk.h"
#include "adc_dma.h"
#include "bldc.h"

int main(void)
{
	// Set clock
	SetSysClockTo72();
	// ADC Init
	ADC_DMA_init();
	// TIM1, outputs, inputs, interrupts, etc. Init
	BLDC_Init();

	// Reverse pin Init
	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_SetBits(GPIOB, GPIO_Pin_0);

    while(1)
    {
    	if (ADCBuffer[0] > BLDC_ADC_START) {
    		if (BLDC_MotorGetSpin() == BLDC_STOP) {
    			// Check Reverse pin
    			if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) != 0) {
    				// Forward
    				BLDC_MotorSetSpin(BLDC_CW);
    			}
    			else {
    				// Backward
    				BLDC_MotorSetSpin(BLDC_CCW);
    			}
    			BLDC_MotorCommutation(BLDC_HallSensorsGetPosition());
    		}
    		BLDC_SetPWM(BLDC_ADCToPWM(ADCBuffer[0]));
    	}
    	else {
    		if (BLDC_MotorGetSpin() != BLDC_STOP) {
    			if (ADCBuffer[0] < BLDC_ADC_STOP) {
    				BLDC_MotorStop();
    			}
    		}
    	}
    }
}

Микроконтроллер должен работать на частоте 72Мгц с использованием внешнего кварцевого резонатора частотой 8МГц. Эта функция настраивает тактирования микроконтроллера:


SetSysClockTo72();

Далее выполняется инициализация ADC:


ADC_DMA_init();

ADC работает с использованием DMA. Результат преобразования с ADC_Channel_9 сохраняется в ADCBuffer [0];

И наконец выполняется инициализация BLDC. Настраиваются выходы и входы, прерывания, первый таймер:


BLDC_Init();

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

    		if (BLDC_MotorGetSpin() == BLDC_STOP) {
    			// Check Reverse pin
    			if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) != 0) {
    				// Forward
    				BLDC_MotorSetSpin(BLDC_CW);
    			}
    			else {
    				// Backward
    				BLDC_MotorSetSpin(BLDC_CCW);
    			}
    			BLDC_MotorCommutation(BLDC_HallSensorsGetPosition());
    		}
    		BLDC_SetPWM(BLDC_ADCToPWM(ADCBuffer[0]));

Он отвечает за старт двигателя. Функция BLDC_MotorSetSpin (BLDC_CCW); задает направление вращения двигателя. Поскольку положения ротора определяется в момент поступления прерываний от датчиков Холла, сразу после старта программы контроллер может и не знать положения ротора, поскольку прерывание еще не возникало. Поэтому надо обязательно перед стартом вызвать функцию
BLDC_MotorCommutation(BLDC_HallSensorsGetPosition());

В главном цикле также устанавливается скважность PWM. Смотри функцию BLDC_SetPWM. Функция BLDC_ADCToPWM преобразует показатель ADC в значение для таймера в зависимости от установленных лимитов ADC и настроек таймера TIM1, в частности в зависимости от частоты PWM. Если Вы планируете управлять оборотами двигателя используя не потенциометр, а другие каналы (последовательный порт и т.д.), следует использовать свою, аналогичную функцию которая будет вычислять значение для записи в таймер. Подробнее о PWM читайте в статье STM32. Программирование STM32F103. TIMER. PWM

Иинициализация таймера

Инициализация первого таймера, настройки выходов и TIM1_BKIN происходят в функции BLDC_PWMTimerInit. Настраивается частота PWM:


TIM_TimeBaseStructure.TIM_Period = BLDC_CHOPPER_PERIOD;

Также устанавливается DeadTime:


TIM_BDTRInitStructure.TIM_DeadTime = BLDC_NOL;

Также настраивается вход TIM1_BKIN. Обратите внимание можно задавать уровень сигнала при котором происходит отключение:


TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;
 TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_Low;

Скважность PWM устанавливается для каждого из трех каналов отдельно. Это выполняет функция BLDC_SetPWM:


void BLDC_SetPWM(uint16_t PWM)
 {
 TIM1->CCR1 = PWM;
 TIM1->CCR2 = PWM;
 TIM1->CCR3 = PWM;
 }

Видео

Управление BLDC двигателями с датчиками – это один из самых простых алгоритмов управления бесколлекторными двигателями. Простота этого алгоритма до сих пор обеспечивает его широкое использование. Но … продолжение следует.

Скачать проект можно по следующей ссылке:
https://github.com/avislab/STM32F103/tree/master/Example_BLDC

Смотри также:

Статьи по бесколлекторным двигателям:

Смотри также:

Желаю успехов.

1 коментар: STM32 – BLDC Motor Control

  • rasel говорить:

    Позвольте вопрос, если нужен код код который обслуживает двигатель с энкодером, крутить его до определенного значения то ка лучше написать такой код? Я написал вот так. Есть такой же код но толь в сведении. Но есть проблема, иногда “выскакивает” из цикла и останавливается до выполнения условия, в чем может быть проблема? Я пытался писать код по разному но результат тот же…?

    if(counter_lcd < calibre_lcd) // Если положение меньше калибра.
    {
    triger = 1; // флаг блокировки кода.
    timer_COMPA_ON(); // подпрограмма включения канала А таймера1, обновления экрана.
    direction_motor = 1;
    nterrupt_on(); // включение прерывания.
    PORTB |= (1<<4); // включение мотора на разведение cw.
    do{
    }
    while(counter_lcd <= calibre_lcd);
    PORTB &= ~(1<<4); // выключение мотора на разведение.
    PORTB |= (1<<2); // Включаем динамическое тормажение.
    dinam_on = 1; // флаг выключения динамическое торможения.
    timer_COMPB_ON(); // подпрограмма включения каннала B таймера 1, динамического торможения.
    }

    ISR(INT0_vect)
    {
    cli();
    uint8_t int_temp = 0x02;
    while(1)
    {
    if((PIND & (1<= calibre_lcd) // temp_calibre старый код
    {
    compare = 0;
    }
    if(compare == 255)
    {

    } */
    goto out_int;
    }
    division_CW++;
    goto out_int;
    }
    backlash_CW++;
    backlash_CWW = 0;
    division_CWW = 0;
    goto out_int;
    }
    }
    else{}
    }
    else
    int_temp–;
    if(int_temp == 0)
    {
    goto out_int;
    }
    }
    out_int:
    sei();
    }

Translate
Архіви

© 2011-2018 Андрій Корягін, Кременчук - Київ, Україна