利用STM32的普通GPIO引腳驅(qū)動步進(jìn)電機(jī)實現(xiàn)逐級加減速--代碼分享

? ? ? ?步進(jìn)電機(jī)是一種將電脈沖信號轉(zhuǎn)換成相應(yīng)角位移或線位移的電動機(jī)。每輸入一個脈沖信號,轉(zhuǎn)子就轉(zhuǎn)動一個角度或前進(jìn)一步,其輸出的角位移或線位移與輸入的脈沖數(shù)成正比,轉(zhuǎn)速與脈沖頻率成正比。
? ? ??

? ? ? ? 脈沖波是指一種間斷的持續(xù)時間極短的突然發(fā)生的電信號。凡是斷續(xù)出現(xiàn)的電壓或電流稱為脈沖電壓或脈沖電流。電信波形來說除了正弦波和由若個正弦分量合成的連續(xù)波以外,都可以稱為脈沖波。

? ? ? 步進(jìn)電機(jī)的控制方法有很多,不同的應(yīng)用場景和使用不同的驅(qū)動設(shè)備所使用的控制方法也有些差異,本例使用的是基于THB6064MQ集成芯片的驅(qū)動模塊驅(qū)動兩相四線的42步進(jìn)電機(jī)。

? ? ? ?控制芯片是基于STM32F103C8T6的32位MCU,使用普通IO口的電平反轉(zhuǎn)來輸出脈沖驅(qū)動步進(jìn)電機(jī)運轉(zhuǎn)的,方法略顯暴力@~@用來作步進(jìn)電機(jī)驅(qū)動效果的演示,請大家共同探討,批評指正,共同學(xué)習(xí)。
#ifndef __MAIN_DEFINE_H__
#define __MAIN_DEFINE_H__
/* 宏定義 --------------------------------------------------------------------*/
#define subdivide 1 //驅(qū)動器細(xì)分?jǐn)?shù)
/*速度標(biāo)稱值:脈沖換向一次所需的循環(huán)數(shù),*/
#define HAL_RCC_count 100000 //滴答定時器中斷1us中斷一次
#define FSPR? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 200// 步進(jìn)電機(jī)單圈步數(shù)? 步距角:1.8° 360/1.8 = 200 正常情況下需要200步轉(zhuǎn)一圈
#define MICRO_STEP? ? ? ? ? ? ? ? ? ? ? ? ? ? 1 // 步進(jìn)電機(jī)驅(qū)動器細(xì)分?jǐn)?shù)
#define SPR? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(FSPR*MICRO_STEP)? ?// 旋轉(zhuǎn)一圈需要的脈沖數(shù)
//轉(zhuǎn)速(轉(zhuǎn)/分鐘)S = S1(轉(zhuǎn)/秒)* 60 = S2 (脈沖/秒)
#define speed_max 1050 //(轉(zhuǎn)/分鐘)
#define speed_1 450 //(轉(zhuǎn)/分鐘)
#define speed_2 750 //(轉(zhuǎn)/分鐘)
#define speed_min 160 //(轉(zhuǎn)/分鐘)
#define Uniform_s? 10? //勻速運動持續(xù)時間(秒)
//#define speed_max_pulse ( speed_max / 60 ) * SPR? //每秒脈沖數(shù)
#define yunsu_count? Uniform_s *? HAL_RCC_count? //勻速運轉(zhuǎn)持續(xù)的循環(huán)數(shù)(與時間相關(guān))
#define biansu_count? 10000 //每個速度持續(xù)的循環(huán)數(shù)(與加減速率相關(guān))進(jìn)過這么多個循環(huán)數(shù)后加一次速度或減速一次
#endif? // __MAIN_DEFINE_H__
//
#ifndef __StepMotor_H__
#define __StepMotor_H__
/* 包含頭文件 ----------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/* 類型定義 ------------------------------------------------------------------*/
typedef enum
{
? StepMotor_Low = 0,? ?//低電平
? StepMotor_High? = 1, //高電平
}StepMotor_State_TypeDef;
#define IS_StepMotor_STATE(STATE)? ? ? ? ? ?(((STATE) == StepMotor_Low) || ((STATE) == StepMotor_High) || ((STATE) == StepMotor_TOGGLE))
/* 宏定義 --------------------------------------------------------------------*/
//PA3定義對應(yīng)測試版上的步進(jìn)電機(jī)R軸的PUL接口
#define StepMotor_RCC_CLK_ENABLE()? ? ? ? ?__HAL_RCC_GPIOA_CLK_ENABLE()
#define StepMotor_GPIO_PIN? ? ? ? ? ? ? ? ?GPIO_PIN_3
#define StepMotor_GPIO? ? ? ? ? ? ? ? ? ? ?GPIOA
#define StepMotor_HIGH? ? ? ? ? ? ? ? ? ? ?HAL_GPIO_WritePin(StepMotor_GPIO,StepMotor_GPIO_PIN,GPIO_PIN_SET)? ? // 輸出高電平
#define StepMotor_LOW? ? ? ? ? ? ? ? ? ? ? HAL_GPIO_WritePin(StepMotor_GPIO,StepMotor_GPIO_PIN,GPIO_PIN_RESET)? // 輸出低電平
#define StepMotor_TOGGLE? ? ? ? ? ? ? ? ? ?HAL_GPIO_TogglePin(StepMotor_GPIO,StepMotor_GPIO_PIN)? ? ? ? ? ? ? ? // 輸出反轉(zhuǎn)
/* 擴(kuò)展變量 ------------------------------------------------------------------*/
/* 函數(shù)聲明 ------------------------------------------------------------------*/
void main_StepMorot(void);//步進(jìn)電機(jī)驅(qū)動相關(guān)初始化程序
void while_StepMotor(void);//步進(jìn)電機(jī)驅(qū)動單循環(huán)子程序
/******************************************************************************/
/**
? ******************************************************************************
? * 文件名程: StepMotor.c?
? * 作? ? 者: 老白
? * 版? ? 本: V1.0
? * 編寫日期: 2020-12-30
? * 功? ? 能: 驅(qū)動步進(jìn)電機(jī)
? ******************************************************************************
? * 說明:簡單驅(qū)動步進(jìn)電機(jī)之一:在主循環(huán)中交替GPIO輸出高低電平方法驅(qū)動步進(jìn)電機(jī)
? *?
? ******************************************************************************
? */
/* 包含頭文件 ----------------------------------------------------------------*/
#include "StepMotor.h"
#include "main_define.h"
/* 私有類型定義 --------------------------------------------------------------*/
/* 私有宏定義 ----------------------------------------------------------------*/
/* 私有變量 ------------------------------------------------------------------*/
/* 擴(kuò)展變量 ------------------------------------------------------------------*/
/* 私有函數(shù)原形 --------------------------------------------------------------*/
/* 函數(shù)體 --------------------------------------------------------------------*/
/**
? * 函數(shù)功能: 步進(jìn)電機(jī)IO引腳初始化.
? * 輸入?yún)?shù): 無
? * 返 回 值: 無
? * 說? ? 明:使用宏定義方法代替具體引腳號,方便程序移植,只要簡單修改led.h
? *? ? ? ? ? ?文件相關(guān)宏定義就可以方便修改引腳。
? */
void StepMotor_GPIO_Init(void)
{
? ?/* 定義IO硬件初始化結(jié)構(gòu)體變量 */
? GPIO_InitTypeDef GPIO_InitStruct;
/* 使能(開啟)LED引腳對應(yīng)IO端口時鐘 */??
? StepMotor_RCC_CLK_ENABLE();
??
? /* 配置StepMotor引腳輸出電壓 */
? HAL_GPIO_WritePin(StepMotor_GPIO, StepMotor_GPIO_PIN, GPIO_PIN_RESET);
? /* 設(shè)定StepMotor對應(yīng)引腳IO編號 */
? GPIO_InitStruct.Pin = StepMotor_GPIO_PIN;
? /* 設(shè)定StepMotor對應(yīng)引腳IO為輸出模式 */
? GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
? /* 設(shè)定StepMotor對應(yīng)引腳IO操作速度 */
? GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
? /* 初始化StepMotor對應(yīng)引腳IO */
? HAL_GPIO_Init(StepMotor_GPIO, &GPIO_InitStruct);
??
?}
//步進(jìn)電機(jī)驅(qū)動相關(guān)初始化程序
?void main_StepMorot(void)
{
? StepMotor_GPIO_Init();//步進(jìn)電機(jī)IO引腳初始化
}
//定義步進(jìn)電機(jī)單循環(huán)循環(huán)數(shù)變量
uint8_t count=0;//定義步進(jìn)電機(jī)單循環(huán)循環(huán)數(shù)變量
uint8_t s_index = HAL_RCC_count / ( ( speed_min / 60 ) * SPR? )? ; //電機(jī)的加速循環(huán)計數(shù)
uint8_t jieduan_bz = 0 ;//0 加速階段? ?1? 高速勻速階段? ?2 減速階段? 3 低速勻速階段
uint32_t yunsu_index = 0 ;? ? ? ? //勻速運轉(zhuǎn)持續(xù)的循環(huán)計數(shù)(與時間相關(guān))
uint32_t biansu_index = 0 ;//每個速度持續(xù)的循環(huán)數(shù)計數(shù)值
//步進(jìn)電機(jī)驅(qū)動單循環(huán)子程序
void while_StepMotor(void)
{
?
? ? if( count > s_index )
? ? { StepMotor_TOGGLE ; count = 0 ;}
? ? else { count++ ;}
//以下代碼與加減速有關(guān)
if ( jieduan_bz? == 0? )//加速階段
{
if( s_index > HAL_RCC_count / ( ( speed_1 / 60 ) * SPR? ) )? //電機(jī)單脈沖需要的循環(huán)數(shù)遞減(電機(jī)加速)
{??
if ( biansu_index >= biansu_count ){ s_index-- ; biansu_index = 0 ; }//加速一次
else { biansu_index++; }
}
else?
{
jieduan_bz = 1 ;//當(dāng)速度到最大的時候變?yōu)楦咚賱蛩匐A段
s_index = HAL_RCC_count / ( ( speed_1 / 60 ) * SPR? ) ; //以第一速度勻速運行
? yunsu_index = 0 ;
}
}
if ( jieduan_bz? == 1? )//勻速階段1
? ? {
? if ( yunsu_index > yunsu_count ){ jieduan_bz? = 2;yunsu_index = 0 ; }
? else { yunsu_index++; }
}
if ( jieduan_bz? == 2? )//加速階段
{
if( s_index > HAL_RCC_count / ( ( speed_2 / 60 ) * SPR? ) )? //電機(jī)單脈沖需要的循環(huán)數(shù)遞減(電機(jī)加速)
{??
if ( biansu_index >= biansu_count ){ s_index-- ; biansu_index = 0 ; }//加速一次
else { biansu_index++; }
}
else?
{
jieduan_bz = 3 ;//當(dāng)速度到最大的時候變?yōu)楦咚賱蛩匐A段
s_index = HAL_RCC_count / ( ( speed_2 / 60 ) * SPR? ) ; //以第一速度勻速運行
? ? ? ? ? ?yunsu_index = 0 ;
}
}
if ( jieduan_bz? == 3? )//勻速階段2
? ? {
? if ( yunsu_index > yunsu_count ){ jieduan_bz? = 4;yunsu_index = 0 ; }
? else { yunsu_index++; }
}
if ( jieduan_bz? == 4? )//加速階段
{
if( s_index > HAL_RCC_count / ( ( speed_max / 60 ) * SPR? ) )? //電機(jī)單脈沖需要的循環(huán)數(shù)遞減(電機(jī)加速)
{??
if ( biansu_index >= biansu_count ){ s_index-- ; biansu_index = 0 ; }//加速一次
else { biansu_index++; }
}
else?
{
jieduan_bz = 5 ;//當(dāng)速度到最大的時候變?yōu)楦咚賱蛩匐A段
s_index = HAL_RCC_count / ( ( speed_max / 60 ) * SPR? ) ; //以第一速度勻速運行
}
}
if ( jieduan_bz? == 5? )//勻速階段3
? ? {
? if ( yunsu_index > yunsu_count ){ jieduan_bz? = 6;yunsu_index = 0 ; }
? else { yunsu_index++; }
}
if ( jieduan_bz? == 6? )//減速階段
{
if( s_index < HAL_RCC_count / ( ( speed_min / 60 ) * SPR? )? )? //電機(jī)單脈沖需要的循環(huán)數(shù)遞減(電機(jī)減速)
{??
if ( biansu_index >= biansu_count ){ s_index++ ; biansu_index = 0 ; }//減速一次
else { biansu_index++; }
}
else?
{
jieduan_bz = 7 ;//當(dāng)速度到最小的時候變?yōu)楦咚賱蛩匐A段
s_index = HAL_RCC_count / ( ( speed_min / 60 ) * SPR? )? ; //以第一速度勻速運行
}
}
if ( jieduan_bz? == 7? )//勻速階段4
? ? {
? if ( yunsu_index > yunsu_count ){ jieduan_bz? = 0;yunsu_index = 0 ; }
? else { yunsu_index++; }
}
}
??
/**
? * 函數(shù)功能: 系統(tǒng)滴答定時器中斷回調(diào)函數(shù)
? * 輸入?yún)?shù): 無
? * 返 回 值: 無
? * 說? ? 明: 每發(fā)生一次滴答定時器中斷進(jìn)入該回調(diào)函數(shù)一次
? */
void HAL_SYSTICK_Callback(void)
{
? ? while_StepMotor();
}
/*******************老白學(xué)習(xí)小組**********************************/
/**
? ******************************************************************************
? * 文件名程: main.c?
? * 作? ? 者: 老白嵌入式學(xué)習(xí)小組
? * 版? ? 本: V1.0
? * 編寫日期: 2021-01-04
? * 功? ? 能: 使用HAL庫方法控制LED燈亮滅實現(xiàn)流水燈效果
? ******************************************************************************
? */
/* 包含頭文件 ----------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
#include "StepMotor.h"
#include "main_define.h"

/* 私有函數(shù)原形 --------------------------------------------------------------*/
void SystemClock_Config(void);
/* 函數(shù)體 --------------------------------------------------------------------*/
/**
? * 函數(shù)功能: 主函數(shù).
? * 輸入?yún)?shù): 無
? * 返 回 值: 無
? * 說? ? 明: 無
? */
int main(void)
{??
? /* 復(fù)位所有外設(shè),初始化Flash接口和系統(tǒng)滴答定時器 */
? HAL_Init();
? /* 配置系統(tǒng)時鐘 */
? SystemClock_Config();
??
?
main_StepMorot();//步進(jìn)電機(jī)驅(qū)動相關(guān)初始化程序
??
? /* 無限循環(huán) */
? while (1)? {? }
}
/**
? * 函數(shù)功能: 系統(tǒng)時鐘配置
? * 輸入?yún)?shù): 無
? * 返 回 值: 無
? * 說? ? 明: 無
? */
void SystemClock_Config(void)
{
? RCC_OscInitTypeDef RCC_OscInitStruct;
? RCC_ClkInitTypeDef RCC_ClkInitStruct;
? RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;? // 外部晶振,8MHz
? RCC_OscInitStruct.HSEState = RCC_HSE_ON;
? RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
? RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
? RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
? RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;? // 9倍頻,得到72MHz主時鐘
? HAL_RCC_OscConfig(&RCC_OscInitStruct);
? RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
? RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;? ? ? ?// 系統(tǒng)時鐘:72MHz
? RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;? ? ? ? ? ? ? // AHB時鐘:72MHz
? RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;? ? ? ? ? ? ? ?// APB1時鐘:36MHz
? RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;? ? ? ? ? ? ? ?// APB2時鐘:72MHz
? HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
? HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/HAL_RCC_count);? // 配置并啟動系統(tǒng)滴答定時器
? /* 系統(tǒng)滴答定時器時鐘源 */
? HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
? /* 系統(tǒng)滴答定時器中斷優(yōu)先級配置 */
? HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/*******************老白學(xué)習(xí)小組**********************************/
