PROGCONT.RU

Вход Регистрация
О САЙТЕ ГЛАВНАЯ
 

STM8S003F3 создание собственного драйвера для униполярного шагового двигателя на контроллере а также примеры программ.


 Эта статья будет для тех, кто хочет создать свой собственный драйвер для униполярного шагового двигателя изучение начнем с простых видов управления это шаг, полушаг и шаг с включением две обмотки одновременно закончим продвинутым управлением с помощью ШИМ.
 Первым делом давайте ознакомимся с моей схемой драйвера, я ее делал универсальную для работы от трех до шести фазных униполярных шаговых движков, вы можете убрать из нее лишнее для собственного устройства, параметры данной схемы зависят от транзисторной сборки AO4828 при питании 12V 5A тока держат уверено в импульсном режиме.

нет рисунка

 Транзисторные сборки AO4828 можете заменить на подходящие одиночные полевые транзисторы, диоды шоттки D1-D6 у меня 60V ток 1A, вывод J1 для прошивки контроллера, вывод J2 питание пин 1.+5V 2.GND 3.от +12 до 50V. Для управления обмотками статора двигателя использую выводы: J3 питание, обмотки двигателя: J7-A; J6-B; J9-C; J8-D и J4 J5 не используется. BT1-BT4 это кнопки для управления двигателем, в примере прошивки STEP-DIR вывод контроллера PA3( кнопка BT4) используется для сигнала STEP и PD6( кнопка BT1) для DIR.

 
Простые виды управления униполярным шаговым двигателем.


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

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

нет рисунка Шаг с включением две обмотки одновременно самый популярный способ управление который использовался в старых станка ЧПУ так как имел максимальный момент на валу.

 Теперь небольшой пример для шагового режима в котором мы просто будем выставлять на нужном выводе высокий уровень на ненужных должен быть низкий, порядок следующий обмотка A( GPIOC, GPIO_PIN_6) -B( GPIOC, GPIO_PIN_7) -C( GPIOC, GPIO_PIN_3) -D( GPIOC, GPIO_PIN_4), для вращения в другом направлении порядок должен быть обратным.

#include "stm8s.h"
//Массив для управления выводами, порядок A-B-C-D.
uint8_t step_pwm[4]={ 64,128,8,16};
//Счетчик для массива.
uint8_t count_step=0;
int main( void )
{
//Настройка кнопок для управления вращением мотора.
GPIO_Init( GPIOD, GPIO_PIN_6, GPIO_MODE_IN_PU_NO_IT);
GPIO_Init( GPIOA, GPIO_PIN_3, GPIO_MODE_IN_PU_NO_IT);
//Настройка выводов для управление обмотками.
GPIO_Init( GPIOC, GPIO_PIN_3, GPIO_MODE_OUT_PP_LOW_FAST); //обмотка C
GPIO_Init( GPIOC, GPIO_PIN_4, GPIO_MODE_OUT_PP_LOW_FAST); //обмотка D
GPIO_Init( GPIOC, GPIO_PIN_6, GPIO_MODE_OUT_PP_LOW_FAST); //обмотка A
GPIO_Init( GPIOC, GPIO_PIN_7, GPIO_MODE_OUT_PP_LOW_FAST); //обмотка B
while(1){
//Если нажата эта кнопка то прибавляем счетчик массива.
if( !GPIO_ReadInputPin( GPIOA, GPIO_PIN_3)){
count_step++;
}
//Если нажата эта кнопка то уменьшаем счетчик массива.
if( !GPIO_ReadInputPin( GPIOD, GPIO_PIN_6)){
count_step--;
}
//Накладываем маску что бы счетчик не превышал 3.
count_step&=3; //Записываем новые данные массива для вращения ротара.
GPIO_Write( GPIOC, step_pwm[ count_step]);
//Тут пауза для скорости вращения.
for( uint32_t i=0; i<1000; i++);
}
return 0;
}
#ifdef USE_FULL_ASSERT
void assert_failed( uint8_t* file, uint32_t line)
{
while (1){}
}
#endif

 Два других двух вариантов управления вы сможете реализовать переписав порядок включения обмоток в массиве step_pwm[4].
   Шаг с включением две обмотки одновременно-step_pwm[4]={ 192,136,24,80};
   Полушаговое управление-step_pwm[8]={ 64, 192, 128, 136, 8, 24, 16, 80}; и так как изменилась длина массива замените count_step&=3; на count_step&=7;.

 Все перечисленные выше способы управления являются самыми простыми но имеют один большой недостаток отсутствие изменения тока в обмотках статора ШД из за которого мы не сможем реализовать более мелкое дробление шага и снижение тока в режиме ожидания. Все эти недостатки мы попробуем победить в нашем драйвере на контроллере STM8S003F3 с использование ШИМ.

 
