My Homemade CNC version 2 with USB Driven PIC16F877A Driver

This is the second version of my CNC machine that is capable of cutting plywood. (see version 1)

DSCF1099

DSCF1590

Skate bearings on L-Iron bars

333

Home made mechanical encoders. I later removed these and made the system open loop.

555

The controller software.

DSCF1589

PSU, Stepper Drivers and PIC

DSCF1588 DSCF1587 DSCF1586

Sketchup Models

1

X-Axis (bed)

2 3

Y-axis with Z-axis motor attached

4

Z-axis and router

Components

* 3A Stepper motors (280 oz-in I guess)
* Cheap TB6560 stepper drivers 24V-3A
* Thread bars and double nuts
* Skate bearings on rails
* 24V 10A SMPS
* CP210x USB-TTL module.
* Homemade Firmware (CCS-C) and driver program (VC++)
* PIC16F877A (more than enough)
* 1/4 inch Trim router + 2mm HSS end mill + V-bit

PIC Program (CCS-C)

core of the code

void main()
{
    int8 c;

    Setup();

    output_high(RED_LED);

    output_low(PIN_X_EN); // disable
    output_high(PIN_Y_EN);
    output_high(PIN_Z_EN);

    delay_ms(1000);
    output_low(RED_LED);
    output_low(GREEN_LED);

    while (TRUE)
    {
       output_high(LED_READY); // RX indicator
       c = my_getc();
       output_low(LED_READY); // RX indicator
       if (c == 0xff) // reset comm
       {
          gi_CmdCount = 0;
          gi_NextCmd = 0;
          continue;
       }
       else if (c == 0xfe) // end of transmission 
       {
          while (gi_CmdCount > 0)
          {
              output_high(LED_WORKING);
              DoNext();
              output_low(LED_WORKING);
          } 
      }

      if (gi_CmdCount >= MAX_CMDS)
      {
          SendNack(ERR_MSG_LIMIT);
          gi_CmdCount = 0;
          gi_NextCmd = 0;
          continue;
      }
      set_cmd(gi_CmdCount, c);
      gi_CmdCount++;
   }
}
//------------------------------------------------------------------------------
void ConfigureDevice(int8 iScale, int8 iActive, int8 iMaxActive)
{
   gi_Active = iActive;
   gi_Active *= 100;
   gi_MaxActive = iMaxActive;
   gi_MaxActive *= 100;
   gi_Scale = iScale;

   output_low(PIN_X_EN); // disable
   output_high(PIN_Y_EN);
   output_high(PIN_Z_EN);
}
//------------------------------------------------------------------------------
void UpdateDelay()
{
   if (gi_CurActive > gi_Active)
   {
      if (gi_CurActive > 3000) 
         gi_CurActive -= 1000;
      else if (gi_CurActive > 1000) 
        gi_CurActive -= 200;
      else
        gi_CurActive -= 50;
   }
}
//------------------------------------------------------------------------------
void Move(signed int iDir, int iAxis)
{
   // Y dir: Reversed to match hardware

   switch (iAxis)
   {
   case AXIS_X:
   {
     output_bit(PIN_X_DIR, iDir == FWD ? 0 : 1);
     output_high(PIN_X_CLK);
     output_high(LED_STEPPING);
     UpdateDelay();
     delay_us(gi_CurActive);
     output_low(PIN_X_CLK);
     output_low(LED_STEPPING);
     break;
   }
   case AXIS_Y:
   {
     output_bit(PIN_Y_DIR, iDir == FWD ? 0 : 1);
     output_high(PIN_Y_CLK);
     output_high(LED_STEPPING);
     UpdateDelay();
     delay_us(gi_CurActive);
     output_low(PIN_Y_CLK);
     output_low(LED_STEPPING);

     break;
  }
  case AXIS_Z:
  {
     output_bit(PIN_Z_DIR, iDir == FWD ? 1 : 0);
     output_high(PIN_Z_CLK);
     output_high(LED_STEPPING);
     UpdateDelay();
     delay_us(gi_CurActive);
     output_low(PIN_Z_CLK);
     output_low(LED_STEPPING);

     break;
  }
 }
}
//------------------------------------------------------------------------------
void RunManual()
{
 int16 i;

 output_low(LED_READY); 

 while (input_state(PIN_MANUAL) == 1)
 {
   if (input_state(PIN_Z_UP) == 1)
   {
      delay_ms(1000);
      gi_CurActive = gi_MaxActive;

      for (i = 0; i < 32000; i++)
         Move(FWD, AXIS_Z);
   }
   else if (input_state(PIN_Z_DOWN) == 1)
   {
       delay_ms(1000);
       gi_CurActive = gi_MaxActive;

       for (i = 0; i < 32000; i++)
           Move(BWD, AXIS_Z);
   }

   output_high(LED_BUSY);
   delay_ms(50);
   output_low(LED_BUSY);
   delay_ms(50);
 }

 delay_ms(1000);
}
//------------------------------------------------------------------------------
void DoNext()
{
   int8 cmd;
   sint16 a;
   int8 i;
   signed int m;
   signed int n;
   signed int k;

   cmd = get_cmd(gi_NextCmd);
   gi_NextCmd++;
   gi_CmdCount--;

   if (cmd == MOVE_XYZ)
   {
      if (gi_CmdCount < 2)
      {
         SendNack(ERR_ARGC);
         gi_CmdCount = 0;
         gi_NextCmd = 0;
         return;
      }
      m = get_cmd(gi_NextCmd) - 125; // distance
      gi_NextCmd++;
      gi_CmdCount--;
      n = get_cmd(gi_NextCmd) - 125; // axis
      gi_NextCmd++;
      gi_CmdCount--;
      gi_CurActive = gi_MaxActive;
      k = (m < 0 ? BWD : FWD);
      a = gi_Scale * abs(m);
     output_high(PIN_X_EN); // enable
     output_low(PIN_Y_EN);
     output_low(PIN_Z_EN);

     while (a > 0)
     {
        for (i = 0; i < 16; i++)
           Move(k, n);
        a--;

        /*if (input_state(PIN_MANUAL) == 1)
          {
              delay_ms(1000);
              RunManual();
              gi_CurActive = gi_MaxActive;
           }*/
      }

       output_low(PIN_X_EN); // disable
       output_high(PIN_Y_EN);
       output_high(PIN_Z_EN);

        gi_CurActive = gi_MaxActive;
    }
    else if (cmd == CONFIGURE_DEVICE)
    {
        if (gi_CmdCount < 3)
        {
             SendNack(ERR_ARGC);
             return;
        }
        m = get_cmd(gi_NextCmd); // scale
        gi_NextCmd++;
        gi_CmdCount--;
        k = get_cmd(gi_NextCmd); // active 
        gi_NextCmd++;
        gi_CmdCount--;

        i = get_cmd(gi_NextCmd); // max active 
        gi_NextCmd++;
        gi_CmdCount--;

        ConfigureDevice(m, k, i);
   }
   else
   {
      SendNack(ERR_NO_SUCH_CMD);
      gi_CmdCount = 0;
      gi_NextCmd = 0;
      return;
   }
   if (gi_CmdCount == 0) // All cmds executed 
   {
       gi_NextCmd = 0;
       SendAck();
   }
}

