Interface PCB connections & C code pre 20110709

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/stepper/instruction selection prior to B0 or B2 action

Outputs:

RC0-3: head stepper select

RC4-7: stepper lines control

RD0-3, RD4-7: head vacuum solenoid on / off (2 banks of 4)

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
  • Move addressed motor 1 half step in required direction
  • After x ms delay, if no additional move instruction, power down targeted head (in the main loop)

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;

// 20110825

// Inputs
// B0 is step clk
// B1 is step direction
// B2 is vacuum toggle/do it
// B4-7 is 0-15 head/stepper selector

//Outputs
// C0-3 is Stepper (Head) select
// C4-7 is Stepper drive
// D0-3/C4-7 are Vacuum control
// 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
void ext_isr(void)

// step clk

{
   switch (CurrentHead)
      // As we use the low 4 bits of the port for the head select & the high
      // 4 for the stepper drivers, we need to left shift the current head position
      // then AND it with the current head selection
      {
      case 0:
         if (input(PIN_B1))
            Head0Position += 1;
          else
            Head0Position -= 1;
           output_c((HalfStep1[Head0Position&0b00000111]<<4) + CurrentHead);
         break;

      case 1:
         if (input(PIN_B1))
            Head1Position += 1;
          else
            Head1Position -= 1;
           output_c((HalfStep1[Head1Position&0b00000111]<<4) + CurrentHead);
         break;
         
      case 2:
         if (input(PIN_B1))
            Head2Position += 1;
          else
            Head2Position -= 1;
           output_c((HalfStep1[Head2Position&0b00000111]<<4) + CurrentHead);
         break;
         
      case 3:
         if (input(PIN_B1))
            Head3Position += 1;
          else
            Head3Position -= 1;
           output_c((HalfStep1[Head3Position&0b00000111]<<4) + CurrentHead);
         break;
         
      case 4:
         if (input(PIN_B1))
            Head4Position += 1;
          else
            Head4Position -= 1;
           output_c((HalfStep1[Head4Position&0b00000111]<<4) + CurrentHead);
         break;
         
      case 5:
         if (input(PIN_B1))
            Head5Position += 1;
          else
            Head5Position -= 1;
           output_c((HalfStep1[Head5Position&0b00000111]<<4) + CurrentHead);
         break;
         
      case 6:
         if (input(PIN_B1))
            Head6Position += 1;
          else
            Head6Position -= 1;
           output_c((HalfStep1[Head6Position&0b00000111]<<4) + CurrentHead);
         break;
         
      case 7:
         if (input(PIN_B1))
            Head7Position += 1;
          else
            Head7Position -= 1;
           output_c((HalfStep1[Head7Position&0b00000111]<<4) + CurrentHead);
         break;
         
      }
     HeadPowerDownCounter = 25;
}

#int_ext2
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|VSS_VDD);
   setup_adc(ADC_OFF);

   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   
   // set vacuum pump SSR off (low)
   output_bit(PIN_A5,0);
   // set buzzer off (low?)
   output_bit(PIN_A4,0);
   
   //Not all the step sequences below are used but we will leave them here
   //for future use

   HalfStep1[0] = 0b00001010;
   HalfStep1[1] = 0b00001000;
   HalfStep1[2] = 0b00001001;
   HalfStep1[3] = 0b00000001;
   HalfStep1[4] = 0b00000101;
   HalfStep1[5] = 0b00000100;
   HalfStep1[6] = 0b00000110;
   HalfStep1[7] = 0b00000010;
   
   FullStep[0] = 0b00001000;
   FullStep[1] = 0b00000001;
   FullStep[2] = 0b00000100;
   FullStep[3] = 0b00000010;
   FullStep[4] = 0b00001000;
   FullStep[5] = 0b00000001;
   FullStep[6] = 0b00000100;
   FullStep[7] = 0b00000010;
   
   HalfStep2[0] = 0b00001000;
   HalfStep2[1] = 0b00001001;
   HalfStep2[2] = 0b00000001;
   HalfStep2[3] = 0b00000101;
   HalfStep2[4] = 0b00000100;
   HalfStep2[5] = 0b00000110;
   HalfStep2[6] = 0b00000010;
   HalfStep2[7] = 0b00001010;  
   
   HalfStep3[0] = 0b00001000;
   HalfStep3[1] = 0b00001010;
   HalfStep3[2] = 0b00000010;
   HalfStep3[3] = 0b00000110;
   HalfStep3[4] = 0b00000100;
   HalfStep3[5] = 0b00000101;
   HalfStep3[6] = 0b00000001;
   HalfStep3[7] = 0b00001001;
   

   Head0Position = Head1Position = Head2Position = Head3Position = 0;
   Head4Position = Head5Position = Head6Position = Head7Position = 0;
   setAllVacuums(0);

   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_C(CurrentHead);
      Output_D(1<<CurrentHead);
      delay_ms(500);
      }
   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);
   output_bit(PIN_C0, input(PIN_B4));
   output_bit(PIN_C1, input(PIN_B5));
   output_bit(PIN_C2, input(PIN_B6));   
   output_bit(PIN_C3, input(PIN_B7));    
   
   // After 25 * the delay below we power off the stepper by outputting
   // 0's on C4-7 (by ouputting
   HeadPowerDownCounter -= 1;
   delay_ms(10);
   if (!HeadPowerDownCounter)
      {
      output_c(CurrentHead);
      }
      
   HeartBeatCounter -= 1;
   if (!HeartBeatCounter)
      {
      HeartBeat = !HeartBeat;
      output_bit(pin_e2,HeartBeat);
      HeartBeatCounter = 25;
      }
   }      
}