上面是我的微信和QQ群,欢迎新朋友的加入。
最近在做42步进电机的东西,记录一下问题。
目录
1.脉冲输出
主控芯片是STM32F030(主要就是便宜)。
脉冲输出最开始我纠结于MCO、TIME CH、或者直接IO驱动三种方式中
1.MCO,单片机只有一路,数量不够,但是速度很高,能出上M的频率,暂空比没法调节
2.定时器输出,数量够,暂空比也可以调节,但是我需要指定制定脉冲个数(可以启用两个定时器,一个输出,一个计数),比较麻烦,另外就是限位开关要快速反应,驱动过程中也有些逻辑操作,如正反转设定
3.IO直接输出,效率低,但是逻辑比较好写
目前使用的是第三种方式,虽然效率低,但是步进电机一般用于比较精准的行程控制,而不是高速的运转。
选用的步进电机控制器
实际测量,芯片主频是48Mhz,不用外部晶振,有些误差,加上逻辑代码,直接跑,最高速度大概是35K左右,通过定时器设定10us周期频率,最高速度是25K左右。
假设步进电机设为6400个脉冲为一圈,则
高速运行:35000/6400=5圈/秒
周期运行:25000/6400=4圈/秒
假设步进电机设为200个脉冲为一圈,则
高速运行:35000/200=175圈/秒
周期运行:25000/200=125圈/秒
实际上,我测试了一下,200个脉冲一圈时,速度到1.2K左右,电机就无法转动了,也就是大概60圈每秒的时候,就不能动了
所以并不需高速运行的模式
2.硬件设计
1.一路电机驱动接口
2.三个位置开关接口,位置接口上加上指示灯
3.控制方式选用串口,其实也考虑IIC,可以支持多机同时存在,SPI就不考虑了,IO不够
4.INT输出控制板的状态
5.一个STOP用于设备急停,直接接按键
6.一个ENABLE,外部可以控制电机暂停或者运动
板子画好后是这样的
P4接电机
后面三个限位开关,开关上加10K上拉以及电容滤波,同时加指示灯,显示开关状态
尺寸为41mm*20mm
实物
3.嵌入式软件设计
PWM输出、位置检测、方向控制、串口通信、状态反馈、急停
程序思路是,开启一个定时器,设定为10us触发一次中断
/* TIM1 init function */
void MX_TIM1_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim1.Instance = TIM1;
htim1.Init.Prescaler = 10-1;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 48-1;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
}
中断任务里面,就只做定时的处理,然后在主循环处理电机逻辑任务
/*
电机运行进程
*/
uint8_t LimitState = 0;
uint8_t OldLimitState = 0;
void MotorProcess(void)
{
//急停与使能都是高电平时,允许电机动作
//没做消抖处理,看后面需求,目前考虑的是要更快的反应速度
if((STOP_GPIO_Port->IDR & STOP_Pin) != (uint32_t)GPIO_PIN_RESET &&
(ENABLE_GPIO_Port->IDR & ENABLE_Pin) != (uint32_t)GPIO_PIN_RESET &&
HardwareParamter.SystemState != SYS_STOP)//(ENABLE_GPIO_Port->IDR & ENABLE_Pin)
{
switch(GetMotorMode())
{
case MOTOR_NORMOL:
SystemModeNormal();
break;
case MOTOR_CYCLE:
SystemModeCycle();
break;
default:break;
}
}
}
发现读IO状态花的时间比较多,就不调用库接口,直接操作寄存器获取数据
串口部分,使用DMA传输的方式,也是在主循环里面处理数据
目前开放以下命令接口
/* USER CODE BEGIN Private defines */
#define COMMAND_OK 0x00//正确应答(数据无效)\r\n");
#define COMMAND_ERR 0x01//异常应答(数据无效)\r\n");
#define COMMAND_READ_SYSTEM_STATE 0x02//读取系统状态(1字节有效数据)\r\n");
#define COMMAND_WRITE_SYSTEM_STATE 0x03//读取系统状态(1字节有效数据)\r\n");
#define COMMAND_WRITE_LEVEL 0x04//写初始电平(1字节有效数据)\r\n");
#define COMMAND_READ_LEVEL 0x05//读初始电平(1字节有效数据)\r\n");
#define COMMAND_WRITE_MODE 0x06//写电机模式(1字节有效数据)\r\n");
#define COMMAND_READ_MODE 0x07//读电机模式(1字节有效数据)\r\n");
#define COMMAND_READ_SHIFT 0x08//读电机位置(4字节有效数据)\r\n");
#define COMMAND_WRITE_CYCLE 0x09//写周期(1字节有效数据)\r\n");
#define COMMAND_READ_CYCLE 0x0A//读周期(1字节有效数据)\r\n");
#define COMMAND_WRITE_DUTY 0x0B//写占空比(1字节有效数据)\r\n");
#define COMMAND_READ_DUTY 0x0C//读占空比(1字节有效数据)\r\n");
#define COMMAND_WRITE_PULSE 0x0D//写脉冲个数(4字节有效数据)\r\n");
#define COMMAND_READ_PULSE 0x0E//读脉冲个数(4字节有效数据)\r\n");
#define COMMAND_WRITE_DIRECT 0x0F//写运行方向(1字节有效数据)\r\n");
#define COMMAND_READ_DIRECT 0x10//读运行方向(1字节有效数据)\r\n");
#define COMMAND_READ_VERSION 0x11//读版本(2字节有效数据)\r\n");
#define COMMAND_WRITE_LIMIT 0x12//读版本(2字节有效数据)\r\n");
#define COMMAND_READ_LIMIT 0x13//读版本(2字节有效数据)\r\n");
#define COMMAND_LIMIT_STATE 0x14//限位状态返回(2字节有效数据)\r\n");
4.控制软件设计
1.通过对位置开关状态的读取,知道电机的位置,也可以直接读取电机在行程中的位置
2.可以设置电机暂停和重置
3.可以设置周期占空比,用百分比表示
4.可以设置输出的脉冲个数,32位I有效数据
5.可以设置允许方向,正转和反转两种方式
6.可以设置为电机模式为循环运行还是运行指定步数