248 lines
6.3 KiB
Plaintext
248 lines
6.3 KiB
Plaintext
#include <TimerOne.h>
|
|
|
|
boolean firstRun = true; // Used for one-run-only stuffs;
|
|
|
|
//First pin being used for floppies, and the last pin. Used for looping over all pins.
|
|
const byte FIRST_PIN = 2;
|
|
const byte PIN_MAX = 17;
|
|
#define RESOLUTION 40 //Microsecond resolution for notes
|
|
|
|
|
|
/*NOTE: Many of the arrays below contain unused indexes. This is
|
|
to prevent the Arduino from having to convert a pin input to an alternate
|
|
array index and save as many cycles as possible. In other words information
|
|
for pin 2 will be stored in index 2, and information for pin 4 will be
|
|
stored in index 4.*/
|
|
|
|
|
|
/*An array of maximum track positions for each step-control pin. Even pins
|
|
are used for control, so only even numbers need a value here. 3.5" Floppies have
|
|
80 tracks, 5.25" have 50. These should be doubled, because each tick is now
|
|
half a position (use 158 and 98).
|
|
*/
|
|
byte MAX_POSITION[] = {
|
|
0,0,158,0,158,0,158,0,158,0,158,0,158,0,158,0,158,0};
|
|
|
|
//Array to track the current position of each floppy head. (Only even indexes (i.e. 2,4,6...) are used)
|
|
byte currentPosition[] = {
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
|
|
|
/*Array to keep track of state of each pin. Even indexes track the control-pins for toggle purposes. Odd indexes
|
|
track direction-pins. LOW = forward, HIGH=reverse
|
|
*/
|
|
int currentState[] = {
|
|
0,0,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW
|
|
};
|
|
|
|
//Current period assigned to each pin. 0 = off. Each period is of the length specified by the RESOLUTION
|
|
//variable above. i.e. A period of 10 is (RESOLUTION x 10) microseconds long.
|
|
unsigned int currentPeriod[] = {
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
|
};
|
|
|
|
//Current tick
|
|
unsigned int currentTick[] = {
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
|
};
|
|
|
|
|
|
|
|
//Setup pins (Even-odd pairs for step control and direction
|
|
void setup(){
|
|
pinMode(13, OUTPUT);// Pin 13 has an LED connected on most Arduino boards
|
|
pinMode(2, OUTPUT); // Step control 1
|
|
pinMode(3, OUTPUT); // Direction 1
|
|
pinMode(4, OUTPUT); // Step control 2
|
|
pinMode(5, OUTPUT); // Direction 2
|
|
pinMode(6, OUTPUT); // Step control 3
|
|
pinMode(7, OUTPUT); // Direction 3
|
|
pinMode(8, OUTPUT); // Step control 4
|
|
pinMode(9, OUTPUT); // Direction 4
|
|
pinMode(10, OUTPUT); // Step control 5
|
|
pinMode(11, OUTPUT); // Direction 5
|
|
pinMode(12, OUTPUT); // Step control 6
|
|
pinMode(13, OUTPUT); // Direction 6
|
|
pinMode(14, OUTPUT); // Step control 7
|
|
pinMode(15, OUTPUT); // Direction 7
|
|
pinMode(16, OUTPUT); // Step control 8
|
|
pinMode(17, OUTPUT); // Direction 8
|
|
|
|
Timer1.initialize(RESOLUTION); // Set up a timer at the defined resolution
|
|
Timer1.attachInterrupt(tick); // Attach the tick function
|
|
|
|
Serial.begin(9600);
|
|
}
|
|
|
|
|
|
void loop(){
|
|
|
|
//The first loop, reset all the drives, and wait 2 seconds...
|
|
if (firstRun)
|
|
{
|
|
firstRun = false;
|
|
resetAll();
|
|
delay(2000);
|
|
}
|
|
|
|
//Only read if we have
|
|
if (Serial.available() > 2){
|
|
//Watch for special 100-message to reset the drives
|
|
if (Serial.peek() == 100) {
|
|
resetAll();
|
|
Serial.flush();
|
|
}
|
|
else{
|
|
currentPeriod[Serial.read()] = (Serial.read() << 8) | Serial.read();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
Called by the timer inturrupt at the specified resolution.
|
|
*/
|
|
void tick()
|
|
{
|
|
/*
|
|
If there is a period set for control pin 2, count the number of
|
|
ticks that pass, and toggle the pin if the current period is reached.
|
|
*/
|
|
if (currentPeriod[2]>0){
|
|
currentTick[2]++;
|
|
if (currentTick[2] >= currentPeriod[2]){
|
|
togglePin(2,3);
|
|
currentTick[2]=0;
|
|
}
|
|
}
|
|
if (currentPeriod[4]>0){
|
|
currentTick[4]++;
|
|
if (currentTick[4] >= currentPeriod[4]){
|
|
togglePin(4,5);
|
|
currentTick[4]=0;
|
|
}
|
|
}
|
|
if (currentPeriod[6]>0){
|
|
currentTick[6]++;
|
|
if (currentTick[6] >= currentPeriod[6]){
|
|
togglePin(6,7);
|
|
currentTick[6]=0;
|
|
}
|
|
}
|
|
if (currentPeriod[8]>0){
|
|
currentTick[8]++;
|
|
if (currentTick[8] >= currentPeriod[8]){
|
|
togglePin(8,9);
|
|
currentTick[8]=0;
|
|
}
|
|
}
|
|
if (currentPeriod[10]>0){
|
|
currentTick[10]++;
|
|
if (currentTick[10] >= currentPeriod[10]){
|
|
togglePin(10,11);
|
|
currentTick[10]=0;
|
|
}
|
|
}
|
|
if (currentPeriod[12]>0){
|
|
currentTick[12]++;
|
|
if (currentTick[12] >= currentPeriod[12]){
|
|
togglePin(12,13);
|
|
currentTick[12]=0;
|
|
}
|
|
}
|
|
if (currentPeriod[14]>0){
|
|
currentTick[14]++;
|
|
if (currentTick[14] >= currentPeriod[14]){
|
|
togglePin(14,15);
|
|
currentTick[14]=0;
|
|
}
|
|
}
|
|
if (currentPeriod[16]>0){
|
|
currentTick[16]++;
|
|
if (currentTick[16] >= currentPeriod[16]){
|
|
togglePin(16,17);
|
|
currentTick[16]=0;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void togglePin(byte pin, byte direction_pin) {
|
|
|
|
//Switch directions if end has been reached
|
|
if (currentPosition[pin] >= MAX_POSITION[pin]) {
|
|
currentState[direction_pin] = HIGH;
|
|
digitalWrite(direction_pin,HIGH);
|
|
}
|
|
else if (currentPosition[pin] <= 0) {
|
|
currentState[direction_pin] = LOW;
|
|
digitalWrite(direction_pin,LOW);
|
|
}
|
|
|
|
//Update currentPosition
|
|
if (currentState[direction_pin] == HIGH){
|
|
currentPosition[pin]--;
|
|
}
|
|
else {
|
|
currentPosition[pin]++;
|
|
}
|
|
|
|
//Pulse the control pin
|
|
digitalWrite(pin,currentState[pin]);
|
|
currentState[pin] = ~currentState[pin];
|
|
}
|
|
|
|
|
|
//
|
|
//// UTILITY FUNCTIONS
|
|
//
|
|
|
|
//Not used now, but good for debugging...
|
|
void blinkLED(){
|
|
digitalWrite(13, HIGH); // set the LED on
|
|
delay(250); // wait for a second
|
|
digitalWrite(13, LOW);
|
|
}
|
|
|
|
//For a given controller pin, runs the read-head all the way back to 0
|
|
void reset(byte pin)
|
|
{
|
|
digitalWrite(pin+1,HIGH); // Go in reverse
|
|
for (byte s=0;s<MAX_POSITION[pin];s+=2){ //Half max because we're stepping directly (no toggle)
|
|
digitalWrite(pin,HIGH);
|
|
digitalWrite(pin,LOW);
|
|
delay(5);
|
|
}
|
|
currentPosition[pin] = 0; // We're reset.
|
|
digitalWrite(pin+1,LOW);
|
|
currentPosition[pin+1] = 0; // Ready to go forward.
|
|
}
|
|
|
|
//Resets all the pins
|
|
void resetAll(){
|
|
|
|
// Old one-at-a-time reset
|
|
//for (byte p=FIRST_PIN;p<=PIN_MAX;p+=2){
|
|
// reset(p);
|
|
//}
|
|
|
|
// New all-at-once reset
|
|
for (byte s=0;s<80;s++){ // For max drive's position
|
|
for (byte p=FIRST_PIN;p<=PIN_MAX;p+=2){
|
|
digitalWrite(p+1,HIGH); // Go in reverse
|
|
digitalWrite(p,HIGH);
|
|
digitalWrite(p,LOW);
|
|
}
|
|
delay(5);
|
|
}
|
|
|
|
for (byte p=FIRST_PIN;p<=PIN_MAX;p+=2){
|
|
currentPosition[p] = 0; // We're reset.
|
|
digitalWrite(p+1,LOW);
|
|
currentState[p+1] = 0; // Ready to go forward.
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|