Interface PCB Microchip PIC18F4610

Generic PIC16F / PIC18F PCB I made in 2007 repurposed for this application..

Has PIC18F4620 40 pin PDIP MCU onboard running at 5V/40mHZ

 

 

Simple firmware using CCS C IDE/Compiler


Fed the Parallel port output needed

Inputs from Mach3:

B0 = Z step

B1 = Z step direction

B2 = vacuum toggle/do it (GCode calls Mach3 vbscript macro to toggle pin)

B3 = unused

B4-B7 = Head/instruction selection prior to B0 or B2 action

Outputs:

RC0-3/RC4-7 Head up down pneumatic valve control

RD0-3, RD4-7 Head vacuum solenoid on

RE0-2: Z movement indicator & heartbeat LED

RA4: Mains Vacuum pump on / off - NOT IMPLEMENTED

RA5: Audio Buzzer on end of cycle

So..

Interrupts on B0 or B2 trigger actions

  • B0 responds to a Z step instruction from Mach 3
  • B2 responds to a vacuum toggle/do it instruction from Mach3.   It is expected that Mach 3 has set pins B4-B7 to the target stepper (Head) or canned instruction.  Note B1 (Direction) is automatically set by Mach 3 per the Z move instruction

B0 interrupt sequence:

  • Read address from PINS B4-B7 (Motor 0-15)
  • Read direction from B1
  • Turn on or off pneumatic solenoid for selected head depending on B1 direction

