/* Fret Cutting System Control Program
Version 1.0.
Written by R. A. Currell (Roseland Audio) October 2005.
Array location addr[3] is used as a scratchpad reflection of the parallel output port
Array location addr[4] is used as a scratchpad reflection of the sensor array
*/
#include <iostream>
#include <math.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include "stdafx.h"
/* ----Prototypes of Inp and Outp--- */
short _stdcall Inp32(short PortAddress);
void _stdcall Out32(short PortAddress, short data);
/* Please Note: This function requires InpOut32.dll to be loaded in the Windows System Directory.
(See Logix4u website for the dll, its coding and usage */
/*--------------------------------*/
// Prototype function definitions.
float GetScaleLength(void);
int GetFretNumber(void);
void CalcFretPosition(int,float,float[]);
void GoToZeroFret(int[]);
void CalcLeadscrewRotations(float,float,int,int,float[],int[]);
void ClockParallelPort(long,int,int,int[]);
void MoveSawToFretPos(int,int[],int[]);
void Delay(int);
bool Sensor(int[]);
int ReadSensors(int[]);
float GetLeadScrewPitch(void);
main()
{
float Length, Fret[50], StepsPerRev;
int FretNum,Steps[50],addr[4],GearRatio;
double LeadscrewPitch;
addr[0]=0x378, addr[1]=0x379, addr[2]=0x37a, addr[3]=0x62, addr[4]=0;
// LeadscrewPitch = 0.9170;//Measured pitch of M6 threaded Studding used for prototype leadscrew.
StepsPerRev = 44; //Resolution of RS Stepper Motor type 351-4580.
GearRatio = 8; //Gear Ratio built into unit.
LeadscrewPitch = GetLeadScrewPitch(); //Read leadscrew pitch from calibration file.
Length = GetScaleLength();
FretNum = GetFretNumber();
CalcFretPosition(FretNum,Length,Fret); //Values of spacings calculated are in mm
CalcLeadscrewRotations(LeadscrewPitch,StepsPerRev,GearRatio,FretNum,Fret,Steps); /*Calculate number
// of Steps to next fret*/
GoToZeroFret(addr);
MoveSawToFretPos(FretNum,Steps,addr); //Position Saw guide to next fret position.
return 0;
}
float GetScaleLength(void)
{
char units;
float ScaleLength;
printf( "\nDo you wish to use Metric or Imperial units (m or i) ? ");
units=(tolower(getche()));
if (units == 'm')
{
printf("\n\nPlease input the scale length to be used in millimeters? ");
scanf("%f",&ScaleLength);
}
else
{
printf("\n\nPlease input the scale length to be used in inches? ");
scanf("%f",&ScaleLength);
ScaleLength=ScaleLength*25.4; //Convert imperial scale length in inches to mm.
}
return ScaleLength;
}
int GetFretNumber(void)
{
int fretNumber;
printf("\nPlease specify the number of frets to be used on the scale? ");
scanf("%u",&fretNumber);
return fretNumber;
}
void CalcFretPosition(int Fretnum, float Scale, float Fret[])
{
double FretConst;
int i;
Fret[0]=0;
FretConst = (1/(exp(log(2)/12)-1))+1;
for (i=1;i<Fretnum+1;i++) Fret[i]=Scale/FretConst;
for (i=1;i<Fretnum+1;i++) Fret[i]=((Scale-Fret[i-1])/FretConst)+Fret[i-1];
return;
}
void CalcLeadscrewRotations(float Pitch, float StepperRes, int Gear ,int FretNum,float Fret[], int Steps[])
{
float StepsPer_mm;
int i;
Steps[0]=0;
StepsPer_mm = StepperRes*Gear/Pitch;
for (i=1;i<FretNum; i++)
{
Steps[i]=int(float((Fret[i]-Fret[i-1])*StepsPer_mm));
}
return;
}
void ClockParallelPort(long clocknum,int del, int dir, int addr[])
//Generate a clock on Bits 1 and 2 of the parallel port and set the direction as specified.
{
int clock=0x03, drivemotor=0x20, i;
addr[3]=((addr[3]^drivemotor)&0x7f)|dir;
for (i=0; i<clocknum; i++)
{
addr[3]=addr[3]^clock;
Out32(addr[0],addr[3]);
Delay(del);
if (kbhit()) break;
}
addr[3]=addr[3]|0x30;
Out32(addr[0],addr[3]); //Turn off the motor power (Bits D5 & D6 both set to 1)
return;
}
void MoveSawToFretPos (int fretnum, int Steps[], int addr[])
{
int i,j,del,dir;
del = 3, dir = 0x00;
printf("\n\nThe saw carriage is now positioned at Fret 0 (or the nut if no zero fret).");
printf("\n\nPlease set up the finger-board and fix it ready for sawing the fret slots.\n\n");
for (i=1; i<fretnum; i++)
{
j=Steps[i];
printf("\nPlease press a key to move saw to the next fret position. Next fret number is %u",i);
while (!kbhit());
if (getch()=='\x1b') break;
ClockParallelPort(j,del,dir,addr);
}
printf("\n\n");
return;
}
void Delay(int del)
// Delay routine. Approximate Delay = del times 1 millisecond.
{
int i,duration;
duration =del * 400000;
for (i=0; i<duration; i++);
return;
}
void GoToZeroFret(int addr[])
// Find the zero point from anywhere beyond zero (at Sensor 1)!
{
int dir,start;
// Check if at a sensor and move appropriately, if a cold boot guess direction as forward.
ReadSensors(addr);
if (addr[4]==1)
{
dir = 0x00; //Select forward.
start = 0;
}
else
{
dir = 0x80;
start =1; //Select reverse.
}
// Find the nearest sensor and decide where to go from there.
printf("\n\nMoving saw carriage to Zero point, Please Wait!\n\n");
while (!Sensor(addr))(ClockParallelPort(4,1,dir,addr)); // Go to nearest available sensor.
if (addr[4]>2) dir = 0x80; //Select reverse.
else dir =0x00; //Select forward if below start point (Sensor 2).
while ((!Sensor(addr))|(addr[4]!=2))(ClockParallelPort(4,1,dir,addr)); // Go to Sensor 2.
// Always ensure that the carriage stops at the high side of zero point sensor.
while (Sensor(addr))(ClockParallelPort(4,1,0x00,addr));
ClockParallelPort(440,1,0x00,addr); // Move about 1mm clear and then nudge back to sensor.
while (!Sensor(addr))(ClockParallelPort(4,3,0x80,addr));
return;
}
bool Sensor(int addr[])
//Read the sensor byte and set flag if a sensor is active
{
bool True = 1, False = 0, Sens1 = False;
int sens;
sens = ReadSensors(addr);
if (sens > 0)
{
Sens1 = True;
}
else
Sens1 = False;
return Sens1;
}
int ReadSensors(int addr[])
/* Read the status of the optical position sensors via the parallel port status register.
Note, sensors 4 and 5 are multiplexed into bit S7 (which is inverted by the PC) as only 5 input
bits are available, these two sensors are demultiplexed using bit D4 of the output port
Hi = Sensor 4, Lo = Sensor 5.
*/
{
int Sens, Sens1, SelSens4;
SelSens4=0x10;
addr[3]=addr[3]|SelSens4;
Out32(addr[0],addr[3]);
Sens = Inp32(addr[1]);
/* Invert, mask out junk bits then 3 right shifts to move sensors to their correct binary position.
NB. Also correct bit 7 which is inverted by the PC.
*/
Sens = Sens^0x7f; // Invert all bits except bit 7 which is inverted by the PC as the sensor inputs are active Lo.
Sens = Sens>>3; // Right shift required info into the correct binary location.
//Now read in sensor 5
addr[3]=addr[3]^SelSens4;
Out32(addr[0],addr[3]);
Sens1 = Inp32(addr[1]);
Sens1 = Sens1&0x80; // Note Bit S7 is already inverted
Sens1 = Sens1>>2; // Put the required bit into bit 5 of Sens variable.
Sens = Sens|Sens1; // Combine it with the rest of the bits.
if (Sens>0) addr[4] = Sens; // Store last detected sensor position in the common array.
return Sens;
}
float GetLeadScrewPitch()
//Read in calibration file data.
{
float pitch;
int pnter=0;
char letter, *string;
FILE *fptr;
string=(char*)malloc(10);
strset(string,'0');
if((fptr=fopen("FretCalFile.cal","r")) == NULL)
{
printf("Calibration file cannot be opened\n"); //Whoops!
while (!kbhit());
exit(1);
}
while ((letter !=EOF) && (letter !='\n'))
{
letter=getc(fptr);
if (letter != '\n')
{
string[pnter]=letter;
pnter=pnter+1;
}
}
fclose(fptr);
pitch=atof(string);
return pitch;
}