Main Site Documentation

Adafruit Motor Shield for Arduino


#1

Hi Everyone,

Has anyone tried to use this motor control by Adafruit.com http://www.adafruit.com/blog/2008/02/19/new-kit-arduino-dc-motorstepperservo-control/? Its a shield made for Arduino but I figured we could use if on the FEZ Domino because Domino is suppose to be Arduino compatible.

It is a pretty powerful product controlling quite a variety and quantity of motor types. But I am not sure how to go about creating a library for it. I am looking for ideas and approaches that I can use to get this thing running.

Thanks everyone!


#2

It should work fine. The only question I have is how steppers are controlled? If it is using a stepper motor controller (SPI or PWM) then moving stepper is easy. If it is using raw IOs to control the stepper then your are limited because of the fact NETMF is not real time.


#3

Motor speed control and servo control is done via PWM.

Motor direction, and thus stepper control, is done via an 8 bit shift register. This will probably be a bit slow for stepper control…

It might work ok for motor control though…

see http://www.ladyada.net/images/mshield/mshieldv1-schem.png

Thanks,
Errol


#4

I am not versed in these types. Can you provide some additional info on why do you think bit shifting is slow?


#5

The shifter isn’t connected to the SPI bus.

Thus to change one bit on the shifter you have to shift eight bits out, one by one.

The code will be something like this:


        public void SendByte(byte b)
        {
            DIR_EN = 0;//Enable shifter outputs outputs
            DIR_CLK = 0;
            for (byte index = 0; index < 8; index++)
            {
                if ((b & 0x01) > 0)
                {
                    DIR_SER = 1;//Next bit is 1
                }
                else
                {
                    DIR_SER = 0;//Next bit is 0
                }
                DIR_CLK = 1;//toggle clock to shift bit into shifter
                DIR_CLK = 0;//ditto.
                b = b > 1;//Shift b one place right.
            }
            //Done shifting into shift register.
            DIR_LATCH = 1;//move contents from shift register to output of chip
            DIR_LATCH = 0;
        }

This is just pseudo code, don’t use… :slight_smile:

If you want to run a stepper then you will have to run that code for every step. If you want any speed then this will keep the cpu busy with little time for anything else…

If you just want to use motors then you only need to run that code when a motor must change direction…


#6

Here is the real code to talk to that shift register on the shield.


#7

If anyone has an interest in working with me to get this Adafruit motor controller working and to build a c# library for it please let me know.


#8

I have been interested in that shield and would very much like to help. I will have to order one when I can.


#9

Great Bob! Please do order one. I have mine build but so far it is just a brick.

I have been reading this article and I believe it is a great start. http://www.google.com/url?sa=t&source=web&cd=1&sqi=2&ved=0CBUQFjAA&url=http%3A%2F%2Fwww.csulb.edu%2F~hill%2Fee347%2FLectures%2FAdafruitPart1SPI.pdf&ei=-f8ATZ9xyqzwBovbrbIH&usg=AFQjCNEwbrJwyysTL7EY6diIwbNxPoSJZA&sig2=pul7wskBuOVOfQr0PtokAw

Like the author, I am a complete novice when it comes to electronics but my experience is in application development using .Net and C#.

Contact me via email at: timothyodell at gmail dot com

And we can discuss an approach.


#10

What happened to you Bob?


#11

Sorry, somehow I missed your message. I will write soon.


#12

If anyone else has an interest in this I sure would appreciate the help. Thanks


#13

Hi everyone!

I am novice in this but I am working on a project that involves controlling 3 DC motors, 2 DC servos and 1 DC Stepper. I have purchased Adafruit Motor Shield and trying to port Netduino driver for it with limited success.

Here is original Netduino driver:


using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;

namespace NetduinoApplication1
{
    // taken from http://forums.netduino.com/index.php?/topic/780-netduino-with-adafruit-motor-shield/
    // As mentioned previously, the Netduino only has 4 PWM pins. 
    // On the Adafruit MotorShield pins 5 and 6 are connected to M3/M4, 
    // while 9 and 10 are connected to the servo headers in the top left.


    public sealed class MotorShield
    {
        public const Cpu.Pin PWM_0A = Pins.GPIO_PIN_D6; // M4
        public const Cpu.Pin PWM_0B = Pins.GPIO_PIN_D5; // M3

        private static MotorShield _instance = new MotorShield();
        public static MotorShield Instance { get { return _instance; } }

        private OutputPort _motorLatch;
        private OutputPort _motorClock;
        private OutputPort _motorEnable;
        private OutputPort _motorData;

        internal byte LatchState = 0x00;

        private MotorShield()
        {
            _motorLatch = new OutputPort(Pins.GPIO_PIN_D12, false);
            _motorClock = new OutputPort(Pins.GPIO_PIN_D4, false);
            _motorEnable = new OutputPort(Pins.GPIO_PIN_D7, false);
            _motorData = new OutputPort(Pins.GPIO_PIN_D8, false);
        }

        internal void LatchTx()
        {
            //LATCH_PORT &= ~_BV(LATCH);
            _motorLatch.Write(false);

            //SER_PORT &= ~_BV(SER);
            _motorData.Write(false);

            for (int i = 0; i < 8; i++)
            {
                //CLK_PORT &= ~_BV(CLK);
                _motorClock.Write(false);

                int mask = (1 << (7 - i));
                if ((LatchState & mask) != 0)
                {
                    //SER_PORT |= _BV(SER);
                    _motorData.Write(true);
                }
                else
                {
                    //SER_PORT &= ~_BV(SER);
                    _motorData.Write(false);
                }
                //CLK_PORT |= _BV(CLK);
                _motorClock.Write(true);
            }
            //LATCH_PORT |= _BV(LATCH);
            _motorLatch.Write(true);
        }
    }

    public sealed class DcMotor
    {
        private PWM _pwm;
        private byte _motorBitA, _motorBitB;

        public DcMotor(MotorHeaders header)
        {
            switch (header)
            {
                case MotorHeaders.M3:
                    _motorBitA = (int)MotorBits.Motor3_A;
                    _motorBitB = (int)MotorBits.Motor3_B;
                    _pwm = new PWM(MotorShield.PWM_0B);
                    break;
                case MotorHeaders.M4:
                    _motorBitA = (int)MotorBits.Motor4_A;
                    _motorBitB = (int)MotorBits.Motor4_B;
                    _pwm = new PWM(MotorShield.PWM_0A);
                    break;
                default:
                    throw new InvalidOperationException("Invalid motor header specified.");
            }

            MotorShield.Instance.LatchState &= (byte)(~(1 << _motorBitA) & ~(1 << _motorBitB));
            MotorShield.Instance.LatchTx();

            _pwm.SetPulse(100, 0);
        }

