Drive a speaker using PWM

Dependencies:   mbed

Dependents:   PwmSpeaker-Example

Committer:
asmellby
Date:
Fri Nov 13 22:22:12 2015 +0000
Revision:
2:840bc39c112e
Parent:
1:10005e388826
Update to create library

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 1:10005e388826 10 /**
asmellby 1:10005e388826 11 * Set output frequency of the speaker.
asmellby 1:10005e388826 12 *
asmellby 1:10005e388826 13 * \param frequency The frequency to set
asmellby 1:10005e388826 14 */
asmellby 0:b7dd35e61bb1 15 void Speaker::set_frequency(uint32_t frequency) {
asmellby 0:b7dd35e61bb1 16 _pwm.period(1.0/frequency);
asmellby 0:b7dd35e61bb1 17 }
asmellby 0:b7dd35e61bb1 18
asmellby 1:10005e388826 19 /**
asmellby 1:10005e388826 20 * Enable or disable speaker output.
asmellby 1:10005e388826 21 *
asmellby 1:10005e388826 22 * \param enable Whether to enable or disable the speaker
asmellby 1:10005e388826 23 */
asmellby 0:b7dd35e61bb1 24 void Speaker::enable(bool enable) {
asmellby 0:b7dd35e61bb1 25 *this = enable;
asmellby 0:b7dd35e61bb1 26 }
asmellby 0:b7dd35e61bb1 27
asmellby 1:10005e388826 28 /**
asmellby 1:10005e388826 29 * Enable or disable the speaker output.
asmellby 1:10005e388826 30 *
asmellby 1:10005e388826 31 * \param setting 0 to disable speaker, other values to enable speaker.
asmellby 1:10005e388826 32 */
asmellby 0:b7dd35e61bb1 33 Speaker& Speaker::operator=(int setting) {
asmellby 0:b7dd35e61bb1 34 if (setting) {
asmellby 0:b7dd35e61bb1 35 _pwm = 0.5;
asmellby 0:b7dd35e61bb1 36 } else {
asmellby 0:b7dd35e61bb1 37 _pwm = 1;
asmellby 0:b7dd35e61bb1 38 }
asmellby 0:b7dd35e61bb1 39 return *this;
asmellby 0:b7dd35e61bb1 40 }
asmellby 0:b7dd35e61bb1 41
asmellby 1:10005e388826 42 /**
asmellby 1:10005e388826 43 * Play an old-school ringtone in RTTTL language.
asmellby 1:10005e388826 44 *
asmellby 1:10005e388826 45 * \param p Char array in RTTTL format
asmellby 0:b7dd35e61bb1 46 */
asmellby 0:b7dd35e61bb1 47 void Speaker::play_rtttl(char * p) {
asmellby 0:b7dd35e61bb1 48 // Absolutely no error checking in here
asmellby 0:b7dd35e61bb1 49
asmellby 0:b7dd35e61bb1 50 uint8_t default_dur = 4;
asmellby 0:b7dd35e61bb1 51 uint8_t default_oct = 6;
asmellby 0:b7dd35e61bb1 52 int bpm = 63;
asmellby 0:b7dd35e61bb1 53 int num;
asmellby 0:b7dd35e61bb1 54 long wholenote;
asmellby 0:b7dd35e61bb1 55 long duration;
asmellby 0:b7dd35e61bb1 56 uint8_t note;
asmellby 0:b7dd35e61bb1 57 uint8_t scale;
asmellby 0:b7dd35e61bb1 58
asmellby 0:b7dd35e61bb1 59 // format: d=N,o=N,b=NNN:
asmellby 0:b7dd35e61bb1 60 // find the start (skip name, etc)
asmellby 0:b7dd35e61bb1 61
asmellby 0:b7dd35e61bb1 62 while(*p != ':') p++; // ignore name
asmellby 0:b7dd35e61bb1 63 p++; // skip ':'
asmellby 0:b7dd35e61bb1 64
asmellby 0:b7dd35e61bb1 65 // get default duration
asmellby 0:b7dd35e61bb1 66 if(*p == 'd')
asmellby 0:b7dd35e61bb1 67 {
asmellby 0:b7dd35e61bb1 68 p++; p++; // skip "d="
asmellby 0:b7dd35e61bb1 69 num = 0;
asmellby 0:b7dd35e61bb1 70 while(isdigit(*p))
asmellby 0:b7dd35e61bb1 71 {
asmellby 0:b7dd35e61bb1 72 num = (num * 10) + (*p++ - '0');
asmellby 0:b7dd35e61bb1 73 }
asmellby 0:b7dd35e61bb1 74 if(num > 0) default_dur = num;
asmellby 0:b7dd35e61bb1 75 p++; // skip comma
asmellby 0:b7dd35e61bb1 76 }
asmellby 0:b7dd35e61bb1 77
asmellby 0:b7dd35e61bb1 78 printf("ddur: %d\n", default_dur);
asmellby 0:b7dd35e61bb1 79
asmellby 0:b7dd35e61bb1 80 // get default octave
asmellby 0:b7dd35e61bb1 81 if(*p == 'o')
asmellby 0:b7dd35e61bb1 82 {
asmellby 0:b7dd35e61bb1 83 p++; p++; // skip "o="
asmellby 0:b7dd35e61bb1 84 num = *p++ - '0';
asmellby 0:b7dd35e61bb1 85 if(num >= 3 && num <=7) default_oct = num;
asmellby 0:b7dd35e61bb1 86 p++; // skip comma
asmellby 0:b7dd35e61bb1 87 }
asmellby 0:b7dd35e61bb1 88
asmellby 0:b7dd35e61bb1 89 printf("doct: %d\n", default_oct);
asmellby 0:b7dd35e61bb1 90
asmellby 0:b7dd35e61bb1 91 // get BPM
asmellby 0:b7dd35e61bb1 92 if(*p == 'b')
asmellby 0:b7dd35e61bb1 93 {
asmellby 0:b7dd35e61bb1 94 p++; p++; // skip "b="
asmellby 0:b7dd35e61bb1 95 num = 0;
asmellby 0:b7dd35e61bb1 96 while(isdigit(*p))
asmellby 0:b7dd35e61bb1 97 {
asmellby 0:b7dd35e61bb1 98 num = (num * 10) + (*p++ - '0');
asmellby 0:b7dd35e61bb1 99 }
asmellby 0:b7dd35e61bb1 100 bpm = num;
asmellby 0:b7dd35e61bb1 101 p++; // skip colon
asmellby 0:b7dd35e61bb1 102 }
asmellby 0:b7dd35e61bb1 103
asmellby 0:b7dd35e61bb1 104 printf("bpm: %d\n",bpm);
asmellby 0:b7dd35e61bb1 105
asmellby 0:b7dd35e61bb1 106 // BPM usually expresses the number of quarter notes per minute
asmellby 0:b7dd35e61bb1 107 wholenote = (60 * 1000L / bpm) * 4; // this is the time for whole note (in milliseconds)
asmellby 0:b7dd35e61bb1 108
asmellby 0:b7dd35e61bb1 109 printf("wn: %d\n", wholenote);
asmellby 0:b7dd35e61bb1 110
asmellby 0:b7dd35e61bb1 111
asmellby 0:b7dd35e61bb1 112 // now begin note loop
asmellby 0:b7dd35e61bb1 113 while(*p)
asmellby 0:b7dd35e61bb1 114 {
asmellby 0:b7dd35e61bb1 115 // first, get note duration, if available
asmellby 0:b7dd35e61bb1 116 num = 0;
asmellby 0:b7dd35e61bb1 117 while(isdigit(*p))
asmellby 0:b7dd35e61bb1 118 {
asmellby 0:b7dd35e61bb1 119 num = (num * 10) + (*p++ - '0');
asmellby 0:b7dd35e61bb1 120 }
asmellby 0:b7dd35e61bb1 121
asmellby 0:b7dd35e61bb1 122 if(num) duration = wholenote / num;
asmellby 0:b7dd35e61bb1 123 else duration = wholenote / default_dur; // we will need to check if we are a dotted note after
asmellby 0:b7dd35e61bb1 124
asmellby 0:b7dd35e61bb1 125 // now get the note
asmellby 0:b7dd35e61bb1 126 note = 0;
asmellby 0:b7dd35e61bb1 127
asmellby 0:b7dd35e61bb1 128 switch(*p)
asmellby 0:b7dd35e61bb1 129 {
asmellby 0:b7dd35e61bb1 130 case 'c':
asmellby 0:b7dd35e61bb1 131 note = 1;
asmellby 0:b7dd35e61bb1 132 break;
asmellby 0:b7dd35e61bb1 133 case 'd':
asmellby 0:b7dd35e61bb1 134 note = 3;
asmellby 0:b7dd35e61bb1 135 break;
asmellby 0:b7dd35e61bb1 136 case 'e':
asmellby 0:b7dd35e61bb1 137 note = 5;
asmellby 0:b7dd35e61bb1 138 break;
asmellby 0:b7dd35e61bb1 139 case 'f':
asmellby 0:b7dd35e61bb1 140 note = 6;
asmellby 0:b7dd35e61bb1 141 break;
asmellby 0:b7dd35e61bb1 142 case 'g':
asmellby 0:b7dd35e61bb1 143 note = 8;
asmellby 0:b7dd35e61bb1 144 break;
asmellby 0:b7dd35e61bb1 145 case 'a':
asmellby 0:b7dd35e61bb1 146 note = 10;
asmellby 0:b7dd35e61bb1 147 break;
asmellby 0:b7dd35e61bb1 148 case 'b':
asmellby 0:b7dd35e61bb1 149 note = 12;
asmellby 0:b7dd35e61bb1 150 break;
asmellby 0:b7dd35e61bb1 151 case 'p':
asmellby 0:b7dd35e61bb1 152 default:
asmellby 0:b7dd35e61bb1 153 note = 0;
asmellby 0:b7dd35e61bb1 154 }
asmellby 0:b7dd35e61bb1 155 p++;
asmellby 0:b7dd35e61bb1 156
asmellby 0:b7dd35e61bb1 157 // now, get optional '#' sharp
asmellby 0:b7dd35e61bb1 158 if(*p == '#')
asmellby 0:b7dd35e61bb1 159 {
asmellby 0:b7dd35e61bb1 160 note++;
asmellby 0:b7dd35e61bb1 161 p++;
asmellby 0:b7dd35e61bb1 162 }
asmellby 0:b7dd35e61bb1 163
asmellby 0:b7dd35e61bb1 164 // now, get optional '.' dotted note
asmellby 0:b7dd35e61bb1 165 if(*p == '.')
asmellby 0:b7dd35e61bb1 166 {
asmellby 0:b7dd35e61bb1 167 duration += duration/2;
asmellby 0:b7dd35e61bb1 168 p++;
asmellby 0:b7dd35e61bb1 169 }
asmellby 0:b7dd35e61bb1 170
asmellby 0:b7dd35e61bb1 171 // now, get scale
asmellby 0:b7dd35e61bb1 172 if(isdigit(*p))
asmellby 0:b7dd35e61bb1 173 {
asmellby 0:b7dd35e61bb1 174 scale = *p - '0';
asmellby 0:b7dd35e61bb1 175 p++;
asmellby 0:b7dd35e61bb1 176 }
asmellby 0:b7dd35e61bb1 177 else
asmellby 0:b7dd35e61bb1 178 {
asmellby 0:b7dd35e61bb1 179 scale = default_oct;
asmellby 0:b7dd35e61bb1 180 }
asmellby 0:b7dd35e61bb1 181
asmellby 0:b7dd35e61bb1 182 scale += _offset;
asmellby 0:b7dd35e61bb1 183
asmellby 0:b7dd35e61bb1 184 if(*p == ',')
asmellby 0:b7dd35e61bb1 185 p++; // skip comma for next note (or we may be at the end)
asmellby 0:b7dd35e61bb1 186
asmellby 0:b7dd35e61bb1 187 // now play the note
asmellby 0:b7dd35e61bb1 188
asmellby 0:b7dd35e61bb1 189 if(note)
asmellby 0:b7dd35e61bb1 190 {
asmellby 0:b7dd35e61bb1 191 //printf("\027\033H");
asmellby 0:b7dd35e61bb1 192 //printf("Playing: %d %d (%d) %d\n", scale, note, notes[(scale - 4) * 12 + note], duration);
asmellby 0:b7dd35e61bb1 193 set_frequency(notes[(scale - 4) * 12 + note]);
asmellby 0:b7dd35e61bb1 194 enable(true);
asmellby 0:b7dd35e61bb1 195 wait_ms(duration);
asmellby 0:b7dd35e61bb1 196 enable(false);
asmellby 0:b7dd35e61bb1 197 }
asmellby 0:b7dd35e61bb1 198 else
asmellby 0:b7dd35e61bb1 199 {
asmellby 0:b7dd35e61bb1 200 //printf("Pausing: %d\n", duration);
asmellby 0:b7dd35e61bb1 201 wait_ms(duration);
asmellby 0:b7dd35e61bb1 202 }
asmellby 0:b7dd35e61bb1 203 }
asmellby 0:b7dd35e61bb1 204 }