Code:
/**
* @brief Play a melody from J. S. Bach.
* Push the left sensor to modify the speed.
* Push the right sensor to modify the sound volume.
*
* The sound quality depends on the underground, how many mechanical parts can vibrate
* on the robot, how the spheres are installed, the volume, etc..
*
* tip Hold the wheels with all fingers to feel the music :)
* This also may reduce rasping/scratchy sound.
*
*
* @author Oliver G.
* @date 2011-10-24
* @version 1.0
*/
#include <nibobee/iodefs.h>
#include <nibobee/led.h>
#include <nibobee/delay.h>
#include <nibobee/sens.h>
#include <nibobee/motpwm.h>
#include <math.h>
volatile uint8_t pulse; // helper for timing
uint16_t noteCnt; // current note of the melody
uint16_t beeperVolume;
uint8_t beeperActive;
uint16_t speed; // length of one note in ms (so actually 1/speed)
void playNote(uint8_t note);
void playNoteTime(uint8_t note, uint16_t time);
void playScales();
void initBeeper();
void listenSensorInput();
// Note names as used by european musicians. a1 = a' = 440 Hz
// (x)es names are missing, but you know that cis' = des' etc.
enum {
_C, _Cis, _D, _Dis, _E, _F, _Fis, _G, _Gis, _A, _Ais, _H,
_c, _cis, _d, _dis, _e, _f, _fis, _g, _gis, _a, _ais, _h,
c1, cis1, d1, dis1, e1, f1, fis1, g1, gis1, a1, ais1, h1,
c2, cis2, d2, dis2, e2, f2, fis2, g2, gis2, a2, ais2, h2,
c3, cis3, d3, dis3, e3, f3, fis3, g3, gis3, a3, ais3, h3, c4
};
// frequencies for _c to _h, the remaining notes will be computed
float freqTable[] = {
130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185, 196, 207.65, 220, 233.08, 246.94
};
// Some nice melody from J.S. Bach!
// we don't need information about the note length,
// cause we can recognize this melody with equal note lengths
uint8_t melody[] = {
c1, e1, g1, c2, e2, g1, c2, e2, c1, e1, g1, c2, e2, g1, c2, e2,
c1, d1, a1, d2, f2, a1, d2, f2, c1, d1, a1, d2, f2, a1, d2, f2,
_h, d1, g1, d2, f2, g1, d2, f2, _h, d1, g1, d2, f2, g1, d2, f2,
c1, e1, g1, c2, e2, g1, c2, e2, c1, e1, g1, c2, e2, g1, c2, e2,
c1, e1, a1, e2, a2, a1, e2, a2, c1, e1, a1, e2, a2, a1, e2, a2,
c1, d1, fis1, a1, d2, fis1, a1, d2, c1, d1, fis1, a1, d2, fis1, a1, d2,
_h, d1, g1, d2, g2, g1, d2, g2, _h, d1, g1, d2, g2, g1, d2, g2,
_h, c1, e1, g1, c2, e1, g1, c2, _h, c1, e1, g1, c2, e1, g1, c2,
_a, c1, e1, g1, c2, e1, g1, c2, _a, c1, e1, g1, c2, e1, g1, c2,
_d, _a, d1, fis1, c2, d1, fis1, c2, _d, _a, d1, fis1, c2, d1, fis1, c2,
_g, _h, d1, g1, h1, d1, g1, h1, _g, _h, d1, g1, h1, d1, g1, h1,
_g, _ais, e1, g1, cis2, e1, g1, cis2, _g, _ais, e1, g1, cis2, e1, g1, cis2,
_f, _a, d1, a1, d2, d1, a1, d2, _f, _a, d1, a1, d2, d1, a1, d2,
_f, _gis, d1, f1, h1, d1, f1, h1, _f, _gis, d1, f1, h1, d1, f1, h1,
_e, _g, c1, g1, c2, c1, g1, c2, _e, _g, c1, g1, c2, c1, g1, c2,
_e, _f, _a, c1, f1, _a, c1, f1, _e, _f, _a, c1, f1, _a, c1, f1,
_d, _f, _a, c1, f1, _a, c1, f1, _d, _f, _a, c1, f1, _a, c1, f1,
_G, _d, _g, _h, f1, _g, _h, f1, _G, _d, _g, _h, f1, _g, _h, f1,
_c, _e, _g, c1, e1, _g, c1, e1, _c, _e, _g, c1, e1, _g, c1, e1,
c1 // melody shortened here...
};
int main() {
motpwm_init();
led_init();
sens_init();
initBeeper(); // (i'm used to camel case naming...)
speed = 130;
beeperVolume = 500;
playScales();
uint8_t i = 3;
while (i-- > 0) {
// short pause
beeperActive = 0;
delay(500);
beeperActive = 1;
noteCnt = 0;
while (noteCnt < sizeof(melody)) {
playNote(melody[noteCnt]);
noteCnt++;
}
delay(4 * speed); // hold last note of the melody
speed -= 20; // play melody a bit faster next time
}
beeperActive = 0;
delay(100);
disable_interrupts();
return 0;
}
/**
* Listen for some user/sensor input.
*/
void listenSensorInput() {
if (sens_getLeft()) {
speed += 10 * sens_getLeft();
while (sens_getLeft());
}
if (sens_getRight()) {
beeperVolume += 100 * sens_getRight();
while (sens_getRight());
}
}
/**
* Play the given note and hold it for the time defined in global var: speed.
*/
void playNote(uint8_t note) {
playNoteTime(note, speed);
}
/**
* Play the given note for the given time (milliseconds).
*/
void playNoteTime(uint8_t note, uint16_t time) {
uint8_t octave = note / 12;
float frequency = freqTable[note%12] * (1<<octave);
// set prescaler and compare value which will trigger interrupt
if (octave == 0) {
TCCR0 = (1<<WGM01) | (1<<CS00) | (1<<CS02); // set prescaler to 1024
OCR0 = roundf( (F_CPU / 1024.0f) / frequency) -1;
} else if (octave <= 2) {
TCCR0 = (1<<WGM01) | (1<<CS02); // set prescaler to 256
OCR0 = roundf( (F_CPU / 256.0f) / frequency) -1;
} else {
TCCR0 = (1<<WGM01) | (1<<CS00) | (1<<CS01); // set prescaler to 64
OCR0 = roundf( (F_CPU / 64.0f) / frequency) -1;
}
delay(time);
/* Uncomment this code for a little pause between the notes
TCCR0 = 0;
motpwm_setLeft(0);
motpwm_setRight(0);
delay(time/3); */
listenSensorInput();
}
/**
* Play some standard scales for sound check.
*/
void playScales() {
// chromatic scale
for (int i = 0; i < 5 * 12; i++)
playNoteTime(i, 20);
// 4 octaves c major scale
uint8_t cMajorScale[] = {
_c, _d, _e, _f, _g, _a, _h,
c1, d1, e1, f1, g1, a1, h1,
c2, d2, e2, f2, g2, a2, h2,
c3, d3, e3, f3, g3, a3, h3, c4
};
for (int i = 0; i < sizeof(cMajorScale); i++)
playNoteTime(cMajorScale[i], 100);
}
/**
* Config timer 0 and set beeper active.
*/
void initBeeper() {
TCCR0 = (1<<WGM01); // set CTC modus
TCCR0 |= (1<<CS02); // set prescaler to 256
OCR0 = (F_CPU/256) / 440 -1; // (value overwritten later)
TIMSK |= (1<<OCIE0); // allow compare interrupt
beeperActive = 1;
enable_interrupts();
}
/**
* Compare interrupt handler
* Is called if TCNT0 = OCR0
*/
ISR (TIMER0_COMP_vect) {
if (beeperActive) {
// let the motor turn left and right quickly to create some noise
// the led_set() calls are just added to create some light effect sync. to the melody
// the noteCnt % 8 distinction is also just for an effect - so deep notes are played on left,
// higher notes on the right motor
if (pulse++ % 2 == 0) {
if (noteCnt % 8 <= 1 ) {
led_set(3, 0);
led_set(2, 0);
led_set(noteCnt % 2, 1);
led_set(!(noteCnt % 2) , 0);
motpwm_setLeft(beeperVolume);
motpwm_setRight(0);
} else {
led_set(noteCnt % 2 + 2, 1);
led_set(!(noteCnt % 2) + 2, 0);
led_set(0, 0);
led_set(1, 0);
motpwm_setRight(beeperVolume);
motpwm_setLeft(0);
}
} else {
if (noteCnt % 8 <= 1) {
motpwm_setLeft(-beeperVolume);
motpwm_setRight(0);
} else {
motpwm_setRight(-beeperVolume);
motpwm_setLeft(0);
}
}
} else {
motpwm_setLeft(0);
motpwm_setRight(0);
}
}
Für Ideen, Anregungen, Verbesserungsvorschläge zum Programm/Code habe ich jederzeit ein offenes Ohr.
Lesezeichen