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;
//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 = 9;
#define RESOLUTION 40 //Microsecond resolution for notes
/*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
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[] = {
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)
byte currentPosition[] = {
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)
boolean stepDirection[] = {
false,false,false,false,false,false,false,false,false,false}; // false = forward, true=reverse (i.e. true=HIGH)
/*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
};
//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[] = {
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
void setup(){
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(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);
}
@ -69,61 +87,79 @@ void loop(){
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
against the currentPeriod for each pin. A period of 0 will skip the pin (i.e. pin is off)
Called by the timer inturrupt at the specified resolution.
*/
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){
stepPin(4,5,4);
if (currentPeriod[4]>0){
currentTick[4]++;
if (currentTick[4] >= currentPeriod[4]){
togglePin(4,5);
currentTick[4]=0;
}
}
if (currentPeriod[6] > 0 && micros()%currentPeriod[6] < 100){
stepPin(6,7,4);
if (currentPeriod[6]>0){
currentTick[6]++;
if (currentTick[6] >= currentPeriod[6]){
togglePin(6,7);
currentTick[6]=0;
}
}
if (currentPeriod[8] > 0 && micros()%currentPeriod[8] < 100){
stepPin(8,9,4);
if (currentPeriod[8]>0){
currentTick[8]++;
if (currentTick[8] >= currentPeriod[8]){
togglePin(8,9);
currentTick[8]=0;
}
}
}
/*
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) {
void togglePin(byte pin, byte direction_pin) {
//Switch directions if end has been reached
if (currentPosition[pin] >= MAX_POSITION[pin]) {
stepDirection[pin] = true;
currentState[direction_pin] = HIGH;
digitalWrite(direction_pin,HIGH);
}
else if (currentPosition[pin] <= 0) {
stepDirection[pin] = false;
currentState[direction_pin] = LOW;
digitalWrite(direction_pin,LOW);
}
//Set direction_pin state, and update currentPosition
if (stepDirection[pin]){
digitalWrite(direction_pin,HIGH);
//Update currentPosition
if (currentState[direction_pin] == HIGH){
currentPosition[pin]--;
}
else {
digitalWrite(direction_pin,LOW);
currentPosition[pin]++;
}
//Pulse the control pin
digitalWrite(pin,HIGH);
delayMicroseconds(wait);
digitalWrite(pin,LOW);
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
@ -135,13 +171,14 @@ void blinkLED(){
void reset(byte pin)
{
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,LOW);
delay(5);
}
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

View File

@ -27,6 +27,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;
SerialPort com;
@ -46,7 +52,7 @@ public class MoppyPlayer implements Receiver {
//Arduino by multipying by 2.
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);
}
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.
//NOTE: Java bytes range from -128 to 127, but we need to make them
//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);
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.
--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.
--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.