Gallery, Projects and General > Project Logs
X2 X-axis Stepper motor Power Feed - (possible CNC conversion?)
<< < (11/19) > >>
kvom:

--- Quote ---My issue is that I have used a lot of messy delay code in my "void CupDisplay" function. Anyone know a better way to do it?

--- End quote ---

I recoded your program to make it a bit less "messy";  Hope this helps.  Unfortunately the website messes up the formatting a bit.


--- Quote ---// define which pins our buttons are on
#define button1 PORTA.b0
#define button2 PORTA.b1
#define button3 PORTA.b2
#define YourLED1 PORTB.b0
#define YourLED2 PORTB.b1
#define YourLED3 PORTB.b2

// 3 buttons 1,2,3 linked to YourLED1, YourLED2, YourLED3
// When button is pressed corresponding LED lights and computer counts CupLED1-3
// CupLED1-3 lights.
// if YourLED = CupLED  you win - flashing. Game Resets
// else...you loose. Game Resets
char buttonPressed;   // a variable that saves our button press
char cup;
char LED[4] = {0b00000000, 0b00000001, 0b00000010, 0b00000100};
char portvals[10] = {1,2,4,2,1,2,4,2,1,2};
int delays[10] = {300,300,400,400,400,500,500,500,650,750};
void cupDisplay ()
{
  for (int i=0; i<10; i++)
    {
      PORTC = portvals;
      delay_ms = delays;
    }
  PORTC = LED[cup];
  delay_ms(1000);
  if (buttonPressed == cup)
    {
      for (int i=0; i<4; i++)
   {
     PORTB = PORTC = 7;
     delay_ms(250);
     PORTB = PORTC = 0;
     delay_ms(250);
   }
    }
  else
    {
      PORTB = PORTC = 7;
      delay_ms(2000);
    }
}

char ReadButtons ()
{
  if (button1)
    return 1;
  if (button2)
    return 2;
  if (button3)
    return 3;
  return 0;
}

void main()
{
    int adc;                // somewhere to put the ADC we read

    // PIC's have lots of hardware - in this case in order to use PORTB
    // we have to turn off the ADC's
    // All ports digital
    ADCON1 = 0x0F;
    CMCON = 0x07;
    // set all the pins on PORT B to 'off' before we start
    PORTA = PORTB = PORTC = 0;
    // set the tri-state buffer. Pins set to '1' are input, '0' are output
    // we've done this in binary to make it easier to see
    // each number is 1 pin, right hand is pin 0, left is pin 7
    TRISA = 0b11111111;
    TRISB = 0b00000000;
    TRISC = 0b00000000;
   
    // ============= Code Proper Starts ========

    while (1)    // loop forever
      {
   while ((buttonPressed = ReadButtons()) == 0);

   cup = 1;
   while (ReadButtons() > 0)     // counts while buttons are pressed
     {
       cup++;
       if (cup > 3)
         cup = 1;
     }

   switch (buttonPressed}
   {
   case 1:
       YourLED1 = 1;
       break;
   case 2:
       YourLED2= 1;
       break;
   case 3:
       YourLED3= 1;
   }
   cupDisplay ();
   PORTA = PORTB = PORTC = 0;
      }
}

--- End quote ---
raynerd:
Thanks for your suggestions, I have the speed running off a variable resistor/pot so it is basically just a twist knob to alter the speed at any point.

I like the idea of auto traverse with one button press from one side to the other and then perhaps wait for a button pressed for the return. I doubt without a multi axis cnc you would wish for it to traverse from one side to the other continuously? Maybe - and I bet it would be easy to code in the function. Also, regarding Tims suggestion of rapid traverse, I could include a button which sets an auto fast speed with a one press it returns it back to the other limit and then auto knocks off, returning back to the variable speed set by the pot for the cut.

Any more suggestions welcome!

