Making Music with PIC10F322 : Twinkle Twinkle Little Star

In a previous post, we explored generating a single tone using the 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 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.

NCO Sound

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 , 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?

jamie@jamiestarling.com


Pin It on Pinterest

Share This