        public void Run(MotorDirection dir)
        {
            switch (dir)
            {
                case MotorDirection.Release:
                    MotorShield.Instance.LatchState &= (byte)(~(1 << _motorBitA));
                    MotorShield.Instance.LatchState &= (byte)(~(1 << _motorBitB));
                    break;
                case MotorDirection.Forward:
                    MotorShield.Instance.LatchState |= (byte)(1 << _motorBitA);
                    MotorShield.Instance.LatchState &= (byte)(~(1 << _motorBitB));
                    break;
                case MotorDirection.Reverse:
                    MotorShield.Instance.LatchState &= (byte)(~(1 << _motorBitA));
                    MotorShield.Instance.LatchState |= (byte)(1 << _motorBitB);
                    break;
                default:
                    throw new InvalidOperationException("Invalid motor direction specified");
            }

            MotorShield.Instance.LatchTx();
        }

        public void SetSpeed(uint speed)
        {
            if (speed > 100)
            {
                speed = 100;
            }

            _pwm.SetDutyCycle(speed);
        }
    }

    public sealed class Stepper
    {
 #if MICROSTEPS_8
                                private static byte[] microstepCurve = {0, 50, 98, 142, 180, 212, 236, 250, 255};
 #else
        private static byte[] microstepCurve = { 0, 25, 50, 74, 98, 120, 141, 162, 180, 197, 212, 225, 236, 244, 250, 253, 255 };
 #endif

        /// <summary>
        /// Steps per revolution
        /// </summary>
        public readonly uint StepsPerRevolution;

        /// <summary>
        /// The port to which the stepper is connected
        /// </summary>
        public readonly StepperPorts stepperPort;

        private uint usPerStep, stepCounter;
        private uint currentStep = 0;
        private PWM coilA, coilB;
        private uint microsteps;

        public enum StepperPorts
        {
            //M1_M2,
            M3_M4,
        }

        public enum StepType
        {
            /// <summary>
            /// Single Coil activation
            /// </summary>
            Single,
            /// <summary>
            /// Double Coil activation
            /// </summary>
            /// <remarks>Higher torque than Single</remarks>
            Double,
            /// <summary>
            /// Alternating between Single and Double.
            /// </summary>
            /// <remarks>Twice the resolution, but half the speed</remarks>
            Interleave,
            /// <summary>
            /// 
            /// </summary>
            Microstep,
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="stepsPerRev">The number of steps per complete revolution of the output shaft</param>
        /// <param name="port">The port to which the stepper is connected</param>
        public Stepper(uint stepsPerRev, StepperPorts port)
        {
            StepsPerRevolution = stepsPerRev;
            stepperPort = port;
            currentStep = 0;
            microsteps = (uint)microstepCurve.Length;

            int latchState = 0;
            switch (stepperPort)
            {
                /*
                case StepperPorts.M1_M2:
                        // Turn off all motor pins
                        latchState &= ~(1 << (int)MotorBits.Motor1_A) & 
                                                  ~(1 << (int)MotorBits.Motor1_B) & 
                                                  ~(1 << (int)MotorBits.Motor2_A) &
                                                  ~(1 << (int)MotorBits.Motor2_B);

                        coilA = new PWM(PwmPins.pwm2A);
                        coilB = new PWM(PwmPins.pwm2B);
                        break;
                 */
                case StepperPorts.M3_M4:
                    // turn off all motor pins
                    latchState &= ~(1 << (int)MotorBits.Motor3_A) &
                                              ~(1 << (int)MotorBits.Motor3_B) &
                                              ~(1 << (int)MotorBits.Motor4_A) &
                                              ~(1 << (int)MotorBits.Motor4_B);

                    coilA = new PWM(MotorShield.PWM_0B);
                    coilB = new PWM(MotorShield.PWM_0A);
                    break;
                default:
                    throw new InvalidOperationException("Invalid motor header specified");
            }

            MotorShield.Instance.LatchState = (byte)latchState;
            MotorShield.Instance.LatchTx(); // Enable channels
            coilA.SetPulse(1000000 / 64000, 0); // 64KHz microstep pwm
            coilB.SetPulse(1000000 / 64000, 0); // 64KHz microstep pwm
        }

        /// <summary>
        /// Move the stepper a specific number of steps
        /// </summary>
        /// <param name="steps">How many steps to move</param>
        /// <param name="dir">The direction in which to rotate</param>
        /// <param name="style">The type of stepping to perform</param>
        public void Step(uint steps, MotorDirection dir, StepType style = StepType.Single)
        {
            uint uspers = usPerStep;
            uint ret = 0;

            if (style == StepType.Interleave)
            {
                uspers /= 2;
            }
            else if (style == StepType.Microstep)
            {
                uspers /= microsteps;
                steps *= microsteps;
            }

            while (steps-- > 0)
            {
                ret = OneStep(dir, style);
                Thread.Sleep((int)uspers / 1000); // in ms
                stepCounter += (uspers % 1000);
                if (stepCounter >= 1000)
                {
                    Thread.Sleep(1);
                    stepCounter -= 1000;
                }
            }

            if (style == StepType.Microstep)
            {
                while ((ret != 0) && (ret != microsteps))
                {
                    ret = OneStep(dir, style);
                    Thread.Sleep((int)uspers / 1000); // in ms
                    stepCounter += (uspers % 1000);
                    if (stepCounter >= 1000)
                    {
                        Thread.Sleep(1);
                        stepCounter -= 1000;
                    }
                }
            }

        }

        /// <summary>
        /// Sets the stepper speed
        /// </summary>
        /// <param name="rpm">The speed in revolutions per minute</param>
        public void SetSpeed(uint rpm)
        {
            usPerStep = 60000000 / (StepsPerRevolution * rpm);
            stepCounter = 0;
        }

