Table of Contents
Making Music with PIC10F322 : Twinkle Twinkle Little Star
In a previous post, we explored generating a single tone using the PIC10F322 microcontroller. Now, we will build on that foundation to create a simple melody: “Twinkle Twinkle Little Star.” This process is reminiscent of using the PLAY command in BASIC on an x86 computer to produce sounds.
Creating the Melody
“Twinkle Twinkle Little Star” is a classic and straightforward melody, making it an ideal starting point for experimenting with music generation on the PIC10F322. While our initial version may not be perfect, it serves as a solid foundation for further refinement.
Steps to Create the Melody
Define the Notes: First, we need to define the notes of the melody. Each note corresponds to a specific frequency, which we will generate using the NCO (Numerically Controlled Oscillator) module of the PIC10F322.
Set Up the Timing: To play the melody correctly, we need to set the timing for each note. This involves specifying the duration of each note and the pauses between them. Although our initial implementation has a fixed timing, it provides a starting point.
Write the Code: Using the XC8 compiler, we will write the code to generate the melody. This involves setting up the NCO to produce the correct frequencies and feeding the notes into it at regular intervals.
Test and Debug: Upload the code to the PIC10F322 and connect a speaker or piezoelectric buzzer to the output pin. Listen to the melody and make any necessary adjustments.
Future Ideas: Expand the code to support timing for each note instead of a fixed timing method.
Adjustments:
__NOTE_DURATION controls how long a note is played
__NOTE_PAUSE controls the silence between notes
__SONG_PAUSE controls how long after the song plays before it plays agian.
The Circuit:
Pretty simple – Speaker connects to Ground and port RA.2 on the PIC10F322.
![Making Music with PIC10F322 : Using XC8 for Sound Generation 1 NCO Sound](https://jamiestarling.com/wp-content/uploads/2024/07/NCO_Sound.jpg)
The Code:
Here’s a simplified version of the code to get started with generating “Twinkle Twinkle Little Star”:
/****************************************************************************
* Title : NCO Twinkle Twinkle Little Star Song
* Filename : nco_songc
* Author : Jamie Starling
* Origin Date : 2024/07/12
* Version : 1.0.0
* Compiler : XC8
* Target : PIC10F322
* Copyright : Jamie Starling
* All Rights Reserved
*
* THIS SOFTWARE IS PROVIDED BY JAMIE STARLING "AS IS" AND ANY EXPRESSED
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL JAMIE STARLING OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
/******************************************************************************
* Includes
*******************************************************************************/
#include <xc.h>
#include <stdint.h>
/******************************************************************************
* Configuration
*******************************************************************************/
//Device Configuration
#pragma config FOSC = INTOSC // Oscillator Selection
#pragma config BOREN = ON // Brown-out Reset
#pragma config WDTE = OFF // Watchdog Timer
#pragma config PWRTE = ON // Power-up Timer
#pragma config MCLRE = OFF // MCLR Pin Function Select bit->MCLR pin function is digital input, MCLR internally tied to VDD
#pragma config CP = OFF // Code Protection
#pragma config LVP = OFF // Low-Voltage Programming
#pragma config LPBOR = ON // Brown-out Reset Selection bits
#pragma config BORV = LO // Brown-out Reset Voltage Selection
#pragma config WRT = OFF // Flash Memory Self-Write Protection
//Used to calculate the delay time - Change depending on processor Speed
#define _XTAL_FREQ 1000000 //16Mhz
/******************************************************************************
* Constants
*******************************************************************************/
#define __NOTE_DURATION 500
#define __SONG_PAUSE 2000
#define __NOTE_PAUSE 50
#define __NOTE_C 549
#define __NOTE_C_SHARP 580
#define __NOTE_D 616
#define __NOTE_D_SHARP 652
#define __NOTE_E 692
#define __NOTE_F 713
#define __NOTE_F_SHARP 775
#define __NOTE_G 822
#define __NOTE_G_SHARP 870
#define __NOTE_A 922
#define __NOTE_A_SHARP 977
#define __NOTE_B 1035
/******************************************************************************
* Variables
*******************************************************************************/
/******************************************************************************
* Function Prototypes
*******************************************************************************/
void setup(void);
void play_note(uint16_t note);
/******************************************************************************
* Functions
*******************************************************************************/
void main(void){
setup();
while(1){
play_note(__NOTE_C);
play_note(__NOTE_C);
play_note(__NOTE_G);
play_note(__NOTE_A);
play_note(__NOTE_A);
play_note(__NOTE_G);
play_note(__NOTE_F);
play_note(__NOTE_F);
play_note(__NOTE_E);
play_note(__NOTE_E);
play_note(__NOTE_D);
play_note(__NOTE_D);
play_note(__NOTE_C);
play_note(__NOTE_G);
play_note(__NOTE_G);
play_note(__NOTE_F);
play_note(__NOTE_F);
play_note(__NOTE_E);
play_note(__NOTE_E);
play_note(__NOTE_D);
play_note(__NOTE_G);
play_note(__NOTE_G);
play_note(__NOTE_F);
play_note(__NOTE_F);
play_note(__NOTE_E);
play_note(__NOTE_E);
play_note(__NOTE_D);
play_note(__NOTE_C);
play_note(__NOTE_C);
play_note(__NOTE_G);
play_note(__NOTE_G);
play_note(__NOTE_A);
play_note(__NOTE_A);
play_note(__NOTE_G);
play_note(__NOTE_F);
play_note(__NOTE_F);
play_note(__NOTE_E);
play_note(__NOTE_E);
play_note(__NOTE_D);
play_note(__NOTE_D);
play_note(__NOTE_C);
__delay_ms(__SONG_PAUSE);
}
}
void setup(void){
OSCCONbits.IRCF = 0b011; //Set System Clock to 1Mhz
TRISAbits.TRISA2 = 0; //Make sure to Set A2 to output - otherwise does not work.
NCO1CLKbits.N1CKS = 0b01; //Clock Source Select bits - Set to FOSC
NCO1CONbits.N1PFM = 0; //NCO operates in Fixed Duty Cycle mode
NCO1CONbits.N1EN = 1; //Enable NCO
}
void play_note(uint16_t note){
NCO1INC = note;
NCO1CONbits.N1OE = 1; //Enable Output
__delay_ms(__NOTE_DURATION);
NCO1CONbits.N1OE = 0; //Disable Output
__delay_ms(__NOTE_PAUSE);
}
/*** End of File **************************************************************/
Creating music with the PIC10F322 and XC8 is a rewarding challenge that combines programming, electronics, and creativity. By starting with a simple melody like “Twinkle Twinkle Little Star,” we can learn the basics of sound generation and gradually improve our skills. Remember, every complex project begins with a simple step. Happy coding!
Have a Project or Idea!?
Seeking Bespoke Technology Solutions?
Contact me today to discover how personalized, high-end tech solutions can meet your unique requirements.