Windows IoT借助树莓派C#改写步进电机驱动

神龙居市 发表于 2022/01/16 16:07:55 2022/01/16
【摘要】 为了完成一个项目案例,驱动2部步进电机,购买的设备驱动板是和树莓派3B定制的扩展版DRV8825芯片,可以驱动2个电机。整体项目是.net core的根据提供的案例,改写成C#版的。工作硬件准备1、硬件:树莓派3B+32GSD卡,DRV8825扩展版,SM24240两相步进电机2个,12V独立电源2、软件:Windows IoT Core、VS2022展示一下硬件图片,整体组装后还是比较干净...

为了完成一个项目案例,驱动2部步进电机,购买的设备驱动板是和树莓派3B定制的扩展版DRV8825芯片,可以驱动2个电机。整体项目是.net core的根据提供的案例,改写成C#版的。

工作硬件准备

1、硬件:树莓派3B+32GSD卡,DRV8825扩展版,SM24240两相步进电机2个,12V独立电源

2、软件:Windows IoT Core、VS2022

展示一下硬件图片,整体组装后还是比较干净利索。

扩展版,可以通过拨码开关组合支持驱动细分。全部、半步、1/4、1/8、1/16、1/32一共6种细分

电机接口支持3种,但是能同时驱动的就是2部,接口不同但是线路相同的。

根据厂家的Python示例,看到驱动不是用PWM而是用GPIO的高低电平切换,来模拟PWM。

根据代码的语义,用C#重新翻译一下。

在.Net Core下有2种GPIO库,一个是VS开发ID已经集成好的Windows.Devices.Gpio,这里面把Gpio都对象化处理,明显是按照面向对象的方式,每一个Pin都是一个对象。另一个是需要单独引用的System.Device.Gpio,这个库根据说明是微软为了适应IoT各种开发环境特意发布的,功能更强。Gpio通过Controller统一控制,没有把每个GPIO对象化。

Python源码示例

import RPi.GPIO as GPIO
import time

MotorDir = [
    'forward',
    'backward',
]

ControlMode = [
    'hardward',
    'softward',
]

class DRV8825():
    def __init__(self, dir_pin, step_pin, enable_pin, mode_pins):
        self.dir_pin = dir_pin
        self.step_pin = step_pin        
        self.enable_pin = enable_pin
        self.mode_pins = mode_pins
        
        GPIO.setmode(GPIO.BCM)
        GPIO.setwarnings(False)
        GPIO.setup(self.dir_pin, GPIO.OUT)
        GPIO.setup(self.step_pin, GPIO.OUT)
        GPIO.setup(self.enable_pin, GPIO.OUT)
        GPIO.setup(self.mode_pins, GPIO.OUT)
        
    def digital_write(self, pin, value):
        GPIO.output(pin, value)
        
    def Stop(self):
        self.digital_write(self.enable_pin, 0)
    
    def SetMicroStep(self, mode, stepformat):
        """
        (1) mode
            'hardward' :    Use the switch on the module to control the microstep
            'software' :    Use software to control microstep pin levels
                Need to put the All switch to 0
        (2) stepformat
            ('fullstep', 'halfstep', '1/4step', '1/8step', '1/16step', '1/32step')
        """
        microstep = {'fullstep': (0, 0, 0),
                     'halfstep': (1, 0, 0),
                     '1/4step': (0, 1, 0),
                     '1/8step': (1, 1, 0),
                     '1/16step': (0, 0, 1),
                     '1/32step': (1, 0, 1)}

        print ("Control mode:",mode)
        if (mode == ControlMode[1]):
            print ("set pins")
            self.digital_write(self.mode_pins, microstep[stepformat])
        
    def TurnStep(self, Dir, steps, stepdelay=0.005):
        if (Dir == MotorDir[0]):
            print ("forward")
            self.digital_write(self.enable_pin, 1)
            self.digital_write(self.dir_pin, 0)
        elif (Dir == MotorDir[1]):
            print ("backward")
            self.digital_write(self.enable_pin, 1)
            self.digital_write(self.dir_pin, 1)
        else:
            print ("the dir must be : 'forward' or 'backward'")
            self.digital_write(self.enable_pin, 0)
            return

        if (steps == 0):
            return
            
        print ("turn step:",steps)
        for i in range(steps):
            self.digital_write(self.step_pin, True)
            time.sleep(stepdelay)
            self.digital_write(self.step_pin, False)
            time.sleep(stepdelay)

C#改写工作类(1)使用Windows.Devices.Gpio类库