        /// <summary>
        /// Movse the stepper one step
        /// </summary>
        /// <param name="dir">The direction in which to move</param>
        /// <param name="style">The type of stepping to use</param>
        /// <returns>Current step count</returns>
        protected uint OneStep(MotorDirection dir, StepType style = StepType.Single)
        {
            byte a, b, c, d;
            byte ocrb, ocra;

            ocra = ocrb = 255;
            switch (stepperPort)
            {
                /*
                case StepperPorts.M1_M2;
                        a = (1<<(int)MotorBits.Motor1_A);
                        b = (1<<(int)MotorBits.Motor2_A);
                        c = (1<<(int)MotorBits.Motor1_B);
                        d = (1<<(int)MotorBits.Motor2_B);
                        break;
                */
                case StepperPorts.M3_M4:
                    a = (1 << (int)MotorBits.Motor3_A);
                    b = (1 << (int)MotorBits.Motor4_A);
                    c = (1 << (int)MotorBits.Motor3_B);
                    d = (1 << (int)MotorBits.Motor4_B);
                    break;
                default:
                    return 0;
            }

            // next determine what sort of stepping procedure we're up to
            if (style == StepType.Single)
            {
                if ((currentStep / (microsteps / 2)) % 2 == 0) // we're at an odd step, weird
                {
                    if (dir == MotorDirection.Forward)
                    {
                        currentStep += microsteps / 2;
                    }
                    else
                    {
                        currentStep -= microsteps / 2;
                    }
                }
                else // go to the next even step
                {
                    if (dir == MotorDirection.Forward)
                    {
                        currentStep += microsteps;
                    }
                    else
                    {
                        currentStep -= microsteps;
                    }
                }
            }

            else if (style == StepType.Double)
            {
                if ((currentStep / (microsteps / 2) % 2) != 0) // we're at an even step, weird
                {
                    if (dir == MotorDirection.Forward)
                    {
                        currentStep += microsteps / 2;
                    }
                    else
                    {
                        currentStep -= microsteps / 2;
                    }
                }
                else  // go to the next odd step
                {
                    if (dir == MotorDirection.Forward)
                    {
                        currentStep += microsteps;
                    }
                    else
                    {
                        currentStep -= microsteps;
                    }
                }
            }

            else if (style == StepType.Interleave)
            {
                if (dir == MotorDirection.Forward)
                {
                    currentStep += microsteps / 2;
                }
                else
                {
                    currentStep -= microsteps / 2;
                }
            }

            if (style == StepType.Microstep)
            {
                if (dir == MotorDirection.Forward)
                {
                    currentStep++;
                }
                else
                {
                    // BACKWARDS
                    currentStep--;
                }

                currentStep += microsteps * 4;
                currentStep %= microsteps * 4;

                ocra = ocrb = 0;
                if ((currentStep >= 0) && (currentStep < microsteps))
                {
                    ocra = microstepCurve[microsteps - currentStep];
                    ocrb = microstepCurve[currentStep];
                }
                else if ((currentStep >= microsteps) && (currentStep < microsteps * 2))
                {
                    ocra = microstepCurve[currentStep - microsteps];
                    ocrb = microstepCurve[microsteps * 2 - currentStep];
                }
                else if ((currentStep >= microsteps * 2) && (currentStep < microsteps * 3))
                {
                    ocra = microstepCurve[microsteps * 3 - currentStep];
                    ocrb = microstepCurve[currentStep - microsteps * 2];
                }
                else if ((currentStep >= microsteps * 3) && (currentStep < microsteps * 4))
                {
                    ocra = microstepCurve[currentStep - microsteps * 3];
                    ocrb = microstepCurve[microsteps * 4 - currentStep];
                }
            }

            currentStep += microsteps * 4;
            currentStep %= microsteps * 4;

            coilA.SetDutyCycle(ocra);
            coilB.SetDutyCycle(ocrb);

            // release all
            MotorShield.Instance.LatchState &= (byte)(~a & ~b & ~c & ~d); // all motor pins to 0

            //Serial.println(step, DEC);
            if (style == StepType.Microstep)
            {
                if ((currentStep >= 0) && (currentStep < microsteps))
                    MotorShield.Instance.LatchState |= (byte)(a | b);
                if ((currentStep >= microsteps) && (currentStep < microsteps * 2))
                    MotorShield.Instance.LatchState |= (byte)(b | c);
                if ((currentStep >= microsteps * 2) && (currentStep < microsteps * 3))
                    MotorShield.Instance.LatchState |= (byte)(c | d);
                if ((currentStep >= microsteps * 3) && (currentStep < microsteps * 4))
                    MotorShield.Instance.LatchState |= (byte)(d | a);
            }
            else
            {
                switch (currentStep / (microsteps / 2))
                {
                    case 0:
                        MotorShield.Instance.LatchState |= (byte)(a); // energize coil 1 only
                        break;
                    case 1:
                        MotorShield.Instance.LatchState |= (byte)(a | b); // energize coil 1+2
                        break;
                    case 2:
                        MotorShield.Instance.LatchState |= (byte)(b); // energize coil 2 only
                        break;
                    case 3:
                        MotorShield.Instance.LatchState |= (byte)(b | c); // energize coil 2+3
                        break;
                    case 4:
                        MotorShield.Instance.LatchState |= (byte)(c); // energize coil 3 only
                        break;
                    case 5:
                        MotorShield.Instance.LatchState |= (byte)(c | d); // energize coil 3+4
                        break;
                    case 6:
                        MotorShield.Instance.LatchState |= (byte)(d); // energize coil 4 only
                        break;
                    case 7:
                        MotorShield.Instance.LatchState |= (byte)(d | a); // energize coil 1+4
                        break;
                }
            }

            MotorShield.Instance.LatchTx();
            return currentStep;
        }

        /// <summary>
        /// Releases the motor, allowing it to spin freely
        /// </summary>
        public void Release()
        {
            int latchState = 0;

            switch (stepperPort)
            {
                /*
                case StepperPorts.M1_M2:
                        // Turn off all motor pins
                        latchState &= ~(1 << (int)MotorBits.Motor1_A) &
                                                  ~(1 << (int)MotorBits.Motor1_B) &
                                                  ~(1 << (int)MotorBits.Motor2_A) &
                                                  ~(1 << (int)MotorBits.Motor2_B);
                        break;
                */
                case StepperPorts.M3_M4:
                    // turn off all motor pins
                    latchState &= ~(1 << (int)MotorBits.Motor3_A) &
                                              ~(1 << (int)MotorBits.Motor3_B) &
                                              ~(1 << (int)MotorBits.Motor4_A) &
                                              ~(1 << (int)MotorBits.Motor4_B);
                    break;
                default:
                    throw new InvalidOperationException("Invalid motor header specified");
            }

            MotorShield.Instance.LatchState = (byte)latchState;
            MotorShield.Instance.LatchTx(); // disable channels

            // Ste speed to 0
            coilA.SetDutyCycle(0);
            coilB.SetDutyCycle(0);

        }
    }

    public enum MotorBits
    {
        Motor4_A = 0,
        Motor4_B = 6,
        Motor3_A = 5,
        Motor3_B = 7
    }

