Now using timer inturrupts for the Arduino.

This commit is contained in:
Sam Archer 2011-10-16 23:59:18 -07:00
parent 93277776bc
commit 2d01e01a65
3 changed files with 97 additions and 40 deletions

View File

@ -1,8 +1,11 @@
#include <TimerOne.h>
boolean firstRun = true; // Used for one-run-only stuffs; 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. //First pin being used for floppies, and the last pin. Used for looping over all pins.
const byte FIRST_PIN = 2; const byte FIRST_PIN = 2;
const byte PIN_MAX = 9; const byte PIN_MAX = 9;
#define RESOLUTION 40 //Microsecond resolution for notes
/*NOTE: Many of the arrays below contain unused indexes. This is /*NOTE: Many of the arrays below contain unused indexes. This is
@ -14,24 +17,36 @@ stored in index 4.*/
/*An array of maximum track positions for each step-control pin. Even pins /*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 are used for control, so only even numbers need a value here. 3.5" Floppies have
80 tracks, 5.25" have 50 (use 79 and 49). 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[] = { byte MAX_POSITION[] = {
0,0,79,0,79,0,79,0,79,0}; 0,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) //Array to track the current position of each floppy head. (Only even indexes (i.e. 2,4,6...) are used)
byte currentPosition[] = { byte currentPosition[] = {
0,0,0,0,0,0,0,0,0,0}; 0,0,0,0,0,0,0,0,0,0};
//Array to keep track of the direction for each floppy head. (Only even indexes are used) /*Array to keep track of state of each pin. Even indexes track the control-pins for toggle purposes. Odd indexes
boolean stepDirection[] = { track direction-pins. LOW = forward, HIGH=reverse
false,false,false,false,false,false,false,false,false,false}; // false = forward, true=reverse (i.e. true=HIGH) */
int currentState[] = {
0,0,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW
};
//Current period assigned to each pin. 0 = off. //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[] = { unsigned int currentPeriod[] = {
0,0,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
};
//Setup pins (Even-odd pairs for step control and direction //Setup pins (Even-odd pairs for step control and direction
void setup(){ void setup(){
pinMode(13, OUTPUT);// Pin 13 has an LED connected on most Arduino boards pinMode(13, OUTPUT);// Pin 13 has an LED connected on most Arduino boards
@ -44,6 +59,9 @@ void setup(){
pinMode(8, OUTPUT); // Step control 4 pinMode(8, OUTPUT); // Step control 4
pinMode(9, OUTPUT); // Direction 5 pinMode(9, OUTPUT); // Direction 5
Timer1.initialize(RESOLUTION); // Set up a timer at the defined resolution
Timer1.attachInterrupt(tick); // Attach the tick function
Serial.begin(9600); Serial.begin(9600);
} }
@ -69,61 +87,79 @@ void loop(){
currentPeriod[Serial.read()] = (Serial.read() << 8) | Serial.read(); currentPeriod[Serial.read()] = (Serial.read() << 8) | Serial.read();
} }
} }
voice();
} }
/* /*
The voice() method controls WHEN each pin will be stepped by mod'ing the Arduino system-clock Called by the timer inturrupt at the specified resolution.
against the currentPeriod for each pin. A period of 0 will skip the pin (i.e. pin is off)
*/ */
void voice() void tick()
{ {
if (currentPeriod[2] > 0 && micros()%currentPeriod[2] < 100){ /*
stepPin(2,3,4); 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 && micros()%currentPeriod[4] < 100){ if (currentPeriod[4]>0){
stepPin(4,5,4); currentTick[4]++;
if (currentTick[4] >= currentPeriod[4]){
togglePin(4,5);
currentTick[4]=0;
}
} }
if (currentPeriod[6] > 0 && micros()%currentPeriod[6] < 100){ if (currentPeriod[6]>0){
stepPin(6,7,4); currentTick[6]++;
if (currentTick[6] >= currentPeriod[6]){
togglePin(6,7);
currentTick[6]=0;
}
} }
if (currentPeriod[8] > 0 && micros()%currentPeriod[8] < 100){ if (currentPeriod[8]>0){
stepPin(8,9,4); currentTick[8]++;
if (currentTick[8] >= currentPeriod[8]){
togglePin(8,9);
currentTick[8]=0;
}
} }
} }
/* void togglePin(byte pin, byte direction_pin) {
The stepPin() method controls the actual stepping of each pin. It uses the
stepDireciton array to determine the state of the direction_pin, and will automatically
reverse the direction when needed.
*/
void stepPin(byte pin, byte direction_pin, byte wait) {
//Switch directions if end has been reached //Switch directions if end has been reached
if (currentPosition[pin] >= MAX_POSITION[pin]) { if (currentPosition[pin] >= MAX_POSITION[pin]) {
stepDirection[pin] = true; currentState[direction_pin] = HIGH;
digitalWrite(direction_pin,HIGH);
} }
else if (currentPosition[pin] <= 0) { else if (currentPosition[pin] <= 0) {
stepDirection[pin] = false; currentState[direction_pin] = LOW;
digitalWrite(direction_pin,LOW);
} }
//Set direction_pin state, and update currentPosition //Update currentPosition
if (stepDirection[pin]){ if (currentState[direction_pin] == HIGH){
digitalWrite(direction_pin,HIGH);
currentPosition[pin]--; currentPosition[pin]--;
} }
else { else {
digitalWrite(direction_pin,LOW);
currentPosition[pin]++; currentPosition[pin]++;
} }
//Pulse the control pin //Pulse the control pin
digitalWrite(pin,HIGH); digitalWrite(pin,currentState[pin]);
delayMicroseconds(wait); currentState[pin] = ~currentState[pin];
digitalWrite(pin,LOW);
} }
//
//// UTILITY FUNCTIONS
//
//Not used now, but good for debugging... //Not used now, but good for debugging...
void blinkLED(){ void blinkLED(){
digitalWrite(13, HIGH); // set the LED on digitalWrite(13, HIGH); // set the LED on
@ -135,13 +171,14 @@ void blinkLED(){
void reset(byte pin) void reset(byte pin)
{ {
digitalWrite(pin+1,HIGH); // Go in reverse digitalWrite(pin+1,HIGH); // Go in reverse
for (byte s=0;s<MAX_POSITION[pin];s++){ for (byte s=0;s<MAX_POSITION[pin];s+=2){ //Half max because we're stepping directly (no toggle)
digitalWrite(pin,HIGH); digitalWrite(pin,HIGH);
digitalWrite(pin,LOW); digitalWrite(pin,LOW);
delay(5); delay(5);
} }
currentPosition[pin] = 0; // We're reset. currentPosition[pin] = 0; // We're reset.
stepDirection[pin] = false; // Ready to go forward. digitalWrite(pin+1,LOW);
currentPosition[pin+1] = LOW; // Ready to go forward.
} }
//Resets all the pins //Resets all the pins

View File

@ -28,6 +28,12 @@ public class MoppyPlayer implements Receiver {
0,0,0,0,0,0,0,0,0,0,0,0 0,0,0,0,0,0,0,0,0,0,0,0
}; };
/**
* Resolution of the Arduino code in microSeconds.
*/
public static int ARDUINO_RESOLUTION = 40;
MoppyBridge mb; MoppyBridge mb;
SerialPort com; SerialPort com;
@ -46,7 +52,7 @@ public class MoppyPlayer implements Receiver {
//Arduino by multipying by 2. //Arduino by multipying by 2.
byte pin = (byte)(2*(message.getStatus() - 127)); byte pin = (byte)(2*(message.getStatus() - 127));
//System.out.println("Got note OFF on pin: " + (channel & 0xFF)); //System.out.println("Got note OFF on pin: " + (pin & 0xFF));
mb.sendEvent(pin, 0); mb.sendEvent(pin, 0);
} }
else if (message.getStatus() > 143 && message.getStatus() < 160){ // Note ON else if (message.getStatus() > 143 && message.getStatus() < 160){ // Note ON
@ -57,10 +63,22 @@ public class MoppyPlayer implements Receiver {
//Get note number from MIDI message, and look up the period. //Get note number from MIDI message, and look up the period.
//NOTE: Java bytes range from -128 to 127, but we need to make them //NOTE: Java bytes range from -128 to 127, but we need to make them
//0-255 to use for lookups. & 0xFF does the trick. //0-255 to use for lookups. & 0xFF does the trick.
int period = microPeriods[(message.getMessage()[1] & 0xff)];
// After looking up the period, devide by (the Arduino resolution * 2).
// The Arduino's timer will only tick once per X microseconds based on the
// resolution. And each tick will only turn the pin on or off. So a full
// on-off cycle (one step on the floppy) is two periods.
int period = microPeriods[(message.getMessage()[1] & 0xff)]/(ARDUINO_RESOLUTION*2);
//System.out.println("Got note ON on pin: " + (pin & 0xFF) + " with period " + period); //System.out.println("Got note ON on pin: " + (pin & 0xFF) + " with period " + period);
mb.sendEvent(pin, period); //System.out.println(message.getLength() + " " + message.getMessage()[message.getLength()-1]);
//Zero velocity events turn off the pin.
if (message.getMessage()[2] == 0){
mb.sendEvent(pin, 0);
} else {
mb.sendEvent(pin, period);
}
} }
} }
} }

