步进电机驱动之面向对象实现(支持多平台)

1.前言

以前写过的步进电机驱动,都是针对一个步进电机做的驱动,当到了需要两个、三个步进电机的场景。复制粘贴出几个,再修改函数名来实现。经常容易出错不说,也显得很不优雅。针对这个痛点,我决定重新编译一份通用性强,跨平台的步进电机驱动。针对跨平台、拓展需求,本次驱动设计基于面向对象思维实现。

2.驱动支持说明

驱动支持三种工作模式,模式0:支持正传、反转、停止;模式1:增量控制旋转角度,控制;模式2,指定角度运行。

3.驱动

用户需要根据平台实现引用可用的uint8_t、int16_t、int32_t、uint32_t头文件或者自行实现。

3.1数据类型引用说明

3.2数据类型实现说明

 #define uint8_t       unsigned char
 #define uint16_t      unsigned short
 #define int16_t       short
 #define int32_t       int
 #define uint32_t      unsigned int

3.3c文件

StepMotorObject_typ_t obj_StepMotor1 = {0};

int StepMotor_init(StepMotorObject_typ_t *obj, StepMotorPinSetType *PinHandle, uint8_t inverter, uint8_t mode)
{
    if (obj == NULL)
    {
        return -1;
    }
    obj->status = 1;
    obj->ctr_level_out_high = 1;
    obj->ctr_level_out_low = 0;
    obj->inverter = inverter;
    obj->mode = mode; //工作模式
    obj->index = 0;
    obj->set_angle = 0; //角度设定
    obj->angle_cnt = 0;
    obj->run_angle_record = 0;
    // -------------------------------
    obj->set_fixed_angle = 0;
    obj->fixed_angle_cnt = 0;
    obj->directing_control = 0;

    if (obj->inverter > 0)
    { //输出反向
        obj->ctr_level_out_high = 0;
        obj->ctr_level_out_low = 1;
    }
    obj->PinHandle = PinHandle;
    return 0;
}

static int32_t angleToBeat(int16_t angle)
{ //转换出角度值
    int32_t beat = 0;
    beat = ((angle * 4096) / 360);
    return beat;
}

