4 changed files with 333 additions and 0 deletions
-
197components/step_motor_45/step_motor_45.cpp
-
74components/step_motor_45/step_motor_45.hpp
-
38components/step_motor_45/step_motor_45_scheduler.cpp
-
24components/step_motor_45/step_motor_45_scheduler.hpp
@ -0,0 +1,197 @@ |
|||
#include "step_motor_45.hpp"
|
|||
|
|||
#include <stdint.h>
|
|||
|
|||
using namespace iflytop; |
|||
#define TAG "StepMotor45"
|
|||
|
|||
typedef struct { |
|||
uint8_t v[4]; |
|||
} stepmotor_control_matrix_t; |
|||
|
|||
stepmotor_control_matrix_t onestepsq1[] = { |
|||
{{0, 1, 1, 1}}, // 0
|
|||
{{0, 0, 1, 1}}, // 1
|
|||
{{1, 0, 1, 1}}, // 2
|
|||
{{1, 0, 0, 1}}, // 3
|
|||
{{1, 1, 0, 1}}, // 4
|
|||
{{1, 1, 0, 0}}, // 5
|
|||
{{1, 1, 1, 0}}, // 6
|
|||
{{0, 1, 1, 0}}, // 7
|
|||
}; |
|||
|
|||
stepmotor_control_matrix_t onestepsq2[] = { |
|||
{{0, 1, 1, 0}}, // 7
|
|||
{{1, 1, 1, 0}}, // 6
|
|||
{{1, 1, 0, 0}}, // 5
|
|||
{{1, 1, 0, 1}}, // 4
|
|||
{{1, 0, 0, 1}}, // 3
|
|||
{{1, 0, 1, 1}}, // 2
|
|||
{{0, 0, 1, 1}}, // 1
|
|||
{{0, 1, 1, 1}}, // 0
|
|||
}; |
|||
|
|||
#define MAX_STEP_TABLE_OFF (ZARRAY_SIZE(onestepsq1) - 1)
|
|||
|
|||
void StepMotor45::initialize(cfg_t cfg) { |
|||
m_cfg = cfg; |
|||
|
|||
// 初始化GPIO
|
|||
ZASSERT(cfg.driverPin[0] != PinNull); |
|||
ZASSERT(cfg.driverPin[1] != PinNull); |
|||
ZASSERT(cfg.driverPin[2] != PinNull); |
|||
ZASSERT(cfg.driverPin[3] != PinNull); |
|||
|
|||
for (size_t i = 0; i < 4; i++) { |
|||
m_driverPinZGPIO[i] = new ZGPIO(); |
|||
ZASSERT(m_driverPinZGPIO[i] != NULL); |
|||
m_driverPinZGPIO[i]->initAsOutput(cfg.driverPin[i], ZGPIO::kMode_nopull, cfg.driverPinMirror, true); |
|||
} |
|||
|
|||
if (cfg.zeroPin != PinNull) { |
|||
m_zeroPinZGPIO = new ZGPIO(); |
|||
ZASSERT(m_zeroPinZGPIO != NULL); |
|||
m_zeroPinZGPIO->initAsInput(cfg.zeroPin, ZGPIO::kMode_pullup, ZGPIO::kIRQ_noIrq, cfg.zeroPinMirror); |
|||
} |
|||
return; |
|||
} |
|||
|
|||
void StepMotor45::rotate(bool direction, int speed) { |
|||
CriticalContext cc; |
|||
if (direction) { |
|||
if (getzeropinstate()) { |
|||
m_calibration = true; |
|||
m_pos = 0; |
|||
} |
|||
} |
|||
m_state = direction ? kforward_rotation : krollback; |
|||
} |
|||
void StepMotor45::stop() { |
|||
CriticalContext cc; |
|||
stop_motor(); |
|||
} |
|||
void StepMotor45::zeroCalibration() { |
|||
CriticalContext cc; |
|||
if (getzeropinstate()) { |
|||
m_calibration = true; |
|||
m_pos = 0; |
|||
return; |
|||
} |
|||
m_exec_zero_calibration_task = true; |
|||
m_state = krollback; |
|||
} |
|||
|
|||
void StepMotor45::onTimIRQ1ms() { |
|||
CriticalContext cc; |
|||
if (m_state == kstop) { |
|||
return; |
|||
} |
|||
schedule(); |
|||
} |
|||
|
|||
void StepMotor45::schedule() { |
|||
/**
|
|||
* @brief 执行零点校准逻辑 |
|||
*/ |
|||
bool iostate = getzeropinstate(); |
|||
bool detect_rising_edge = false; |
|||
bool detect_falling_edge = false; |
|||
if (m_lastzeropinstate != iostate) { |
|||
if (iostate) { |
|||
detect_rising_edge = true; |
|||
} else { |
|||
detect_falling_edge = true; |
|||
} |
|||
m_lastzeropinstate = iostate; |
|||
} |
|||
|
|||
if ((detect_rising_edge && m_state == krollback) || (detect_falling_edge && m_state == kforward_rotation)) { |
|||
/**
|
|||
* @brief 触发零点 |
|||
*/ |
|||
m_pos = 0; |
|||
m_calibration = true; |
|||
|
|||
if (m_exec_zero_calibration_task) { |
|||
m_exec_zero_calibration_task = 0; |
|||
stop_motor(); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
/**
|
|||
* @brief 零点限位触发,电机停止运行 |
|||
*/ |
|||
if (m_cfg.enable_zero_limit && m_state == krollback) { |
|||
if (iostate) { |
|||
stop_motor(); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
/**
|
|||
* @brief 触发最大位置限位,电机停止运行 |
|||
*/ |
|||
if (m_cfg.enable_max_pos_limit && m_state == kforward_rotation) { |
|||
if (m_pos >= m_cfg.max_pos) { |
|||
stop_motor(); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
/**
|
|||
* @brief 如果使能了最大位置限位,且电机没有校准过,则电机不允许正转 |
|||
*/ |
|||
if (m_cfg.enable_max_pos_limit && !m_calibration) { |
|||
if (m_state == kforward_rotation) { |
|||
return; |
|||
} |
|||
} |
|||
|
|||
/**
|
|||
* @brief |
|||
* 按照相位表执行电机驱动 |
|||
*/ |
|||
int direction = 0; |
|||
if (m_state == kforward_rotation) { |
|||
direction = 1; |
|||
} else if (m_state == krollback) { |
|||
direction = -1; |
|||
} |
|||
|
|||
m_off += direction; |
|||
if (m_off < 0) { |
|||
m_off = MAX_STEP_TABLE_OFF; |
|||
} else if (m_off > MAX_STEP_TABLE_OFF) { |
|||
m_off = 0; |
|||
} |
|||
|
|||
stepmotor_control_matrix_t* table = NULL; |
|||
if (m_cfg.mirror) { |
|||
table = onestepsq2; |
|||
} else { |
|||
table = onestepsq1; |
|||
} |
|||
|
|||
setdriverpinstate(table[m_off].v[0], table[m_off].v[1], table[m_off].v[2], table[m_off].v[3]); |
|||
|
|||
m_pos += direction; |
|||
} |
|||
|
|||
bool StepMotor45::getzeropinstate() { |
|||
if (!m_zeroPinZGPIO) { |
|||
return false; |
|||
} |
|||
bool state = m_zeroPinZGPIO->getState(); |
|||
return state; |
|||
} |
|||
void StepMotor45::setdriverpinstate(bool s1, bool s2, bool s3, bool s4) { |
|||
ZLOGI(TAG, "setdriverpinstate %d%d%d%d", s1, s2, s3, s4); |
|||
|
|||
m_driverPinZGPIO[0]->setState(s1); |
|||
m_driverPinZGPIO[1]->setState(s2); |
|||
m_driverPinZGPIO[2]->setState(s3); |
|||
m_driverPinZGPIO[3]->setState(s4); |
|||
} |
|||
|
|||
void StepMotor45::stop_motor() { m_state = kstop; } |
@ -0,0 +1,74 @@ |
|||
#pragma once
|
|||
|
|||
#include "sdk/os/zos.hpp"
|
|||
|
|||
namespace iflytop { |
|||
using namespace std; |
|||
|
|||
/**
|
|||
* @brief 四线五项步进电机 |
|||
* https://iflytop1.feishu.cn/wiki/MtaawWm8yijb0tkpWoic1IhsnZc
|
|||
*/ |
|||
|
|||
class StepMotor45 { |
|||
public: |
|||
typedef enum { |
|||
kstop, |
|||
kforward_rotation, |
|||
krollback, |
|||
} state_t; |
|||
|
|||
typedef struct { |
|||
int max_pos = INT32_MAX; // 最大位置
|
|||
bool enable_zero_limit = false; // 是否启用零点限位
|
|||
bool enable_max_pos_limit = false; // 是否启用最大位置限位
|
|||
bool mirror = false; // 是否镜像
|
|||
|
|||
Pin_t zeroPin = PinNull; |
|||
bool zeroPinMirror = false; |
|||
|
|||
Pin_t driverPin[4] = {PinNull, PinNull, PinNull, PinNull}; |
|||
bool driverPinMirror = false; |
|||
} cfg_t; |
|||
|
|||
private: |
|||
int m_off; // 相位偏移
|
|||
int m_pos; // 当前位置
|
|||
bool m_calibration; // 校准状态,是否已经校准
|
|||
state_t m_state; // 当前状态
|
|||
bool m_lastzeropinstate; // 上一次零点限位状态
|
|||
int m_acceleration; // 加速度
|
|||
/**
|
|||
* @brief 控制 |
|||
*/ |
|||
// 执行零点校准任务,如果执行,则电机会自动停止
|
|||
bool m_exec_zero_calibration_task; |
|||
|
|||
/**
|
|||
* @brief 配置 |
|||
*/ |
|||
|
|||
ZGPIO *m_driverPinZGPIO[4]; |
|||
ZGPIO *m_zeroPinZGPIO; |
|||
|
|||
cfg_t m_cfg; |
|||
|
|||
public: |
|||
void initialize(cfg_t cfg); |
|||
|
|||
void rotate(bool direction, int speed); |
|||
void stop(); |
|||
void zeroCalibration(); |
|||
|
|||
private: |
|||
bool getzeropinstate(); |
|||
void setdriverpinstate(bool s1, bool s2, bool s3, bool s4); |
|||
|
|||
void schedule(); |
|||
void stop_motor(); |
|||
|
|||
public: |
|||
void onTimIRQ1ms(); |
|||
}; |
|||
|
|||
} // namespace iflytop
|
@ -0,0 +1,38 @@ |
|||
#include "step_motor_45_scheduler.hpp"
|
|||
|
|||
using namespace iflytop; |
|||
|
|||
void StepMotor45Scheduler::initialize(zchip_tim_t* tim, int freq) { |
|||
m_htim = tim; |
|||
|
|||
uint32_t prescaler = 0; |
|||
uint32_t autoreload = 0; |
|||
|
|||
ZASSERT(chip_calculate_prescaler_and_autoreload_by_expect_freq(chip_get_timer_clock_sorce_freq(m_htim), freq, &prescaler, &autoreload)); |
|||
|
|||
HAL_TIM_Base_DeInit(m_htim); |
|||
m_htim->Init.Prescaler = prescaler; |
|||
m_htim->Init.CounterMode = TIM_COUNTERMODE_UP; |
|||
m_htim->Init.Period = autoreload; |
|||
m_htim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; |
|||
HAL_TIM_Base_Init(m_htim); |
|||
|
|||
HAL_NVIC_SetPriority(chip_tim_get_irq(m_htim), IFLYTOP_PREEMPTPRIORITY_DEFAULT, 0); |
|||
HAL_NVIC_EnableIRQ(chip_tim_get_irq(m_htim)); |
|||
|
|||
// HAL_TIM_Base_Start_IT(m_htim);
|
|||
|
|||
ZIRQDispatcher::instance().regTimIrqListener([this](zchip_tim_t* tim) { |
|||
if (tim != m_htim) return; |
|||
loop(); |
|||
}); |
|||
} |
|||
|
|||
void StepMotor45Scheduler::start() { HAL_TIM_Base_Start_IT(m_htim); } |
|||
void StepMotor45Scheduler::addMotor(StepMotor45* motor) { m_motor_list.push_back(motor); } |
|||
|
|||
void StepMotor45Scheduler::loop() { |
|||
for (auto motor : m_motor_list) { |
|||
motor->onTimIRQ1ms(); |
|||
} |
|||
} |
@ -0,0 +1,24 @@ |
|||
#pragma once
|
|||
|
|||
#include "sdk/os/zos.hpp"
|
|||
#include "step_motor_45.hpp"
|
|||
namespace iflytop { |
|||
using namespace std; |
|||
|
|||
class StepMotor45Scheduler { |
|||
public: |
|||
zchip_tim_t* m_htim; |
|||
|
|||
list<StepMotor45*> m_motor_list; |
|||
|
|||
public: |
|||
void initialize(zchip_tim_t* tim, int freq); |
|||
void addMotor(StepMotor45* motor); |
|||
|
|||
void start(); |
|||
|
|||
private: |
|||
void loop(); |
|||
}; |
|||
|
|||
} // namespace iflytop
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue