Drive a speaker using PWM

Dependencies:   mbed

Dependents:   PwmSpeaker-Example

Committer:
asmellby
Date:
Thu Nov 12 21:04:11 2015 +0000
Revision:
0:b7dd35e61bb1
Child:
1:10005e388826
Initial commit;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
asmellby 0:b7dd35e61bb1 1 #include "Speaker.h"
asmellby 0:b7dd35e61bb1 2
asmellby 0:b7dd35e61bb1 3 static int notes[] = {0,
asmellby 0:b7dd35e61bb1 4 NOTE_C4, NOTE_CS4, NOTE_D4, NOTE_DS4, NOTE_E4, NOTE_F4, NOTE_FS4, NOTE_G4, NOTE_GS4, NOTE_A4, NOTE_AS4, NOTE_B4,
asmellby 0:b7dd35e61bb1 5 NOTE_C5, NOTE_CS5, NOTE_D5, NOTE_DS5, NOTE_E5, NOTE_F5, NOTE_FS5, NOTE_G5, NOTE_GS5, NOTE_A5, NOTE_AS5, NOTE_B5,
asmellby 0:b7dd35e61bb1 6 NOTE_C6, NOTE_CS6, NOTE_D6, NOTE_DS6, NOTE_E6, NOTE_F6, NOTE_FS6, NOTE_G6, NOTE_GS6, NOTE_A6, NOTE_AS6, NOTE_B6,
asmellby 0:b7dd35e61bb1 7 NOTE_C7, NOTE_CS7, NOTE_D7, NOTE_DS7, NOTE_E7, NOTE_F7, NOTE_FS7, NOTE_G7, NOTE_GS7, NOTE_A7, NOTE_AS7, NOTE_B7
asmellby 0:b7dd35e61bb1 8 };
asmellby 0:b7dd35e61bb1 9
asmellby 0:b7dd35e61bb1 10 void Speaker::set_frequency(uint32_t frequency) {
asmellby 0:b7dd35e61bb1 11 _pwm.period(1.0/frequency);
asmellby 0:b7dd35e61bb1 12 }
asmellby 0:b7dd35e61bb1 13
asmellby 0:b7dd35e61bb1 14 void Speaker::enable(bool enable) {
asmellby 0:b7dd35e61bb1 15 *this = enable;
asmellby 0:b7dd35e61bb1 16 }
asmellby 0:b7dd35e61bb1 17
asmellby 0:b7dd35e61bb1 18 Speaker& Speaker::operator=(int setting) {
asmellby 0:b7dd35e61bb1 19 if (setting) {
asmellby 0:b7dd35e61bb1 20 _pwm = 0.5;
asmellby 0:b7dd35e61bb1 21 } else {
asmellby 0:b7dd35e61bb1 22 _pwm = 1;
asmellby 0:b7dd35e61bb1 23 }
asmellby 0:b7dd35e61bb1 24 return *this;
asmellby 0:b7dd35e61bb1 25 }
asmellby 0:b7dd35e61bb1 26
asmellby 0:b7dd35e61bb1 27 /*
asmellby 0:b7dd35e61bb1 28 * Plays an old-school ringtone in RTTTL language.
asmellby 0:b7dd35e61bb1 29 */
asmellby 0:b7dd35e61bb1 30 void Speaker::play_rtttl(char * p) {
asmellby 0:b7dd35e61bb1 31 // Absolutely no error checking in here
asmellby 0:b7dd35e61bb1 32
asmellby 0:b7dd35e61bb1 33 uint8_t default_dur = 4;
asmellby 0:b7dd35e61bb1 34 uint8_t default_oct = 6;
asmellby 0:b7dd35e61bb1 35 int bpm = 63;
asmellby 0:b7dd35e61bb1 36 int num;
asmellby 0:b7dd35e61bb1 37 long wholenote;
asmellby 0:b7dd35e61bb1 38 long duration;
asmellby 0:b7dd35e61bb1 39 uint8_t note;
asmellby 0:b7dd35e61bb1 40 uint8_t scale;
asmellby 0:b7dd35e61bb1 41
asmellby 0:b7dd35e61bb1 42 // format: d=N,o=N,b=NNN:
asmellby 0:b7dd35e61bb1 43 // find the start (skip name, etc)
asmellby 0:b7dd35e61bb1 44
asmellby 0:b7dd35e61bb1 45 while(*p != ':') p++; // ignore name
asmellby 0:b7dd35e61bb1 46 p++; // skip ':'
asmellby 0:b7dd35e61bb1 47
asmellby 0:b7dd35e61bb1 48 // get default duration
asmellby 0:b7dd35e61bb1 49 if(*p == 'd')
asmellby 0:b7dd35e61bb1 50 {
asmellby 0:b7dd35e61bb1 51 p++; p++; // skip "d="
asmellby 0:b7dd35e61bb1 52 num = 0;
asmellby 0:b7dd35e61bb1 53 while(isdigit(*p))
asmellby 0:b7dd35e61bb1 54 {
asmellby 0:b7dd35e61bb1 55 num = (num * 10) + (*p++ - '0');
asmellby 0:b7dd35e61bb1 56 }
asmellby 0:b7dd35e61bb1 57 if(num > 0) default_dur = num;
asmellby 0:b7dd35e61bb1 58 p++; // skip comma
asmellby 0:b7dd35e61bb1 59 }
asmellby 0:b7dd35e61bb1 60
asmellby 0:b7dd35e61bb1 61 printf("ddur: %d\n", default_dur);
asmellby 0:b7dd35e61bb1 62
asmellby 0:b7dd35e61bb1 63 // get default octave
asmellby 0:b7dd35e61bb1 64 if(*p == 'o')
asmellby 0:b7dd35e61bb1 65 {
asmellby 0:b7dd35e61bb1 66 p++; p++; // skip "o="
asmellby 0:b7dd35e61bb1 67 num = *p++ - '0';
asmellby 0:b7dd35e61bb1 68 if(num >= 3 && num <=7) default_oct = num;
asmellby 0:b7dd35e61bb1 69 p++; // skip comma
asmellby 0:b7dd35e61bb1 70 }
asmellby 0:b7dd35e61bb1 71
asmellby 0:b7dd35e61bb1 72 printf("doct: %d\n", default_oct);
asmellby 0:b7dd35e61bb1 73
asmellby 0:b7dd35e61bb1 74 // get BPM
asmellby 0:b7dd35e61bb1 75 if(*p == 'b')
asmellby 0:b7dd35e61bb1 76 {
asmellby 0:b7dd35e61bb1 77 p++; p++; // skip "b="
asmellby 0:b7dd35e61bb1 78 num = 0;
asmellby 0:b7dd35e61bb1 79 while(isdigit(*p))
asmellby 0:b7dd35e61bb1 80 {
asmellby 0:b7dd35e61bb1 81 num = (num * 10) + (*p++ - '0');
asmellby 0:b7dd35e61bb1 82 }
asmellby 0:b7dd35e61bb1 83 bpm = num;
asmellby 0:b7dd35e61bb1 84 p++; // skip colon
asmellby 0:b7dd35e61bb1 85 }
asmellby 0:b7dd35e61bb1 86
asmellby 0:b7dd35e61bb1 87 printf("bpm: %d\n",bpm);
asmellby 0:b7dd35e61bb1 88
asmellby 0:b7dd35e61bb1 89 // BPM usually expresses the number of quarter notes per minute
asmellby 0:b7dd35e61bb1 90 wholenote = (60 * 1000L / bpm) * 4; // this is the time for whole note (in milliseconds)
asmellby 0:b7dd35e61bb1 91
asmellby 0:b7dd35e61bb1 92 printf("wn: %d\n", wholenote);
asmellby 0:b7dd35e61bb1 93
asmellby 0:b7dd35e61bb1 94
asmellby 0:b7dd35e61bb1 95 // now begin note loop
asmellby 0:b7dd35e61bb1 96 while(*p)
asmellby 0:b7dd35e61bb1 97 {
asmellby 0:b7dd35e61bb1 98 // first, get note duration, if available
asmellby 0:b7dd35e61bb1 99 num = 0;
asmellby 0:b7dd35e61bb1 100 while(isdigit(*p))
asmellby 0:b7dd35e61bb1 101 {
asmellby 0:b7dd35e61bb1 102 num = (num * 10) + (*p++ - '0');
asmellby 0:b7dd35e61bb1 103 }
asmellby 0:b7dd35e61bb1 104
asmellby 0:b7dd35e61bb1 105 if(num) duration = wholenote / num;
asmellby 0:b7dd35e61bb1 106 else duration = wholenote / default_dur; // we will need to check if we are a dotted note after
asmellby 0:b7dd35e61bb1 107
asmellby 0:b7dd35e61bb1 108 // now get the note
asmellby 0:b7dd35e61bb1 109 note = 0;
asmellby 0:b7dd35e61bb1 110
asmellby 0:b7dd35e61bb1 111 switch(*p)
asmellby 0:b7dd35e61bb1 112 {
asmellby 0:b7dd35e61bb1 113 case 'c':
asmellby 0:b7dd35e61bb1 114 note = 1;
asmellby 0:b7dd35e61bb1 115 break;
asmellby 0:b7dd35e61bb1 116 case 'd':
asmellby 0:b7dd35e61bb1 117 note = 3;
asmellby 0:b7dd35e61bb1 118 break;
asmellby 0:b7dd35e61bb1 119 case 'e':
asmellby 0:b7dd35e61bb1 120 note = 5;
asmellby 0:b7dd35e61bb1 121 break;
asmellby 0:b7dd35e61bb1 122 case 'f':
asmellby 0:b7dd35e61bb1 123 note = 6;
asmellby 0:b7dd35e61bb1 124 break;
asmellby 0:b7dd35e61bb1 125 case 'g':
asmellby 0:b7dd35e61bb1 126 note = 8;
asmellby 0:b7dd35e61bb1 127 break;
asmellby 0:b7dd35e61bb1 128 case 'a':
asmellby 0:b7dd35e61bb1 129 note = 10;
asmellby 0:b7dd35e61bb1 130 break;
asmellby 0:b7dd35e61bb1 131 case 'b':
asmellby 0:b7dd35e61bb1 132 note = 12;
asmellby 0:b7dd35e61bb1 133 break;
asmellby 0:b7dd35e61bb1 134 case 'p':
asmellby 0:b7dd35e61bb1 135 default:
asmellby 0:b7dd35e61bb1 136 note = 0;
asmellby 0:b7dd35e61bb1 137 }
asmellby 0:b7dd35e61bb1 138 p++;
asmellby 0:b7dd35e61bb1 139
asmellby 0:b7dd35e61bb1 140 // now, get optional '#' sharp
asmellby 0:b7dd35e61bb1 141 if(*p == '#')
asmellby 0:b7dd35e61bb1 142 {
asmellby 0:b7dd35e61bb1 143 note++;
asmellby 0:b7dd35e61bb1 144 p++;
asmellby 0:b7dd35e61bb1 145 }
asmellby 0:b7dd35e61bb1 146
asmellby 0:b7dd35e61bb1 147 // now, get optional '.' dotted note
asmellby 0:b7dd35e61bb1 148 if(*p == '.')
asmellby 0:b7dd35e61bb1 149 {
asmellby 0:b7dd35e61bb1 150 duration += duration/2;
asmellby 0:b7dd35e61bb1 151 p++;
asmellby 0:b7dd35e61bb1 152 }
asmellby 0:b7dd35e61bb1 153
asmellby 0:b7dd35e61bb1 154 // now, get scale
asmellby 0:b7dd35e61bb1 155 if(isdigit(*p))
asmellby 0:b7dd35e61bb1 156 {
asmellby 0:b7dd35e61bb1 157 scale = *p - '0';
asmellby 0:b7dd35e61bb1 158 p++;
asmellby 0:b7dd35e61bb1 159 }
asmellby 0:b7dd35e61bb1 160 else
asmellby 0:b7dd35e61bb1 161 {
asmellby 0:b7dd35e61bb1 162 scale = default_oct;
asmellby 0:b7dd35e61bb1 163 }
asmellby 0:b7dd35e61bb1 164
asmellby 0:b7dd35e61bb1 165 scale += _offset;
asmellby 0:b7dd35e61bb1 166
asmellby 0:b7dd35e61bb1 167 if(*p == ',')
asmellby 0:b7dd35e61bb1 168 p++; // skip comma for next note (or we may be at the end)
asmellby 0:b7dd35e61bb1 169
asmellby 0:b7dd35e61bb1 170 // now play the note
asmellby 0:b7dd35e61bb1 171
asmellby 0:b7dd35e61bb1 172 if(note)
asmellby 0:b7dd35e61bb1 173 {
asmellby 0:b7dd35e61bb1 174 //printf("\027\033H");
asmellby 0:b7dd35e61bb1 175 //printf("Playing: %d %d (%d) %d\n", scale, note, notes[(scale - 4) * 12 + note], duration);
asmellby 0:b7dd35e61bb1 176 set_frequency(notes[(scale - 4) * 12 + note]);
asmellby 0:b7dd35e61bb1 177 enable(true);
asmellby 0:b7dd35e61bb1 178 wait_ms(duration);
asmellby 0:b7dd35e61bb1 179 enable(false);
asmellby 0:b7dd35e61bb1 180 }
asmellby 0:b7dd35e61bb1 181 else
asmellby 0:b7dd35e61bb1 182 {
asmellby 0:b7dd35e61bb1 183 //printf("Pausing: %d\n", duration);
asmellby 0:b7dd35e61bb1 184 wait_ms(duration);
asmellby 0:b7dd35e61bb1 185 }
asmellby 0:b7dd35e61bb1 186 }
asmellby 0:b7dd35e61bb1 187 }