    public enum MotorDirection
    {
        Release, Forward, Reverse
    }

    public enum MotorHeaders
    {
        M3, M4
    }
}


Here is my code:


using System;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using System.Threading;
using GHIElectronics.NETMF.Hardware;
using GHIElectronics.NETMF.FEZ;


namespace GHIElectronics.NETMF
{
   
        // taken from http://forums.netduino.com/index.php?/topic/780-netduino-with-adafruit-motor-shield/
        // As mentioned previously, the Netduino only has 4 PWM pins. 
        // On the Adafruit MotorShield pins 5 and 6 are connected to M3/M4, 
        // while 9 and 10 are connected to the servo headers in the top left.

        public sealed class MotorShield
        {
            public const Cpu.Pin PWM_0A = (Cpu.Pin)FEZ_Pin.PWM.Di10; //   Pins.GPIO_PIN_D11; // M2
            public const Cpu.Pin PWM_0B = (Cpu.Pin)FEZ_Pin.PWM.Di9;  //Pins.GPIO_PIN_D3; // M1
            public const Cpu.Pin PWM_1A = (Cpu.Pin)FEZ_Pin.PWM.Di5;  //   Pins.GPIO_PIN_D6; // M4
            public const Cpu.Pin PWM_1B = (Cpu.Pin)FEZ_Pin.PWM.Di6;  //Pins.GPIO_PIN_D5; // M3

           // public PWM Coil0A;  // M2
           // public  PWM Coil0B;  // M1
           // public  PWM Coil1A;  // M4
           // public  PWM Coil1B;  // M3
            

            private static MotorShield _instance = new MotorShield();
            public static MotorShield Instance { get { return _instance; } }

            private OutputPort _motorLatch;
            private OutputPort _motorClock;
            private OutputPort _motorEnable;
            private OutputPort _motorData;

            internal byte LatchState = 0x00;

