一、特点:
·功能:PWM电机驱动 最高32细分
·具有多种衰减模式:混合衰减 低速衰减 快速衰减
·操作电压 8.2V-45V
·最大2.5A 驱动电流 (24V,25°C)
·简单的 步数/方向 交互
·小电流睡眠模式
·内建3.3V参考电压
·小封装
·安全模式: 过流保护 热关机 欠压锁定 故障指示引脚 nFUAULT
安全说明:内部关闭功能用于过流,短路,欠压锁定和过热
内部引脚说明:
CAP1/CAP2 :两端间连0.01uF/50V电容
VCP:并联 0.1uF /16V 陶瓷电容 和1M电阻 至VM端
VMA,VMB 连接至绕组端, 两端必须是同样的端电压, 连接一个0.1uf的高频滤波电容,和一个大容量电容
V3P3OUT: 连接一个 0.47uF/6,3V陶瓷电容 用来做VREF的支撑电压。
AVREF/BVREF:AB桥的电流控制端,连接至同一参考电压,可以连接至V3P3OUT引脚
DECAY:衰减控制 低电平:低衰减模式 高电平:高速衰减模式 悬空(open) 混合衰减模式 【引脚内置上下拉】
DIR:方向控制: 【内置下拉】
MODE0/1/2:细分设置 【内置下拉】
nENBL:逻辑高电平去禁止驱动输出,逻辑低电平使能 【内置下拉】
nRESRT: 低电平有效,复位输入初始化驱动器逻辑并, 禁用H桥输出【内置下拉】
nSLEEP: 逻辑高使能器件,逻辑低电平进入低功耗睡眠模式【内置下拉】
STEP :上升沿导致驱动器移动一步【内置下拉】
nFAULT:错误会导致 引脚低电平(过热过流)
nHOME: 处于 初始位置时 引脚置低
AOUT1/2: 连接至步进电机绕组A 正向电流由1流向2
BOUT1/2:连接至步进电机绕组B 正向电流由1流向2
ISENA/B:连接到电桥A/B的电流检测电阻。
相管参数: Step Frequency Max= 250M 最佳温度 25°C
电流检测 :斩波电流的设置是由流经检测电阻的电压的五倍去和参考电压做对比
Ichop=VxREF/(5*Risense)
例 I=2.5/(0.25*5)=2A 2.5V的参考电压 0.25的欧姆的电流检测电阻