Описание работы программы управления с помощью ШИМ.

 Для ШИМ управления обмотками двигателя нам потребуется TIM1 по тому что имеет четыре отдельных выхода для генерации нужного сигнала.
 Да незабываем переназначить Alternate function remapping bits, чтобы подключить TIM1_CH1 и TIM1_CH2 к выводам контроллера, должно быть так.

нет рисунка

 Основное действие будет осуществлять TIM1, настраиваем его и его выводы в режиме PWM( ШИМ), в примере выше мы просто изменяли состояние нужного вывода тут будет принцип похожий только будем менять продолжительность импульса в TIM1_CH1, TIM1_CH2, TIM1_CH3 и TIM1_CH4 который будет браться из массива.
нет рисунка  Основной функционал программы будет работать в прерывании от переполнения TIM1, там мы контролируем скорость и вход в режим ожидания.
 Скорость контролируется путем отсчета прерываний прибавлением count_speed_up и если выполнится условие count_speed_up> count_speed то разрешается изменения позиции в массиве импульсов для каждой обмотки, направление изменение позиции зависит от нажатой кнопки BT1 вращение вправо уменьшаем позиции( fase1, fase2, fase3, fase4) или BT4 вращение влево прибавляем. Скорость вращения count_speed меняется в основном теле программы тоже нажатием соответствующей кнопки BT2 увеличивает скорость уменьшая count_speed и BT3 уменьшает скорость соответственно увеличивая count_speed.
 Один из важных действий в управлении ШД является реализации режима ожидания или удержания, когда происходит вращение в обмотках действует активное и реактивное сопротивление которое значительно снижает проходящий через обмотки ток, без вращения действует только активное что вызывает более большой ток и соответственно перегрев двигателя. Удержание реализовано на счетчике бездействия count_wait если он равен нулю то будет использоваться массив удержания в котором импульсы намного меньше чем в рабочем массиве, count_wait устанавливается в максимальное значение если была нажата одна из кнопок вращение и соответственно будет использоваться рабочий массив пока он не обнулиться в покое. В программе я использую очень большую задержку для ухода в этот режим для демонстрации на самом деле она должна быть минимальна, подберите экспериментальным путем.
 В примере ниже продемонстрировано как можно управлять двигателем с помощью кнопок изменяя направление и скорость вращения, использования режима удержания и реализовать полушаговый вариант вращения.

#include "stm8s.h"
//Рабочий массив.
uint16_t step_pwm[8]={ 0,0,0,0,283,400,283,0};
//Массив для режима ожидания.
uint16_t step_pwm_wait[8]={ 0,0,0,0,71,100,71,0};
//Счетчик для ухода в режим ожидания.
uint16_t count_wait=0;
//Положение в массиве нужного импульса для ШИМ.
uint8_t fase1=0;
uint8_t fase2=2;
uint8_t fase3=4;
uint8_t fase4=6;
//Счетчик скорости вращения ротора.
uint32_t count_speed_up=0;
//Скорость вращения ротора.
uint32_t count_speed=1000;

