找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4046|回复: 6
打印 上一主题 下一主题
收起左侧

简易单片机电子琴源程序Proteus仿真设计 洞洞板和工业制板PCB文件都有

  [复制链接]
跳转到指定楼层
楼主
由高音阶的七个音和低音阶的七个音组成的14键的简易电子琴。
带有录音回放,演奏歌曲功能。

Altium Designer画的单片机电子琴原理图和PCB图如下:(51hei附件中可下载工程文件)
电路PCB(洞洞板)


电路PCB(工业制板)


仿真原理图如下(proteus仿真工程文件可到本帖附件中下载).


元件清单:
元件名称    参考数量   
STC89C52RC    1   
IC底座    1   
排阻 4.7K/10K    1   
11.0592M/12M晶振    1   
30pf瓷片电容    2   
10uf电解电容    1   
33Ω电阻    1    根据实际情况选择
10K电阻    2   
按键开关    18   
排针    3   
S8050    2   
跳线    10    根据实际情况选择
喇叭    1   
线路板/洞洞板    1   

电子琴程序源码(含固定曲)
源程序如下:
  1. #include <STC89C5xRC.H>
  2. #include <intrins.h>

  3. #define PKEY P1                                                                        //定义4x4按键接的IO口        行扫描
  4. sbit PLAY = P2^0;                                                                //播放按键
  5. sbit SPK  = P2^2;                                                                //音频信号输出

  6. #define ALLSONG         3                                                          //歌曲总数 按实际写
  7. #define CODEMAX 30                                                                //最大音符数

  8. unsigned char tone_h;               
  9. unsigned char tone_l;                        

  10. unsigned char t1_flag   = 0;                                        //用于记录定时器1进入中断的次数
  11. unsigned char PressTime = 0;                                        //按键按下的时间(节拍)

  12. unsigned char code chuzhi[3][16]={                          //音调对应的计数初值
  13.                                 0xff,0xff,                                                //用任意值占0位,因为音调从1开始
  14.                                 0xf8,0x8c,                                                //低1  
  15.                                 0xf9,0x5b,                                                //低2                 
  16.                                 0xfa,0x15,                                                //低3                 
  17.                                 0xfa,0x67,                                                //低4                 
  18.                                 0xfb,0x04,                                                //低5                 
  19.                                 0xfb,0x90,                                                //低6                 
  20.                                 0xfc,0x0c,                                                //低7

  21.                                 0xff,0xff,                                                //占0位
  22.                                 0xfc,0x44,                                                //中1   
  23.                                 0xfc,0xac,                                                //中2
  24.                                 0xfd,0x09,                                                //中3
  25.                                 0xfd,0x34,                                                //中4
  26.                                 0xfd,0x82,                                                //中5
  27.                                 0xfd,0xc8,                                                //中6
  28.                                 0xfe,0x06,                                                //中7   
  29.                
  30.                                 0xff,0xff,                                                //占0位
  31.                                 0xfe,0x22,                                                //高1                           
  32.                                 0xfe,0x56,                                                //高2               
  33.                                 0xfe,0x85,                                                //高3               
  34.                                 0xfe,0x9a,                                                //高4               
  35.                                 0xfe,0xc1,                                                //高5               
  36.                                 0xfe,0xe4,                                                //高6               
  37.                                 0xff,0x03                                                 //高7                             
  38.                                                 };        



  39. unsigned int code srkl[] = {                                         //生日快乐
  40.         205,205,406,405,411,807,
  41.         205,205,406,405,412,811,
  42.         205,205,415,413,411,407,406,
  43.         314,114,413,411,413,812,
  44.         305,105,406,405,411,807,
  45.         305,105,406,405,412,811,
  46.         305,105,415,413,411,
  47.         407,406,314,114,413,411,412,811,410,
  48.         0xffff        
  49. };


  50. unsigned int code lq1990[] = {                                        //恋曲1990歌词
  51.         613,213,412,411,613,213,412,                                //前奏
  52.         411,613,213,412,411,1213,110,                                //前奏
  53.         215,215,215,215,413,412,                                        //乌溜溜的黑眼珠
  54.         613,211,211,212,413,1206,                                        //和你的笑脸
  55.         212,213,212,213,415,213,212,                                //怎么也难忘记
  56.         612,211,211,206,405,1213,110,                                //你 容颜的转变
  57.         215,215,215,215,213,212,                                        //轻飘飘的旧时
  58.         613,211,211,212,213,1206,                                        //光 就这么溜走
  59.         212,213,212,213,415,213,212,                                //转头回去看看
  60.         612,205,213,212,413,1211,110,                                //时 已匆匆数年
  61.         
  62.         215,215,215,215,413,412,                                        //苍茫茫的天涯
  63.         613,211,211,212,413,1206,                                        //路 是你的漂泊
  64.         212,213,212,213,415,213,212,                                //寻寻觅觅长相
  65.         612,211,211,206,405,1213,110,                                //守 是我的脚步
  66.         215,215,215,215,213,212,                                        //黑漆漆的孤枕
  67.         613,211,211,212,213,1206,                                        //边 是你的温柔
  68.         212,213,212,213,415,213,212,                                //醒来时的清晨
  69.         612,205,213,212,413,1211,110,                                //里 是我的哀愁
  70.         
  71.         215,215,215,215,413,412,                                        //轰隆隆的雷雨
  72.         613,211,211,212,413,1206,                                        //声 在我的窗前
  73.         212,213,212,213,415,213,212,                                //怎么也难忘记
  74.         612,211,211,206,405,1213,110,                                //你 离去的转变
  75.         215,215,215,215,213,212,                                        //孤单单的身影
  76.         613,211,211,212,213,1206,                                        //后 寂寥的心情
  77.         212,213,212,213,415,213,212,                                //永远无怨
  78.         612,205,213,212,413,1211,110,                                //的 是我的双眼
  79.         
  80.         615,213,415,416,                                                        //或许明日
  81.         621,216,421,416,                                                        //太阳西下
  82.         415,415,415,416,1213,                                                //倦鸟已归时
  83.         212,213,212,213,415,413,                                        //你将已经踏上
  84.         612,211,411,413,1212,210,                                        //旧时的归途
  85.         613,213,412,413,                                                        //人生难得
  86.         615,213,415,416,                                                        //再次寻觅
  87.         421,421,421,422,1216,                                                //相知的伴侣
  88.         221,221,221,221,416,415,                                        //生命终究难舍
  89.         212,412,212,412,413,1215,1610,        1610,                //蓝蓝的白云天
  90.         
  91.         0xFFFF,                                                                                //结束
  92. };


  93. void delayms(unsigned int a)                                        //延时函数
  94. {
  95.         unsigned char i, j;
  96.         unsigned int b=0;
  97.         for(b=0;b<a;b++)
  98.         {

  99.                 _nop_();
  100.                 _nop_();
  101.                 _nop_();
  102.                 i = 11;
  103.                 j = 190;
  104.                 do
  105.                 {
  106.                         while (--j);
  107.                 } while (--i);
  108.         }
  109. }


  110. void Timer1_Init(void)                                                        //定时器1,测量按键持续的节拍数
  111. {
  112.         EA = 1;
  113.         ET1 = 1;
  114.         TMOD &= 0x0F;
  115.         TMOD |= 0x10;
  116.         TH1 = (65536-25000)/256;
  117.         TL1 = (65536-25000)%256;                                        //25ms中断一次
  118. }


  119. void timer1() interrupt 3
  120. {
  121.         TH1 = (65536-25000)/256;
  122.         TL1 = (65536-25000)%256;                                        //25ms中断一次
  123.         t1_flag++;
  124.         if(t1_flag == 5)                                                        //125ms
  125.         {
  126.                 t1_flag = 0;
  127.                 if(PressTime < 16)                                                //最多16 即最长4秒
  128.                         PressTime++;
  129.         }
  130. }

  131. /***************************
  132.         按键扫描函数 【行扫描】
  133.         低4位接行,高4位接列
  134.                 键值分布
  135.         0        1        2        3
  136.         4        5        6        7
  137.         8        9        10        11
  138.         12        13        14        15
  139. ****************************/
  140. unsigned char keyScan(void)
  141. {
  142.         unsigned char hang;                                                        //行
  143.         unsigned char key;
  144.         unsigned char temp;
  145.         for(hang = 0;hang < 4;hang++)
  146.         {
  147.                 PKEY = ~(1<<hang);               
  148.                 temp = PKEY&0xF0;                                                //取高4位的值
  149.                 temp >>= 4;                                                                //将高四位右移到低四位
  150.                 if(temp  != 0x0F)                                                //有按键按下
  151.                 {
  152.                         switch(temp)
  153.                         {
  154.                                 case 14:key = 4*hang+0;break;        //temp:1110
  155.                                 case 13:key = 4*hang+1;break;        //temp:1101
  156.                                 case 11:key = 4*hang+2;break;        //temp:1011
  157.                                 case 7:        key = 4*hang+3;break;        //temp:0111
  158.                         }
  159.                         break;                                                                //有键按下,获取键值后,终止扫描
  160.                 }
  161.                 else                                                                        //没有按键按下 返回255
  162.                         key = 255;
  163.         }
  164.         return key;
  165. }


  166. void RhythmDelay(unsigned int pai)                                //节拍延时
  167. {
  168.         while(pai--)
  169.         {
  170.                 delayms(20);
  171.         }        
  172. }

  173. //======================
  174. //定时器0 产生音调
  175. //======================
  176. void Timer0_Init(void)
  177. {
  178.         EA = 1;
  179.         ET0 = 1;
  180.         TMOD &= 0xF0;
  181.         TMOD |= 0x01;
  182.         PT0 = 1;
  183.         TH0 = 255;
  184.         TL0 = 255;
  185. }
  186. //======================
  187. //定时器0中断  每进入一次,SPK取反
  188. //======================
  189. void timer0() interrupt 1
  190. {
  191.         TH0 = tone_h;
  192.         TL0 = tone_l;
  193.         SPK = ~SPK;
  194. }
  195. //======================
  196. //存储弹奏的歌曲
  197. //0xffff代表歌曲结束
  198. //千位与百位表示节拍
  199. //十位:低中高音[分别是0,1,2]
  200. //个位:音调[0~7] [0代表不发声]
  201. //======================
  202. unsigned int  music[CODEMAX] =
  203. {
  204.         215,215,215,215,413,412,                                                //乌溜溜的黑眼珠
  205.         613,211,211,212,413,1206,                                                //和你的笑脸
  206.         212,213,212,213,415,213,212,                                        //怎么也难忘记
  207.         612,211,211,206,405,1213,110,                                        //你 容颜的转变
  208.         0xffff,
  209. };
  210. //====================================
  211. //播放函数
  212. //播放完毕后返回1,否则返回0
  213. //music:歌曲数组,note:发第几个音
  214. //====================================
  215. unsigned char PlayMusic(unsigned int *music,unsigned int note)
  216. {
  217.         unsigned char yin1;        //低中高音 0,1,2
  218.         unsigned char yin2;        //音调 0~7  0代表不发声,但有节拍
  219.         unsigned char jiepai;//节拍
  220.         
  221.         if(music[note] == 0xffff)        //如果歌曲结束
  222.                 return 1;                                //返回1
  223.         else
  224.         {
  225.                 if(music[note]%10 != 0)        //音调不为0 【音调为0时表示不发声,但有节拍】
  226.                 {
  227.                         yin1 = music[note]%100/10;
  228.                         yin2 = music[note]%10;
  229.                         tone_h = TH0 = chuzhi[yin1][yin2*2 ];                //音调高位 【二维数组 第1维表示低中高音,第二维表示音调】
  230.                         tone_l = TL0 = chuzhi[yin1][yin2*2 + 1];        //音调低位
  231.                         TR0 = 1;                //开启定时器0 开始发声
  232.                 }
  233.                 jiepai = music[note]/100;
  234.                 RhythmDelay(jiepai);        //节拍
  235.                
  236.                 TR0 = 0;                //已经响够节拍数,停止发声。
  237.                 TR1 = 0;                //停止显示节拍
  238.                
  239.                 delayms(30);                //每个节拍结束后,停一段时间
  240.                 return 0;
  241.         }
  242. }
  243. //======================
  244. //主函数
  245. //======================
  246. void main(void)
  247. {        
  248.         unsigned char key = 255;
  249.         unsigned char save = 0;
  250.         unsigned int note = 0;                //音符
  251.         unsigned char note2 = 0;
  252.         unsigned char play_flag = 0;
  253.         unsigned char yin1 = 0;                //低中高音 0,1,2
  254.         unsigned char yin2 = 1;                //音调 0~7,0代表不发声,但有节拍
  255.         
  256.         unsigned char PlayID = 0;        //播放歌曲的序号
  257.         unsigned char PlayIDb = 0;        //上次播放的歌曲序号
  258.         
  259.         music[CODEMAX-1] = 0xffff;                //防止歌曲数组无0xffff出现错误
  260.         
  261.         Timer0_Init();//定时器0 产生音调
  262.         Timer1_Init();//定时器1 测量按键持续的节拍数
  263.         
  264.         
  265.         
  266.         while(1)
  267.         {
  268.                 if(PLAY == 0)                //按下PLAY键
  269.                 {
  270.                         PLAY = 0;        //引脚置0 进入播放模式
  271.                         
  272.                         //切换了播放歌曲,从第0个音符开始播放,
  273.                         if(PlayID != PlayIDb)
  274.                         {
  275.                                 PlayIDb = PlayID;
  276.                                 note = 0;
  277.                         }
  278.                         
  279.                         
  280.                         
  281. //==================== 重点 ========================
  282.                         if(play_flag %2 == 0)                //play_flag为偶数时播放,奇数时暂停播放
  283.                         {                        
  284.                                 if(PlayID == 0)
  285.                                 {
  286.                                         if(PlayMusic(music,note) == 0)                //播放音符
  287.                                                 note++;                                //为结束播放下一个音符
  288.                                         else
  289.                                         {
  290.                                                 if(PlayID < ALLSONG-1)        PlayID++;//播放下一首
  291.                                                 else                        PlayID = 0;
  292.                                         }
  293.                                 }
  294.                                 
  295.                                 else if(PlayID == 1)
  296.                                 {
  297.                                         if(PlayMusic(srkl,note) == 0)                //播放音符
  298.                                                 note++;                                //为结束播放下一个音符
  299.                                         else
  300.                                         {
  301.                                                 if(PlayID < ALLSONG-1)                PlayID++;        //播放下一首
  302.                                                 else                                PlayID = 0;
  303.                                         }
  304.                                 }
  305.                                 else if(PlayID == 2)
  306.                                 {
  307.                                         if(PlayMusic(lq1990,note) == 0)                //播放音符
  308.                                                 note++;                                //为结束播放下一个音符
  309.                                         else
  310.                                         {
  311.                                                 if(PlayID < ALLSONG-1)                PlayID++;        //播放下一首
  312.                                                 else                                                PlayID = 0;
  313.                                         }
  314.                                 }
  315.                         }
  316. //===================================================================                        
  317.                         key = keyScan();                                //要稍微按久一点才有反应
  318.                         if(key == 15)                                        //按下15号按键,停止播放
  319.                         {
  320.                                 
  321.                                 
  322.                                 PLAY = 1;
  323.                                 note = 0;                                //停止后再按播放,从头开始播放。
  324.                                 play_flag = 0;
  325.                                 
  326.                                 TR0 = 0;
  327.                                 tone_h = TH0 = chuzhi[2][2*2];                        
  328.                                 tone_l = TL0 = chuzhi[2][2*2+1];                        
  329.                                 TR0 = 1;
  330.                                 delayms(100);                                //按键后响一声
  331.                                 TR0 = 0;
  332.                                 
  333.                                 while(keyScan() != 255);                //放开按键时(255时) 跳出循环
  334.                         }
  335.                         else if(key == 13)                                //按下13号键 暂停与暂停后播放
  336.                         {
  337.                                 play_flag++;
  338.                                 
  339.                                 if(play_flag %2 == 0)        //播放
  340.                         
  341.                                 
  342.                                 TR0 = 0;
  343.                                 tone_h = TH0 = chuzhi[2][2*2];                        
  344.                                 tone_l = TL0 = chuzhi[2][2*2+1];                        
  345.                                 TR0 = 1;
  346.                                 delayms(100);                                //开始或者暂停都响一声
  347.                                 TR0 = 0;
  348.                                 while(keyScan() != 255);        //放开按键时(255时) 跳出循环
  349.                         }
  350.                         else if(key == 12)                //播放上一首
  351.                         {
  352.                                 if(PlayID > 0)                PlayID--;
  353.                                 else                                         PlayID = ALLSONG-1;
  354.                                 
  355.                                 TR0 = 0;
  356.                                 tone_h = TH0 = chuzhi[2][2*2];                        
  357.                                 tone_l = TL0 = chuzhi[2][2*2+1];                        
  358.                                 TR0 = 1;
  359.                                 delayms(100);                                //按键后响一声
  360.                                 TR0 = 0;
  361.                                 
  362.                                 while(keyScan() != 255);        //放开按键时(255时) 跳出循环
  363.                         }
  364.                         else if(key == 14)                //播放下一首
  365.                         {
  366.                                 if(PlayID < ALLSONG-1)                PlayID++;
  367.                                 else                                PlayID = 0;
  368.                                 
  369.                                 TR0 = 0;
  370.                                 tone_h = TH0 = chuzhi[2][2*2];                        
  371.                                 tone_l = TL0 = chuzhi[2][2*2+1];                        
  372.                                 TR0 = 1;
  373.                                 delayms(100);                                //按键后响一声
  374.                                 TR0 = 0;
  375.                                 
  376.                                 while(keyScan() != 255);        //放开按键时(255时) 跳出循环
  377.                         }
  378.                 }//=================  弹奏模式 =====================
  379.                 else if(PLAY == 1)                                
  380.                 {
  381.                         PlayID = 0;
  382.                         note = 0;
  383.                         
  384.         
  385.                         
  386.                         
  387.                         key = keyScan();
  388.                         
  389.                         if(key == 0)                                //按下0键开始记录
  390.                         {
  391.                                 if(save == 0)                        //第一次按 表示开始弹奏
  392.                                 {
  393.                                         save = 1;                        //标记,存储
  394.                                         note2 = 0;               
  395.                                         tone_h = TH0 = chuzhi[0][1*2];                        
  396.                                         tone_l = TL0 = chuzhi[0][1*2+1];                        
  397.                                         TR0 = 1;
  398.                                         delayms(100);        //开始录制,响一短低音
  399.                                         TR0 = 0;
  400.                                 }
  401.                                 else                                                        //第二次按 表示弹奏结束 写入结束符0xffff
  402.                                 {
  403.                                         save = 0;                        //标记,结束存储
  404.                                         music[note2] = 0xffff;
  405.                                        
  406.                                         tone_h = TH0 = chuzhi[1][3*2];                        
  407.                                         tone_l = TL0 = chuzhi[1][3*2+1];                        
  408.                                         TR0 = 1;
  409.                                         delayms(100);        //录制完成,响一短高音
  410.                                         TR0 = 0;
  411.                                 }
  412.                                 while(keyScan() != 255);                //放开按键时(255时) 跳出循环
  413.                         }
  414.                         else if(key != 255)        //按下1~15键
  415.                         {
  416.                                 t1_flag = 0;
  417.                                 PressTime = 0;
  418.                                 TH1 = (65536-25000)/256;
  419.                                 TL1 = (65536-25000)%256;                //25ms中断一次
  420.                                 TR1 = 1;                        //开启定时器1,开始计算按键按下时间
  421.                                 
  422.                                 //判断被按下按键的键值
  423.                                 if(key >= 1 && key <= 7)                                //按键 1~7
  424.                                 {        yin1 = 0;        yin2 = key+0;        }                //低音        
  425.                                 
  426.                                 else if(key >= 8 && key <= 11)                        //按键 8~11
  427.                                 {        yin1 = 1;        yin2 = key - 4;        }                //中音        
  428.                                 
  429.                                 else if(key >= 12 && key <= 15)                        //按键 12~15
  430.                                 {        yin1 = 2;        yin2 = key - 8;        }                //高音        
  431.                                 
  432.                                 
  433.                                 tone_h = TH0 = chuzhi[yin1][yin2*2];                        //音调高位 【二维数组 第1维表示低中高音,第二维表示音调】
  434.                                 tone_l = TL0 = chuzhi[yin1][yin2*2+1];                //音调低位
  435.                                 if(yin2 != 0)        //非0音时,开启定时器0,发声
  436.                                         TR0 = 1;
  437.                                 
  438.                                 while(1)                        //释放按键时 跳出循环
  439.                                 {                                                

  440.                                         key = keyScan();
  441.                                         if(key == 255)                //放开按键
  442.                                         {
  443.                                                 TR1 = 0;
  444.                                                 TR0 = 0;                                //停止发声
  445.                                                 if(save == 1)                //save变量为1时,将弹奏的信息保存
  446.                                                 {
  447.                                                         TR1 = 0;                        //关闭定时器1,停止
  448.                                                         music[note2] = (unsigned int)PressTime*100 + yin1*10 + yin2;
  449.                                                         if(note2 < CODEMAX - 2)                                //长度有限制
  450.                                                                 note2++;
  451.                                                 }
  452.                                                 break;
  453.                                         }
  454.                                 }
  455.                         }
  456.                         
  457.                 }
  458.         }
  459. }
