找回密码
 立即注册

QQ登录

只需一步,快速开始

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

注释详细的51单片机电子琴的仿真和程序 内含多种音乐,可以自己调节

[复制链接]
跳转到指定楼层
楼主
51电子琴的设计  内含多种音乐,可以自己调节

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


带注释的单片机源程序如下:

  1. #include <reg52.h>

  2. #define SONG 4                                        // 歌曲的数量

  3. #define uchar unsigned char                // 以后unsigned char就可以用uchar代替
  4. #define uint  unsigned int                // 以后unsigned int 就可以用uint 代替
  5. #define ulong unsigned long                // 以后unsigned long就可以用ulong代替

  6. sbit Key1_P = P1^3;                                // 弹奏键1的管脚
  7. sbit Key2_P = P1^7;                                // 弹奏键2的管脚
  8. sbit Key3_P = P3^2;                                // 弹奏键3的管脚
  9. sbit Key4_P = P3^3;                                // 弹奏键4的管脚
  10. sbit Key5_P = P1^2;                                // 弹奏键5的管脚
  11. sbit Key6_P = P1^6;                                // 弹奏键6的管脚
  12. sbit Key7_P = P3^1;                                // 弹奏键7的管脚
  13. sbit Key8_P = P3^5;                                // 弹奏键8的管脚

  14. sbit Key9_P = P1^4;                                // 播放内置歌曲的按键管脚
  15. sbit Beep_P = P2^7;                                // 扬声器管脚           

  16. uchar gTone=0;                                        // gTone代表当前要播放的音调
  17. uchar gPlayStatus;                                // gPlayStatus代表当前的播放状态,0是停止,1是播放
  18. uchar gSong;                                    // gSong代表当前播放到第几首歌


  19. /*  定时器初值          低1  低2  低3  低4  低5  低6  低7  中1  中2  中3  中4  中5  中6  中7  高1  高2  高3  高4  高5  高6  高7 */
  20. uchar code  ArrTL0[]={ 140,  91,  21, 103,   4, 144,  12,  68, 121, 220,  52, 130, 200,   6,  34,  86, 133, 154, 193, 228,   3 };
  21. uchar code  ArrTH0[]={ 248, 249, 250, 250, 251, 251, 252, 252, 252, 252, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 255 };
  22. //                      0    1    2    3     4   5    6     7           8   9          10   11   12   13   14   15   16   17   18   19   20

  23. /*  数码管的显示值       1    2    3    4    5     6   7 */
  24. uchar code  ArrDig[]={ 0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8};



  25. /*  《水手》的乐谱  */
  26. uchar code Music1[]={
  27.         
  28.         8,3,  7,1,  7,4
  29.         } ;




  30. /********************************************************************
  31. * 名称 : uchar ChangeFor(uchar dat)
  32. * 功能 : 交换一个字节位的位置,用于数码管显示
  33. * 输入 : 需要改变的数
  34. * 输出 : 改变后的数
  35. ***********************************************************************/
  36. #define LED_a                6        //数码管段选的a段接在段选IO口的第0位
  37. #define LED_b                7
  38. #define LED_c                5
  39. #define LED_d                3
  40. #define LED_e                2
  41. #define LED_f                1
  42. #define LED_g                0
  43. #define LED_dp        4

  44. uchar ChangeFor(uchar dat)
  45. {
  46.         uchar temp=0;
  47.         if(dat&0x01)                //判断数据的第一位是否为1
  48.                 temp|=0x01<<LED_a;//如果为1,放到控制数码管a段的位置
  49.         if(dat&0x02)
  50.                 temp|=0x01<<LED_b;
  51.         if(dat&0x04)
  52.                 temp|=0x01<<LED_c;
  53.         if(dat&0x08)
  54.                 temp|=0x01<<LED_d;
  55.         if(dat&0x10)
  56.                 temp|=0x01<<LED_e;
  57.         if(dat&0x20)
  58.                 temp|=0x01<<LED_f;
  59.         if(dat&0x40)
  60.                 temp|=0x01<<LED_g;
  61.         if(dat&0x80)
  62.                 temp|=0x01<<LED_dp;
  63.         return temp;
  64. }

  65. /*********************************************************/
  66. // 毫秒级的延时函数,time是要延时的毫秒数
  67. /*********************************************************/
  68. void DelayMs(uint time)
  69. {
  70.         uint i,j;
  71.         for(i=time;i>0;i--)
  72.                 for(j=110;j>0;j--);
  73. }



  74. /*********************************************************/
  75. // 发出指定音调及其节拍的声音,tone代表音调,beat代表节拍
  76. /*********************************************************/                 
  77. void PlayTone(uchar tone,float beat)
  78. {
  79.         int i;
  80.         P0=ChangeFor(ArrDig[tone%7]);                        // 数码管显示当前音调值
  81.         gTone=tone;                                        // 将音调值赋给全局变量gTone
  82.         TH0 = ArrTH0[tone];                        // 装入定时器TH0的初值
  83.         TL0 = ArrTL0[tone];                        // 装入定时器TL0的初值
  84.         TR0=1;                                                // 启动定时器
  85.         for(i=0;i<beat;i++)               
  86.         {
  87.                 DelayMs(200);         
  88.         }
  89.         TR0=0;                                                // 停止定时器
  90.         P0=0xff;                                   // 关闭数码管显示                 
  91. }


  92. /*********************************************************/
  93. // 播放内置的音乐
  94. // arr[]是要播放的乐谱数组,num是数组里面的元素个数
  95. /*********************************************************/
  96. void PlayMusic(uchar music[],uint num)
  97. {
  98.         uint i=0;
  99.         while(i<num)                        
  100.         {   
  101.                 if(gPlayStatus==1)                                                  // 判断播放状态是否为播放还是暂停
  102.                 {   
  103.                         PlayTone(music[i],music[i+1]);                   // 开始演奏一个节拍
  104.                         i+=2;                                                                // 进入下一个节拍,因为每2个数为1组,所以每次要加2
  105.                         if(i==num)                                                        // 判断歌曲是否播放完了
  106.                         {
  107.                                 gPlayStatus=0;                                        // 播放完了的话,则把播放状态改为暂停,否则会循环播放
  108.                         }
  109.                 }
  110.                
  111.                 if(Key9_P==0)                                                         // 下一曲
  112.                 {
  113.                         DelayMs(10);                                                // 消除按键按下的抖动
  114.                         while(!Key9_P);                                            // 等待按键释放
  115.                         DelayMs(10);                                                // 消除按键松开的抖动
  116.                         gSong++;                                                        // 把当前播放到第几首歌的变量gSong加1,即切到下一曲
  117.                         if(gSong>SONG)                                                // 如果gSong为SONG,说明到后面的尽头了,则转为第一首
  118.                                 gSong=1;
  119.                         break;        
  120.                 }                                
  121.         }
  122. }



  123. /*********************************************************/
  124. // 定时器初始化函数
  125. /*********************************************************/
  126. void TimerInit()
  127. {
  128.         TMOD=1;                        // 定时器0,工作方式1
  129.         TH0=0;                        // 装定时器TH0的初值
  130.         TL0=0;                        // 装定时器TL0的初值
  131.         ET0=1;                        // 开启定时器0中断                  
  132.         EA=1;                        // 开启总中断
  133. }


  134. /*********************************************************/
  135. // 弹奏键扫描函数
  136. /*********************************************************/
  137. uchar KeyScanf()
  138. {
  139.         if(Key1_P==0)        // 按键1被按下,返回1
  140.                 return 1;
  141.         if(Key2_P==0)        // 按键2被按下,返回2
  142.                 return 2;
  143.         if(Key3_P==0)         // 按键3被按下,返回3
  144.                 return 3;
  145.         if(Key4_P==0)         // 按键4被按下,返回4
  146.                 return 4;
  147.         if(Key5_P==0)         // 按键5被按下,返回5
  148.                 return 5;
  149.         if(Key6_P==0)        // 按键6被按下,返回6
  150.                 return 6;
  151.         if(Key7_P==0)        // 按键7被按下,返回7
  152.                 return 7;
  153.         if(Key8_P==0)          // 按键8被按下,返回8
  154.                 return 8;
  155.         return 0;                  // 8个按键都没被按下,返回0
  156. }


  157. /*********************************************************/
  158. // 主函数,程序从这里开始执行
  159. /*********************************************************/        
  160. void main()
  161. {  
  162.         uchar ret;                                        // 用于保存音调键函数的返回值

  163.         TimerInit();
  164.         gSong=0;                                        // 上电默认第一首歌
  165.         gPlayStatus=0;                                // 上电默认是0停止状态(1为播放状态)

  166.         while(1)
  167.         {
  168.                 if(gPlayStatus==1)                // 如果处于播放状态,则判断是哪一首歌曲需要播放
  169.                 {
  170.                         switch(gSong)                 
  171.                         {
  172.                                 case 1 : PlayMusic(Music1,sizeof(Music1)); break;
  173.                                 case 2 : PlayMusic(Music2,sizeof(Music2)); break;
  174.                                 case 3 : PlayMusic(Music3,sizeof(Music3)); break;
  175.                                 case 4 : PlayMusic(Music4,sizeof(Music4)); break;
  176.                                 default:                                       break;        
  177.                         }        
  178.                 }
  179.                
  180.                 if(Key9_P==0)                                                // 开始播放
  181.                 {
  182.                         DelayMs(10);                                        // 消除按键按下的抖动
  183.                         while(!Key9_P);                                        // 等待按键释放
  184.                         DelayMs(10);                                        // 消除按键松开的抖动
  185.                         gSong++;                                                // 把当前播放到第几首歌的变量gSong加1,即切到下一曲
  186.                         if(gSong>SONG)                                        // 如果gSong为SONG,说明到后面的尽头了,则转为第一首
  187.                                 gSong=1;
  188.                         gPlayStatus=1;                                         // 播放状态改为1,即播放
  189.                         
  190.                 }
  191.                                 
  192.                 ret=KeyScanf();
  193.                 if(ret!=0)
  194.                 {
  195.                         P0=ChangeFor(ArrDig[(ret-1)%7]);                        // 数码管显示当前音调值
  196.                         TH0 = ArrTH0[ret+6];                        // 装入定时器TH0的初值
  197.                         TL0 = ArrTL0[ret+6];                        // 装入定时器TL0的初值
  198.                         gTone=ret+6;
  199.                         TR0=1;
  200.                         while(KeyScanf());                                // 等待按键释放
  201.                         DelayMs(70);                                        // 按键释放之后,再播放70毫秒,达到余音的效果
  202.                         TR0=0;                                                        // 停止定时器
  203.                         P0=0xff;                                           // 关闭数码管显示
  204.                 }               
  205.         }
  206. }

  207.                                        
  208. /*********************************************************/
  209. // 功能:定时器0中断处理函数
  210. /*********************************************************/                  
  211. void time0() interrupt 1
  212. {
  213.         Beep_P=!Beep_P;                        // 将控制扬声器的管脚取反
  214.         TH0=ArrTH0[gTone];                // 重装定时器TH0的初值
  215.         TL0=ArrTL0[gTone];                // 重装定时器TL0的初值        
  216. }
复制代码

Keil代码与Proteus仿真下载:
01__c程序 注释.zip (128.94 KB, 下载次数: 29)

评分

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

查看全部评分

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

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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