Все когда-то начинают работу с двигателями. Без этого любое устройство, взаимодействующее с реальным миром, как-бы не до конца настоящее.
Вне зависимости от целей, будь то управление валами ваше станка с ЧПУ или гениальной модели 3D принтера, часов, задвижки для ворот или любого другого необходимого приспособления, перед вами маячит задача как-то двигать мотором.
Я не ставлю своей целью описать как работают биполярные шаговые двигатели или как использовать H-Bridge. Управление МОЩНЫМ двигателем, обмотки которого будут потреблять больше, чем может выдать gpio микроконтроллера, отлично освещено. Этого добра в сети предостаточно, равно как и специализированных микросхем и учебников от производителей.
Совредоточимся на малости: есть ОЧЕНЬ маленький моторчик. Например, шаговый биполярный двигатель от компании NIBEC. И вам нужно им управлять.
Всё классически: 4 провода, 2 фазы, биполярный. Например, Вам повезло как и мне, и вы имеете вот такие дешевые моторчики с AliExpress:
Во-первых, их описание на AliExpress не соответствует действительности. Мне стоило больших трудов найти производителя, а найдя его, горестно убедиться в том, что datasheet на этот моторчик составляет целых полстраницы. При этом в даташите нет ни сведений о его потреблении, ни о том, как расположены выводы обмоток.
Может быть это настолько очевидно, не знаю. Для начинающего точно нет. Поэтому определять мы будем следующим образом: прозванивая выводы на сопротивления. Сопротивление должно быть в районе 20 Ohm, если Вам повезло и у вас тоже модель MSEU. Чтобы ни писали китайцы, по даташиту его максимальный вольтаж 3.3В. Поэтому пихать ему или нет 5 вольт решайте сами. Я не стал.
Я подумал, что для такого малюсенького мотора нет никакого смысла в H-Bridge. Его максимальное потребление по току лежит наверно значительно ниже возможностей GPIO stm32 Cortex-M3. Не найдя информации как подключить такой маленький двигатель к выводам микроконтроллера напрямую, я решил написать для себя и для тех, кому эта информация может пригодиться, такую шпаргалку, как это всё сделать.
Прозвонив моторчик, определили как у него распределены контакты:
Я хочу ещё раз подчеркнуть для пуристов и этих, как его, перфекционистов: это “неправильное” подключение шагового двигателя к микроконтроллеру можно осуществлять только в том случае, если вы уверены, что по току выводы микроконтроллера позволяют это делать относительно аппетита моторчика. В противном случае Вы рискуете навсегда спалить себе порты своего mcu.
Шаговые двигатели имеют контактные площадки, или выводы, которые позволяют току от источника питания (в этом примере, непосредственно от микроконтроллера), попасть в обмотки катушек мотора. Сформированные импульсы “правильной” формы и последовательности создают электромагнитные поля, “поворачивающие” магнитный сердечник. Всего существует несколько способов реализовать задуманное. В целом, для двухфазных двигателей, таких как у нас, разделяют 3 подхода:
Это руководство реализует полушаг. В нашем случае это будет означать сдвиг на 9 градусов за каждый “полушаг”. Всего 40 шагов на полный оборот шпинделя двигателя.
Логика наших действий следующая: подключая все четыре провода к портам ввода/вывода mcu, мы выдаём на них 0
или 1
. Замкнутые через катушки двигателя, такие порты формируют электрическую цепь ток в которой протекает в нужном нам направлении.
Диаграмма направлений идеальным образом представлена в документе Quick Start for Beginners to Drive a Stepper Motor от шикарной компании NXP.
Приведу небольшую выдержку:
Реализовывать будем на arm-none-eabi-gcc
с использованием великолепной библиотеки libopencm3.
// Объявляем
#define MOTOR_PORTA GPIOA
#define MOTOR_A0 GPIO8
#define MOTOR_A1 GPIO9
#define MOTOR_PORTB GPIOA
#define MOTOR_B0 GPIO10
#define MOTOR_B1 GPIO11
static uint8_t halfStep[8][4] = {{1,0,0,0}, {1,0,1,0},
{0,0,1,0}, {0,1,1,0},
{0,1,0,0}, {0,1,0,1},
{0,0,0,1},{1,0,0,1}};
...
// конфигурируем
rcc_clock_setup_in_hse_8mhz_out_72mhz();
rcc_periph_clock_enable(RCC_GPIOA);
gpio_set_mode(MOTOR_PORT, GPIO_MODE_OUTPUT_50_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL,
MOTOR_A0 | MOTOR_A1 | MOTOR_B0 | MOTOR_B1);
gpio_clear(MOTOR_PORT, MOTOR_A0 | MOTOR_A1 | MOTOR_B0 | MOTOR_B1);
...
void motorPinToggle(uint8_t state, uint32_t port, uint16_t pin) {
if (state)
gpio_set(port, pin);
else
gpio_clear(port, pin);
}
void motorStep(uint8_t state[4]) {
motorPinToggle(state[0], MOTOR_PORT, MOTOR_A0);
motorPinToggle(state[1], MOTOR_PORT, MOTOR_A1);
motorPinToggle(state[2], MOTOR_PORT, MOTOR_B0);
motorPinToggle(state[3], MOTOR_PORT, MOTOR_B1);
}
...
// реализуем вращение на полный оборот и смену направления
while (1) {
motorStep(halfStep[index]);
pcd8544_display();
index+=dirIndex;
for (int i = 0; i < 1000000; i++)
__asm__("nop");
if (dirIndex && index>7 )
index = 0;
else if (index<0)
index = 7;
steps += dirIndex;
if (steps>40) {
steps = 40;
dirIndex = dirIndex * -1;
} else if (steps<0) {
steps = 0;
dirIndex = dirIndex * -1;
}
}
Вот и всё. Надеюсь кому-то поможет. Ссылка на пример реализации: stm32-nidec на github.
Внимание!
Спустя сутки непрерывной работы моторчика (MCU практчески холодный) я произвёл замеры потребления тока на каждой из обмоток. Выяснилось, что реальное потребление составляет около 38 миллиампер, что ВЫШЕ рекомендованного и не так уж далеко от максимально возможного. Учитывая, что двигатель может эксплуатироваться в режиме с нагрузкой, использовать такое подключение нельзя!
ИСПОЛЬЗОВАНИЕ БЕЗ H-BRIDGE, например, без такого: DRV8836 Dual Low-Voltage H-Bridge IC или такого DRV8833C Dual H-Bridge Motor Driver, МОЖЕТ ПРИВЕСТИ К НЕИСПРАВНОСТИ МИКРОКОНТРОЛЛЕРА.
В этой связи, данные, приведённые в этой статье следует рассматривать лишь как информационно-справочные, но не как руководство к действию.