            private MotorShield()
            {
                _motorLatch = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di12, false);
                _motorClock = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di4, false);
                _motorEnable = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di7, false);
                _motorData = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di11, false);

               // Coil0A = new PWM((PWM.Pin)FEZ_Pin.PWM.Di10);  // M2
               // Coil0B = new PWM((PWM.Pin)FEZ_Pin.PWM.Di5);  // M1
               // Coil1A = new PWM((PWM.Pin)FEZ_Pin.PWM.Di9);  // M4
               // Coil1B = new PWM((PWM.Pin)FEZ_Pin.PWM.IO4);  // M3
                //_motorData = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di8, false);
            }

            internal void LatchTx()
            {
                //LATCH_PORT &= ~_BV(LATCH);
                _motorLatch.Write(false);

                //SER_PORT &= ~_BV(SER);
                _motorData.Write(false);

                for (int i = 0; i < 8; i++)
                {
                    //CLK_PORT &= ~_BV(CLK);
                    _motorClock.Write(false);

                    int mask = (1 << (7 - i));
                    if ((LatchState & mask) != 0)
                    {
                        //SER_PORT |= _BV(SER);
                        _motorData.Write(true);
                    }
                    else
                    {
                        //SER_PORT &= ~_BV(SER);
                        _motorData.Write(false);
                    }
                    //CLK_PORT |= _BV(CLK);
                    _motorClock.Write(true);
                }
                //LATCH_PORT |= _BV(LATCH);
                _motorLatch.Write(true);
            }
        }

        public sealed class DcMotor
        {
            private PWM _pwm;
            private byte _motorBitA, _motorBitB;

            public DcMotor(MotorHeaders header)
            {
                switch (header)
                {
                    case MotorHeaders.M1:
                        _motorBitA = (int)MotorBits.Motor1_A;
                        _motorBitB = (int)MotorBits.Motor1_B;
                        _pwm = new PWM((PWM.Pin)MotorShield.PWM_0B);
                        //_pwm = new PWM(MotorShield.PWM_0B);
                        break;

                    case MotorHeaders.M2:
                        _motorBitA = (int)MotorBits.Motor2_A;
                        _motorBitB = (int)MotorBits.Motor2_B;
                        _pwm = new PWM((PWM.Pin)MotorShield.PWM_0A);
                        //_pwm = new PWM(MotorShield.PWM_0B);
                        break;

                    case MotorHeaders.M3:
                        _motorBitA = (int)MotorBits.Motor3_A;
                        _motorBitB = (int)MotorBits.Motor3_B;
                        _pwm = new PWM((PWM.Pin)MotorShield.PWM_1B);
                        //_pwm = new PWM(MotorShield.PWM_0B);
                        break;
                    case MotorHeaders.M4:
                        _motorBitA = (int)MotorBits.Motor4_A;
                        _motorBitB = (int)MotorBits.Motor4_B;
                        _pwm = new PWM((PWM.Pin)MotorShield.PWM_1A);
                        break;
                    default:
                        throw new InvalidOperationException("Invalid motor header specified.");
                }

                MotorShield.Instance.LatchState &= (byte)(~(1 << _motorBitA) & ~(1 << _motorBitB));
                MotorShield.Instance.LatchTx();

                _pwm.SetPulse(100, 0);
            }

            public void Run(MotorDirection dir)
            {
                switch (dir)
                {
                    case MotorDirection.Release:
                        MotorShield.Instance.LatchState &= (byte)(~(1 << _motorBitA));
                        MotorShield.Instance.LatchState &= (byte)(~(1 << _motorBitB));
                        break;
                    case MotorDirection.Forward:
                        MotorShield.Instance.LatchState |= (byte)(1 << _motorBitA);
                        MotorShield.Instance.LatchState &= (byte)(~(1 << _motorBitB));
                        break;
                    case MotorDirection.Reverse:
                        MotorShield.Instance.LatchState &= (byte)(~(1 << _motorBitA));
                        MotorShield.Instance.LatchState |= (byte)(1 << _motorBitB);
                        break;
                    default:
                        throw new InvalidOperationException("Invalid motor direction specified");
                }

                MotorShield.Instance.LatchTx();
            }

            public void SetSpeed(uint speed)
            {
                if (speed > 100)
                {
                    speed = 100;
                }

                //_pwm.Set(0, (byte)speed);
                _pwm.Set(500, (byte)speed);
                //_pwm.SetDutyCycle(speed);
            }
        }

        public sealed class Stepper
        {
            #if MICROSTEPS_8
                private static byte[] microstepCurve = {0, 50, 98, 142, 180, 212, 236, 250, 255};
            #else
                private static byte[] microstepCurve = { 0, 25, 50, 74, 98, 120, 141, 162, 180, 197, 212, 225, 236, 244, 250, 253, 255 };
            #endif

            /// <summary>
            /// Steps per revolution
            /// </summary>
            public readonly uint StepsPerRevolution;

            /// <summary>
            /// The port to which the stepper is connected
            /// </summary>
            public readonly StepperPorts stepperPort;

            private uint usPerStep, stepCounter;
            private uint currentStep = 0;
            private PWM coilA, coilB;
            private uint microsteps;
           // private MotorShield AFMotorSheild;

            public enum StepperPorts
            {
                M1_M2,
                M3_M4,
            }

            public enum StepType
            {
                /// <summary>
                /// Single Coil activation
                /// </summary>
                Single,
                /// <summary>
                /// Double Coil activation
                /// </summary>
                /// <remarks>Higher torque than Single</remarks>
                Double,
                /// <summary>
                /// Alternating between Single and Double.
                /// </summary>
                /// <remarks>Twice the resolution, but half the speed</remarks>
                Interleave,
                /// <summary>
                /// 
                /// </summary>
                Microstep,
            }

            /// <summary>
            /// Constructor
            /// </summary>
            /// <param name="stepsPerRev">The number of steps per complete revolution of the output shaft</param>
            /// <param name="port">The port to which the stepper is connected</param>
            public Stepper(uint stepsPerRev, StepperPorts port)
            {
                StepsPerRevolution = stepsPerRev;
                stepperPort = port;
                currentStep = 0;
                microsteps = (uint)microstepCurve.Length;
              //  AFMotorSheild = MotorShield.Instance;

                int latchState = 0;
                switch (stepperPort)
                {
                    
                    case StepperPorts.M1_M2:
                            // Turn off all motor pins
                        latchState &= ~(1 << (int)MotorBits.Motor1_A) & 
                                      ~(1 << (int)MotorBits.Motor1_B) & 
                                      ~(1 << (int)MotorBits.Motor2_A) &
                                      ~(1 << (int)MotorBits.Motor2_B);

                            //coilA = new PWM(PwmPins.pwm2A);
                            //coilB = new PWM(PwmPins.pwm2B);
                        coilA = new PWM((PWM.Pin)MotorShield.PWM_0B);
                        coilB = new PWM((PWM.Pin)MotorShield.PWM_0A);
                        //coilA = AFMotorSheild.Coil0A;
                        //coilB = AFMotorSheild.Coil0B;
                            break;
                    
                    case StepperPorts.M3_M4:
                        // turn off all motor pins
                        latchState &= ~(1 << (int)MotorBits.Motor3_A) &
                                      ~(1 << (int)MotorBits.Motor3_B) &
                                      ~(1 << (int)MotorBits.Motor4_A) &
                                      ~(1 << (int)MotorBits.Motor4_B);

                        coilA = new PWM((PWM.Pin)MotorShield.PWM_1B);
                        coilB = new PWM((PWM.Pin)MotorShield.PWM_1A);
                       // coilA = new PWM(MotorShield.PWM_0B);
                        //coilB = new PWM(MotorShield.PWM_0A);

                        //coilA = AFMotorSheild.Coil1A;
                        //coilB = AFMotorSheild.Coil1B;
                        break;
                    default:
                        throw new InvalidOperationException("Invalid motor header specified");
                }

 //               AFMotorSheild.LatchState = (byte)latchState;
 //               AFMotorSheild.LatchTx(); // Enable channels
                MotorShield.Instance.LatchState = (byte)latchState;
                MotorShield.Instance.LatchTx(); // Enable channels

                // 600 pps max !!!
                coilA.SetPulse(1000000 / 64000, 0); // 64KHz microstep pwm
                coilB.SetPulse(1000000 / 64000, 0); // 64KHz microstep pwm
            }

            /// <summary>
            /// Move the stepper a specific number of steps
            /// </summary>
            /// <param name="steps">How many steps to move</param>
            /// <param name="dir">The direction in which to rotate</param>
            /// <param name="style">The type of stepping to perform</param>
            public void Step(uint steps, MotorDirection dir, StepType style = StepType.Single)
            {
                uint uspers = usPerStep;
                uint ret = 0;

                if (style == StepType.Interleave)
                {
                    uspers /= 2;
                }
                else if (style == StepType.Microstep)
                {
                    uspers /= microsteps;
                    steps *= microsteps;
                }

                while (steps-- > 0)
                {
                    ret = OneStep(dir, style);
                    Thread.Sleep((int)uspers / 1000); // in ms
                    stepCounter += (uspers % 1000);
                    if (stepCounter >= 1000)
                    {
                        Thread.Sleep(1);
                        stepCounter -= 1000;
                    }
                }

                if (style == StepType.Microstep)
                {
                    while ((ret != 0) && (ret != microsteps))
                    {
                        ret = OneStep(dir, style);
                        Thread.Sleep((int)uspers / 1000); // in ms
                        stepCounter += (uspers % 1000);
                        if (stepCounter >= 1000)
                        {
                            Thread.Sleep(1);
                            stepCounter -= 1000;
                        }
                    }
                }

            }

            /// <summary>
            /// Sets the stepper speed
            /// </summary>
            /// <param name="rpm">The speed in revolutions per minute</param>
            public void SetSpeed(uint rpm)
            {
                usPerStep = 60000000 / (StepsPerRevolution * rpm);
                stepCounter = 0;
            }

            /// <summary>
            /// Movse the stepper one step
            /// </summary>
            /// <param name="dir">The direction in which to move</param>
            /// <param name="style">The type of stepping to use</param>
            /// <returns>Current step count</returns>
            protected uint OneStep(MotorDirection dir, StepType style = StepType.Single)
            {
                byte a, b, c, d;
                byte ocrb, ocra;

                ocra = ocrb = 255;
                switch (stepperPort)
                {

                    case StepperPorts.M1_M2:
                        a = (1 << (int)MotorBits.Motor1_A);
                        b = (1 << (int)MotorBits.Motor2_A);
                        c = (1 << (int)MotorBits.Motor1_B);
                        d = (1 << (int)MotorBits.Motor2_B);
                        break;

                    case StepperPorts.M3_M4:
                        a = (1 << (int)MotorBits.Motor3_A);
                        b = (1 << (int)MotorBits.Motor4_A);
                        c = (1 << (int)MotorBits.Motor3_B);
                        d = (1 << (int)MotorBits.Motor4_B);
                        break;
                    default:
                        return 0;
                }

                // next determine what sort of stepping procedure we're up to
                if (style == StepType.Single)
                {
                    if ((currentStep / (microsteps / 2)) % 2 == 0) // we're at an odd step, weird
                    {
                        if (dir == MotorDirection.Forward)
                        {
                            currentStep += microsteps / 2;
                        }
                        else
                        {
                            currentStep -= microsteps / 2;
                        }
                    }
                    else // go to the next even step
                    {
                        if (dir == MotorDirection.Forward)
                        {
                            currentStep += microsteps;
                        }
                        else
                        {
                            currentStep -= microsteps;
                        }
                    }
                }

                else if (style == StepType.Double)
                {
                    if ((currentStep / (microsteps / 2) % 2) != 0) // we're at an even step, weird
                    {
                        if (dir == MotorDirection.Forward)
                        {
                            currentStep += microsteps / 2;
                        }
                        else
                        {
                            currentStep -= microsteps / 2;
                        }
                    }
                    else  // go to the next odd step
                    {
                        if (dir == MotorDirection.Forward)
                        {
                            currentStep += microsteps;
                        }
                        else
                        {
                            currentStep -= microsteps;
                        }
                    }
                }

                else if (style == StepType.Interleave)
                {
                    if (dir == MotorDirection.Forward)
                    {
                        currentStep += microsteps / 2;
                    }
                    else
                    {
                        currentStep -= microsteps / 2;
                    }
                }

                if (style == StepType.Microstep)
                {
                    if (dir == MotorDirection.Forward)
                    {
                        currentStep++;
                    }
                    else
                    {
                        // BACKWARDS
                        currentStep--;
                    }

                    currentStep += microsteps * 4;
                    currentStep %= microsteps * 4;

                    ocra = ocrb = 0;
                    if ((currentStep >= 0) && (currentStep < microsteps))
                    {
                        ocra = microstepCurve[microsteps - currentStep];
                        ocrb = microstepCurve[currentStep];
                    }
                    else if ((currentStep >= microsteps) && (currentStep < microsteps * 2))
                    {
                        ocra = microstepCurve[currentStep - microsteps];
                        ocrb = microstepCurve[microsteps * 2 - currentStep];
                    }
                    else if ((currentStep >= microsteps * 2) && (currentStep < microsteps * 3))
                    {
                        ocra = microstepCurve[microsteps * 3 - currentStep];
                        ocrb = microstepCurve[currentStep - microsteps * 2];
                    }
                    else if ((currentStep >= microsteps * 3) && (currentStep < microsteps * 4))
                    {
                        ocra = microstepCurve[currentStep - microsteps * 3];
                        ocrb = microstepCurve[microsteps * 4 - currentStep];
                    }
                }

                currentStep += microsteps * 4;
                currentStep %= microsteps * 4;

                //coilA.SetDutyCycle(ocra);
                //coilB.SetDutyCycle(ocrb);
                coilA.Set(600, ocra); // 600 ppa max
                coilB.Set(600, ocrb); // 600 ppa max
                // frequency in hZ, dutycycle byte

                // release all
                MotorShield.Instance.LatchState &= (byte)(~a & ~b & ~c & ~d); // all motor pins to 0

                //Serial.println(step, DEC);
                if (style == StepType.Microstep)
                {
                    if ((currentStep >= 0) && (currentStep < microsteps))
                        MotorShield.Instance.LatchState |= (byte)(a | b);
                    if ((currentStep >= microsteps) && (currentStep < microsteps * 2))
                        MotorShield.Instance.LatchState |= (byte)(b | c);
                    if ((currentStep >= microsteps * 2) && (currentStep < microsteps * 3))
                        MotorShield.Instance.LatchState |= (byte)(c | d);
                    if ((currentStep >= microsteps * 3) && (currentStep < microsteps * 4))
                        MotorShield.Instance.LatchState |= (byte)(d | a);
                }
                else
                {
                    switch (currentStep / (microsteps / 2))
                    {
                        case 0:
                            MotorShield.Instance.LatchState |= (byte)(a); // energize coil 1 only
                            break;
                        case 1:
                            MotorShield.Instance.LatchState |= (byte)(a | b); // energize coil 1+2
                            break;
                        case 2:
                            MotorShield.Instance.LatchState |= (byte)(b); // energize coil 2 only
                            break;
                        case 3:
                            MotorShield.Instance.LatchState |= (byte)(b | c); // energize coil 2+3
                            break;
                        case 4:
                            MotorShield.Instance.LatchState |= (byte)(c); // energize coil 3 only
                            break;
                        case 5:
                            MotorShield.Instance.LatchState |= (byte)(c | d); // energize coil 3+4
                            break;
                        case 6:
                            MotorShield.Instance.LatchState |= (byte)(d); // energize coil 4 only
                            break;
                        case 7:
                            MotorShield.Instance.LatchState |= (byte)(d | a); // energize coil 1+4
                            break;
                    }
                }

                MotorShield.Instance.LatchTx();
                return currentStep;
            }

            /// <summary>
            /// Releases the motor, allowing it to spin freely
            /// </summary>
            public void Release()
            {
                int latchState = 0;

                switch (stepperPort)
                {

                    case StepperPorts.M1_M2:
                        // Turn off all motor pins
                        latchState &= ~(1 << (int)MotorBits.Motor1_A) &
                                                  ~(1 << (int)MotorBits.Motor1_B) &
                                                  ~(1 << (int)MotorBits.Motor2_A) &
                                                  ~(1 << (int)MotorBits.Motor2_B);
                        break;

                    case StepperPorts.M3_M4:
                        // turn off all motor pins
                        latchState &= ~(1 << (int)MotorBits.Motor3_A) &
                                                  ~(1 << (int)MotorBits.Motor3_B) &
                                                  ~(1 << (int)MotorBits.Motor4_A) &
                                                  ~(1 << (int)MotorBits.Motor4_B);
                        break;
                    default:
                        throw new InvalidOperationException("Invalid motor header specified");
                }

                MotorShield.Instance.LatchState = (byte)latchState;
                MotorShield.Instance.LatchTx(); // disable channels

                // Ste speed to 0
                coilA.Set(64000, 0);
                coilB.Set(64000, 0);
                //coilA.SetDutyCycle(0);
                //coilB.SetDutyCycle(0);

            }
        }

        public enum MotorBits
        {
            Motor1_A = 0,
            Motor1_B = 1,
            Motor2_A = 2,
            Motor2_B = 3,
            Motor3_A = 4,
            Motor3_B = 5,
            Motor4_A = 6,
            Motor4_B = 7
        }

        public enum MotorDirection
        {
            Release, Forward, Reverse
        }

        public enum MotorHeaders
        {
            M1, M2, M3, M4
        }
   }