void ctr_beat_out(StepMotorObject_typ_t *obj, uint8_t index)
{
    uint8_t out_index = 0;

    if (obj == NULL)
    {
        return;
    }

    if (obj->status != 1)
    { //未初始化
        return;
    }

    // obj->PinHandle[StepMotor_A1](1);
    // obj->PinHandle[StepMotor_A2](1);
    // obj->PinHandle[StepMotor_B1](1);
    // obj->PinHandle[StepMotor_B2](1);

    // obj->PinHandle[StepMotor_A1](0);
    // obj->PinHandle[StepMotor_A2](0);
    // obj->PinHandle[StepMotor_B1](0);
    // obj->PinHandle[StepMotor_B2](0);

    out_index = index;
    switch (out_index)
    {
    case 0:
        //---------------      1      ----------------------------
        obj->PinHandle[StepMotor_A1](obj->ctr_level_out_low);
        obj->PinHandle[StepMotor_A2](obj->ctr_level_out_high);
        obj->PinHandle[StepMotor_B1](obj->ctr_level_out_high);
        obj->PinHandle[StepMotor_B2](obj->ctr_level_out_high);
        break;
    case 1:
        //---------------      2      ----------------------------
        obj->PinHandle[StepMotor_A1](obj->ctr_level_out_low);
        obj->PinHandle[StepMotor_A2](obj->ctr_level_out_low);
        obj->PinHandle[StepMotor_B1](obj->ctr_level_out_high);
        obj->PinHandle[StepMotor_B2](obj->ctr_level_out_high);
        break;
    case 2:
        //---------------      3      ----------------------------
        obj->PinHandle[StepMotor_A1](obj->ctr_level_out_high);
        obj->PinHandle[StepMotor_A2](obj->ctr_level_out_low);
        obj->PinHandle[StepMotor_B1](obj->ctr_level_out_high);
        obj->PinHandle[StepMotor_B2](obj->ctr_level_out_high);
        break;
    case 3:
        //---------------      4      ----------------------------
        obj->PinHandle[StepMotor_A1](obj->ctr_level_out_high);
        obj->PinHandle[StepMotor_A2](obj->ctr_level_out_low);
        obj->PinHandle[StepMotor_B1](obj->ctr_level_out_low);
        obj->PinHandle[StepMotor_B2](obj->ctr_level_out_high);
        break;
    case 4:
        //---------------      5      ----------------------------
        obj->PinHandle[StepMotor_A1](obj->ctr_level_out_high);
        obj->PinHandle[StepMotor_A2](obj->ctr_level_out_high);
        obj->PinHandle[StepMotor_B1](obj->ctr_level_out_low);
        obj->PinHandle[StepMotor_B2](obj->ctr_level_out_high);
        break;
    case 5:
        //---------------      6      ----------------------------
        obj->PinHandle[StepMotor_A1](obj->ctr_level_out_high);
        obj->PinHandle[StepMotor_A2](obj->ctr_level_out_high);
        obj->PinHandle[StepMotor_B1](obj->ctr_level_out_low);
        obj->PinHandle[StepMotor_B2](obj->ctr_level_out_low);
        break;
    case 6:
        //---------------      7      ----------------------------
        obj->PinHandle[StepMotor_A1](obj->ctr_level_out_high);
        obj->PinHandle[StepMotor_A2](obj->ctr_level_out_high);
        obj->PinHandle[StepMotor_B1](obj->ctr_level_out_high);
        obj->PinHandle[StepMotor_B2](obj->ctr_level_out_low);
        break;
    case 7:
        //---------------      8      ----------------------------
        obj->PinHandle[StepMotor_A1](obj->ctr_level_out_low);
        obj->PinHandle[StepMotor_A2](obj->ctr_level_out_high);
        obj->PinHandle[StepMotor_B1](obj->ctr_level_out_high);
        obj->PinHandle[StepMotor_B2](obj->ctr_level_out_low);
        break;
    default:
        obj->PinHandle[StepMotor_A1](obj->ctr_level_out_high); //关闭输出
        obj->PinHandle[StepMotor_A2](obj->ctr_level_out_high);
        obj->PinHandle[StepMotor_B1](obj->ctr_level_out_high);
        obj->PinHandle[StepMotor_B2](obj->ctr_level_out_high);
        break;
    }
}
void ctr_beat_out_off(StepMotorObject_typ_t *obj)
{
    if (obj == NULL)
    {
        return;
    }
    if (obj->status != 1)
    { //未初始化
        return;
    }

    obj->PinHandle[StepMotor_A1](obj->ctr_level_out_high); //关闭输出

    obj->PinHandle[StepMotor_A2](obj->ctr_level_out_high);
    obj->PinHandle[StepMotor_B1](obj->ctr_level_out_high);
    obj->PinHandle[StepMotor_B2](obj->ctr_level_out_high);

    //  obj->PinHandle[0](0);
}

void StepMotor_cycle_handle(StepMotorObject_typ_t *obj)
{
    if (obj == NULL)
    {
        return;
    }
    if (obj->status != 1)
    { //未初始化
        return;
    }
    if (obj->mode == 1)
    { //角度控制

        obj->angle_cnt += angleToBeat(obj->set_angle); // 需要增加限幅
        obj->set_angle = 0;                            //清0

        if (obj->run_angle_record < obj->angle_cnt) //正传
        {
            if (obj->run_angle_record < 2147483647)
            {
                obj->run_angle_record++;
            }
            if (++obj->index > 7)
                obj->index = 0;
        }
        else if (obj->run_angle_record > obj->angle_cnt) //反转
        {
            if (obj->run_angle_record > -2147483648)
            {
                obj->run_angle_record--;
            }

            if (obj->index != 0)
            {
                obj->index--;
            }
            else
            {
                obj->index = 7;
            }
        }
        else
        {
            ctr_beat_out_off(obj);
            return;
        }
        ctr_beat_out(obj, obj->index);
    }
    else if (obj->mode == 2)
    {                                                             //指定角度运行
        obj->fixed_angle_cnt = angleToBeat(obj->set_fixed_angle); // 固定角度
        if (obj->run_angle_record < obj->fixed_angle_cnt)         //正传
        {
            if (obj->run_angle_record < 2147483647)
            {
                obj->run_angle_record++;
            }
            if (++obj->index > 7)
            {
                obj->index = 0;
            }

            ctr_beat_out(obj, obj->index);
        }
        else if (obj->run_angle_record > obj->fixed_angle_cnt) //反转
        {
            if (obj->run_angle_record > -2147483648)
            {
                obj->run_angle_record--;
            }
            ctr_beat_out(obj, obj->index);
        }
        else
        {
            ctr_beat_out_off(obj);
        }
    }
    else
    {
        if (obj->directing_control == -1)
        {
            if (++obj->index > 7)
                obj->index = 0;
            ctr_beat_out(obj, obj->index);
        }
        else if (obj->directing_control == 1)
        {
            if (obj->index != 0)
            {
                obj->index--;
            }
            else
            {
                obj->index = 7;
            }
            ctr_beat_out(obj, obj->index);
        }
        else
        {
            ctr_beat_out_off(obj);
            return;
        }
    }
}