复制代码

所有资料51hei提供下载:
基于51单片机的电子琴设计2019-6-25 133408.7z (1.9 MB, 下载次数: 109)

评分

参与人数 2黑币 +80 收起 理由
1963781320 + 30 共享资料的黑币奖励!
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏4 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:649660 发表于 2019-11-26 14:02 | 只看该作者
51hei电子论坛有你更精彩!!!!!!!
回复

使用道具 举报

板凳
ID:777557 发表于 2020-6-12 19:41 来自手机 | 只看该作者
赞  要是实现实时弹奏并记忆功能 改怎么弄?
回复

使用道具 举报

地板
ID:982529 发表于 2021-11-24 18:26 来自手机 | 只看该作者
楼主那个喇叭呢,喇叭怎么接线,那个PCB的文件都没有
回复

使用道具 举报

5#
ID:982529 发表于 2021-11-24 21:53 来自手机 | 只看该作者
谁知道这个东西的实物喇叭该接到哪里去吗?
回复

使用道具 举报

6#
ID:262 发表于 2021-11-26 01:37 | 只看该作者
wssbwssb 发表于 2021-11-24 21:53
谁知道这个东西的实物喇叭该接到哪里去吗?

仿真原理图上面有,初步用Proteus7.5初步仿真了下 可以运行 ,喇叭是p2.2通过三极管放大输出的,,所以接在三极管旁边的那个接线柱上面的
回复

使用道具 举报

7#
ID:987923 发表于 2021-12-15 18:44 | 只看该作者
heicad 发表于 2021-11-26 01:37
仿真原理图上面有,初步用Proteus7.5初步仿真了下 可以运行 ,喇叭是p2.2通过三极管放大输出的,,所以接在三 ...

楼主你好 麻烦问一下 具体咋接啊,我接到P1的任意两个上面  喇叭都不响。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表