Add music to your next project
Rodger Richey, Microchip Technology Inc, Chandler, AZ -- EDN, 12/23/1999
Adding music to your next design is as simple as using one I/O pin to drive the speaker and approximately 150 words of program memory to play the music. You can store the musical notes and durations internally in program memory or externally in a serial EEPROM. Frequently, implementing musical playback requires an external processor with memory or a specialized melody device. Both cases can bring increased cost and can limit the number of songs you can play back. The approach described here uses a Microchip Technology midrange PIC WC with a free 8-bit timer resource. Two implementations are possible. The one presented here uses internal program memory to store the musical notes. This method allows as many as 127 notes per song. The other technique is to use an external serial EEPROM to store the notes.The first important point to consider is that the musical playback is completely interrupt-driven. Therefore, the main application can run in the foreground and can accept interrupts as necessary from the musical playback. Timer0 controls the playback; you can find it on any of the midrange PIC WCs—from the eight-pin PIC12C671 to the 68-pin PIC16C924. This timer is a generic 8-bit timer with an 8-bit prescaler. You can download the assembly code. The code is designed to run a PIC WC at 4 MHz. You can accommodate other frequencies by changing defines in the code. At 4 MHz, you use a 1-to-8 prescaler to provide the correct frequencies for the notes to play. Again, you can modify the prescale value to suit the desired operating frequency by changing the value in the Option register. One I/O pin provides the musical notes to the speaker. Figure 1 shows the simple connections. You can modify the source code and hardware to drive the speaker differentially using two I/O pins.
Toggling an I/O pin at twice the frequency of the desired note generates each note. This technique creates software-based pulse-width modulation with a 50% duty cycle and a tone at the desired frequency. At each Timer0 interrupt, the routine reloads TMR0 with the number of ticks for the desired frequency. You use the following formula to calculate the number of ticks for each note:
TICKS(Freqx)=[256–((CLOCK/4/PRESCALER/Freqx/2)–1)]
Using CLOCK=4MHz, PRESCALER=8, and Freqx=523, the calculated number of ticks for an A tone is 137. The number of ticks required is actually 118, but by subtracting this number from 256 in the formula, you can get the value to load into TMR0. A table designated Notes in the source code lists only seven notes, but it's easy to add more. You can determine the duration of each note by counting the number of Timer0 interrupts. Because the timer interrupt period differs for every note, the number of Timer0 interrupts differs for every note. A table called Durations in the source code contains the note duration for the corresponding note in the Notes table. On each Timer0 interrupt, the Notes value loads into TMR0 and the note duration decrements. At the end of each note, a pause of 1/64 occurs to emphasize the note you are playing. The routine creates the pause by not toggling the output pin during the pause interrupts. Again, each note requires a different number of interrupts to generate a pause of a set duration. To simplify the pause generation, the program subtracts the number of interrupts required for a pause from each note duration. The routine creates the pause by setting the timer such that the pause occurs from one timer interrupt. If the clock frequency is such that you cannot create the pause with one interrupt, you can alter the value STOP_LENGTH in the source code. The program loads the next note to play after the pause interrupt. A 0 in the Notes and Durations tables in the source code denotes the end of the song. At this point, the program plays the song again.
Using internal memory to store the notes and durations has some limitations. Without some extra table-handling code, tables are limited to 255 elements and must start on a 256-byte boundary. Because the duration values are 16 bits long, the number of notes the PIC WC can play is 127. Depending on the size of program memory, you can place many songs in 256-byte blocks and play them individually. By using two more I/O pins (SCL and SDA), the PIC WC can interface to an external serial EEPROM and play any number of notes up to the maximum memory size divided by 3. A 24LC01B from Microchip Technology can hold 341 notes plus corresponding durations. (DI #2456)


