int main( void )
{ CLK_HSIPrescalerConfig( CLK_PRESCALER_HSIDIV1);
//Настраиваем кнопки для управления.
GPIO_Init( GPIOD, GPIO_PIN_4, GPIO_MODE_IN_PU_NO_IT);// Уменьшаем скорость кнопка BT3
GPIO_Init( GPIOD, GPIO_PIN_5, GPIO_MODE_IN_PU_NO_IT);// Прибавляем скорость кнопка BT2
GPIO_Init( GPIOD, GPIO_PIN_6, GPIO_MODE_IN_PU_NO_IT);// Вращение вправо кнопка BT1
GPIO_Init( GPIOA, GPIO_PIN_3, GPIO_MODE_IN_PU_NO_IT);// Вращение влево кнопка BT4
//Настраиваем выводы для управления транзисторами.
GPIO_Init( GPIOC, GPIO_PIN_3, GPIO_MODE_OUT_PP_LOW_FAST);//Обмотка C TIM1_CH3
GPIO_Init( GPIOC, GPIO_PIN_4, GPIO_MODE_OUT_PP_LOW_FAST);//Обмотка D TIM1_CH4
GPIO_Init( GPIOC, GPIO_PIN_6, GPIO_MODE_OUT_PP_LOW_FAST);//Обмотка A TIM1_CH1
GPIO_Init( GPIOC, GPIO_PIN_7, GPIO_MODE_OUT_PP_LOW_FAST);//Обмотка B TIM1_CH2
//Настройка TIM1 и его выводы а также прерывание.
TIM1_TimeBaseInit( 0, TIM1_COUNTERMODE_UP, 400, 0);
TIM1_OC1Init( TIM1_OCMODE_PWM1, TIM1_OUTPUTSTATE_ENABLE, TIM1_OUTPUTNSTATE_DISABLE, 0, TIM1_OCPOLARITY_HIGH, TIM1_OCNPOLARITY_HIGH, TIM1_OCIDLESTATE_RESET, TIM1_OCNIDLESTATE_RESET);
TIM1_OC2Init( TIM1_OCMODE_PWM1, TIM1_OUTPUTSTATE_ENABLE, TIM1_OUTPUTNSTATE_DISABLE, 0, TIM1_OCPOLARITY_HIGH, TIM1_OCNPOLARITY_HIGH, TIM1_OCIDLESTATE_RESET, TIM1_OCNIDLESTATE_RESET);
TIM1_OC3Init( TIM1_OCMODE_PWM1, TIM1_OUTPUTSTATE_ENABLE, TIM1_OUTPUTNSTATE_DISABLE, 0, TIM1_OCPOLARITY_HIGH, TIM1_OCNPOLARITY_HIGH, TIM1_OCIDLESTATE_RESET, TIM1_OCNIDLESTATE_RESET);
TIM1_OC4Init( TIM1_OCMODE_PWM1, TIM1_OUTPUTSTATE_ENABLE, 0, TIM1_OCPOLARITY_HIGH, TIM1_OCIDLESTATE_RESET);
TIM1_ARRPreloadConfig( ENABLE);
TIM1_OC1PreloadConfig( ENABLE);
TIM1_OC2PreloadConfig( ENABLE);
TIM1_OC3PreloadConfig( ENABLE);
TIM1_OC4PreloadConfig( ENABLE);
TIM1_CtrlPWMOutputs( ENABLE);
TIM1_ClearFlag( TIM1_FLAG_UPDATE);
TIM1_ITConfig( TIM1_IT_UPDATE, ENABLE);
TIM1_Cmd( ENABLE);
enableInterrupts();
//Основное тело программы, здесь мы управляем скоростью.
while(1){
if( !GPIO_ReadInputPin( GPIOD, GPIO_PIN_5)){ if( count_speed!=50){ count_speed--;} for( uint32_t i=0; i<400; i++);}
if( !GPIO_ReadInputPin( GPIOD, GPIO_PIN_4)){ if( count_speed!=2000){count_speed++;} for( uint32_t i=0; i<400; i++);}
}
return 0;
}
//Прерывание от переполнения счетчика TIM1 где все происходит, управление направлением вращения, скоростью и уходом в режим ожидания.
INTERRUPT_HANDLER(TIM1_UPD_OVF_TRG_BRK_IRQHandler, 11)
{
if( TIM1_GetFlagStatus( TIM1_FLAG_UPDATE)){
//Ждем пока не произойдет количество count_speed срабатывание прерываний.
if( count_speed_up> count_speed){
//Если нажата кнопка BT4 ротор крутится влево.
if( !GPIO_ReadInputPin( GPIOA, GPIO_PIN_3)){
fase1++; fase1&=7;
fase2++; fase2&=7;
fase3++; fase3&=7;
fase4++; fase4&=7;
count_wait=30000;
}
//Если нажата кнопка BT1 ротор крутится вправо.
if( !GPIO_ReadInputPin( GPIOD, GPIO_PIN_6)){
fase1--; fase1&=7;
fase2--; fase2&=7;
fase3--; fase3&=7;
fase4--; fase4&=7;
//Значение count_wait подберите экспериментальным путем.
count_wait=30000;
} count_speed_up=0;
}else{ count_speed_up++;}
//Если не было вращения после отсчета count_wait уходим в ожидание или продолжаем работать в обычном режиме.
if( count_wait==0){
TIM1_SetCompare1( step_pwm_wait[fase1]);
TIM1_SetCompare2( step_pwm_wait[fase2]);
TIM1_SetCompare3( step_pwm_wait[fase3]);
TIM1_SetCompare4( step_pwm_wait[fase4]);
}else{
TIM1_SetCompare1( step_pwm[fase1]);
TIM1_SetCompare2( step_pwm[fase2]);
TIM1_SetCompare3( step_pwm[fase3]);
TIM1_SetCompare4( step_pwm[fase4]);
count_wait--;}
TIM1_ClearFlag( TIM1_FLAG_UPDATE);
}
}
#ifdef USE_FULL_ASSERT
void assert_failed( uint8_t* file, uint32_t line)
{
while (1){}
}
#endif


 И конечно пример для ЧПУшников, использование для управление ШД сигналов STEP( шаг) и DIR( направление), тут для управления мы будем использовать прерывание от внешнего источника EXTI_PORT_GPIOA.
 Все действие будет происходить следующим образом, приходит сигнал STEP возникает спад с высокого на низкий уровень на выводе 3 GPIOA программа уходит в прерывание где мы проверяем происхождение прерывания от помехи или сигнала, если сигнала то проверяем вывод 6 GPIOD на нем должен быть выставлен сигнал направления вращения в зависимости которого мы прибавляем или отнимаем от fase1-fase4( расположение сигнала для каждой обмотки в массиве), если прерывание сработала от помехи то просто выходим из обработчика. Режим удержания контролируется теперь в основном теле программы, максимальное значение счетчика ожидания count_wait устанавливается в прерывании от STEP.