using Recyclable.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
using Windows.Devices.Gpio;
namespace Recyclable.Services
{
    internal class DRV8825
    {
        GpioPin _DirPin;
        GpioPin _StepPin;
        GpioPin _EnablePin;
        List<GpioPin> _ModelPins;
        Dictionary<string, int[]> _MicroStep;
        /// <summary>
        /// 方向引脚
        /// </summary>
        /// <param name="dirpin">方向引脚13</param>
        /// <param name="steppin">步进引脚19</param>
        /// <param name="enablepin">使能引脚12</param>
        /// <param name="modelpins">细分引脚</param>
        public DRV8825(int dirpin, int steppin, int enablepin, int[] modelpins)
        {
            _MicroStep = new Dictionary<string, int[]>
            {
                {"fullstep", new int[] {0, 0, 0 } },
                {"halfstep", new int[] {1, 0, 0 } },
                {"1/4step", new int[] {0, 1, 0 } },
                {"1/8step", new int[] {1, 1, 0 } },
                {"1/16step", new int[] {0, 0, 1 } },
                {"1/32step", new int[] {1, 0, 1 } }
            };

            var controller = GpioController.GetDefault();
            _ModelPins = new List<GpioPin>();
            _DirPin = controller.OpenPin(dirpin);
            _DirPin.SetDriveMode(GpioPinDriveMode.Output);

            _StepPin = controller.OpenPin(steppin);
            _StepPin.SetDriveMode(GpioPinDriveMode.Output);

            _EnablePin = controller.OpenPin(enablepin);
            _EnablePin.SetDriveMode(GpioPinDriveMode.Output);

            foreach (var pin in modelpins)
            {
                controller.TryOpenPin(pin, GpioSharingMode.Exclusive, out GpioPin p, out GpioOpenStatus status);
                p.SetDriveMode(GpioPinDriveMode.Output);
                _ModelPins.Add(p);
            }
        }
        public void SetMicroStep(ControlMode mode, string stepformat)
        {
            if (mode == ControlMode.Softward)
            {
                var format = _MicroStep[stepformat];
                for (int i = 0; i < format.Length; i++)
                {
                    _ModelPins[i].Write((GpioPinValue)format[i]);
                }
            }
        }
        public void Stop()
        {
            _EnablePin.Write(GpioPinValue.Low);
        }

        public async Task TurnStepAsync(MotorDirection dir, int steps, int delay)
        {
            SetMicroStep(ControlMode.Softward, "fullstep");
            _EnablePin.Write(GpioPinValue.High);
            if (dir == MotorDirection.Forward)
            {
                _DirPin.Write(GpioPinValue.Low);
            }
            else
            {
                _DirPin.Write(GpioPinValue.High);
            }
            if (steps > 0)
            {
                for (int i = 0; i < steps; i++)
                {
                    _StepPin.Write(GpioPinValue.High);
                    await Task.Delay(delay);
                    _StepPin.Write(GpioPinValue.Low);
                    await Task.Delay(delay);
                }

            }
        }
    }
}

C#改写工作类(2)使用System.Devices.Gpio类库

using Recyclable.Models;
using System.Collections.Generic;
using System.Device.Gpio;
using System.Threading.Tasks;

namespace Recyclable.Services
{
    internal class DRV88252
    {
        int _DirPin;
        int _StepPin;
        int _EnablePin;
        int[] _ModelPins;
        Dictionary<string, int[]> _MicroStep;

        GpioController _Controller;
        /// <summary>
        /// 方向引脚
        /// </summary>
        /// <param name="dirpin">方向引脚13</param>
        /// <param name="steppin">步进引脚19</param>
        /// <param name="enablepin">使能引脚12</param>
        /// <param name="modelpins">细分引脚</param>
        public DRV88252(int dirpin, int steppin, int enablepin, int[] modelpins)
        {           
            _DirPin = dirpin;
            _StepPin = steppin;
            _EnablePin = enablepin;
            _ModelPins = modelpins;
            _MicroStep = new Dictionary<string, int[]>
            {
                {"fullstep", new int[] {0, 0, 0 } },
                {"halfstep", new int[] {1, 0, 0 } },
                {"1/4step", new int[]  {0, 1, 0 } },
                {"1/8step", new int[]  {1, 1, 0 } },
                {"1/16step", new int[] {0, 0, 1 } },
                {"1/32step", new int[] {1, 0, 1 } }
            };

            _Controller = new GpioController(PinNumberingScheme.Logical);
            _Controller.OpenPin(_DirPin);
            _Controller.SetPinMode(_DirPin, PinMode.Output);
            _Controller.OpenPin(_StepPin);
            _Controller.SetPinMode(_StepPin, PinMode.Output);
            _Controller.OpenPin(_EnablePin);
            _Controller.SetPinMode(_EnablePin, PinMode.Output);

            Stop();

            foreach (var pin in _ModelPins)
            {
                _Controller.OpenPin(pin);
                _Controller.SetPinMode(pin, PinMode.Output);
            }
        }
        public void SetMicroStep(ControlMode mode, string stepformat)
        {
            if (mode == ControlMode.Softward)
            {
                var format = _MicroStep[stepformat];
                for (int i = 0; i < format.Length; i++)
                {
                    _Controller.Write(_ModelPins[i], (PinValue)format[i]);
                }
            }
        }
        public void Stop()
        {
            _Controller.Write(_EnablePin, PinValue.Low);
        }

        public async Task TurnStepAsync(MotorDirection dir, int steps, int delay)
        {
            //SetMicroStep(ControlMode.Softward, "1/32step");
            _Controller.Write(_EnablePin, PinValue.High);
            if (dir == MotorDirection.Forward)
            {
                _Controller.Write(_DirPin, PinValue.Low);
            }
            else
            {
                _Controller.Write(_DirPin, PinValue.High);
            }
            if (steps > 0)
            {
                for (int i = 0; i < steps; i++)
                {
                    _Controller.Write(_StepPin, PinValue.High);
                    await Task.Delay(delay);
                    _Controller.Write(_StepPin, PinValue.Low);
                    await Task.Delay(delay);
                }

            }
        }
    }
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:cloudbbs@huaweicloud.com进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。