I can’t figure out how to convert the following lines:


coilA.SetDutyCycle(ocra);
coilB.SetDutyCycle(ocrb);


#14

Hi !

I have made last year a driver for this shield, it used to be available on the code section, but seem to have disapeared !

Technicaly, it’s still here : http://code.tinyclr.com/project/323/adafruit-motor-shield-driver/

The image is correct, however the descrition and code are messed up with another of my drivers. Stay tunned, I am asking help from someone at GHI’s to see if they can fix it ! IF not, I will check in my archives to find it back…


#15

much appreciated! That would be great to see your version to.


#16

In the mean time, here is my code I finally found back. Have fun ;D


using System;
using System.Threading;

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.Hardware;

using GHIElectronics.NETMF.FEZ;

namespace Mshield
{
    public class Program
    {
        public static void Main()
        {
            // Initialize both driver on Motor Shield
            Mshield MyMotors = new Mshield(Mshield.Drivers.Both);

            // Create servo motors (not used in this example)
            PWM servo1 = new PWM(MyMotors.Servo1);
            PWM servo2 = new PWM(MyMotors.Servo2);

            // Blink board LED
            bool ledState = false;
            OutputPort led = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.LED, ledState);
            
            while (true)
            {
                ledState = !ledState;
                led.Write(ledState);

                // We have one motor connected on port M4 (Warning ! on some shields, M3 and M4 indications are reversed !)
                // Increase it speed to its maximum. Direction change at each loop
                for (int i = 0; i <= 255; i++, Thread.Sleep(20)) MyMotors.MotorControl(Mshield.Motors.M4, (byte)i, ledState);
                // Then decrease it to zero
                for (int i = 255; i >= 0; i--, Thread.Sleep(20)) MyMotors.MotorControl(Mshield.Motors.M4, (byte)i, ledState);
                Thread.Sleep(1000);

                // We have one stepper connected on driver1 (M0/M1)
                // Have it run 5s in "Hi-Torque" (High power, high speed, high power usage...)
                MyMotors.StepperMove(Mshield.Steppers.S1, Mshield.BipolarStepping.HiTorque, 0, true, 0, 5000, false);
                Thread.Sleep(1000);

                // Then 5s in the other direction
                MyMotors.StepperMove(Mshield.Steppers.S1, Mshield.BipolarStepping.HiTorque, 0, false, 0, 5000, false);
                Thread.Sleep(1000); 
            }
        }

    }

