本篇博文最后修改时间:2017年02月12日,13:59。
一、简介
本文介绍如何使用STM32通过DRV8834控制步进电机,使用PWM方式控制转动。
二、实验平台
库版本:STM32F10x_StdPeriph_Lib_V3.5.0
编译软件:MDK4.53
硬件平台:STM32开发板(主芯片stm32f103c8t6)
仿真器:JLINK
三、版权声明
博主:甜甜的大香瓜
声明:喝水不忘挖井人,转载请注明出处。
原文地址:http://blog.csdn.NET/feilusia
联系方式:[email protected]
香瓜BLE之CC2541群:127442605
香瓜BLE之CC2640群:557278427
香瓜BLE之Android群:541462902
2)《STM32之timer2的精准延时》:http://blog.csdn.net/feilusia/article/details/54434274
3)《STM32之timer3产生PWM》:http://blog.csdn.net/feilusia/article/details/53634882
五、基础知识
暂无六、实验步骤
1、编写并添加电机驱动
1)编写驱动GUA_DRV8834.c(存放在“……\HARDWARE”)
//******************************************************************************
//name: GUA_DRV8834.c
//introduce: DRV8834驱动
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2017.02.12
//******************************************************************************
#include "stm32f10x.h"
#include "GUA_DRV8834.h"
#include "GUA_SysTick.h"
#include "GUA_Timer3_PWM.h"
#include "GUA_Timer2.h"
/*********************宏定义************************/
#define GUA_DRV8834_STEP_PER_CIRCLE (GUA_32)(15331) //电机转动一圈的步数
//引脚宏定义
#define GUA_DRV8834_SLEEP GPIOA
#define GUA_DRV8834_SLEEP_PIN GPIO_Pin_7
#define GUA_DRV8834_M1 GPIOB
#define GUA_DRV8834_M1_PIN GPIO_Pin_10
#define GUA_DRV8834_M0 GPIOB
#define GUA_DRV8834_M0_PIN GPIO_Pin_11
#define GUA_DRV8834_DIR GPIOB
#define GUA_DRV8834_DIR_PIN GPIO_Pin_2
#define GUA_DRV8834_STEP GPIOB
#define GUA_DRV8834_STEP_PIN GPIO_Pin_0
//查询电机剩余时间的宏
#define GUA_CHECK_MOVE_RESIDUE_TIME_FLAG_ON 0
#define GUA_CHECK_MOVE_RESIDUE_TIME_FLAG_OFF 1
/*********************内部变量************************/
//初始化结构体变量
GUA_MOTOR_CONFIG stGUA_Motor_Config = {0, 500, 0x00, 0x00000000, GUA_MOTOR_CONFIG_STATUS_IDLE, 0x00000000}; //初始化电机参数为0步,500个脉冲每秒的速度,整步,本次电机转动时长为0,空闲,当前为0位置
//查询时间的标志
static GUA_U8 sGUA_CheckMoveResidueTime_Flag = GUA_CHECK_MOVE_RESIDUE_TIME_FLAG_OFF;
/*********************内部函数************************/
static void GUA_DRV8834_IO_Init(void);
static void GUA_DRV8834_Set_Direction(GUA_32 nGUA_Direction);
static void GUA_DRV8834_Set_Size(GUA_U8 nGUA_Size);
//******************************************************************************
//name: GUA_DRV8834_IO_Init
//introduce: 电机驱动的IO初始化
//parameter: none
//return: none
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2017.02.12
//******************************************************************************
static void GUA_DRV8834_IO_Init(void)
{
//IO结构体
GPIO_InitTypeDef GPIO_InitStructure;
//时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
//SLEEP配置
GPIO_InitStructure.GPIO_Pin = GUA_DRV8834_SLEEP_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GUA_DRV8834_SLEEP, &GPIO_InitStructure);
//M1配置
GPIO_InitStructure.GPIO_Pin = GUA_DRV8834_M1_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GUA_DRV8834_M1, &GPIO_InitStructure);
//M0配置
GPIO_InitStructure.GPIO_Pin = GUA_DRV8834_M0_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GUA_DRV8834_M0, &GPIO_InitStructure);
//DIR配置
GPIO_InitStructure.GPIO_Pin = GUA_DRV8834_DIR_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GUA_DRV8834_DIR, &GPIO_InitStructure);
//STEP配置
GPIO_InitStructure.GPIO_Pin = GUA_DRV8834_STEP_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GUA_DRV8834_STEP, &GPIO_InitStructure);
}
//******************************************************************************
//name: GUA_DRV8834_Control
//introduce: 电机的配置
//parameter: nGUA_DRV8834_control:需要配置的参数;nGUA_DRV8834_control_vaule:配置的数值
//return: none
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2017.02.12
//******************************************************************************
void GUA_DRV8834_Control(GUA_U8 nGUA_DRV8834_control, GUA_U8 nGUA_DRV8834_control_vaule)
{
switch(nGUA_DRV8834_control)
{
//睡眠模式选择
case GUA_DRV8834_CONTROL_SLEEP:
{
//睡眠
if(nGUA_DRV8834_control_vaule == GUA_DRV8834_CONTROL_SLEEP_ON)
{
GPIO_WriteBit(GUA_DRV8834_SLEEP, GUA_DRV8834_SLEEP_PIN, Bit_RESET); //SLEEP 0
}
//禁止睡眠
if(nGUA_DRV8834_control_vaule == GUA_DRV8834_CONTROL_SLEEP_OFF)
{
GPIO_WriteBit(GUA_DRV8834_SLEEP, GUA_DRV8834_SLEEP_PIN, Bit_SET); //SLEEP 1
}
break;
}
//步数选择
case GUA_DRV8834_CONTROL_MICROSTEP:
{
//满步(M1=0, M0=0)
if(nGUA_DRV8834_control_vaule == GUA_DRV8834_CONTROL_MICROSTEP_FULL)
{
GPIO_WriteBit(GUA_DRV8834_M1, GUA_DRV8834_M1_PIN, Bit_RESET); //M1 0
GPIO_WriteBit(GUA_DRV8834_M0, GUA_DRV8834_M0_PIN, Bit_RESET); //M0 0
}
//1/2步(M1=0, M0=1)
if(nGUA_DRV8834_control_vaule == GUA_DRV8834_CONTROL_MICROSTEP_1_2)
{
GPIO_WriteBit(GUA_DRV8834_M1, GUA_DRV8834_M1_PIN, Bit_RESET); //M1 0
GPIO_WriteBit(GUA_DRV8834_M0, GUA_DRV8834_M0_PIN, Bit_SET); //M0 1
}
/*
//1/4步(M1=0, M0=Z)
if(nGUA_DRV8834_control_vaule == GUA_DRV8834_CONTROL_MICROSTEP_1_4)
{
GPIO_WriteBit(GUA_DRV8834_M1, GUA_DRV8834_M1_PIN, Bit_RESET); //M1 0
GPIO_WriteBit(GUA_DRV8834_M0, GUA_DRV8834_M0_PIN, GPIO_MODE_OUT_OD_HIZ_FAST); //M0 Z
}
*/
//1/8步(M1=1, M0=0)
if(nGUA_DRV8834_control_vaule == GUA_DRV8834_CONTROL_MICROSTEP_1_8)
{
GPIO_WriteBit(GUA_DRV8834_M1, GUA_DRV8834_M1_PIN, Bit_SET); //M1 1
GPIO_WriteBit(GUA_DRV8834_M0, GUA_DRV8834_M0_PIN, Bit_RESET); //M0 0
}
//1/16步(M1=1, M0=1)
if(nGUA_DRV8834_control_vaule == GUA_DRV8834_CONTROL_MICROSTEP_1_16)
{
GPIO_WriteBit(GUA_DRV8834_M1, GUA_DRV8834_M1_PIN, Bit_SET); //M1 1
GPIO_WriteBit(GUA_DRV8834_M0, GUA_DRV8834_M0_PIN, Bit_SET); //M0 1
}
/*
//1/32步(M1=1, M0=Z)
if(nGUA_DRV8834_control_vaule == GUA_DRV8834_CONTROL_MICROSTEP_1_32)
{
GPIO_WriteBit(GUA_DRV8834_M1, GUA_DRV8834_M1_PIN, Bit_SET); //M1 1
GPIO_WriteBit(GUA_DRV8834_M0, GUA_DRV8834_M0_PIN, GPIO_MODE_OUT_OD_HIZ_FAST); //M0 Z
}
*/
break;
}
//方向选择
case GUA_DRV8834_CONTROL_DIR:
{
//正向
if(nGUA_DRV8834_control_vaule == GUA_DRV8834_CONTROL_DIR_POSITIVE)
{
GPIO_WriteBit(GUA_DRV8834_DIR, GUA_DRV8834_DIR_PIN, Bit_SET);
}
//反向
if(nGUA_DRV8834_control_vaule == GUA_DRV8834_CONTROL_DIR_NEGATIVE)
{
GPIO_WriteBit(GUA_DRV8834_DIR, GUA_DRV8834_DIR_PIN, Bit_RESET);
}
break;
}
//其他
default:
{
break;
}
}
}
//******************************************************************************
//name: GUA_DRV8834_Set_Direction
//introduce: 电机的方向设置
//parameter: nGUA_Direction:1为正向,0为反向
//return: none
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2017.02.12
//******************************************************************************
static void GUA_DRV8834_Set_Direction(GUA_32 nGUA_Direction)
{
//方向
switch(nGUA_Direction)
{
//电机转轴朝上,逆时针,反向
case GUA_MOTOR_CONFIG_DIRECTION_NEGATIVE:
{
GUA_DRV8834_Control(GUA_DRV8834_CONTROL_DIR, GUA_DRV8834_CONTROL_DIR_NEGATIVE);
break;
}
//电机转轴朝上,顺时针,正向
case GUA_MOTOR_CONFIG_DIRECTION_POSITIVE:
{
GUA_DRV8834_Control(GUA_DRV8834_CONTROL_DIR, GUA_DRV8834_CONTROL_DIR_POSITIVE);
break;
}
//其他
default:
{
break;
}
}
}
//******************************************************************************
//name: GUA_DRV8834_Set_Size
//introduce: 电机的步长设置
//parameter: nSize:0为整步,1为半步
//return: none
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2017.02.12
//******************************************************************************
static void GUA_DRV8834_Set_Size(GUA_U8 nGUA_Size)
{
//步长大小
switch(nGUA_Size)
{
//整步
case GUA_MOTOR_CONFIG_SIZE_FULL:
{
GUA_DRV8834_Control(GUA_DRV8834_CONTROL_MICROSTEP, GUA_DRV8834_CONTROL_MICROSTEP_FULL);
break;
}
//半步
case GUA_MOTOR_CONFIG_SIZE_1_2:
{
GUA_DRV8834_Control(GUA_DRV8834_CONTROL_MICROSTEP, GUA_DRV8834_CONTROL_MICROSTEP_1_2);
break;
}
//其他
default:
{
break;
}
}
}
//******************************************************************************
//name: GUA_DRV8834_Move
//introduce: 电机的启动
//parameter: pMotor_Config:电机核心参数结构体数据
//return: none
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2017.02.12
//******************************************************************************
void GUA_DRV8834_Move(GUA_MOTOR_CONFIG *pGUA_Motor_Config)
{
GUA_32 nGUA_Steps = pGUA_Motor_Config->DirectionSteps; //保存步数
GUA_32 nGUA_Direction = (nGUA_Steps >= 0)?1:-1; //计算方向
GUA_U8 nGUA_Size = pGUA_Motor_Config->Size; //保存步长
GUA_U16 nGUA_PWM_Frequency = pGUA_Motor_Config->PulsePerSecond; //PWM需要的频率值
GUA_U64 nGUA_PWM_Time = (1000L/pGUA_Motor_Config->PulsePerSecond)*(nGUA_Steps*nGUA_Direction); //PWM执行时间=周期*步数
//如果电机开关没开启,则退出
if(pGUA_Motor_Config->Status == GUA_MOTOR_CONFIG_STATUS_IDLE)
{
return;
}
//唤醒
GUA_DRV8834_Control(GUA_DRV8834_CONTROL_SLEEP, GUA_DRV8834_CONTROL_SLEEP_OFF);
//设置方向
GUA_DRV8834_Set_Direction(nGUA_Direction);
//设置步长
GUA_DRV8834_Set_Size(nGUA_Size);
//电机转动
GUA_Timer2_StartDelayMs_1(nGUA_PWM_Time); //开始定时
GUA_Timer3_PWM_Init(1000000/nGUA_PWM_Frequency); //设置PWM频率
GUA_Timer3_PWM_SetDutyCycle(50); //设置PWM占空比
GUA_Timer3_PWM_Status(GUA_TIMER3_PWM_STATUS_ON); //使能PWM
//打查询时间的标志
sGUA_CheckMoveResidueTime_Flag = GUA_CHECK_MOVE_RESIDUE_TIME_FLAG_ON;
}
//******************************************************************************
//name: GUA_DRV8834_CheckMoveResidueTime
//introduce: 获取电机运行剩余时间
//parameter: none
//return: GUA_CHECK_MOVE_RESIDUE_TIME_RESULT_NOSTART
// GUA_CHECK_MOVE_RESIDUE_TIME_RESULT_ENDING
// GUA_CHECK_MOVE_RESIDUE_TIME_RESULT_RUNNING
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2017.02.12
//******************************************************************************
GUA_U8 GUA_DRV8834_CheckMoveResidueTime(void)
{
//没开电机
if(sGUA_CheckMoveResidueTime_Flag == GUA_CHECK_MOVE_RESIDUE_TIME_FLAG_OFF)
{
return GUA_CHECK_MOVE_RESIDUE_TIME_RESULT_NOSTART;
}
//开了电机
else
{
//运行时间到了
if(GUA_Timer2_CheckDelayMs_1() == 0)
{
return GUA_CHECK_MOVE_RESIDUE_TIME_RESULT_ENDING;
}
//运行时间没到
{
return GUA_CHECK_MOVE_RESIDUE_TIME_RESULT_RUNNING;
}
}
}
//******************************************************************************
//name: GUA_DRV8834_Stop
//introduce: 电机的停止
//parameter: pGUA_Motor_Config:电机核心参数结构体数据
//return: none
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2017.02.12
//******************************************************************************
void GUA_DRV8834_Stop(GUA_MOTOR_CONFIG *pGUA_Motor_Config)
{
GUA_32 nGUA_Steps = pGUA_Motor_Config->DirectionSteps; //保存步数
GUA_32 nGUA_Direction = (nGUA_Steps >= 0)?1:-1; //计算方向
GUA_U64 nGUA_PWM_Time = (1000L/pGUA_Motor_Config->PulsePerSecond)*(nGUA_Steps*nGUA_Direction); //PWM执行时间=周期*步数
GUA_32 nGUA_StepsElapse; //实际走的步数
//停止PWM
GUA_Timer3_PWM_Status(GUA_TIMER3_PWM_STATUS_OFF);
//清除状态
pGUA_Motor_Config->Status = GUA_MOTOR_CONFIG_STATUS_IDLE;
//睡眠
GUA_DRV8834_Control(GUA_DRV8834_CONTROL_SLEEP, GUA_DRV8834_CONTROL_SLEEP_ON);
//计算实际运行时间
pGUA_Motor_Config->TimeElapse = nGUA_PWM_Time - GUA_Timer2_CheckDelayMs_1();
//计算实际走的步数
nGUA_StepsElapse = (pGUA_Motor_Config->TimeElapse)/(1000L/pGUA_Motor_Config->PulsePerSecond);
//计算实际位移
pGUA_Motor_Config->DirectionPosition += nGUA_StepsElapse;
//打查询时间的标志
sGUA_CheckMoveResidueTime_Flag = GUA_CHECK_MOVE_RESIDUE_TIME_FLAG_OFF;
}
//******************************************************************************
//name: GUA_DRV8834_Init
//introduce: 电机的初始化
//parameter: none
//return: none
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2017.02.12
//******************************************************************************
void GUA_DRV8834_Init(void)
{
//IO初始化
GUA_DRV8834_IO_Init();
//睡眠
GUA_DRV8834_Control(GUA_DRV8834_CONTROL_SLEEP, GUA_DRV8834_CONTROL_SLEEP_ON);
//nENBL使能
GUA_DRV8834_Control(GUA_DRV8834_CONTROL_OUTPUTS, GUA_DRV8834_CONTROL_OUTPUTS_ENABLE);
}
//******************************************************************************
//name: GUA_DRV8834.h
//introduce: DRV8834驱动头文件
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2017.02.12
//******************************************************************************
#ifndef _GUA_DRV8834_H_
#define _GUA_DRV8834_H_
/*********************宏定义************************/
//类型宏
#ifndef GUA_U8
typedef unsigned char GUA_U8;
#endif
#ifndef GUA_8
typedef signed char GUA_8;
#endif
#ifndef GUA_U16
typedef unsigned short GUA_U16;
#endif
#ifndef GUA_16
typedef signed short GUA_16;
#endif
#ifndef GUA_U32
typedef unsigned long GUA_U32;
#endif
#ifndef GUA_32
typedef signed long GUA_32;
#endif
#ifndef GUA_U64
typedef unsigned long long GUA_U64;
#endif
#ifndef GUA_64
typedef signed long long GUA_64;
#endif
//睡眠模式选择
#define GUA_DRV8834_CONTROL_SLEEP 0
#define GUA_DRV8834_CONTROL_SLEEP_ON 0
#define GUA_DRV8834_CONTROL_SLEEP_OFF 1
//步数选择
#define GUA_DRV8834_CONTROL_MICROSTEP 1
#define GUA_DRV8834_CONTROL_MICROSTEP_FULL 0
#define GUA_DRV8834_CONTROL_MICROSTEP_1_2 1
#define GUA_DRV8834_CONTROL_MICROSTEP_1_4 2
#define GUA_DRV8834_CONTROL_MICROSTEP_1_8 3
#define GUA_DRV8834_CONTROL_MICROSTEP_1_16 4
#define GUA_DRV8834_CONTROL_MICROSTEP_1_32 5
//方向选择
#define GUA_DRV8834_CONTROL_DIR 2
#define GUA_DRV8834_CONTROL_DIR_POSITIVE 0
#define GUA_DRV8834_CONTROL_DIR_NEGATIVE 1
//输出选择
#define GUA_DRV8834_CONTROL_OUTPUTS 3
#define GUA_DRV8834_CONTROL_OUTPUTS_ENABLE 0
#define GUA_DRV8834_CONTROL_OUTPUTS_DISABLE 1
//电机参数的宏
#define GUA_MOTOR_CONFIG_DIRECTION_NEGATIVE -1
#define GUA_MOTOR_CONFIG_DIRECTION_POSITIVE 1
#define GUA_MOTOR_CONFIG_SIZE_FULL 0
#define GUA_MOTOR_CONFIG_SIZE_1_2 1
#define GUA_MOTOR_CONFIG_STATUS_IDLE 0
#define GUA_MOTOR_CONFIG_STATUS_ACTIVE 1
//查询电机剩余时间的结果宏
#define GUA_CHECK_MOVE_RESIDUE_TIME_RESULT_NOSTART 0
#define GUA_CHECK_MOVE_RESIDUE_TIME_RESULT_RUNNING 1
#define GUA_CHECK_MOVE_RESIDUE_TIME_RESULT_ENDING 2
/*********************外部变量************************/
typedef struct
{
GUA_32 DirectionSteps; //含方向的步数
GUA_U16 PulsePerSecond; //每秒给的脉冲数
GUA_U8 Size; //步长
GUA_U8 Status; //电机转动状态
GUA_32 DirectionPosition; //含方向的位置
GUA_U64 TimeElapse; //使用时间
}GUA_MOTOR_CONFIG;
extern GUA_MOTOR_CONFIG stGUA_Motor_Config;
/*********************函数声明************************/
void GUA_DRV8834_Control(GUA_U8 nGUA_DRV8834_control, GUA_U8 nGUA_DRV8834_control_vaule);
void GUA_DRV8834_Move(GUA_MOTOR_CONFIG *pGUA_Motor_Config);
GUA_U8 GUA_DRV8834_CheckMoveResidueTime(void);
void GUA_DRV8834_Stop(GUA_MOTOR_CONFIG *pGUA_Motor_Config);
void GUA_DRV8834_Init(void);
#endif
4)在MDK设置中添加驱动源文件路径
2、在应用层中调用
1)添加头文件(main.c中)
#include "GUA_DRV8834.h"
//电机初始化
GUA_DRV8834_Init();
①添加一个电机转一圈的测试代码(main.c中)
//******************************************************************************
//name: GUA_Test
//introduce: 测试代码
//parameter: none
//return: none
//author: 甜甜的大香瓜
//email: [email protected]
//QQ group 香瓜单片机之STM8/STM32(164311667)
//changetime: 2017.02.12
//******************************************************************************
#define GUA_DRV8834_STEP_PER_CIRCLE (GUA_U32)(15331) //电机转动一圈的步数
static void GUA_Test(void)
{
GUA_U8 nGUA_Ret = 0;
//配置电机参数
stGUA_Motor_Config.DirectionSteps = GUA_DRV8834_STEP_PER_CIRCLE; //步数,4字节
stGUA_Motor_Config.PulsePerSecond = 1000; //速度,2字节
stGUA_Motor_Config.Size = 0x00; //步长,1字节
stGUA_Motor_Config.Status = GUA_MOTOR_CONFIG_STATUS_ACTIVE; //电机启动,1字节
//启动电机
GUA_DRV8834_Move(&stGUA_Motor_Config);
//时刻查询电机运行时间,到时则停止
while(1)
{
nGUA_Ret = GUA_DRV8834_CheckMoveResidueTime();
if(nGUA_Ret == GUA_CHECK_MOVE_RESIDUE_TIME_RESULT_ENDING)
{
GUA_DRV8834_Stop(&stGUA_Motor_Config);
}
}
}
由于我使用的电机除了电机自带的减速,还有外壳上的减速,因此一圈为15331步。
②添加测试代码的调用(main.c的main函数中)
//测试代码
GUA_Test();
测试代码要放在初始化之后。
仿真并设置断点在测试代码处,可发现电机转动至停止一共约15S多,这是因为一圈为15331步,速度设置为1000步每秒,计算可得约为15.331S。
因此实验成功。