#include "public.h"
#include "key.h"
#include "beep.h"
#include "songdata.h"
#define Clk 0x070000


unsigned char data val_H; //计数器高字节
unsigned char data val_L; //计数器低字节


#define ROWS 4
#define COLS 4


sbit P00 = P2^5; //扬声器控制引脚


// 定义矩阵键盘的行列对应的引脚
sbit row1 = P1^7;
sbit row2 = P1^6;
sbit row3 = P1^5;
sbit row4 = P1^4;
sbit col1 = P1^3;
sbit col2 = P1^2;
sbit col3 = P1^1;
sbit col4 = P1^0;


// 音符频率数组
unsigned int freq[] = {262, 294, 330, 349, 392, 440, 494, 523, 0, 587, 659, 698, 784};

// 音乐保存缓冲区，最多可以保存32个音符
unsigned char music_buffer[32];
unsigned char music_length = 0;

// 定义矩阵键盘的键值
const unsigned char keymap[ROWS][COLS] = {
    {'1', '2', '3', 'A'},
    {'4', '5', '6', 'B'},
    {'7', '8', '9', 'C'},
    {'*', '0', '#', 'D'}
};


bit song_playing = 0; // 添加歌曲播放标志

void t0_isr() interrupt 1 //定时器 0 中断处理程序
{
    if (song_playing) { // 当歌曲播放标志为真时，产生方波
        P00 = ~P00;
    } else {
        P00 = 1; // 不产生方波，关闭蜂鸣器
    }
    TH0 = val_H; //重新装入计数值
    TL0 = val_L;
}



void Delay(unsigned char cnt) //单位延时
{
  unsigned char i;
   unsigned int j;
   for(i=0; i<cnt; i++)
{
    for(j=0; j<0x3600; j++);
}
}



char matrix_keypad_scan() 
{
    char key = 0;
    int i, j;

    // 将所有行置为高电平，所有列置为输入模式
    row1 = 1; row2 = 1; row3 = 1; row4 = 1;
    col1 = 0; col2 = 0; col3 = 0; col4 = 0;

    // 检测每一行的状态
    for (i = 0; i < ROWS; i++) {
        switch (i) {
            case 0: row1 = 0; break;
            case 1: row2 = 0; break;
            case 2: row3 = 0; break;
            case 3: row4 = 0; break;
        }
        delay_10us(1000);

        // 检测每一列的状态
        for (j = 0; j < COLS; j++) {
            if (col1 == 0) {
                key = keymap[i][j];
                break;
            }
            if (col2 == 0) {
                key = keymap[i][j+1];
                break;
            }
            if (col3 == 0) {
                key = keymap[i][j+2];
                break;
            }
            if (col4 == 0) {
                key = keymap[i][j+3];
                break;
            }
        }

        // 如果检测到按键，跳出循环
        if (key != 0) {
            break;
        }

        // 恢复所有列的状态为输入模式
        col1 = 1; col2 = 1; col3 = 1; col4 = 1;
    }

    // 等待按键释放
    while (col1==0 || col2==0 || col3==0 || col4==0);

    return key;
}




void main()
{
    u8 key = 0;
    u8 beep_flag1 = 0; //蜂鸣器状态标志
    u8 beep_flag2 = 0;
    u8 beep_flag3 = 0;
	u8 beep_flag4 = 0;
    unsigned int val;
    unsigned char i = 0;
    TMOD = 0x01; //初始化
    IE = 0x82;
    TR0 = 1;
    while (1)
    {
        key = key_scan(0); //检测按键
      if (key == KEY1_PRESS) //K1按下，放第一首歌
        {
            beep_flag1 = !beep_flag1;
            beep_flag2 = 0;
            beep_flag3 = 0;
			beep_flag4=0;
            i = 0;
        }
        else if (key == KEY2_PRESS) //K2按下放第二首歌
        {
            beep_flag2 = !beep_flag2;
            beep_flag1 = 0;
            beep_flag3 = 0;
			beep_flag4=0;
            i = 0;
        }
        else if (key == KEY3_PRESS) //K3按下放第三首歌
        {
            beep_flag3 = !beep_flag3;
            beep_flag1 = 0;
            beep_flag2 = 0;
			beep_flag4 = 0;
            i = 0;
        }
		else if (key == KEY4_PRESS) //K4按下放第四首歌
        {
            beep_flag4 = !beep_flag4;
            beep_flag1 = 0;
            beep_flag2 = 0;
			beep_flag3 = 0;
            i = 0;
        }


        if (beep_flag1) 
		{
            song_playing = 1;
            while (freq_list1[i]) // 频率为 0 重新开始
            {
                val = Clk / (freq_list1[i]);
                val = 0xFFFF - val; // 计算计数值
                val_H = (val >> 8) & 0xff;
                val_L = val & 0xff;
                TH0 = val_H;
                TL0 = val_L;
                Delay(time_list1[i]);
                i++;
                 if (key_scan(0) != KEY_UNPRESS)
				  {
        beep_flag1 = beep_flag2 = beep_flag3 =beep_flag4= 0; // 清除当前正在播放的歌曲标志，停止播放并退出循环
        break;
                  }
            }
        }
        else if (beep_flag2) {
            song_playing = 1;
            while (freq_list2[i]) // 频率为 0 重新开始
            {
                val = Clk / (freq_list2[i]);
                val = 0xFFFF - val; // 计算计数值
                val_H = (val >> 8) & 0xff;
                val_L = val & 0xff;
                TH0 = val_H;
                TL0 = val_L;
                Delay(time_list2[i]);
                i++;
                if (key_scan(0) != KEY_UNPRESS) {
         beep_flag1 = beep_flag2 = beep_flag3 =beep_flag4= 0; // 清除当前正在播放的歌曲标志，停止播放并退出循环
        break;
    }
            }
        }
        else if (beep_flag3)
		 {
            song_playing = 1;
            while (freq_list3[i]) // 频率为 0 重新开始
            {
                val = Clk / (freq_list3[i]);
                val = 0xFFFF - val; // 计算计数值
                val_H = (val >> 8) & 0xff;
                val_L = val & 0xff;
                TH0 = val_H;
                TL0 = val_L;
                Delay(time_list3[i]);
                i++;
                if (key_scan(0) != KEY_UNPRESS) {
         beep_flag1 = beep_flag2 = beep_flag3 =beep_flag4= 0; // 清除当前正在播放的歌曲标志，停止播放并退出循环
        break;
    }
            }
        }
		 else if (beep_flag4)
		 {
            song_playing = 1;
            while (freq_list4[i]) // 频率为 0 重新开始
            {
                val = Clk / (freq_list4[i]);
                val = 0xFFFF - val; // 计算计数值
                val_H = (val >> 8) & 0xff;
                val_L = val & 0xff;
                TH0 = val_H;
                TL0 = val_L;
                Delay(time_list4[i]);
                i++;
                if (key_scan(0) != KEY_UNPRESS) {
         beep_flag1 = beep_flag2 = beep_flag3 =beep_flag4= 0; // 清除当前正在播放的歌曲标志，停止播放并退出循环
        break;
    }
            }
        }
        else {
            song_playing = 0; // 没有歌曲在播放，设置歌曲播放标志为假
        }



    }
}
在这个基础上修改，使用4×4矩阵键盘作为电子琴键，按下键演奏出相应的音符，能够保存所演奏的音乐，并重复自动播放。