51单片机LCD1602音乐播放器设计(带源码、仿真和原理图)

[复制链接]
查看66 | 回复0 | 2021-7-6 16:32:22 | 显示全部楼层 |阅读模式
关于音乐播放程序的调试,我首先采用Proteus软件来仿真,但是该仿真软件中没有喇叭或蜂鸣器等声音播放工具。于是本人将图3-4中的单片机的P1.0处接了一个示波器,想通过这样来仿真并调试音乐播放程序,但是效果不是很理想。程序运行的时候,能看见示波器有不同频率的波形交替出现,但是频率变换得很快,无法确认是否显示的是所需要的频率,并且无法辨别音频变换的节奏是否正确。此方法并不适用。

接着,我制作了一个简单的单片机播放器电路。即在实验板上焊接实验电路,电路由单片机89C51、按钮外围电路组成,并在单片机的P1.0处用三极管连接一个简单的音频放大器,再外接一个蜂鸣器。将程序写入单片机中,这样就能听出声音和音乐节奏是否正确。
1.jpg
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
2.png
  1. //////////////////////////////////////////////
  2. //51单片机音乐播放器程序
  3. //共三个按键:上一曲、一下曲、播放\暂停
  4. //注意:按键必须按下约1S才有相应动作,播放完一首歌曲无按键按下时顺序播放

  5. //////////////////////////////////////////////
  6. #include<REG52.H>
  7. sbit play_up=P1^3;           //上一首歌
  8. sbit play_down=P3^5;   //下一首歌
  9. sbit pause=P3^2;       //播放\暂停
  10. sbit speaker=P1^0;     //无源蜂鸣器
  11. sbit RS=P2^5;
  12. sbit RW=P2^6;
  13. sbit EN=P2^7;
  14. //////////////////////////////////////////////
  15. unsigned char timer0h,timer0l,time;//timer0h,timer0l为定时器T0的高低位初值,time为对应的节拍时间
  16. unsigned char music_num;       //music_num为歌曲编号,music_num=0表示刚开机时的状态,num是查找歌曲数据表的地址
  17. unsigned int num;
  18. unsigned char code   list[8][16]={        "Yan Hua Yi Leng ",
  19.                                                                         "   Fa Ru Xue    ",
  20.                                                                         "  Jian Dan Ai   ",
  21.                                                                         "Zhi You Mama Hao",
  22.                                                                         " Dang Ni Gu Dan ",
  23.                                                                         "XiangJian XiaoLu",
  24.                                                                         "    Song Bie    ",
  25.                                                                         "Lang Man De Shi "};
  26. signed int fre;                   //对应频率数据表的地址
  27. bit play_enable;                   //歌曲播放的使能标志位,用于播放\暂停
  28. void delay(unsigned char t);           //延时子函数,控制发音的时间长度
  29. void delayms(unsigned int t);           //普通延时子程序,可用于按键消抖
  30. void song(void);                           //演奏一个音符
  31. void music_play(void);                   //播放歌曲
  32. //////////////////////////////////////////////
  33. //每三个数字,代表一个音符
  34. //第一个数字是音符的数值1234567之一(第几个音),代表哆来咪发...
  35. //第二个数字是0123之一,代表低音\中音\高音\超高音(第几个八度)
  36. //第三个数字是时间长度,以半拍为单位,乐曲数据表的结尾是三个0
  37. //////////////////////////////////////////////

  38. //《烟花易冷》
  39. unsigned char code song1[]={
  40.      5,2,1, 3,2,1, 2,2,2, 2,2,4, 3,2,1, 1,2,1, 2,2,1, 3,2,4,
  41.          5,2,1, 3,2,1, 2,2,2, 2,2,2, 5,1,1, 3,2,1, 4,2,1, 3,2,4,
  42.          3,2,1, 3,2,1, 7,2,1, 3,2,1, 2,2,2, 1,2,1, 7,1,1, 1,2,1,
  43.          2,2,1, 3,2,1, 6,2,3, 6,1,1, 1,2,1, 3,2,1, 2,2,1, 6,1,1,
  44.          1,2,1, 7,1,1, 5,1,1, 6,1,6, 5,2,1, 3,2,1, 2,2,2, 2,2,1,
  45.          2,2,1, 3,2,1, 1,2,1, 2,2,1, 3,2,4, 5,2,1, 3,2,1, 2,2,2,
  46.          2,2,1, 2,2,1, 5,1,1, 3,2,1, 4,2,1, 3,2,4, 3,2,1, 3,2,1,
  47.          7,2,3, 3,2,1, 2,2,2, 1,2,1, 7,1,1, 1,2,1, 2,2,1, 3,2,1,
  48.          6,2,3, 6,1,1, 1,2,1, 3,2,1, 2,2,1, 6,1,1, 1,2,1, 7,1,2,
  49.          5,1,2, 6,1,6, 0,0,0 };

  50. //《发如雪》
  51. unsigned char code song2[]={
  52.      5,1,1, 2,2,1, 3,2,2, 2,2,1, 3,2,1, 5,2,1, 6,2,1, 5,2,3, 1,2,1, 2,2,1,
  53.          3,2,1, 6,2,1, 5,2,1, 3,2,1, 5,2,3, 5,2,1, 6,2,1, 1,3,2, 6,2,1, 5,2,1,
  54.          3,2,1, 5,2,1, 3,2,2, 1,2,1, 2,2,1, 3,2,1, 1,2,1, 6,1,1, 3,2,1, 2,2,1,
  55.          5,1,1, 2,2,1, 3,2,2, 2,2,1, 3,2,1, 5,2,1, 6,2,1, 5,2,3, 1,2,1, 2,2,1,
  56.          3,2,1, 6,2,1, 5,2,3, 5,2,1, 6,2,1, 1,3,2, 6,2,1,
  57.          5,2,1, 3,2,1, 5,2,1, 3,2,2, 5,2,1, 6,1,1, 3,2,1, 2,2,1, 1,2,1, 6,1,1,
  58.          1,2,1, 2,2,1, 2,2,1, 1,2,4, 0,0,0 };

  59. //《简单爱》
  60. unsigned char code song3[]={
  61.      5,1,1, 1,2,1, 2,2,1, 3,2,1, 2,2,1, 3,2,1, 4,2,1, 5,2,1, 5,2,1, 5,2,1,
  62.          4,2,1, 3,2,1, 2,2,3, 5,1,1, 1,2,1, 2,2,1, 3,2,1, 4,2,1, 5,2,1, 5,2,1,
  63.          5,2,1, 6,2,1, 5,2,2, 2,2,1, 3,2,1, 1,2,2, 1,2,1, 6,1,1, 2,2,1, 2,2,1,
  64.          3,2,1, 3,2,1, 1,2,1, 5,2,1, 1,2,1, 5,2,1, 1,2,1, 7,1,1, 1,2,1, 1,2,1, 6,1,1,
  65.          2,2,1, 2,2,1, 3,2,1, 3,2,1, 5,2,1, 5,2,1,
  66.          5,2,1, 6,2,1, 5,2,2, 2,2,1, 3,2,1, 1,2,2,  
  67.          5,1,1, 1,2,1, 2,1,2, 3,2,1, 2,2,1, 3,2,1, 4,2,1, 5,2,1, 5,2,1, 5,2,1,
  68.          4,2,1, 3,2,1, 2,2,3, 5,1,1, 1,2,1, 2,2,1, 3,2,1, 2,2,1, 3,2,1, 4,2,1,
  69.          5,2,1, 5,2,1, 5,2,2, 2,2,1, 3,2,1, 1,2,2, 1,2,1, 6,1,1, 2,2,1, 2,2,1,
  70.          3,2,1, 3,2,1, 1,2,2, 5,2,1, 1,2,1, 5,2,1, 5,2,1, 7,1,1, 1,2,1, 0,0,0 };

  71. //《世上只有妈妈好》
  72. unsigned char code song4[]={
  73.      6,2,3, 5,2,1, 3,2,2, 5,2,2, 1,3,2, 6,2,1,
  74.          //6,2,3代表6,中音,3个半拍;
  75.          //5,2,1代表5,中音,1个半拍;
  76.          //3,2,2代表3,中音,2个半拍;
  77.          //5,2,2代表5,中音,2个半拍;
  78.          //1,3,2代表1,高音,2个半拍;
  79.          //...
  80.      5,2,1,6,2,4, 3,2,2, 5,2,1, 6,2,1, 5,2,2, 3,2,2, 1,2,1,6,1,1, 5,2,1,
  81.          3,2,1, 2,2,4, 2,2,3, 1,2,1, 5,2,2, 5,2,1, 6,2,1, 3,2,2, 2,2,2,
  82.          1,2,4, 5,2,3, 3,2,1,2,2,1, 1,2,1, 6,1,1, 1,2,1, 5,1,6, 0,0,0};

  83. //《当你孤单你会想起谁》
  84. unsigned char code song5[]={
  85.      3,2,2, 3,2,1, 4,2,1, 3,2,2, 2,2,1, 1,2,1,  2,2,2, 5,2,2, 2,2,2, 2,2,3,
  86.          1,2,2, 1,2,1, 6,2,1, 1,2,2, 7,1,1, 6,1,1, 7,1,2, 3,2,2, 7,1,2, 7,1,3,
  87.          6,1,2, 2,2,1, 3,2,1, 2,2,1, 1,2,1, 6,1,2, 5,1,2, 2,2,1, 3,2,1, 2,2,1,
  88.          1,2,1, 6,1,2, 6,1,2, 2,2,1, 3,2,1, 2,2,1, 1,2,1, 6,1,1, 7,1,1, 1,2,6, 0,0,0 };

  89. //《乡间小路》
  90. unsigned char code song6[]={
  91.      3,1,2, 3,1,1, 3,1,1, 6,0,1, 6,0,1, 1,1,2,
  92.      6,0,1, 5,0,1, 6,0,4, 6,0,2, 6,0,1 ,6,0,1, 6,0,2, 6,0,1, 1,1,1,
  93.      2,1,2, 2,1,1, 3,1,1, 2,1,4, 3,5,1, 3,1,1, 3,1,1, 2,1,1, 4,1,2,
  94.      4,1,2, 3,1,2, 2,1,1, 1,1,1, 2,1,4, 7,0,1, 7,0,1, 7,0,1, 6,0,1,
  95.      5,0,1, 5,0,1, 6,0,1, 7,0,1, 7,0,1, 6,0,1, 5,0,1, 6,0,4, 6,1,2,
  96.      3,1,1, 6,1,1, 7,1,1, 6,1,1, 5,1,1, 5,1,2, 5,1,1, 2,1,1, 5,1,1,
  97.      6,1,1, 5,1,1, 4,1,1, 4,1,2, 4,1,1, 3,1,1, 2,1,2, 1,1,1, 2,1,1,
  98.      3,1,1, 2,1,1, 1,1,1, 2,1,1, 3,1,4, 6,1,2, 3,1,1, 6,1,1, 7,1,1,
  99.          6,1,1, 5,1,1, 5,1,2, 2,1,1, 5,1,1, 6,1,1, 5,1,1, 4,1,1, 0,0,0};     

  100. //《送别》
  101. unsigned char code song7[]={
  102.      5,1,2, 3,1,3, 5,1,1, 1,2,3, 6,1,2, 1,2,2,
  103.      5,1,4, 5,1,2, 1,1,1, 2,1,1, 3,1,2, 2,1,1, 1,1,1, 2,1,4, 5,1,2,
  104.          3,1,1, 5,1,1, 1,2,2, 7,1,1, 6,1,2, 1,2,2, 5,1,4, 5,1,2, 2,1,1,
  105.          3,1,1, 4,1,2, 7,0,1, 1,1,4, 6,1,2, 1,2,2, 1,2,4, 7,1,2, 6,1,1,
  106.          7,1,1, 1,2,4, 6,1,1, 7,1,1, 1,2,1, 6,1,1, 6,1,1, 5,1,1, 3,1,1,
  107.          1,1,1, 2,1,8, 5,1,2, 3,1,1, 5,1,1, 1,2,2, 7,1,1, 6,1,2, 1,2,2,
  108.          5,1,4, 5,1,2, 2,1,1, 3,1,1, 4,1,2, 7,0,2, 1,1,4, 0,0,0};

  109. //《最浪漫的事》
  110. unsigned char code song8[]={
  111.      5,1,1, 6,1,1, 1,2,1, 6,1,2, 6,1,1, 5,1,1, 6,1,1, 5,1,1, 3,1,1, 5,1,5,
  112.          5,1,1, 6,1,1, 1,2,1, 6,1,2, 6,1,1, 5,1,1, 6,1,1, 5,1,1, 6,1,1, 1,1,5,
  113.          1,1,1, 2,1,1, 3,1,1, 2,1,1, 2,1,1, 2,1,1, 1,1,1, 2,1,1, 1,1,1, 6,1,1,
  114.          3,1,2, 2,1,3, 5,1,1, 6,1,1, 1,2,1, 6,1,2, 6,1,1, 5,1,1, 6,1,1, 5,1,1,
  115.          6,1,1, 1,1,5, 1,1,1, 2,1,1, 3,1,1, 4,1,2, 4,1,1, 5,1,1, 6,1,1, 6,1,1,
  116.          5,1,1, 6,1,2, 1,2,1, 6,1,3, 1,2,1, 6,1,1, 5,1,1, 5,1,4, 1,1,1, 6,1,1,
  117.          5,1,5, 5,1,1, 6,1,1, 1,2,1, 3,1,1, 2,1,1, 3,1,1, 1,1,6, 0,0,0};

  118. // 频率-半周期数据表 高八位  共保存了四个八度的28个频率数据
  119. unsigned char code FREQH[]={
  120.     0xF2, 0xF3, 0xF5, 0xF5, 0xF6, 0xF7, 0xF8,    //低音1234567
  121.     0xF9, 0xF9, 0xFA, 0xFA, 0xFB, 0xFB, 0xFC, 0xFC,//1,2,3,4,5,6,7,i
  122.     0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFE,            //高音 234567
  123.     0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF};   //超高音 1234567

  124. // 频率-半周期数据表 低八位
  125. unsigned char code FREQL[]={
  126.     0x42, 0xC1, 0x17, 0xB6, 0xD0, 0xD1, 0xB6,    //低音1234567
  127.     0x21, 0xE1, 0x8C, 0xD8, 0x68, 0xE9, 0x5B, 0x8F, //1,2,3,4,5,6,7,i
  128.     0xEE, 0x44, 0x6B, 0xB4, 0xF4, 0x2D,             //高音 234567
  129.     0x47, 0x77, 0xA2, 0xB6, 0xDA, 0xFA, 0x16};   //超高音 1234567  

  130. /*************************lcd1602程序**************************/
  131. void delay1ms(unsigned int ms)//延时1毫秒(不够精确的)
  132. {unsigned int i,j;
  133.    for(i=0;i<ms;i++)
  134.     for(j=0;j<100;j++);
  135. }

  136. void wr_com(unsigned char com)//写指令//
  137. {  delay1ms(1);
  138.    RS=0;
  139.    RW=0;
  140.    EN=0;
  141.    P0=com;
  142.    delay1ms(1);
  143.    EN=0;
  144.    delay1ms(1);
  145.    EN=1;
  146.   }

  147. void wr_dat(unsigned char dat)//写数据//
  148. {  delay1ms(1);;
  149.    RS=1;
  150.    RW=1;
  151.    EN=1;
  152.    P0=dat;
  153.    delay1ms(1);
  154.    EN=0;
  155.    delay1ms(1);
  156.    EN=1;
  157. }

  158. void lcd_init()//初始化设置//
  159. {delay1ms(15);
  160. wr_com(0x01);
  161.   wr_com(0x38);delay1ms(5);
  162. wr_com(0x0c);
  163. wr_com(0x06);
  164. }
  165. void init_play()
  166. {
  167. wr_com(0x80+40+4);
  168. wr_dat('W');
  169. wr_dat('E');
  170. wr_dat('L');
  171. wr_dat('C');
  172. wr_dat('O');
  173. wr_dat('M');
  174. wr_dat('E');
  175. wr_dat('!');
  176.   
  177. }
  178. void display(unsigned char i)
  179. {
  180.    unsigned char j;
  181.    wr_com(0x80);
  182.    wr_dat(i+0x30);
  183.    wr_dat(':');
  184.    wr_com(0xc0);
  185.    for(j=0;j<16;j++)
  186.    {
  187.     wr_dat(list[i-1][j]);
  188.         }
  189. }
  190. void main(void)
  191. {
  192.         TMOD=0x11; //T0 T1 均在工作方式1
  193.         ET0=1;  //T0开中断
  194.         EA=1;   //CPU开中断         
  195.         lcd_init();
  196.         init_play();
  197.         while(1)
  198.         {
  199.                 music_play();        //根据当前状态播放相应歌曲的某个音符

  200.                 if(!pause)                //暂停键处理
  201.                 {
  202.                 delayms(5);
  203.                 if(!pause)
  204.                 {
  205.                         if(music_num==0)    //music_num=0只有在刚开机,且未按下暂停键时存在,表示刚开机时的状态,按下后从第一首开始播放
  206.                         {
  207.                                 music_num=1;    //歌曲序号置1
  208.                                 num=0;                //从头播放
  209.                                 play_enable=1;        //允许播放
  210.                                 display(1);
  211.                                         if(play_enable)
  212.                                 {wr_com(0x86);wr_dat('P'); wr_dat('L');wr_dat('A');wr_dat('Y');wr_dat(' ');        }
  213.                         }
  214.                         else
  215.                         {
  216.                                 play_enable=~play_enable;
  217.                             speaker=1;
  218.                                 if(play_enable)
  219.                                 {wr_com(0x86);wr_dat('P'); wr_dat('L');wr_dat('A');wr_dat('Y');wr_dat(' ');        }
  220.                                 if(!play_enable)
  221.                                 {wr_com(0x86);wr_dat('P'); wr_dat('A');wr_dat('U');wr_dat('S');wr_dat('E');        }

  222.                         }
  223.                         while(!pause)         //若按着暂停键不放手时的处理
  224.                         {
  225.                         if(play_enable==0){}                //如果是暂停,则显示时间不变//(暂停时play_enable==0)
  226.                         }

  227.                   }//暂停键处理结束
  228.         }//while结束

  229.                 if((!play_up)&&(music_num!=0)) //上一首按键
  230.                 {
  231.                 delayms(5);
  232.                 if((!play_up)&&(music_num!=0))
  233.                 {   speaker=1;
  234.                         music_num-=1;//歌曲编号减一
  235.                         if(music_num<=0)
  236.                         music_num=8;
  237.                         num=0;                 //从头开始播放
  238.                                 display(music_num);
  239.                         delayms(500);//歌曲切换时延时0.5S
  240.                 }      
  241.                 }

  242.                 if((!play_down)&&(music_num!=0))
  243.                 {
  244.                 delayms(5);
  245.                 if((!play_down)&&(music_num!=0))
  246.                 {   speaker=1;
  247.                         music_num+=1;//歌曲编号加一
  248.                         if(music_num>=9)
  249.                         music_num=1;
  250.                         num=0;                  //从头开始播放
  251.                                 display(music_num);
  252.                         delayms(500);//歌曲切换时延时0.5S
  253.                 }
  254.                 }

  255.         }
  256. }

  257. void delayms(unsigned int t)           //MS延时子程序
  258. {
  259.         unsigned int i,j;
  260.         for(i=0;i<t;i++)
  261.         {
  262.                 for(j=0;j<123;j++)
  263.                         ;
  264.         }
  265. }

  266. void delay(unsigned char t)            //延时子函数,控制发音的时间长度,每个节拍0.4S
  267. {
  268.         unsigned char t1;
  269.         unsigned long t2;
  270.         for(t1=0;t1<t;t1++)               //嵌套循环, 共延时t个半拍
  271.         {
  272.             for(t2=0;t2<8000;t2++) //延时期间, 可进入T0中断去发音
  273.         {
  274.                 ;
  275.         }
  276.         }
  277.         TR0=0;                               //关闭T0, 停止发音
  278. }

  279. void timer0(void) interrupt 2  //T0中断程序,控制发音的音调
  280. {
  281.         speaker=!speaker;//输出方波, 发音
  282.         TH0=timer0h;         //下次的中断时间,这个时间控制音调高低
  283.         TL0=timer0l;
  284. }

  285. void song(void)          //演奏一个音符
  286. {
  287.         TH0=timer0h;    //控制音调
  288.         TL0=timer0l;
  289.         TR0=1;                    //启动T0, 由T0输出方波发音
  290.         delay(time);    //每个音符的演奏时间
  291. }
  292. ////////////////////////////////////////////////////////////////////////////////////
  293. void music_play(void)//播放相应歌曲的某个音符
  294. {
  295.         if((music_num==1)&&(play_enable==1))
  296.         {
  297.                 fre=song1[num]+8*song1[num+1]-1;//第i个是音符,第i+1个是第几个八度
  298.                 timer0h=FREQH[fre];                    //从数据表中读出频率数值,实际上是定时的时间长度
  299.             timer0l=FREQL[fre];
  300.             time=song1[num+2];              //读出时间长度数值
  301.             num+=3;
  302.                 if(fre<0)                //判断歌曲的结束位,结束后转到下一首
  303.                 {
  304.                         num=0;            //下一首从头播放
  305.                         music_num=2;
  306.                                 display(2);
  307.             }
  308.                 song();                //发出一个音符
  309.         }
  310. ////////////////////////////////////////////////////////////////////////////////////
  311.         if((music_num==2)&&(play_enable==1))
  312.         {  
  313.                 fre=song2[num]+8*song2[num+1]-1;
  314.                 timer0h=FREQH[fre];
  315.             timer0l=FREQL[fre];
  316.             time=song2[num+2];
  317.             num+=3;
  318.                 if(fre<0)
  319.                 {
  320.                         num=0;
  321.                         music_num=3;
  322.                                 display(3);
  323.             }
  324.                 song();               
  325.         }
  326. ////////////////////////////////////////////////////////////////////////////////////
  327.                 if((music_num==3)&&(play_enable==1))
  328.         {  
  329.                 fre=song3[num]+8*song3[num+1]-1;
  330.                 timer0h=FREQH[fre];
  331.             timer0l=FREQL[fre];
  332.             time=song3[num+2];
  333.             num+=3;
  334.                 if(fre<0)
  335.                 {
  336.                         num=0;
  337.                         music_num=4;
  338.                                 display(4);
  339.             }
  340.                 song();               
  341.         }
  342. ////////////////////////////////////////////////////////////////////////////////////
  343.         if((music_num==4)&&(play_enable==1))
  344.         {
  345.                 fre=song4[num]+8*song4[num+1]-1;
  346.                 timer0h=FREQH[fre];
  347.             timer0l=FREQL[fre];
  348.             time=song4[num+2];
  349.             num+=3;
  350.                 if(fre<0)
  351.                 {
  352.                         num=0;
  353.                         music_num=5;
  354.                                 display(5);
  355.             }
  356.                 song();               
  357.         }
  358. ////////////////////////////////////////////////////////////////////////////////////
  359.         if((music_num==5)&&(play_enable==1))
  360.         {
  361.                 fre=song5[num]+8*song5[num+1]-1;
  362.                 timer0h=FREQH[fre];
  363.             timer0l=FREQL[fre];
  364.             time=song5[num+2];
  365.             num+=3;
  366.                 if(fre<0)
  367.                 {
  368.                         num=0;
  369.                         music_num=6;
  370.                                 display(6);
  371.             }
  372.                 song();               
  373.         }
  374. ////////////////////////////////////////////////////////////////////////////////////
  375.         if((music_num==6)&&(play_enable==1))
  376.         {
  377. ……………………

  378. …………限于本文篇幅 余下代码请从下载附件…………
复制代码
音乐盒proteus仿真和c源代码.rar (205.5 KB, 售价: 2 工控币)
音乐盒元件清单.doc (24 KB)
原理图.pdf (43.15 KB)

回复

使用道具 举报

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

本版积分规则