代码:
#ifndef _MDL_MOTOR_H
#define _MDL_MOTOR_H
#include "stdint.h"
#ifdef _MDL_MOTOR_INIT
#define EXTERN_MOTOR_INIT
#else
#define EXTERN_MOTOR_INIT extern
#endif
#define uSTEP GPIO_PIN_11
#define uSTEP_HIGH gpio_bit_set (GPIOE, uSTEP)
#define uSTEP_LOW gpio_bit_reset (GPIOE, uSTEP)
#define uDIR GPIO_PIN_12
#define uDIR_HIGH gpio_bit_set (GPIOE, uDIR)
#define uDIR_LOW gpio_bit_reset (GPIOE, uDIR)
#define unSlEEP GPIO_PIN_13
#define unSLEEP_HIGH gpio_bit_set (GPIOE, unSlEEP)
#define unSLEEP_LOW gpio_bit_reset (GPIOE, unSlEEP)
#define uVREF GPIO_PIN_14
#define uVREF_HIGH gpio_bit_set (GPIOE, uVREF)
#define uVREF_LOW gpio_bit_reset (GPIOE, uVREF)
#define MCU_OPTIN1 GPIO_PIN_0
#define READ_OPTIN1 gpio_input_bit_get (GPIOD, MCU_OPTIN1)
#define MCU_OPTIN2 GPIO_PIN_1
#define READ_OPTIN2 gpio_input_bit_get (GPIOD, MCU_OPTIN2)
#define MCU_OPTIN3 GPIO_PIN_3
#define READ_OPTIN3 gpio_input_bit_get (GPIOD, MCU_OPTIN3)
#define MCU_OPTIN4 GPIO_PIN_4
#define READ_OPTIN4 gpio_input_bit_get (GPIOD, MCU_OPTIN4)
#define MCU_OPTIN5 GPIO_PIN_5
#define READ_OPTIN5 gpio_input_bit_get (GPIOD, MCU_OPTIN5)
enum
{
Move_ConstantType =0, //恒速运行模式
Move_AddType =1, //只加速运行,无减速段
Move_CurveType =2, //曲线运行模式
};
#define abs(a,b) (a>b)?(a-b):(b-a)
//电机运行 结构体
typedef struct
{
volatile uint8_t lockEn; //电机锁步使能
volatile uint8_t stepMark; //电机脉冲标志
volatile uint16_t testFreq; //测量频率
volatile uint16_t stepCount; //电机运行实时记步
volatile uint8_t dir; //运行方向
volatile uint16_t addDis; //加速步数
volatile uint16_t subDis; //减速步数
volatile uint16_t runFreq; //电机当次运行的最大频率
volatile uint16_t startFreq; //起始频率
volatile uint16_t addFreq; //加速段频率递增量
volatile uint16_t runStep; //电机运行步数
volatile uint8_t OPTStep; //仪器运行状态
volatile uint8_t irNum; //光电检测序号
volatile uint16_t standbyDis; //电机从光电开关到待机位步长
volatile uint16_t throwFreq; //丢卡频率
volatile uint8_t runSta; //仪器运行状态
}Def_MotorDev;
EXTERN_MOTOR_INIT Def_MotorDev mMotorDev;
//系统参数 变量结构体
typedef struct
{
volatile uint8_t MotorSide; //电机安装位置 不同的安装位置会导致运行方向相反 0-左侧 1-右侧
volatile uint8_t ResetDir; //电机复位方向 0-复位光电在外侧(插卡位) 1-复位光电在最内侧
volatile uint8_t LightUnit; //光路盒模组 0-旧光路盒(模拟信号) 1-数字光路盒
volatile uint16_t ClientNum2; //客户代码
volatile uint8_t Subdivision; //电机细分
volatile uint8_t IDCardType; //ID卡类型 0-ID卡 1-外购串口IC卡 2-自制IC卡
volatile uint8_t SysLockSta; //系统上锁状态
volatile uint16_t DecryptTime; //解密系统延时
volatile uint8_t BarCodeType; //条码类型 0-蓝勃条码 1-一维码 2-二维码
volatile uint16_t DlyTime; //时间延时
volatile uint8_t LedOpenMode; //荧光扫描时LED灯开灯位置 0-窗口起点开灯 1-复位点开灯
volatile uint8_t Smooth_Deal; //荧光曲线平滑处理模式 0-蓝勃体系 1-万孚体系(曲线平滑滤波有区别)
volatile uint8_t CardFlag; //卡颜色标志 0黑色 1白色
volatile uint16_t CardCheckDis; //试剂卡插卡检测位置 AFS-1000默认在最外端检测,AFS626的检测光电在内侧,需要向内移动一定步长后再检测
/* volatile INT8U ulSysTick; //系统节拍
volatile INT8U ForwardDir; //电机前进方向
*/
}Def_System;
EXTERN_MOTOR_INIT Def_System d_System;
uint8_t Mdl_OPT_Check(uint8_t Num);
void Mdl_Motor_DirSet(uint8_t dir);
void Mdl_Move_Step(uint16_t freq);
void Mdl_Motor_Gpio_Init(void);
void Mdl_Func_TestMove(uint8_t num);
void Mdl_Func_MotorDriver_T(uint8_t runType);
uint8_t Mdl_Func_MoveStanby(void);
void Mdl_Func_Stanby(void);
uint8_t Mdl_Func_MoveReset(void);
void Mdl_Func_Reset(void);
void Mdl_Move_init(void);
void Mdl_Func_Check(void);
void Mdl_Motor_StatueSet(uint8_t sta);
#endif
#define _MDL_MOTOR_INIT
#include "mdl_head_all.h"
/*
*电机模块的IO口配置
*/
void Mdl_Motor_Gpio_Init(void)
{
rcu_periph_clock_enable(RCU_GPIOE);
gpio_init(GPIOE,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,11);
gpio_init(GPIOE,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,12);
gpio_init(GPIOE,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,13);
gpio_init(GPIOE,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,14);
}
void Mdl_Func_Check(void)
{
Uart0Dev.Buf[9] = READ_OPTIN1;
Uart0Dev.Buf[10]= READ_OPTIN2;
Uart0Dev.Buf[18] = mMotorDev.runSta; //错误标志
Uart0Dev.Buf[5] = 0xAA; //新底层
Mdl_UartSendCom(24);
}
/*
*函数功能:检测光电开关
*Num:
*(1)
*(2)
*/
uint8_t Mdl_OPT_Check(uint8_t Num)
{
uint8_t Rev = 0;
switch (Num)
{
case 1: Rev = READ_OPTIN1; break;
case 2: Rev = READ_OPTIN2; break;
case 3: Rev = READ_OPTIN3; break;
case 4: Rev = READ_OPTIN4; break;
case 5: Rev = READ_OPTIN5; break;
}
return (Rev);
}
/*
*函数功能:设置马达方向
*参数:电机的方向
*
*/
void Mdl_Motor_DirSet(uint8_t dir)
{
if (d_System.MotorSide == 0) //电机左侧安装,默认运行方向为正
{
switch (d_System.ResetDir)
{
case ResetOPTOutSide: //复位光电在最外面
if (dir)
uDIR_LOW; //向内走,前行
else
uDIR_HIGH; //向外走,复位
break;
case ResetOPTInSide: //复位光电在最里面
if (dir)
uDIR_HIGH; //向外走,前行
else
uDIR_LOW; //向内走,复位
break;
default:
break;
}
}
else
{
switch (d_System.ResetDir) //电机右侧安装,默认运行方向相反
{
case ResetOPTOutSide: //复位光电在最外面
if (dir) uDIR_HIGH; //向内走,前行
else uDIR_LOW; //向外走,复位
break;
case ResetOPTInSide: //复位光电在最里面
if (dir) uDIR_LOW; //向外走,前行
else uDIR_HIGH; //向内走,复位
break;
default:
break;
}
}
}
/*
*函数功能:马达移动一步
*/
void Mdl_Move_Step(uint16_t freq)
{
uSTEP_LOW;
mMotorDev.stepMark = 0x00; //清定时标志
timer_auto_reload_shadow_enable (TIMER0);
timer_autoreload_value_config (TIMER0, 18000000/freq);
timer_counter_value_config(TIMER0,0);
timer_enable(TIMER0);
uSTEP_HIGH;
mMotorDev.stepMark = 0x00; //清定时标志
timer_auto_reload_shadow_enable (TIMER0);
timer_autoreload_value_config (TIMER0, 18000000/freq);
timer_counter_value_config(TIMER0,0);
timer_enable(TIMER0);
}
/*
*函数功能:控制电机使能
*/
void Mdl_Motor_StatueSet(uint8_t sta)
{
if (sta)
{
unSLEEP_HIGH; //电机使能,关闭睡眠
uVREF_HIGH; //取消半流锁步
}
else //电机锁步设置
{
if (mMotorDev.lockEn)
uVREF_LOW; //驱动器半流锁步
else
unSLEEP_LOW; //驱动器睡眠
}
}
/*
*函数功能:测试时候移动电机步数
*/
void Mdl_Func_TestMove(uint8_t num)
{
if (mMotorDev.dir == MotorDirBackrward) //复位光电在最里面
{
mMotorDev.stepCount -= num; //向内走接近复位光电,计步减少
}
else
{
mMotorDev.stepCount += num; //向内走远离复位光电,计步增加
}
for (;num>0;num--)
{
Mdl_Move_Step(mMotorDev.testFreq);
}
Mdl_Func_SPI_ADMEAS(); //AD转换
}
/*
*函数功能:电机运动方式
*/
void Mdl_Func_MotorDriver_T(uint8_t runType)
{
uint16_t i,tmp;
uint8_t OPT_Stemp=0;//光电触发步数20181008增加
Mdl_Motor_StatueSet(FunEnable); //电机使能
Mdl_Motor_DirSet(mMotorDev.dir); //方向设置
switch(runType)
{
case Move_ConstantType: //匀速运行
mMotorDev.addDis = 0;
mMotorDev.subDis = 0;
tmp = mMotorDev.runFreq;
break;
case Move_AddType: //只有加速段和匀速段,没有减速段
if (mMotorDev.runFreq > mMotorDev.startFreq)
{
mMotorDev.addDis = (mMotorDev.runFreq - mMotorDev.startFreq)/mMotorDev.addFreq; //计算加速步数
mMotorDev.subDis = 0; //没有减速段
tmp = mMotorDev.startFreq; //起始频率赋值
if (mMotorDev.addDis > mMotorDev.runStep) //运行总步数小于加速步数时,
{
mMotorDev.addDis = mMotorDev.runStep/2;
tmp = mMotorDev.runFreq - mMotorDev.addDis*mMotorDev.addFreq; //重新计算曲线起始频率
}
}
else //
{
mMotorDev.addDis = 0;
mMotorDev.subDis = 0;
tmp = mMotorDev.runFreq; //起始频率都大于匀速频率,就直接以匀速频率运行
}
break;
case Move_CurveType: //曲线模式,有加速段、匀速段和减速段
if (mMotorDev.runFreq > mMotorDev.startFreq)
{
mMotorDev.addDis = (mMotorDev.runFreq - mMotorDev.startFreq)/mMotorDev.addFreq; //计算加速步数
tmp = mMotorDev.startFreq;
if (mMotorDev.addDis*2 >= mMotorDev.runStep) //运行总步数小于加速步数时,
{
mMotorDev.addDis = mMotorDev.runStep/2; //每段各占1/3步长
tmp = mMotorDev.runFreq - mMotorDev.addDis*mMotorDev.addFreq; //重新计算曲线起始频率
}
mMotorDev.subDis = mMotorDev.addDis; //减速段步长 = 加速段步长
}
else //
{
mMotorDev.addDis = 0;
mMotorDev.subDis = 0;
tmp = mMotorDev.runFreq; //起始频率都大于匀速频率,就直接以匀速频率运行
}
break;
default:
break;
}
mMotorDev.OPTStep=optStep*d_System.Subdivision; //补偿步数运算
for (i=0;i<mMotorDev.runStep;i++)
{
if ((mMotorDev.irNum > 0)&&(Mdl_OPT_Check(mMotorDev.irNum) == 0))//如果步数大于0,同时光电进行触发
{
/***以下为光电新判断方式20181008****/
if(OPT_Stemp>=mMotorDev.OPTStep||i<=0)//判断当前的光电触发是否遮挡了optStep步,或者是否为已经在触发位
{
break; //检测到光电开关,终止运动
}
else
{
OPT_Stemp++;
}
}
if (mMotorDev.addDis)
{
if (i<mMotorDev.addDis) //加速段
{
tmp +=mMotorDev.addFreq;
}
else if (i<(mMotorDev.runStep - mMotorDev.subDis))
{
tmp = mMotorDev.runFreq; //匀速段
}
else
{
tmp -=mMotorDev.addFreq; //减速段
}
}
Mdl_Move_Step(tmp);
if (mMotorDev.dir == MotorDirBackrward) //复位方向运行
{
if (mMotorDev.stepCount)
mMotorDev.stepCount--; //走接近复位光电,计步减少
}
else
{
mMotorDev.stepCount++; //远离复位光电,计步增加
}
}
Mdl_Motor_StatueSet(FunUnable); //电机睡眠/锁步
}
/*
*函数功能:电机丢卡位置
*/
uint8_t Mdl_Func_MoveStanby(void)
{
uint8_t sta = 0;
mMotorDev.runStep = abs(mMotorDev.standbyDis,mMotorDev.stepCount);//取待机位的步数
mMotorDev.runFreq = mMotorDev.throwFreq; //丢卡频率
mMotorDev.dir = (mMotorDev.standbyDis>mMotorDev.stepCount)?MotorDirForward:MotorDirBackrward; //前行
if (d_System.ResetDir == ResetOPTOutSide) //如果向外复位,则待机位需要检测2号光电
{
mMotorDev.irNum = 2; //检测2号光电
mMotorDev.runStep = mMotorDev.standbyDis*2; //到光电位停止
mMotorDev.dir = MotorDirForward; //向前走
}
Mdl_Func_MotorDriver_T(Move_CurveType);
if (d_System.ResetDir == ResetOPTOutSide) //如果是外复位模式
{
if((READ_OPTIN1 == 0)||(READ_OPTIN2 != 0)) //判断复位光电是否遮挡,或者丢卡微动开关是否未触发
{
Mdl_Delay_ms(200);//消抖
if((READ_OPTIN1 == 0)||(READ_OPTIN2 != 0)) //判断复位光电是否遮挡,或者丢卡微动开关是否未触发
{
Mdl_Delay_ms(200);//消抖
if((READ_OPTIN1 == 0)||(READ_OPTIN2 != 0)) //判断复位光电是否遮挡,或者丢卡微动开关是否未触发
sta = CommUnusual;
}
}
}
else
if(READ_OPTIN1 == 0) sta = CommUnusual;
mMotorDev.runFreq = mMotorDev.testFreq; //修改默认频率为荧光扫描频率
mMotorDev.irNum = 0; //清空光电序号
return(sta);
}
/*
*函数功能:丢卡指令动作
*/
void Mdl_Func_Stanby(void)
{
mMotorDev.runSta = Mdl_Func_MoveStanby(); //到待机位,丢卡/卡舌伸出
if(mMotorDev.runSta==0)
{
if (d_System.ResetDir == ResetOPTInSide)
//20170905修改01加入关机功能
//如果是内复位形式的话就要进行一个复位动作做为跑到待机位的操作
mMotorDev.runSta = Mdl_Func_MoveReset();
}
Uart0Dev.Buf[8] =mMotorDev.runSta; //丢卡运动 返回仪器状态信息
Uart0Dev.Buf[5] = 0xAA; //新底层
Mdl_UartSendCom(24);
}
/*
*函数功能:电机复位
*/
uint8_t Mdl_Func_MoveReset(void)
{
uint8_t sta =0;
if (d_System.ResetDir == ResetOPTOutSide)
{
if (Mdl_OPT_Check(1) == 0) //当前已在光电位,则先正向走出光电位,再返回到光电位
{
mMotorDev.runStep = SmallStep; //向前运行一小段
mMotorDev.dir = MotorDirForward;
Mdl_Func_MotorDriver_T(Move_CurveType);
if (Mdl_OPT_Check(1) == 0) //如果走完后光电依然触发,代表运动没有执行,返回错误标志位
{
mMotorDev.stepCount =0; //计步数清零
mMotorDev.irNum = 0; //光电序号清空
sta = CommUnusual;
return(sta);
}
}
}
mMotorDev.runStep = mMotorDev.standbyDis*2;
mMotorDev.dir = MotorDirBackrward; //回走
mMotorDev.irNum = 1; //检测1号光电
Mdl_Func_MotorDriver_T(Move_CurveType);
if (d_System.ResetDir == ResetOPTOutSide)
{
if((READ_OPTIN1 != 0)||(READ_OPTIN2 == 0))
{
Mdl_Delay_ms(200);//消抖
if((READ_OPTIN1 != 0)||(READ_OPTIN2 == 0))
sta = CommUnusual;
}
}
else
if(READ_OPTIN1 != 0)
{
Mdl_Delay_ms(200);//消抖
if(READ_OPTIN1 != 0)
sta = CommUnusual;
}
/*检测光电信号,不论是外复位还是内复位,若初始时1号光电未触发,
则电机会向光电位置运动,之后1号光电应该是触发状态,若不是触发状态,则有问题*/
// if((sta != 0) && (sta != CommERR)) sta= CommUnusual; //当1号光电有问题,时,stat=1,与CommUnusual相同,保留此句仅供理解程序思路
mMotorDev.stepCount =0; //计步数清零
mMotorDev.irNum = 0; //光电序号清空
return(sta);
}
/*
*函数功能:接收复位指令处理相应操作
*/
void Mdl_Func_Reset(void)
{
mMotorDev.runSta = Mdl_Func_MoveReset(); //复位
if (d_System.ResetDir == ResetOPTInSide)
mMotorDev.runSta=Mdl_Func_MoveStanby(); //内复位模式,需要自动伸出载卡舌
Uart0Dev.Buf[8] = mMotorDev.runSta; //返回仪器状态信息
Uart0Dev.Buf[5] = 0xAA; //新底层标志
Mdl_UartSendCom(24);
}
/*
*函数功能:上电初始化电机工作
*/
void Mdl_Move_init(void)
{
//开机伸出卡舌
Mdl_Func_MoveReset(); //初始化电机复位
if (d_System.ResetDir == ResetOPTInSide)
{
Mdl_Func_MoveStanby(); //内复位模式,需要自动伸出载卡舌
}
if (d_System.IDCardType == lanbo_ICCard) //初始化IC卡
{
rcu_periph_clock_enable(RCU_GPIOD);
gpio_init(GPIOD,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,ID_INT0); //设置为输出
ID_INT0_L;
Mdl_Delay_10ns(2000);
Mdl_Rc522Init();
}
}
这篇博客详细介绍了如何使用DRV8825驱动两相步进电机,包括其特点、操作电压、电流规格和安全模式。还提供了GPIO配置代码,展示了电机方向控制、细分设置、使能控制等关键步骤,适用于GD32或STM32平台。
1万+

被折叠的 条评论
为什么被折叠?