B2 responds to vacuum toggle instructions from Mach 3:

  • Read address from PINS B4-B7 (Motor 0-7, canned instruction 8-15)
  • If address is 0-7 toggle addressed vacuum output
  • If address is 8-15 then special functions:
    • 8 = end of cycle:
      • open all vacuum valves (temporary until we put in ssr to turn off vacuum pump)
      • set RA5 high to sound buzzer
    • 9 = start of cycle:
      • close all vacuum pumps
      • set RA5 low (no buzzer

Additionally, we display a heartbeat on RE0


Future: Move to Plug And Program MC32MX64GP mainboard but need to ensure child PCB's are 3.3v compatible..

  • More IO available
  • Can add LCD to show status, ie last address, last action
  • Has the oomph to replace Mach 3 and could do a control interface directly in the browser

Programmed in CCS C:

#include <18F4610.h>
#include  <string.h>
#include  <math.h>
#include <stdlib.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES WDT128                   //Watch Dog Timer uses 1:128 Postscale
#FUSES H4                       //High speed osc with HW enabled 4X PLL
#FUSES NOPROTECT                //Code not protected from reading
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES BORV25                   //Brownout reset at 2.5V
#FUSES PUT                      //Power Up Timer
#FUSES STVREN                   //Stack full/underflow will cause reset
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOIESO                   //Internal External Switch Over mode disabled
#FUSES NOFCMEN                  //Fail-safe clock monitor disabled
#FUSES NOPBADEN                 //PORTB pins are configured as digital I/O on RESET
#FUSES NOWRTC                   //configuration not registers write protected
#FUSES NOWRTB                   //Boot block not write protected
#FUSES NOEBTR                   //Memory not protected from table reads
#FUSES NOEBTRB                  //Boot block not protected from table reads
#FUSES NOCPB                    //No Boot Block code protection
#FUSES NOLPT1OSC                //Timer1 configured for higher power operation
#FUSES MCLR                     //Master Clear pin enabled
//#FUSES XINST                    //Extended set extension and Indexed Addressing mode enabled

#use delay(clock=40000000)


//int FullStep[8];
//int HalfStep1[8];
//int HalfStep2[8];
//int HalfStep3[8];
//int HeadPowerDownCounter;
int HeartBeatCounter;
int1 HeartBeat;

int CurrentHead;


//long Head0Position, Head1Position, Head2Position, Head3Position;
int1 Head0VacuumOn, Head1VacuumOn, Head2VacuumOn, Head3VacuumOn;

//long Head4Position, Head5Position, Head6Position, Head7Position;
int1 Head4VacuumOn, Head5VacuumOn, Head6VacuumOn, Head7VacuumOn;

// 20110907

// Inputs
// B0 is do move head up/down
// B1 is move direction
// B2 is vacuum toggle/do it
// B4-7 is 0-15 head/stepper selector

//Outputs
// C0-3/C4-7 are head pneumatic valves
// D0-3/C4-7 are Vacuum control solenoids
// E0-3 Display LEDs
// A4-5 = Buzzer & Vacuum pump SSR

void outputAllVacuums(void)
{
   output_bit(PIN_D0,Head0VacuumOn);
   output_bit(PIN_D1,Head1VacuumOn);
   output_bit(PIN_D2,Head2VacuumOn);
   output_bit(PIN_D3,Head3VacuumOn);
   
   output_bit(PIN_D4,Head4VacuumOn);
   output_bit(PIN_D5,Head5VacuumOn);
   output_bit(PIN_D6,Head6VacuumOn);
   output_bit(PIN_D7,Head7VacuumOn);
}

void setAllVacuums(int1 setting)
{
   Head0VacuumOn = Head1VacuumOn = Head2VacuumOn = Head3VacuumOn = setting;
   Head4VacuumOn = Head5VacuumOn = Head6VacuumOn = Head7VacuumOn = setting;
   outputAllVacuums();
}


#int_ext    //B0
void ext_isr(void)
{
   switch (CurrentHead)
      {
      case 0:
         if (input(PIN_B1))
         {
            output_bit(PIN_C0,1);
         }
         else
         {
            output_bit(PIN_C0,0);
         }
         break;

      case 1:
         if (input(PIN_B1))
         {
            output_bit(PIN_C1,1);
         }
         else
         {
            output_bit(PIN_C1,0);
         }
         break;
         
      case 2:
         if (input(PIN_B1))
         {
            output_bit(PIN_C2,1);
         }
         else
         {
            output_bit(PIN_C2,0);
         }
         break;
         
      case 3:
         if (input(PIN_B1))
         {
            output_bit(PIN_C3,1);
         }
         else
         {
            output_bit(PIN_C3,0);
         }
         break;
         
      case 4:
         if (input(PIN_B1))
         {
            output_bit(PIN_C4,1);
         }
         else
         {
            output_bit(PIN_C4,0);
         }
         break;
         
      case 5:
         if (input(PIN_B1))
         {
            output_bit(PIN_C5,1);
         }
         else
         {
            output_bit(PIN_C5,0);
         }
         break;
         
      case 6:
         if (input(PIN_B1))
         {
            output_bit(PIN_C6,1);
         }
         else
         {
            output_bit(PIN_C6,0);
         }
         break;
         
      case 7:
         if (input(PIN_B1))
         {
            output_bit(PIN_C7,1);
         }
         else
         {
            output_bit(PIN_C7,0);
         }
         break;
         
      }
}

#int_ext2   //B2
void ext2_isr(void)

// toggle vacuum / do it
{
   switch (CurrentHead)
      {
      // vacuum toggling
      case 0:
         Head0VacuumOn = !Head0VacuumOn;
         output_bit(PIN_D0,Head0VacuumOn);
         break;
         
      case 1:
         Head1VacuumOn = !Head1VacuumOn;
         output_bit(PIN_D1,Head1VacuumOn);
         break;
      
      case 2:
         Head2VacuumOn = !Head2VacuumOn;
         output_bit(PIN_D2,Head2VacuumOn);
         break;
         
      case 3:
         Head3VacuumOn = !Head3VacuumOn;
         output_bit(PIN_D3,Head3VacuumOn);
         break;

      case 4:
         Head4VacuumOn = !Head4VacuumOn;
         output_bit(PIN_D4,Head4VacuumOn);
         break;
         
      case 5:
         Head5VacuumOn = !Head5VacuumOn;
         output_bit(PIN_D5,Head5VacuumOn);
         break;
      
      case 6:
         Head6VacuumOn = !Head6VacuumOn;
         output_bit(PIN_D6,Head6VacuumOn);
         break;
         
      case 7:
         Head7VacuumOn = !Head7VacuumOn;
         output_bit(PIN_D7,Head7VacuumOn);
         break;
         
      // toggle/do it signal for addresses 8-15 are canned functions
      case 8:  // Buzzer off
         output_bit(PIN_A4,0);
         setAllVacuums(0);
         break;
      case 9:  // Buzzer on
         output_bit(PIN_A4,1);
         break;
      case 10:  // SSR off
         output_bit(PIN_A5,0);
         break;
      case 11:  // SSR on
         output_bit(PIN_A5,1);
         break;
      }
}


void main()
{
   //-------------------------------------
   //Startup sequence
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);

   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   
   Output_A(0);
   Output_C(0);
   Output_D(0);
   //Not all the step sequences below are used but we will leave them here
   //for future use

   HeartBeatCounter = 25;
   HeartBeat = 0;

   // Cycle through all the head selects so we can see startup on the
   // the Stepper controller PCB & cycle all vacuum solenoids
   for(CurrentHead = 0;CurrentHead<=7;++CurrentHead)
      {
      Output_D(1<<CurrentHead);
      output_bit(PIN_A4,CurrentHead&1);
      delay_ms(500);
      }
   Output_A(0);
   Output_C(0);
   Output_D(0);

   // ext_int_edge(1,H_TO_L);
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_EXT);
   enable_interrupts(INT_EXT2);
   
   // end startup squence
   //-------------------------------------  
   while(1)
   {
   // constantly monitor head selection input and pass through to head select output
   CurrentHead = (input(PIN_B7) << 3) + (input(PIN_B6) << 2) + (input(PIN_B5) << 1) + input(PIN_B4);   
      
   HeartBeatCounter -= 1;
   if (!HeartBeatCounter)
      {
      HeartBeat = !HeartBeat;
      output_bit(pin_e2,HeartBeat);
      HeartBeatCounter = 25;
      }
   }      
}