/*  Adafruit motor "Shield v1.0" / See: http://www.ladyada.net/make/mshield/index.html
*  Driver v0.1a - Copyright 2011 Nicolas Ricquemaque
* 
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License. 
*
* ------------------------------------------------------------------------
* 
*  The Adafruit Motor Shield can drive up to four motors (including speed and direction)
*  or max 2 steppers motors (each stepper using one of the 2 shield drivers, instead of 2 motors).
*  You can use for an example one stepper motor on ports M1 and M2, and two motors on ports M3 and M4.
*  Two servo connectors are available on the shield, directly from pins DI9 and DI10 (no control
*  of servos is made by the board or by this driver, however there use is simple, just look at the
*  beginner's guide).
*  
*  Due to the differences between The Fez boards (donimo / panda) and the original arduino, only the motors
*  connected to M3 and M4 can vary their speed. M1 and M2 have just on/off and direction choice
*  (because M1 and M2 are controlled using DI3 and DI11 which are not PWM capable on the FEZ)
*  Also, due to the same problem, and also because of timing constraints, no micro-stepping is performed
*  (that would need RLP programming which we are not doing here)
*  The handling of stepper motors is blocking untill the action requested is completed
*  However, this is not the case for simple motors: just set a state, and the motor will keep it.
*  
*  Please report bugs to f1iqf (at) hotmail (dot) com
*  
*/

public class Mshield : IDisposable
{
    public enum Drivers : byte { None = 0, Driver1, Driver2, Both }
    public enum Motors : byte { M1 = 0, M2, M3, M4 }
    public enum Steppers : byte { S1 = 0, S2 }
    public enum BipolarStepping : byte { WaveDrive = 0, HiTorque, HalfStep }
        
    /// <summary>
    /// On board Servo1 connector, for external reference only
    /// </summary>
    public PWM.Pin Servo1 = (PWM.Pin)FEZ_Pin.PWM.Di9;
    /// <summary>
    /// On board Servo2 connector, for external reference only
    /// </summary>
    public PWM.Pin Servo2 = (PWM.Pin)FEZ_Pin.PWM.Di10;

    private Drivers UsedDriver;
    private OutputPort Motor1A, Motor1B; // Enable L293D driver #1a and #1b
    private PWM Motor2A, Motor2B; // Enable L293D driver #1a and #1b
    private OutputPort MotorLatch,MotorEnable,MotorClk, MotorData; // 74HCT595 commands
    byte latch_state; // Actual 74HCT595 output state