View File

@ -9,10 +9,12 @@ by Sammy1Am
Moppy is a M_usical Fl_oppy controller program built for the Ardiuno UNO. Moppy is a M_usical Fl_oppy controller program built for the Ardiuno UNO.
--INSTALLATION-- --INSTALLATION--
The Arduino code requires the TimeOne library available here: http://www.arduino.cc/playground/Code/Timer1
You will need to follow the directions in the appropriate Java/SerialDrivers folder for your system to install the serial drivers prior to running Moppy.
Upload the included Arduino code to the Arduino of your choice, and open up the included Java code in your favorite IDE. This code includes a NetBeans project for your convenience, so you should be able to open the project directly in NetBeans. Upload the included Arduino code to the Arduino of your choice, and open up the included Java code in your favorite IDE. This code includes a NetBeans project for your convenience, so you should be able to open the project directly in NetBeans.
--HARDWARE-- --HARDWARE--
I built Moppy using an Arduino UNO, though it should work just fine on most Arduinos. The pins are connected in pairs to floppy drives as follows: Even pins (2,4,6...) are connected to the drive's STEP pin, the matching odd pins (3,5,7...) are connected to the drive's DIRECTION control pin. I built Moppy using an Arduino UNO, though it should work just fine on most Arduinos. The pins are connected in pairs to floppy drives as follows: Even pins (2,4,6...) are connected to the drive's STEP pin, the matching odd pins (3,5,7...) are connected to the drive's DIRECTION control pin.