int StepMotorSetMode(StepMotorObject_typ_t *obj, uint8_t mode)
{
    if (obj == NULL)
    {
        return -1;
    }
    if (obj->status != 1)
    { //未初始化
        return -2;
    }
    obj->mode = mode; //工作模式
    return 0;
}

int StepMotorSetForwardAngle(StepMotorObject_typ_t *obj, int16_t set_angle)
{
    if (obj == NULL)
    {
        return -1;
    }
    if (obj->status != 1)
    { //未初始化
        return -2;
    }
    if (obj->mode != 1)
    {
        return -3;
    }
    if (set_angle < 0)
    {
        return -3;
    }
    obj->set_angle = set_angle;

    return 0;
}

int StepMotorSetReversalAngle(StepMotorObject_typ_t *obj, int16_t set_angle)
{
    if (obj == NULL)
    {
        return -1;
    }
    if (obj->status != 1)
    { //未初始化
        return -2;
    }
    if (obj->mode != 1)
    {
        return -3;
    }
    if (set_angle < 0)
    {
        return -3;
    }
    obj->set_angle = 0 - set_angle;

    return 0;
}

int StepMotorSetFixedAngle(StepMotorObject_typ_t *obj, int16_t set_fixed_angle)
{
    if (obj == NULL)
    {
        return -1;
    }
    if (obj->status != 1)
    { //未初始化
        return -2;
    }
    if (obj->mode != 2)
    {
        return -3;
    }

    obj->set_fixed_angle = set_fixed_angle;
    return 0;
}

int StepMotorSetForward(StepMotorObject_typ_t *obj)
{
    if (obj == NULL)
    {
        return -1;
    }
    if (obj->status != 1)
    { //未初始化
        return -2;
    }
    if (obj->mode != 0)
    {
        return -3;
    }
    obj->directing_control = 1;
    return 0;
}
int StepMotorSetReversal(StepMotorObject_typ_t *obj)
{
    if (obj == NULL)
    {
        return -1;
    }
    if (obj->status != 1)
    { //未初始化
        return -2;
    }
    if (obj->mode != 0)
    {
        return -3;
    }
    obj->directing_control = -1;
    return 0;
}
int StepMotorSetStop(StepMotorObject_typ_t *obj)
{
    if (obj == NULL)
    {
        return -1;
    }
    if (obj->status != 1)
    { //未初始化
        return -2;
    }
    if (obj->mode != 0)
    {
        return -3;
    }
    obj->directing_control = 0;
    return 0;
}

3.4h文件


/*定义步进电机控制引脚枚举*/
typedef enum StepMotorPin{
  StepMotor_A1=0,
  StepMotor_A2=1,
  StepMotor_B1=2,
  StepMotor_B2=3
}StepMotorPinType;
/*定义引脚操作函数指针类型*/
typedef void (* StepMotorPinSetType)(uint8_t value);

/* 定义步进电机的对象类型 */
typedef struct StepMotorObject {
   uint8_t status;

   uint8_t  ctr_level_out_high; //输出相位1
   uint8_t  ctr_level_out_low;  //输出相位0
   uint8_t  inverter; //输入输出是否为反相器 1反向  0 正常 
   uint8_t  mode;  //工作模式
   uint8_t  index; // 步进

   int16_t  set_angle;  //角度设定
   int32_t  angle_cnt;    
   int32_t  run_angle_record;
   // -------------------------------
    int16_t  set_fixed_angle;
    int32_t  fixed_angle_cnt;   
   // -------------------------------
    int8_t directing_control;
    StepMotorPinSetType *PinHandle;
}StepMotorObject_typ_t;

extern StepMotorObject_typ_t   obj_StepMotor1;

int StepMotor_init(StepMotorObject_typ_t *obj, StepMotorPinSetType *PinHandle, uint8_t inverter, uint8_t mode);
 void ctr_beat_out(StepMotorObject_typ_t *obj, uint8_t index);