    // Steper sequences for each stepper. Have a look here : http://www.stepperworld.com/Tutorials/pgBipolarTutorial.htm
    private byte[][] BipolarSteppingWaveDrive = new byte[][] {  new byte [] {4,2,8,16},
                                                                new byte [] {1,128,64,32}};
    private byte[][] BipolarSteppingHiTorque = new byte[][] {   new byte [] {20,24,10,6},
                                                                new byte [] {129,192,96,33}};
    private byte[][] BipolarSteppingHalfStep = new byte[][] {   new byte [] {4,20,16,24,8,10,2,6},
                                                                new byte [] {1,129,128,192,64,96,32,33}};
        
    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="driver"> Which driver to initialize : 1=driver 1, 2=driver 2, 3=both</param>
    public Mshield(Drivers driver=Drivers.Both) 
    {
        UsedDriver = driver;
        if (driver == Drivers.Driver1 || driver == Drivers.Both)
        {
            Motor1A = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di11, false);
            Motor1B = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di3, false);
        }
        if (driver == Drivers.Driver2 || driver == Drivers.Both)
        {
            Motor2A = new PWM((PWM.Pin)FEZ_Pin.PWM.Di5);
            Motor2A.Set(false);
            Motor2B = new PWM((PWM.Pin)FEZ_Pin.PWM.Di6);
            Motor2B.Set(false);
        }
        MotorLatch = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di12, true);
        MotorEnable = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di7, false);
        MotorClk = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di4, true);
        MotorData = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di8, true);

        latch_state = 0;
        latch_tx();
    }

    #region IDisposable Members
    public void Dispose()
    {
        latch_state = 0;
        latch_tx();

        if (UsedDriver == Drivers.Driver1 || UsedDriver == Drivers.Both)
        {
            Motor1A.Dispose();
            Motor1B.Dispose();
        }
        if (UsedDriver == Drivers.Driver2 || UsedDriver == Drivers.Both)
        {
            Motor2A.Dispose();
            Motor2B.Dispose();
        }
        MotorLatch.Dispose();
        MotorEnable.Dispose();
        MotorClk.Dispose();
        MotorData.Dispose();
    }
    #endregion IDisposable Members


    // Send byte to the 74HCT595 demux
    private void latch_tx ()
    {
        MotorLatch.Write(false);
        for (int i = 8; i >= 0 ; i--)
        {
            MotorClk.Write(false);
            MotorData.Write((latch_state & (1 << i))>0);
            MotorClk.Write(true);
        }
        MotorLatch.Write(true);
    }

    /// <summary>
    /// Move a stepper. Only one param between steps and msec but be set different from 0.
    /// Blocking call.
    /// </summary>
    /// <param name="which">Which stepper to drive</param>
    /// <param name="mode">Stepping mode</param>
    /// <param name="speed">Number of ms between each step (0 : no pause=max speed)</param>
    /// <param name="direction">True = foward, False = backward</param>
    /// <param name="steps">If non-zero, number of steps to run</param>
    /// <param name="msec">If non-zero, number of ms to run</param>
    /// <param name="hold">True if stepper shall stay energized when task done</param>
    /// <returns>Number of steps ran</returns>
    public uint StepperMove(Steppers which, BipolarStepping mode, int speed, bool direction, int steps, int msec, bool hold = false)
    {
        byte[] MotorSteps = BipolarSteppingWaveDrive[(byte)which]; // Get the stepping pattern
        if (mode == BipolarStepping.HiTorque) MotorSteps = BipolarSteppingHiTorque[(byte)which];
        if (mode == BipolarStepping.HalfStep) MotorSteps = BipolarSteppingHalfStep[(byte)which];

        // Find where we stopped last time
        byte last;
        int pos;
        uint step = 0;
        if (which == 0) last = (byte)(latch_state & 0x1E);
        else last = (byte)(latch_state & 0xE1);
        for (pos = 0; pos < MotorSteps.Length; pos++) if (MotorSteps[pos] == last) break;
        if (pos == MotorSteps.Length) pos = 0;

        if (which == 0) { Motor1A.Write(true); Motor1B.Write(true); }
        else { Motor2A.Set(true); Motor2B.Set(true); }

        byte Mask = (byte)((which == 0) ? 0xE1 : 0x1E);

        if (steps > 0) // user chose to move from a number of steps
        {               
            for (; step < steps; step++)
            {
                if (direction) pos = (pos + 1) % MotorSteps.Length;
                else if (--pos < 0) pos = MotorSteps.Length - 1;
                latch_state = (byte)((latch_state & Mask) | MotorSteps[pos]);
                latch_tx();
                if (speed > 0) Thread.Sleep(speed);
            }

        }
        else // So no number of steps, the user must have given a time to run
        {
            long endtime = DateTime.Now.Ticks + msec * TimeSpan.TicksPerMillisecond;
            for (; DateTime.Now.Ticks < endtime;step++ )
            {
                if (direction) pos = (pos + 1) % MotorSteps.Length;
                else if (--pos < 0) pos = MotorSteps.Length - 1;
                latch_state = (byte)((latch_state & Mask) | MotorSteps[pos]);
                latch_tx();
                if (speed > 0) Thread.Sleep(speed);
            }
        }

        if (!hold) // Remove energy from stepper
        {
            if (which == 0) { Motor1A.Write(false); Motor1B.Write(false); }
            else { Motor2A.Set(false); Motor2B.Set(false); }
        }

        return step;
    }

    /// <summary>
    /// Control a motor; Non-blocking call. Set speed to 0 to stop.
    /// Frequency might need to be adjusted deppending on motor, or to match other PWMs
    /// </summary>
    /// <param name="which">Which motor to drive</param>
    /// <param name="speed">Steed, between 0 and 255 (0 to stop, 255 = max speed)</param>
    /// <param name="direction">True = foward, False = backward</param>
    /// <param name="freq">Frequency in Hz of the PWM controlling the motor</param>
    public void MotorControl(Motors which, byte speed, bool direction, int freq=100)
    {
        uint period = (uint)(1000000000D / (double)freq);
        switch (which)
        {
            case Motors.M1: 
                latch_state = (byte)((latch_state & 0xF3) | (direction ? 4 : 8));
                latch_tx();
                Motor1A.Write(speed > 0);
                break;

            case Motors.M2:
                latch_state = (byte)((latch_state & 0xED) | (direction ? 2 : 16));
                latch_tx();
                Motor1B.Write(speed > 0);
                break;
            case Motors.M3: // This motor can have its speed controlled through PWM                  
                if (speed == 0) Motor2A.Set(false);
                else
                {
                    latch_state = (byte)((latch_state & 0xBE) | (direction ? 1 : 64));
                    latch_tx();
                    Motor2A.SetPulse(period, (uint)(period * (double)speed / 255D));
                }
                break;
            case Motors.M4: // This motor can have its speed controlled through PWM                  
                if (speed == 0) Motor2B.Set(false);
                else
                {
                    latch_state = (byte)((latch_state & 0x5F) | (direction ? 32 : 128));
                    latch_tx();
                    Motor2B.SetPulse(period, (uint)(period * (double)speed / 255D));
                }
                break;
        }
    }      
}
}



#17

Thanks Nicolas3.

Your driver looks great!

I will give it a try and let you know.

:wink:


#18

Hi Nicolas3,

Tested DC motor and stepper they work fine. Had to switch M3 and M4 to make them to work.

Great job! ;D


#19

Hi Nicolas3,

I am having strange problem with Motor Shield.
I have the following setup:

  • Panda II with 7.5v DC power supply
  • AF Motor shield with stepper (M1,M2) and two motors connected to M3 and M4 with 15v power supply. Power jumpers are removed to isolate MS from MB
  • Matrix keypad (pins 39,41,43,45,47,49,51)
  • 4 line 20 char LCD (pins 21,23,25,27,29,31)

After setting motors to some speed every time I push any button on keypad motors speed jumps to max value (voltage)

There is no function calls from keypad push button event to motor shield object.

Do you know what may be causing this behavior?

Also MotorEnable is not used in code after it is created. Is it necessarily?

Thanks in advance for your help.


#20

@ mgut, can you put breakpoints in your code and show what it is doing? OR even step through your code to see where the button press takes you.