#include "pitches.h"
/*
Code for driving remote controlled tank
Includes code for:
external interrupt 0 on pin 2
midi sounds through speaker using tone() on pin 8
H-bridge for driving motors
Flashing LED that doesn't use a delay
Serial port communication
*/
//Number of melodies to allocate for the speaker
#define NUM_SONGS 3
//Phase Definitions
#define STOPPED 0
#define FORWARD 1
#define RIGHT 2
#define LEFT 3
#define REVERSE 4
//H-Bridge Pin assignments
const unsigned char PIN_HBRIDGE_1A = 5;
const unsigned char PIN_HBRIDGE_2A = 3;
const unsigned char PIN_HBRIDGE_3A = 6;
const unsigned char PIN_HBRIDGE_4A = 9;
const unsigned char ledPin = 13; // LED that will flash
const unsigned char speakerPin = 8; // Speaker for melodies
const unsigned char buttonPin = 2; // the number of the pushbutton pin
const unsigned char int0 = 0; // pin 2 is attached to interrupt 0
//LED settings
long ledInterval = 500; // interval at which to blink (milliseconds)
int ledState = LOW; // start LED turned off
long ledPreviousMillis = 0; // keep track of the last flash of the LED
//Serial port settings
unsigned char prompt = 1; // should we prompt for a keystroke?
int inByte = 0; // incoming serial byte
//Determines the tanks current task
unsigned int phase = STOPPED;
//Melody containers
int melodyLength[NUM_SONGS];
int* melody[NUM_SONGS];
int* noteDurations[NUM_SONGS];
//Melody 0
int melodyLength0 = 8;
int melody0[] = {
NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4};
int noteDurations0[] = {
4, 8, 8, 4,4,4,4,4 };
//Melody 1 - Beep
int melodyLength1 = 1;
int melody1[] = {
NOTE_C4};
int noteDurations1[] = {
2};
//Melody 2 - Lord of the Rings theme
int melodyLength2 = 16;
int melody2[] = {
NOTE_A4,NOTE_G4,NOTE_G4,NOTE_G4,NOTE_A4,
NOTE_D5,NOTE_E5,NOTE_F5,NOTE_E5,NOTE_D5,NOTE_C5,NOTE_D5,NOTE_E5,
NOTE_D5,NOTE_C5,NOTE_B4};
int noteDurations2[] = {
1,1,8,8,1,8,8,1,8,8,1,8,8,1,2,2};
void setup() {
//Attach pins
pinMode(PIN_HBRIDGE_1A, OUTPUT);
pinMode(PIN_HBRIDGE_2A, OUTPUT);
pinMode(PIN_HBRIDGE_3A, OUTPUT);
pinMode(PIN_HBRIDGE_4A, OUTPUT);
pinMode(ledPin, OUTPUT);
pinMode(buttonPin, INPUT);
//Setup interrupts
attachInterrupt(int0, ButtonInterrupt, RISING);
// start serial port at 9600 bps:
Serial.begin(9600);
//Setup melodies and play startup sound
CreateMelodies();
PlayMelody(0);
Serial.println("Starting tank...");
}
//Interrupt handler for button press
void ButtonInterrupt() {
//Debounce button press
static unsigned long lastInterruptTime = 0;
unsigned long interruptTime = millis();
// If interrupts come faster than 200ms, assume it's a bounce and ignore
if(interruptTime - lastInterruptTime > 200) {
//Button interrupt handler
//Increment phase, rollover after 4
Serial.println("Interrupt!!");
if (++phase == 5)
phase = STOPPED;
}
lastInterruptTime = interruptTime;
}
void loop() {
if (prompt) {
PromptKeyPress();
}
if (Serial.available() > 0) {
ReadKeyPress();
}
//This block of code can be uncommented and adjusted
//for atonomous dead reckoning of the tank
/*
TankForward();
delay(4000);
TankRight();
delay(1500);
TankForward();
delay(4000);
TankLeft();
delay(1500);
TankStop();
delay(2000);
*/
switch(phase) {
case STOPPED:
TankStop();
Serial.println("Tank stop");
break;
case FORWARD:
TankForward();
Serial.println("Tank forward");
break;
case RIGHT:
TankRight();
Serial.println("Tank right");
break;
case LEFT:
TankLeft();
Serial.println("Tank left");
break;
case REVERSE:
TankReverse();
Serial.println("Tank reverse");
break;
default:
TankStop();
Serial.println("Tank stop");
break;
}
FlashLed();
// PlayMelody(1);
}
//Sets up melodies
void CreateMelodies() {
Serial.println("Creating melodies...");
melodyLength[0] = melodyLength0;
melody[0] = melody0;
noteDurations[0] = noteDurations0;
melodyLength[1] = melodyLength1;
melody[1] = melody1;
noteDurations[1] = noteDurations1;
melodyLength[2] = melodyLength2;
melody[2] = melody2;
noteDurations[2] = noteDurations2;
Serial.println("Done.");
}
//Plays melodies by assigned number
void PlayMelody(int s) {
Serial.println("Playing melody...");
// iterate over the notes of the melody:
for (int thisNote = 0; thisNote < melodyLength[s]; thisNote++) {
// to calculate the note duration, take one second
// divided by the note type.
//e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
int noteDuration = 1000/noteDurations[s][thisNote];
tone(speakerPin, melody[s][thisNote],noteDuration);
// to distinguish the notes, set a minimum time between them.
// the note's duration + 30% seems to work well:
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);
}
Serial.println("Done.");
}
void PromptKeyPress() {
Serial.println("Press a number");
prompt = 0;
}
//Read key presses over serial
void ReadKeyPress() {
inByte = Serial.read();
switch (inByte)
{
case '2':
phase = REVERSE;
break;
case '4':
phase = LEFT;
break;
case '5':
phase = STOPPED;
break;
case '6':
phase = RIGHT;
break;
case '8':
phase = FORWARD;
break;
default:
Serial.println("Invalid command");
break;
}
prompt = 1;
}
//Flashes onboard LED periodically without using DELAY
void FlashLed() {
if (millis() - ledPreviousMillis > ledInterval) {
// save the last time you blinked the LED
ledPreviousMillis = millis();
// if the LED is off turn it on and vice-versa:
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
}
//These functions control the tank
void TankForward() {
MotorLeftForward();
MotorRightForward();
}
void TankStop() {
MotorLeftStop();
MotorRightStop();
}
void TankReverse() {
MotorLeftReverse();
MotorRightReverse();
}
void TankLeft() {
MotorLeftForward();
MotorRightReverse();
}
void TankRight() {
MotorLeftReverse();
MotorRightForward();
}
//These functions perform the low-level control of H-Bridge
void MotorRightStop() {
digitalWrite(PIN_HBRIDGE_1A, LOW);
digitalWrite(PIN_HBRIDGE_2A, LOW);
}
void MotorRightForward() {
digitalWrite(PIN_HBRIDGE_1A, HIGH);
digitalWrite(PIN_HBRIDGE_2A, LOW);
}
void MotorRightReverse() {
digitalWrite(PIN_HBRIDGE_1A, LOW);
digitalWrite(PIN_HBRIDGE_2A, HIGH);
}
void MotorLeftStop() {
digitalWrite(PIN_HBRIDGE_3A, LOW);
digitalWrite(PIN_HBRIDGE_4A, LOW);
}
void MotorLeftForward() {
digitalWrite(PIN_HBRIDGE_3A, LOW);
digitalWrite(PIN_HBRIDGE_4A, HIGH);
}
void MotorLeftReverse() {
digitalWrite(PIN_HBRIDGE_3A, HIGH);
digitalWrite(PIN_HBRIDGE_4A, LOW);
}