6 thoughts on “My Homemade CNC version 2 with USB Driven PIC16F877A Driver

  1. Pingback: Homemade CNC v1 | Rajith's Workbench

  2. Pingback: My Homemade CNC version 3 driven by LinuxCNC and TB6560 Drivers | Rajith's Workbench

    • Keep the cnc dream aside. You should first try to create a sturdy linear motion with hardware available to you. You probably need v-grove bearings or some alternative bearing assembly as I have used. You have to understand how a threaded rod and a nut is used to make a linear motion. You should use a proper stepper driver. Do not use homemade drivers at the beginning. cheap TB6560 drivers worked for me. And strong enough stepper motors (rated more than 1A). You can use NEMA steppers. Cylindrical shaped steppers salvaged from printers won’t work here.
      For the step generation, the easiest way is to use a pc with a parallel port along with LinuxCNC (free) or Mach software. If you really cannot find such thing you can go for an Arduino. You should not try to write your own driver firmware at this moment. Stepper motors are not innocent things. They won’t rotate as expected if you ignore proper timing of pulses. There are arduino firmware projects in the internet for driving a cnc.
      It is good to look at my other CNCs and lots of other cncs in the internet.

  3. Ok.first i will try a linear motion, but i didn.t understand how the motion is controlled: counting the number of steps or counting the time? And wich hardware does this: the cnc interface or the computer? I apologise for my english If isn.t to well but i.m from Romania. Eventualy If You have some links where i can read more about cnc to understand good can You five me? Thank You for your answers.

    • Motion is controlled by the number of pulses not the timing. Pulses are generated by the software not the stepper driver(i.e pc parallel port or the microcontroller. You cannot use serial to parallel or usb to parallel convertors). 1pulse =1.8 degree rotation = few micrometers of linear movement of the nut.
      First observe the pinout of the stepper driver. http://m.ebay.com/itm/221498779603
      Direction pin is set to low or high which selects the direction of the rotation. Second pin is for stepping signals. four outputs are directly connected to the motor. Connect a bipolar stepper to the driver and you can rotate it giving pulses by hand. You should have some understanding of electronics.
      Google is your friend here. Search for following topics. Bipolar stepper pinout, single axis stepper controller, leadscrew, stepper resonance, pull up resistor, homemade cnc, getting started with arduino. Let me know what kind of hardware available to you.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s