void ctr_beat_out_off(StepMotorObject_typ_t *obj);
void StepMotor_cycle_handle(StepMotorObject_typ_t *obj);

int StepMotorSetMode(StepMotorObject_typ_t *obj , uint8_t mode);

int StepMotorSetForwardAngle(StepMotorObject_typ_t *obj, int16_t set_angle);
int StepMotorSetReversalAngle(StepMotorObject_typ_t *obj, int16_t set_angle);

int StepMotorSetFixedAngle(StepMotorObject_typ_t *obj, int16_t set_fixed_angle); 

int StepMotorSetForward(StepMotorObject_typ_t *obj);
int StepMotorSetReversal(StepMotorObject_typ_t *obj);

4使用示例

4.1接口实现

接口部分根据不同平台进项修改,这里以ESP32为例

void StepMotor1_Pin_init(void)
{
    gpio_reset_pin(19);
    /* Set the GPIO as a push/pull output */
    gpio_set_direction(19, GPIO_MODE_OUTPUT);

    gpio_reset_pin(5);
    /* Set the GPIO as a push/pull output */
    gpio_set_direction(5, GPIO_MODE_OUTPUT);

    gpio_reset_pin(25);
    /* Set the GPIO as a push/pull output */
    gpio_set_direction(25, GPIO_MODE_OUTPUT);
    gpio_reset_pin(15);
    /* Set the GPIO as a push/pull output */
    gpio_set_direction(15, GPIO_MODE_OUTPUT);
}
static void StepMotor1_A1(uint8_t value)
{
    if (value)
    {
        gpio_set_level(19, 1);
    }
    else
    {
         gpio_set_level(19, 0);
    }
}
static void StepMotor1_A2(uint8_t value)
{
    if (value)
    {
       gpio_set_level(5, 1);
    }
    else
    {
       gpio_set_level(5, 0);
    }
}
static void StepMotor1_B2(uint8_t value)
{
    if (value)
    {
        gpio_set_level(25, 1);
    }
    else
    {
       gpio_set_level(25, 0);
    }
}
static void StepMotor1_B1(uint8_t value)
{
    if (value)
    {
        gpio_set_level(15, 1);
    }
    else
    {
       gpio_set_level(15, 0);
    }
}
 static StepMotorPinSetType setmotor_PIN[4] = {StepMotor1_A1, StepMotor1_A2, StepMotor1_B1, StepMotor1_B2};

4.2定时器刷新接口

static bool timer_callback(void *args){  
    uint64_t val;
     static uint8_t index = 0;
    BaseType_t pxHigherPriorityTaskWoken = pdFALSE;
    val = timer_group_get_counter_value_in_isr(0, 0);
      StepMotor_cycle_handle(&obj_StepMotor1);  //定时刷新步进电机节拍
    return pxHigherPriorityTaskWoken;
}

4.3初始化于使用

void app_main(void)
{
    timer_config_t config = {
        .alarm_en = 1,
        .counter_en = 0,
        .counter_dir = TIMER_COUNT_UP,
        .auto_reload = 1,
        .divider = 16,
    };
    timer_init(0, 0, &config);
    timer_set_counter_value(0, 0, 0x00ull);
    // timer_set_alarm_value(0, 0, TIMER_FREQ * 3);
   // timer_set_alarm_value(0, 0, 12500); //200HZ
//    timer_set_alarm_value(0, 0, 5000); //500HZ
//   timer_set_alarm_value(0, 0, 25000); //100HZ
 //   timer_set_alarm_value(0, 0, 50000); //50HZ
  timer_set_alarm_value(0, 0, 4800); //
  timer_enable_intr(0, 0);
    timer_isr_callback_add(0, 0, timer_callback, NULL, ESP_INTR_FLAG_IRAM);
     /*启动定时器*/
	timer_start(TIMER_GROUP_0,TIMER_0); //开始计数
    StepMotor1_Pin_init();                               //步进电机初始化端口
    StepMotor_init(&obj_StepMotor1, setmotor_PIN, 1, 2); //配置步进电机工作模式
    StepMotorSetFixedAngle(&obj_StepMotor1,500);        //转动500°
}

5总结

以后再增加步进电机或者移植到别的的单片机钟,不需要再动驱动部分,只需要修改实现4部分接口便可以快速完成步进电机拓展。大大增加了灵活性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值