Kvom - I really appreciate the time taken for you to run through my code. I have actually done some bits of it already myself. I had removed the duplicated "if" statements at the bottom of my code and replaced it with the "switch" statement as you have. I also managed to have a go at a loop for the delay and display sequence. I knew I should be using the for statement and have seen through googling that the use of i for a variable is common for a count. I couldn`t get it to work properly with the delays because I hadn`t put them in a delay array as you have. I totally see now why it was not working and your corrections have really helped me understand how I should have done that, thanks!

Could you or anyone else explain to me or better still show me how I could change the following code for my x-axis controller so that the actual motor stepping sequence will be carried out on an interrupt? At the present time, the motor stepping sequence ("stepMotor") is a global function and as such the PIC is not scanning anything else while carrying out this function. I believe if I put the stepMotor sequence as an interupt, it will both allow the controller unit to be functional (i.e to scan for other user input operations, stop, or "do something else!") while the motor is running and also, I believe interupts are a better timing sequence and will allow sharper control of the pulse timing. I am not to sure, therefore, if the motorStep sequence is moved to an interupt whether the use of a delay as a speed control will be changed?? Or something to do with the interupt itself being used for timing. I`m all a bit muddled up...

Chris


--- Quote ---// Function:
// Press 'mem', light comes on.
// Move left & right until at position.
// Press 'mem' light starts to flash.
// Press left or right to set that limit, light goes out and unit works as before.
// SHOULD THE MEMORY SETTING BE CHANGED TO WORK THE FOLLOWING?????
//A button that toggles free move or limited.
//at any point in either mode you can simply press the 'memory' button followed
//by left or right to set the limit.

// define which pins our buttons are on
#define right PORTC.b0
#define left PORTC.b1
#define stop PORTC.b2
#define memory PORTC.b3

// define which pins our motor is connected to
#define memoryLed PORTC.b4
#define motorLed PORTC.b5
#define step PORTC.b6
#define direction PORTC.b7

// LCD display config.
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// End LCD module connections


long tablePos = 0;
long limitLeft = -10000;
long limitRight = 10000;
int motorRun = 0;

// mode == 0 : running
// mode == 1 : setting limits
char mode = 0;

//===========================================
// this function moves the motor 1 step
// only moving if it can and also updates the table position

void stepMotor()
{
    if (!mode)                  // we only take note of the limits in mode 0 (otherwise we're setting them)
    {
    // if going right then check right limit - if greater than limit, motorRun = 0, stops motor.
        if (direction)
        {
            if (tablePos >= limitRight)
            {
                motorRun = 0;
                return;
            }
        }
        else
        {
            if (tablePos <= limitLeft)
            {
                motorRun = 0;
                return;
            }
        }
    }

    // these 3 lines step the motor
    step = 1;       // set the step line high
    delay_us(1);    // wait 1 micro second
    step = 0;       // and low again - the motor will now move one step

    // update the table position
    if (direction)
        tablePos++;
    else
        tablePos--;
}

//===========================================
// when the PIC is first switched on it will start to run at "main"

void main()
{
    char motorSpeed = 3;    // 3 = fast, 255 = slow
    char count;             // misc use
    int adc;                // somewhere to put the ADC we read

    // set ADC's
    ADCON0 = 1;         // enable ADC
    ADCON1 = 0b1110;    // enable ADC only for ADC 0

    // set all the pins on PORT B to 'off' before we start
    PORTC = 0;

    // set the tri-state buffer. Pins set to '1' are input, '0' are output
    // we've done this in binary to make it easier to see
    // each number is 1 pin, right hand is pin 0, left is pin 7
    TRISC = 0b00001111;
    TRISB = 0;
    TRISA = 0b11111111;

    while(1)
    {
        if (left) // is left button pressed?
        {  // if we get in here button must be pressed
            direction = 0;  //set direction to 0
            motorRun = 1; // start the motor
        }

        //------------------------------
        // check for right button
        if (right) // right button pressed
        {
            direction = 1;   // set direction to 1
            motorRun = 1; // start the motor
        }

        //------------------------------
        // check for stopping the motor
        if (stop)   // stop button pressed
            motorRun = 0; // stop the motor

        //------------------------------
        // handle setting the limits.
        //------------------------------
        // is memory button pressed?
        if (memory)
        {
            // wait for it to be released
            while (memory);

            // if in 'run' mode, change to 'limit set' mode
            if (!mode)
                mode = 1;
            else
            {
                // in limit set mode - wait for left or right to be pressed
                while (!left && !right) // if neither are pressed then stay here
                {
                    // be clever here and flash the memory light to show we're waiting
                    delay_ms(2);
                    count++;            // count is 8 bits (char) - when it gets to 255, the next time it increments it goes to zero
                    if (count > 128)    // 5ms * 128 is a bit over  1/4 seconds - so light should flash about 2hz
                        memoryLed = 0;
                    else
                        memoryLed = 1;
                }

                // depending on which button was pressed set the appropriate limit
                if (left)
                    limitLeft = tablePos;
                if (right)
                    limitRight = tablePos;

                // wait for left/right to be released and then we're done
                while (left || right);

                // we're finished so go back to 'run' mode
                mode = 0;
            }
        }

        //------------------------------
        // if in 'limit set' mode then light the memory LED
        if (mode == 1)
            memoryLed = 1;
        else
            memoryLed = 0;

        //------------------------------
        // step the motor
        if (motorRun)   // are we moving the motor?
        {
            motorLed = 1;
            stepMotor();

            // read the ADC and set the speed (delay)
            adc = ADC_Read(0);
            adc = adc >> 2;         // divide by 4
            if (adc < 3)
                adc = 3;
            for(count = 0; count < 10; count++)
                Delay_Cyc(adc);
        }
        else
            motorLed = 0;
        }
}

--- End quote ---
spuddevans:

--- Quote from: craynerd on January 09, 2010, 01:04:45 PM --- I could include a button which sets an auto fast speed with a one press it returns it back to the other limit and then auto knocks off, returning back to the variable speed set by the pot for the cut.

--- End quote ---

Why not code it so that the fast-traverse-button activates the fast traverse until a direction button is pressed and then released, ie you press the fast traverse button, press and hold the relevent direction button, then when the button is released then fast traverse function automatically is cancelled, returning the speed to the previously set speed via the pot.

You could code it along the lines of the fast traverse button sets a flag to "1" and then the direction button could test that flag to see if it is set, if it is then it would traverse at the high speed, and then when the direction button is released it would clear the flag thereby cancelling the fast traverse.


Tim
BobWarfield:
That's the beauty of it being a computer: you can make it do anything.

I imagine it is not all that much more costly than a regular power feed, yet it has the potential to be a lot more powerful.  Just by changing software and adding a few switches you can provide a variety of functions:

-  Fast jog
-  Slow jog with potentiometer to control speed
-  Speed readout in IPM so you can adjust to match a recommended feed.  Turn the potentiometer until you get the number
-  Or, provide a keypad to enter a feedrate
-  Push a button to set a stop.  Now the stepper will always stop after that many step pulses and you have effectively got a software stop on your feed
-  Interface a handwheel-style pulse generator
-  Simple DRO function.  Push a button to zero, and then the readout will tell you how far you've moved.

The list goes on and on.  It would not be hard to add a couple of circuits so that you can take the step/dir right out of a Mach3 breakout board.  Now you have the ability to either run the g-code via Mach or run as a manual with power feeds.


I've said for a long time the cost of fitting CNC is about the cost of power feeds and a nice DRO.

Cheers,

BW
raynerd:
Tim, excellent idea. In C it will be even easier than that:

if (left)
{
     if (fastTraverse)
     motorSpeed = **TopSpeed;
     else
     motorSpeed = **ACD_PotSpeed
Rest of move code.....
}

OK - over simplified but it won`t be far off.


Bob - your totally right and thanks for the nice ideas.

Regards
Chris

Chris
Navigation
Message Index
Next page
Previous page

Go to full version