#include "stm8s.h"
//Рабочий массив.
uint16_t step_pwm[8]={ 0,0,0,0,283,400,283,0};
//Массив для режима ожидания.
uint16_t step_pwm_wait[8]={ 0,0,0,0,71,100,71,0};
//Положение в массиве нужного импульса для ШИМ.
uint8_t fase1=0;
uint8_t fase2=2;
uint8_t fase3=4;
uint8_t fase4=6;
//Счетчик для ухода в режим ожидания.
uint16_t count_wait=0;

int main( void )
{
CLK_HSIPrescalerConfig( CLK_PRESCALER_HSIDIV1);
//Настраиваем GPIOD вывод 6 как вход для DIR( направление).
GPIO_Init( GPIOD, GPIO_PIN_6, GPIO_MODE_IN_PU_NO_IT);
//Настраиваем GPIOA вывод 3 как вход с прерывание для STEP( шаг).
GPIO_Init( GPIOA, GPIO_PIN_3, GPIO_MODE_IN_PU_IT);
//Подключаем GPIOA к внешним прерыванием.
EXTI_SetExtIntSensitivity( EXTI_PORT_GPIOA, EXTI_SENSITIVITY_FALL_ONLY);
enableInterrupts();
//Настройка выводов для TIM1 и его самого.
GPIO_Init( GPIOC, GPIO_PIN_3, GPIO_MODE_OUT_PP_LOW_FAST);//C TIM1_CH3
GPIO_Init( GPIOC, GPIO_PIN_4, GPIO_MODE_OUT_PP_LOW_FAST);//D TIM1_CH4
GPIO_Init( GPIOC, GPIO_PIN_6, GPIO_MODE_OUT_PP_LOW_FAST);//A TIM1_CH1
GPIO_Init( GPIOC, GPIO_PIN_7, GPIO_MODE_OUT_PP_LOW_FAST);//B TIM1_CH2
TIM1_TimeBaseInit( 0, TIM1_COUNTERMODE_UP, 400, 0);
TIM1_OC1Init( TIM1_OCMODE_PWM1, TIM1_OUTPUTSTATE_ENABLE, TIM1_OUTPUTNSTATE_DISABLE, 0, TIM1_OCPOLARITY_HIGH, TIM1_OCNPOLARITY_HIGH, TIM1_OCIDLESTATE_RESET, TIM1_OCNIDLESTATE_RESET);
TIM1_OC2Init( TIM1_OCMODE_PWM1, TIM1_OUTPUTSTATE_ENABLE, TIM1_OUTPUTNSTATE_DISABLE, 0, TIM1_OCPOLARITY_HIGH, TIM1_OCNPOLARITY_HIGH, TIM1_OCIDLESTATE_RESET, TIM1_OCNIDLESTATE_RESET);
TIM1_OC3Init( TIM1_OCMODE_PWM1, TIM1_OUTPUTSTATE_ENABLE, TIM1_OUTPUTNSTATE_DISABLE, 0, TIM1_OCPOLARITY_HIGH, TIM1_OCNPOLARITY_HIGH, TIM1_OCIDLESTATE_RESET, TIM1_OCNIDLESTATE_RESET);
TIM1_OC4Init( TIM1_OCMODE_PWM1, TIM1_OUTPUTSTATE_ENABLE, 0, TIM1_OCPOLARITY_HIGH, TIM1_OCIDLESTATE_RESET);
TIM1_ARRPreloadConfig( ENABLE);
TIM1_OC1PreloadConfig( ENABLE);
TIM1_OC2PreloadConfig( ENABLE);
TIM1_OC3PreloadConfig( ENABLE);
TIM1_OC4PreloadConfig( ENABLE);
TIM1_CtrlPWMOutputs( ENABLE);
TIM1_Cmd( ENABLE);
while(1){
//Ожидаем обнуление счетчика ожидания если случилось уходим в режим удержания.
if( count_wait==0){
TIM1_SetCompare1( step_pwm_wait[fase1]);
TIM1_SetCompare2( step_pwm_wait[fase2]);
TIM1_SetCompare3( step_pwm_wait[fase3]);
TIM1_SetCompare4( step_pwm_wait[fase4]);
}else{count_wait--;}
for( uint32_t i=0; i<1000; i++);
}
return 0;
}
INTERRUPT_HANDLER(EXTI_PORTA_IRQHandler, 3)
{
//Защита от помех, проверка 4 раза GPIOA вывод 3.
if( !GPIO_ReadInputPin( GPIOA, GPIO_PIN_3)){
if( !GPIO_ReadInputPin( GPIOA, GPIO_PIN_3)){
if( !GPIO_ReadInputPin( GPIOA, GPIO_PIN_3)){
if( !GPIO_ReadInputPin( GPIOA, GPIO_PIN_3)){
//Если не помеха то вращаем ротор в зависимости от состояния GPIOD вывода 6.
if( !GPIO_ReadInputPin( GPIOD, GPIO_PIN_6)){
fase1++; fase1&=7;
fase2++; fase2&=7;
fase3++; fase3&=7;
fase4++; fase4&=7;
}else{
fase1--; fase1&=7;
fase2--; fase2&=7;
fase3--; fase3&=7;
fase4--; fase4&=7;
}
TIM1_SetCompare1( step_pwm[fase1]);
TIM1_SetCompare2( step_pwm[fase2]);
TIM1_SetCompare3( step_pwm[fase3]);
TIM1_SetCompare4( step_pwm[fase4]);
//Значение count_wait подберите экспериментальным путем.
count_wait=100;
}
}
}
}
}
#ifdef USE_FULL_ASSERT
void assert_failed( uint8_t* file, uint32_t line)
{
while (1){}
}
#endif

 Теперь после всего прочитанного вы скажете а как же реализация дробление шага, весь фокус заключается в деление угла 90 на нужное количество дробления, например как у меня в примере 1/2 значит делить тоже нужно на два получается 90/2=45 это угол одного шага, далее просто высчитываем через SIN сколько это будет от периода TIM1, два прибавления и два отнимания по 45.
Пример вычисления дробления 1/2 период 400.
 первый результат прибавляем sin( 0+45)*400=283
 второй результат прибавляем sin( 45+45)*400=400
 третий результат отнимаем sin( 90-45)*400=283
 четвертый результат отнимаем sin( 45-45)*400=0
Длина массива будет 4 умноженное на количество дробления итог 8, результат наших вычислений может располагаться в любом месте массива но последовательность менять нельзя.
Пример вычисления дробления 1/4 период 400, угол шага 90/4=22.5.
 первый результат прибавляем sin( 0+22.5)*400=153
 второй результат прибавляем sin( 22.5+22.5)*400=283
 третий результат прибавляем sin( 45+22.5)*400=370
 четвертый результат прибавляем sin( 67.5+22.5)*400=400
 пятый результат отнимаем sin( 90-22.5)*400=370
 шестой результат отнимаем sin( 67.5-22.5)*400=283
 седьмой результат отнимаем sin( 45-22.5)*400=153
 восьмой результат отнимаем sin( 22.5-22.5)*400=0
Длина массива 4*4=16

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

Статья №28 Дата:24/09/2018

Комментарии.