Designing a Music Box Based on 51 Microcontroller

Designing a Music Box Based on 51 Microcontroller

Today we will design an interesting music box project that combines the LCD1602 display and a buzzer to allow our microcontroller to play music.

System Design Block Diagram

Note Frequency Table

// Note frequency definitions (unit: Hz)
unsigned int TONE_TAB[] = {
    523,  //do-low
    587,  //re
    659,  //mi
    698,  //fa
    784,  //so
    880,  //la
    988,  //si
    1047  //do-high
};

// Note duration definitions
unsigned char BEAT_TAB[] = {
    1,   // whole note
    2,   // half note
    4,   // quarter note
    8    // eighth note
};

Basic Hardware Driver

1. Buzzer Control Function

// Buzzer pin definition
sbit BEEP = P2^3;

// Note sound function
void Play_Tone(unsigned int freq, unsigned char time)
{
    unsigned int i, cycles;
    unsigned int period;
    
    period = 1000000/freq;     // Calculate period (us)
    cycles = freq * time/1000;  // Calculate loop count
    
    for(i=0; i<cycles; i++)
    {
        BEEP = 1;
        delay_us(period/2);
        BEEP = 0;
        delay_us(period/2);
    }
}

2. LCD Display Control

// Display current playing information
void Display_Music_Info(unsigned char *music_name, 
                       unsigned char note_index)
{
    LCD_WriteCmd(0x80);
    LCD_WriteString(music_name);
    
    LCD_WriteCmd(0xC0);
    LCD_WriteString("Playing...");
    LCD_WriteData(note_index + '0');
}

Music Data Structure

1. Score Definition

// Music structure definition
typedef struct {
    unsigned char tone;   // Note
    unsigned char beat;   // Beat
} MUSIC_NOTE;

// Little Star score
MUSIC_NOTE LITTLE_STAR[] = {
    {1,4}, {1,4}, {5,4}, {5,4},  // do do so so
    {6,4}, {6,4}, {5,2},         // la la so
    {4,4}, {4,4}, {3,4}, {3,4},  // fa fa mi mi
    {2,4}, {2,4}, {1,2},         // re re do
    {0,1}  // End symbol
};

2. Music Playback Control

void Play_Music(MUSIC_NOTE *music)
{
    unsigned char i = 0;
    
    while(music[i].tone != 0)  // Not end symbol
    {
        if(KEY_STOP == 0)      // Check stop key
            break;
            
        // Play note
        Play_Tone(TONE_TAB[music[i].tone-1], 
                 1000/music[i].beat);
                 
        // Display progress
        Display_Music_Info("Little Star", i);
        
        // Short pause between notes
        delay_ms(50);
        i++;
    }
}

Function Expansion Implementation

1. Music Selection Menu

void Music_Select()
{
    unsigned char music_index = 0;
    char *music_list[] = {
        "Little Star",
        "Happy Birthday",
        "Jingle Bells"
    };
    
    LCD_WriteCmd(0x80);
    LCD_WriteString("Select Music:");
    
    while(1)
    {
        LCD_WriteCmd(0xC0);
        LCD_WriteString(music_list[music_index]);
        
        if(KEY_UP == 0)   // Scroll up
        {
            delay_ms(10);
            if(KEY_UP == 0)
                music_index++;
        }
        
        if(KEY_DOWN == 0) // Scroll down
        {
            delay_ms(10);
            if(KEY_DOWN == 0)
                music_index--;
        }
        
        if(KEY_OK == 0)   // Confirm
            return music_index;
    }
}

2. Volume Control

void Volume_Control(unsigned char *volume)
{
    if(KEY_VOL_UP == 0)
    {
        delay_ms(10);
        if(KEY_VOL_UP == 0 && *volume < 8)
            (*volume)++;
    }
    
    if(KEY_VOL_DOWN == 0)
    {
        delay_ms(10);
        if(KEY_VOL_DOWN == 0 && *volume > 0)
            (*volume)--;
    }
    
    // Display volume bar
    LCD_WriteCmd(0xC0);
    LCD_WriteString("VOL:");
    for(unsigned char i=0; i<*volume; i++)
        LCD_WriteData('*');
}

3. Tempo Adjustment

void Tempo_Adjust(unsigned char *tempo)
{
    unsigned int base_time;
    base_time = 1000 / (*tempo);  // Base beat time value
    
    if(KEY_TEMPO_UP == 0)
        (*tempo)++;
    if(KEY_TEMPO_DOWN == 0)
        (*tempo)--;
        
    LCD_WriteCmd(0xC0);
    LCD_WriteString("Tempo:");
    LCD_WriteNum(*tempo);
}

Precautions

  1. Buzzer Driver Optimization
// Use timer to generate square wave
void Timer0_PWM()
{
    TH0 = 0xFF;   // Timer reload value
    TL0 = 0xF0;
    TR0 = 1;      // Start timer
}
  1. Key Debounce Processing
bit Key_Scan(unsigned char key_pin)
{
    if(key_pin == 0)
    {
        delay_ms(10);  // Debounce delay
        if(key_pin == 0)
        {
            while(!key_pin);  // Wait for release
            return 1;
        }
    }
    return 0;
}
  1. Power Saving Mode
void Power_Save()
{
    if(no_operation_time > 30)  // 30 seconds without operation
    {
        LCD_WriteCmd(0x08);     // Turn off display
        PCON |= 0x02;           // Enter power-down mode
    }
}

Practical Suggestions:

  • Set volume reasonably
  • Add startup animation
  • Save user settings
  • Support resume playback

The music box, although simple in principle, requires attention to detail to make it fun. It is recommended to add more user-friendly interaction designs after implementing the basic functions.

Leave a Comment