当前位置:   article > 正文

51单片机自学笔记_51单片机蜂鸣器音乐代码青花瓷

51单片机蜂鸣器音乐代码青花瓷

目录

1,程序安装与运行

1,keil程序下载安装

2,烧录程序

2,常见错误

1,main.c(2): error C100: unprintable character 0xA0 skipped

2,error : syntax error near 'int'-for循环头部中尽量不要去定义变量

3,小案例程序

1,设置执行n边的流水LED灯

2,独立按键(设置独立按键控制流水LED灯实现)

3,动态数码管

4,LCD1602显示 

5,青花瓷歌曲



1,程序安装与运行

1,keil程序下载安装

下载程序:

链接:https://pan.baidu.com/s/18ffD5c3lSp1F1-xd8vnnjg 
提取码:2rft 
复制这段内容后打开百度网盘手机App,操作更方便哦

1,解压:

2,点击安装

3,直接next完后安装。

4,解压破解工具(注意如果解压文件夹下面没有文件的话,要关闭360等杀毒软件)

5,

以管理员的身份启动程序,,并且打开破解软件

将CID的内容复制粘贴到破解软件。

 

完成安装。 

2,烧录程序

文件接下直接可以运行

2,常见错误

1,main.c(2): error C100: unprintable character 0xA0 skipped

原因:keil里面出现了中文输入法时写的标点,例如: //lcm_w_word("abc您好");  不能出现全角的任何字符,包括空格在内 任何标点符号和空格都只能在英文的状态下输入,提示这个错误的话 把全角的字符或者标点替换一下即可。

全角字符和半角字符之间的区别:

一个汉字字符在电脑上要占两个英文字符的位置,当输入符号的时候全角的字符也是要占两个英文字符的位置,半角的只占一个字符也就是半个汉字的位置。这就是全角和半角的区

2,error : syntax error near 'int'-for循环头部中尽量不要去定义变量

 

3,小案例程序

1,设置执行n边的流水LED灯

 

  1. #include <REGX52.H>//启动头文件
  2. #include <INTRINS.H>//_nop_()命令需要的头文件
  3. #include <intrins.h>//移位头文件
  4. // 延时函数
  5. void delay(int n)
  6. {
  7. while(n)
  8. {
  9. unsigned char i, j, k;
  10. _nop_();
  11. i = 8;
  12. j = 154;
  13. k = 122;
  14. do
  15. {
  16. do
  17. {
  18. while (--k);
  19. } while (--j);
  20. } while (--i);
  21. n--;
  22. }
  23. }
  24. void LED_flow(int n)//执行n次流水灯
  25. {
  26. // 0表示接通 1表示断开
  27. int i;
  28. while(n>0)
  29. {
  30. for(i=0;i<8;i++)
  31. {
  32. P2=~(0x01<<i); //1右移i位,然后将结果赋值到P2
  33. delay(1); //大约延时450ms
  34. }
  35. n--;
  36. }
  37. }
  38. void main()
  39. {
  40. LED_flow(1);//执行一次流水灯
  41. while(1)// 后面为卡住使灯灭
  42. {
  43. P2=0xFF;
  44. }
  45. }

 

2,独立按键(设置独立按键控制流水LED灯实现)

 

  1. #include <REGX52.H>//启动头文件
  2. #include <INTRINS.H>//_nop_()命令需要的头文件
  3. #include <intrins.h>//移位头文件
  4. // 延时函数
  5. void delay_ms(int n)
  6. {
  7. while(n)
  8. {
  9. unsigned char i, j;
  10. i = 12;
  11. j = 169;
  12. do
  13. {
  14. while (--j);
  15. } while (--i);
  16. n--;
  17. }
  18. }
  19. //流水LED灯
  20. void LED_flow(int n)//执行n次流水灯
  21. {
  22. // 0表示接通 1表示断开
  23. int i;
  24. while(n>0)
  25. {
  26. for(i=0;i<8;i++)
  27. {
  28. P2=~(0x01<<i); //1右移i位,然后将结果赋值到P2
  29. delay_ms(1000); //大约延时1s
  30. }
  31. n--;
  32. }
  33. }
  34. //按键控制流水LED灯
  35. void indepence_button()
  36. {
  37. int count=7;
  38. while(1)
  39. {
  40. if(P3_1==0)// K1键控制
  41. {
  42. delay_ms(20);
  43. while(P3_1==0);// 因为独立按键存在抖动的情况,故添加循环判断度过抖动期
  44. delay_ms(20);
  45. count++;
  46. if(count>=8)count=0;
  47. P2=~(0x01<<count);
  48. }
  49. if(P3_0==0)// K2键控制
  50. {
  51. delay_ms(20);
  52. while(P3_0==0);// 因为独立按键存在抖动的情况,故添加循环判断度过抖动期
  53. delay_ms(20);
  54. if(count==0)count=7;
  55. else count--;
  56. P2=~(0x01<<count);
  57. }
  58. }
  59. }
  60. void main()
  61. {
  62. indepence_button();
  63. }

 

3,动态数码管

 用于控制LED的选中,通过译码器可以减少接线口的使用。

 

 

  1. #include <REGX52.H>//启动头文件
  2. #include <INTRINS.H>//_nop_()命令需要的头文件
  3. #include <intrins.h>//移位头文件
  4. // 延时函数
  5. void delay_ms(int n)
  6. {
  7. while(n)
  8. {
  9. unsigned char i, j;
  10. i = 12;
  11. j = 169;
  12. do
  13. {
  14. while (--j);
  15. } while (--i);
  16. n--;
  17. }
  18. }
  19. //流水LED灯
  20. void LED_flow(int n)//执行n次流水灯
  21. {
  22. // 0表示接通 1表示断开
  23. int i;
  24. while(n>0)
  25. {
  26. for(i=0;i<8;i++)
  27. {
  28. P2=~(0x01<<i); //1右移i位,然后将结果赋值到P2
  29. delay_ms(1000); //大约延时1s
  30. }
  31. n--;
  32. }
  33. }
  34. //按键控制流水LED灯
  35. void indepence_button()
  36. {
  37. int count=7;
  38. while(1)
  39. {
  40. if(P3_1==0)// K1键控制
  41. {
  42. delay_ms(20);
  43. while(P3_1==0);// 因为独立按键存在抖动的情况,故添加循环判断度过抖动期
  44. delay_ms(20);
  45. count++;
  46. if(count>=8)count=0;
  47. P2=~(0x01<<count);
  48. }
  49. if(P3_0==0)// K2键控制
  50. {
  51. delay_ms(20);
  52. while(P3_0==0);// 因为独立按键存在抖动的情况,故添加循环判断度过抖动期
  53. delay_ms(20);
  54. if(count==0)count=7;
  55. else count--;
  56. P2=~(0x01<<count);
  57. }
  58. }
  59. }
  60. //动态数码管显示
  61. void dynamic_LED(int position,int number)
  62. {
  63. unsigned char number_tool[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
  64. 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//显示0~F的值
  65. if(position<=0||position>8)return;
  66. switch(position)
  67. {
  68. case 1:P2_2=0;P2_3=0;P2_4=0;break;
  69. case 2:P2_2=1;P2_3=0;P2_4=0;break;
  70. case 3:P2_2=0;P2_3=1;P2_4=0;break;
  71. case 4:P2_2=1;P2_3=1;P2_4=0;break;
  72. case 5:P2_2=0;P2_3=0;P2_4=1;break;
  73. case 6:P2_2=1;P2_3=0;P2_4=1;break;
  74. case 7:P2_2=0;P2_3=1;P2_4=1;break;
  75. case 8:P2_2=1;P2_3=1;P2_4=1;break;
  76. }
  77. P0=number_tool[number];
  78. delay_ms(1);//必须存在 否则会出现暗影的问题
  79. }
  80. void main()
  81. {
  82. while(1)
  83. {
  84. dynamic_LED(8,5);
  85. P0=0x00;//消隐
  86. dynamic_LED(5,2);
  87. P0=0x00;//消隐
  88. dynamic_LED(1,0);
  89. P0=0x00;//消隐
  90. }
  91. }

 

4,LCD1602显示 

LCD1602.c

  1. #include <REGX52.H>
  2. //引脚配置:
  3. sbit LCD_RS=P2^6;
  4. sbit LCD_RW=P2^5;
  5. sbit LCD_EN=P2^7;
  6. #define LCD_DataPort P0
  7. //函数定义:
  8. /**
  9. * @brief LCD1602延时函数,12MHz调用可延时1ms
  10. * @param 无
  11. * @retval 无
  12. */
  13. void LCD_Delay()
  14. {
  15. unsigned char i, j;
  16. i = 2;
  17. j = 239;
  18. do
  19. {
  20. while (--j);
  21. } while (--i);
  22. }
  23. /**
  24. * @brief LCD1602写命令
  25. * @param Command 要写入的命令
  26. * @retval 无
  27. */
  28. void LCD_WriteCommand(unsigned char Command)
  29. {
  30. LCD_RS=0;
  31. LCD_RW=0;
  32. LCD_DataPort=Command;
  33. LCD_EN=1;
  34. LCD_Delay();
  35. LCD_EN=0;
  36. LCD_Delay();
  37. }
  38. /**
  39. * @brief LCD1602写数据
  40. * @param Data 要写入的数据
  41. * @retval 无
  42. */
  43. void LCD_WriteData(unsigned char Data)
  44. {
  45. LCD_RS=1;
  46. LCD_RW=0;
  47. LCD_DataPort=Data;
  48. LCD_EN=1;
  49. LCD_Delay();
  50. LCD_EN=0;
  51. LCD_Delay();
  52. }
  53. /**
  54. * @brief LCD1602设置光标位置
  55. * @param Line 行位置,范围:1~2
  56. * @param Column 列位置,范围:1~16
  57. * @retval 无
  58. */
  59. void LCD_SetCursor(unsigned char Line,unsigned char Column)
  60. {
  61. if(Line==1)
  62. {
  63. LCD_WriteCommand(0x80|(Column-1));
  64. }
  65. else if(Line==2)
  66. {
  67. LCD_WriteCommand(0x80|(Column-1+0x40));
  68. }
  69. }
  70. /**
  71. * @brief LCD1602初始化函数
  72. * @param 无
  73. * @retval 无
  74. */
  75. void LCD_Init()
  76. {
  77. LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
  78. LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
  79. LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
  80. LCD_WriteCommand(0x01);//光标复位,清屏
  81. }
  82. /**
  83. * @brief 在LCD1602指定位置上显示一个字符
  84. * @param Line 行位置,范围:1~2
  85. * @param Column 列位置,范围:1~16
  86. * @param Char 要显示的字符
  87. * @retval 无
  88. */
  89. void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
  90. {
  91. LCD_SetCursor(Line,Column);
  92. LCD_WriteData(Char);
  93. }
  94. /**
  95. * @brief 在LCD1602指定位置开始显示所给字符串
  96. * @param Line 起始行位置,范围:1~2
  97. * @param Column 起始列位置,范围:1~16
  98. * @param String 要显示的字符串
  99. * @retval 无
  100. */
  101. void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
  102. {
  103. unsigned char i;
  104. LCD_SetCursor(Line,Column);
  105. for(i=0;String[i]!='\0';i++)
  106. {
  107. LCD_WriteData(String[i]);
  108. }
  109. }
  110. /**
  111. * @brief 返回值=X的Y次方
  112. */
  113. int LCD_Pow(int X,int Y)
  114. {
  115. unsigned char i;
  116. int Result=1;
  117. for(i=0;i<Y;i++)
  118. {
  119. Result*=X;
  120. }
  121. return Result;
  122. }
  123. /**
  124. * @brief 在LCD1602指定位置开始显示所给数字
  125. * @param Line 起始行位置,范围:1~2
  126. * @param Column 起始列位置,范围:1~16
  127. * @param Number 要显示的数字,范围:0~65535
  128. * @param Length 要显示数字的长度,范围:1~5
  129. * @retval 无
  130. */
  131. void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
  132. {
  133. unsigned char i;
  134. LCD_SetCursor(Line,Column);
  135. for(i=Length;i>0;i--)
  136. {
  137. LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
  138. }
  139. }
  140. /**
  141. * @brief 在LCD1602指定位置开始以有符号十进制显示所给数字
  142. * @param Line 起始行位置,范围:1~2
  143. * @param Column 起始列位置,范围:1~16
  144. * @param Number 要显示的数字,范围:-32768~32767
  145. * @param Length 要显示数字的长度,范围:1~5
  146. * @retval 无
  147. */
  148. void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
  149. {
  150. unsigned char i;
  151. unsigned int Number1;
  152. LCD_SetCursor(Line,Column);
  153. if(Number>=0)
  154. {
  155. LCD_WriteData('+');
  156. Number1=Number;
  157. }
  158. else
  159. {
  160. LCD_WriteData('-');
  161. Number1=-Number;
  162. }
  163. for(i=Length;i>0;i--)
  164. {
  165. LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
  166. }
  167. }
  168. /**
  169. * @brief 在LCD1602指定位置开始以十六进制显示所给数字
  170. * @param Line 起始行位置,范围:1~2
  171. * @param Column 起始列位置,范围:1~16
  172. * @param Number 要显示的数字,范围:0~0xFFFF
  173. * @param Length 要显示数字的长度,范围:1~4
  174. * @retval 无
  175. */
  176. void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
  177. {
  178. unsigned char i,SingleNumber;
  179. LCD_SetCursor(Line,Column);
  180. for(i=Length;i>0;i--)
  181. {
  182. SingleNumber=Number/LCD_Pow(16,i-1)%16;
  183. if(SingleNumber<10)
  184. {
  185. LCD_WriteData(SingleNumber+'0');
  186. }
  187. else
  188. {
  189. LCD_WriteData(SingleNumber-10+'A');
  190. }
  191. }
  192. }
  193. /**
  194. * @brief 在LCD1602指定位置开始以二进制显示所给数字
  195. * @param Line 起始行位置,范围:1~2
  196. * @param Column 起始列位置,范围:1~16
  197. * @param Number 要显示的数字,范围:0~1111 1111 1111 1111
  198. * @param Length 要显示数字的长度,范围:1~16
  199. * @retval 无
  200. */
  201. void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
  202. {
  203. unsigned char i;
  204. LCD_SetCursor(Line,Column);
  205. for(i=Length;i>0;i--)
  206. {
  207. LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
  208. }
  209. }

 LCD1602.h

  1. #ifndef __LCD1602_H__
  2. #define __LCD1602_H__
  3. //用户调用函数:
  4. void LCD_Init();
  5. void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
  6. void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
  7. void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
  8. void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
  9. void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
  10. void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
  11. #endif

 

小demo

  1. #include <REGX52.H>//启动头文件
  2. #include <INTRINS.H>//_nop_()命令需要的头文件
  3. #include <intrins.h>//移位头文件
  4. #include "LCD1602.h"
  5. // 延时函数
  6. void delay_ms(int n)
  7. {
  8. while(n)
  9. {
  10. unsigned char i, j;
  11. i = 12;
  12. j = 169;
  13. do
  14. {
  15. while (--j);
  16. } while (--i);
  17. n--;
  18. }
  19. }
  20. //流水LED灯
  21. void LED_flow(int n)//执行n次流水灯
  22. {
  23. // 0表示接通 1表示断开
  24. int i;
  25. while(n>0)
  26. {
  27. for(i=0;i<8;i++)
  28. {
  29. P2=~(0x01<<i); //1右移i位,然后将结果赋值到P2
  30. delay_ms(1000); //大约延时1s
  31. }
  32. n--;
  33. }
  34. }
  35. //按键控制流水LED灯
  36. void indepence_button()
  37. {
  38. int count=7;
  39. while(1)
  40. {
  41. if(P3_1==0)// K1键控制
  42. {
  43. delay_ms(20);
  44. while(P3_1==0);// 因为独立按键存在抖动的情况,故添加循环判断度过抖动期
  45. delay_ms(20);
  46. count++;
  47. if(count>=8)count=0;
  48. P2=~(0x01<<count);
  49. }
  50. if(P3_0==0)// K2键控制
  51. {
  52. delay_ms(20);
  53. while(P3_0==0);// 因为独立按键存在抖动的情况,故添加循环判断度过抖动期
  54. delay_ms(20);
  55. if(count==0)count=7;
  56. else count--;
  57. P2=~(0x01<<count);
  58. }
  59. }
  60. }
  61. //动态数码管显示
  62. void dynamic_LED(int position,int number)
  63. {
  64. unsigned char number_tool[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
  65. 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//显示0~F的值
  66. if(position<=0||position>8)return;
  67. switch(position)
  68. {
  69. case 1:P2_2=0;P2_3=0;P2_4=0;break;
  70. case 2:P2_2=1;P2_3=0;P2_4=0;break;
  71. case 3:P2_2=0;P2_3=1;P2_4=0;break;
  72. case 4:P2_2=1;P2_3=1;P2_4=0;break;
  73. case 5:P2_2=0;P2_3=0;P2_4=1;break;
  74. case 6:P2_2=1;P2_3=0;P2_4=1;break;
  75. case 7:P2_2=0;P2_3=1;P2_4=1;break;
  76. case 8:P2_2=1;P2_3=1;P2_4=1;break;
  77. }
  78. P0=number_tool[number];
  79. delay_ms(1);//必须存在 否则会出现暗影的问题
  80. }
  81. //动态数码管显示520
  82. void dynamic_LED_520()
  83. {
  84. dynamic_LED(8,5);
  85. P0=0x00;//消隐
  86. dynamic_LED(5,2);
  87. P0=0x00;//消隐
  88. dynamic_LED(1,0);
  89. P0=0x00;//消隐
  90. }
  91. //LCD1602显示
  92. void LCD1602()
  93. {
  94. LCD_Init();
  95. LCD_ShowChar(1,1,'A');
  96. while(1)
  97. {
  98. }
  99. }
  100. void main()
  101. {
  102. LCD1602();
  103. }

 

5,青花瓷歌曲

  1. #include <REG51.H>
  2. #define uchar unsigned char
  3. sbit beepIO=P1^5; //定义蜂鸣器端口为p1^5,根据单片机实际蜂鸣器实际接口改变
  4. uchar m,n; //定义4个八度 每八度12分音律 共48音律
  5. uchar code T[49][2]= {{0,0}, //定义音律49个二维数组
  6. {0xF9,0x1F},{0xF9,0x82},{0xF9,0xDF},{0xFA,0x37},{0xFA,0x8A},{0xFA,0xD8},{0xFB,0x23},{0xFB,0x68},{0xFB,0xAA},{0xFB,0xE9},{0xFC,0x24},{0xFC,0x5B},
  7. {0xFC,0x8F},{0xFC,0xC1},{0xFC,0xEF},{0xFD,0x1B},{0xFD,0x45},{0xFD,0x6C},{0xFD,0x91},{0xFD,0xB4},{0xFD,0xD5},{0xFD,0xF4},{0xFE,0x12},{0xFE,0x2D},
  8. {0xFE,0x48},{0xFE,0x60},{0xFE,0x78},{0xFE,0x86},{0xFE,0xA3},{0xFE,0xB6},{0xFE,0xC9},{0xFE,0xDA},{0xFF,0xEB},{0xFE,0xFA},{0xFF,0x09},{0xFF,0x17},
  9. {0xFF,0x24},{0xFF,0x30},{0xFF,0x3C},{0xFF,0x47},{0xFF,0x51},{0xFF,0x5B},{0xFF,0x64},{0xFF,0x6D},{0xFF,0x75},{0xFF,0x7D},{0xFF,0x84},{0xFF,0x8B}
  10. };
  11. uchar code music[][2]= {{0,4}, //定义曲谱数组,前数为音律,后数为音符节拍 ,要换歌改变简谱对应的音律号即可
  12. {0,1},{1,1},{3,1},{5,1},{6,1},{8,1},{10,1},{12,1},{13,1},//演示超低音八度 123457671
  13. {0,1},{13,1},{15,1},{17,1},{18,1},{20,1},{22,1},{24,1},{25,1},//演示低音八度12345671
  14. {0,1},{25,1},{27,1},{29,1},{30,1},{32,1},{34,1},{36,1},{37,1},//演示中音八度12345671
  15. {0,1},{37,1},{39,1},{41,1},{42,1},{44,1},{46,1},{48,2},//演示高音八度 1234567
  16. {0,4},{24,4},{24,4},{21,4},{19,4},{21,4},{14,8},{19,4},{21,4},{24,4},{21,4},{19,16},//记录菊花台简谱歌词:0553236 23532 天青色等烟雨 而我在等你
  17. {0,4},{24,4},{24,4},{21,4},{19,4},{21,4},{12,8},{19,4},{21,4},{24,4},{19,4},{17,16},//简谱歌词:0553235 23521 炊烟袅袅升起 隔江千万里
  18. {0,4},{17,4},{19,4},{21,4},{24,4},{26,4},{24,4},{22,4},{24,4},{21,4},{21,4},{19,4},{19,16},//简谱歌词:01235654 53322 在平地书刻你房间上的飘影
  19. {0,4},{17,4},{19,4},{17,4},{17,4},{19,4},{17,4},{19,4},{19,4},{21,8},{24,4},{21,4},{21,12},//简谱歌词:就当我为遇见你伏笔
  20. {0,4},{24,4},{24,4},{21,4},{19,4},{21,4},{14,8},{19,4},{21,4},{24,4},{21,4},{19,16}, //简谱歌词:0553236 23532 天青色等烟雨 而我在等你
  21. {0,4},{24,4},{24,4},{21,4},{19,4},{21,4},{12,8},{19,4},{21,4},{24,4},{19,4},{17,16}, //简谱歌词:0553235 23521 月色被打捞起 掩盖了结局
  22. {0,4},{17,4},{19,4},{21,4},{24,4},{26,4},{24,4},{22,4},{24,4},{21,4},{21,4},{19,4},{19,12},//简谱歌词:0123 5654 5332 25 322 11 如传世的青花瓷在独自美丽
  23. {12,4},{21,8},{19,8},{19,4},{17,20}, //简谱歌词:你眼带笑意
  24. {0xFF,0xFF}
  25. }; //歌曲结尾标识
  26. void delay(uchar p) //延时函数 无符号字符型变量
  27. {
  28. uchar i,j; //定义无符号字符型变量J和I
  29. for(; p>0; p--) // 此处P值即主函数的n值节拍个数
  30. for(i=181; i>0; i--) //延时181*181个机器周期约35毫秒,即一个1/16节拍
  31. for(j=181; j>0; j--);
  32. }
  33. void T0_int() interrupt 1
  34. {
  35. beepIO=!beepIO; //蜂鸣器翻转发声
  36. TH0=T[m][0];
  37. TL0=T[m][1];
  38. //音律延时周期次数码表赋给定时寄存器作为计数初始值,每TH0TL0个机器周期触发蜂鸣器端口翻转,演奏出不同音符
  39. }
  40. void main()
  41. {
  42. uchar i=0; //定义无符号字符型变量i,初始值为0
  43. TMOD=0x01;
  44. EA=1;
  45. ET0=1; //开启T0定时16位方式,总中断开启,开启T0外部中断请求
  46. while(1) //开始曲谱演奏,循环无限重复
  47. {
  48. m=music[i][0]; //将音律号赋值给m
  49. n=music[i][1]; //将节拍号赋值给n
  50. if(m==0x00) //如果音律号为0
  51. {
  52. TR0=0;
  53. delay(n);
  54. i++;
  55. } //关闭计时器,延迟n拍,将循环数I加1 ,准备读下一个音符
  56. else if(m==0xFF) //否则如果音律数为FF
  57. {
  58. TR0=0;
  59. delay(30);
  60. i=0;
  61. } //开启节拍延时301/16节拍,歌曲停顿2秒,将循环数I置0
  62. else if(m==music[i+1][0]) // 否则如果把下一个音律号数给变量m
  63. {
  64. TR0=1;
  65. delay(n);
  66. TR0=0;
  67. i++;
  68. } //定时器0打开延迟n拍,关闭定时器T0,读下一个音符,循环数加1读下一个音律
  69. else //音符若不为零
  70. {
  71. TR0=1;
  72. delay(n);
  73. i++;
  74. }//打开定时器,延时n个1/16拍,循环数I加1 ,准备演奏下一个音符
  75. }
  76. }

 

6,我和我的祖国 

  1. #include <reg52.h>
  2. sbit beep = P1^5;
  3. unsigned char timer0H, timer0L, time;
  4. //单片机晶振采用11.0592MHz
  5. // 频率-半周期数据表 高八位 本软件共保存了四个八度的28个频率数据
  6. code unsigned char FREQH[] = {
  7. 0xF2, 0xF3, 0xF5, 0xF5, 0xF6, 0xF7, 0xF8, //低音1234567
  8. 0xF9, 0xF9, 0xFA, 0xFA, 0xFB, 0xFB, 0xFC, 0xFC,//1,2,3,4,5,6,7,i
  9. 0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFE, //高音 234567
  10. 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF}; //超高音 1234567
  11. // 频率-半周期数据表 低八位
  12. code unsigned char FREQL[] = {
  13. 0x42, 0xC1, 0x17, 0xB6, 0xD0, 0xD1, 0xB6, //低音1234567
  14. 0x21, 0xE1, 0x8C, 0xD8, 0x68, 0xE9, 0x5B, 0x8F, //1,2,3,4,5,6,7,i
  15. 0xEE, 0x44, 0x6B, 0xB4, 0xF4, 0x2D, //高音 234567
  16. 0x47, 0x77, 0xA2, 0xB6, 0xDA, 0xFA, 0x16}; //超高音 1234567
  17. //数据表
  18. code unsigned char song[] = {
  19. 5, 2, 2, 6, 2, 2, 5, 2, 2, 4, 2, 2, 3, 2, 2, 2, 2, 2, 1, 2, 6, 5, 1, 6, //我和我的祖国
  20. 1, 2, 2, 3, 2, 2, 1, 3, 2, 7, 2, 2, 6, 2, 3, 3, 2, 1, 5, 2, 12, //一刻也不能分割
  21. 6, 2, 2, 7, 2, 2, 6, 2, 2, 5, 2, 2, 4, 2, 2, 3, 2, 2, 2, 2, 6, 6, 1, 6, //无论我走到哪里
  22. 7, 1, 2, 6, 1, 2, 5, 1, 2, 5, 2, 2, 1, 2, 3, 2, 2, 1, 3, 2, 12, //都唱出一首赞歌
  23. 5, 2, 2, 6, 2, 2, 5, 2, 2, 4, 2, 2, 3, 2, 2, 2, 2, 2, 1, 2, 6, 5, 1, 6, //我歌唱每一座高山
  24. 1, 2, 2, 3, 2, 2, 1, 3, 2, 7, 2, 2, 2, 3, 3, 1, 3, 1, 6, 2, 12, //我歌唱每一条河
  25. 1, 3, 2, 7, 2, 2, 6, 2, 2, 5, 2, 6, //袅袅炊烟
  26. 6, 2, 2, 5, 2, 2, 4, 2, 2, 3, 2, 6, //小小村落
  27. 7, 1, 4, 6, 1, 2, 5, 1, 4, 2, 2, 2, 1, 2, 12, //路上一道辙
  28. 8, 2, 2, 2, 3, 2, 3, 3, 2, 2, 3, 2, 8, 2, 2, 6, 2, 2, 7, 2, 2, 6, 2, 3, 3, 2, 1, 5, 2, 12,//我最亲爱的祖国
  29. 8, 2, 2, 2, 3, 2, 3, 3, 2, 2, 3, 2, 8, 2, 2, 6, 2, 2, 7, 2, 2, 5, 2, 3, 3, 2, 1, 6, 2, 12,//我永远紧依着你的心窝
  30. 5, 2, 2, 4, 2, 2, 3, 2, 2, 2, 2, 6, 7, 1, 2, 6, 1, 2, 5, 1, 2, 3, 2, 6,4, 2, 6, 2, 2, 4, 1, 2, 2,1, 2, 10,//你用你那母亲的脉搏和我诉说
  31. };
  32. //一个音符有三个数字。前为第几个音、中为第几个八度、后为时长(以半拍为单位)。
  33. //6, 2, 3 分别代表:6, 中音, 3个半拍;
  34. //5, 2, 1 分别代表:5, 中音, 1个半拍;
  35. void t0int() interrupt 1 //T0中断程序,控制发音的音调
  36. {
  37. TR0 = 0; //先关闭T0
  38. beep = !beep; //输出方波, 发音
  39. TH0 = timer0H; //下次的中断时间, 这个时间, 控制音调高低
  40. TL0 = timer0L;
  41. TR0 = 1; //启动T0
  42. }
  43. void delay(unsigned char t) //延时程序,控制发音的时间长度
  44. {
  45. unsigned char t1;
  46. unsigned long t2;
  47. for(t1 = 0; t1 < t; t1++) //双重循环, 共延时t个半拍
  48. for(t2 = 0; t2 < 4000; t2++); //延时期间, 可进入T0中断去发音
  49. TR0 = 0; //关闭T0, 停止发音
  50. }
  51. void sing() //演奏一个音符
  52. {
  53. TH0 = timer0H; //控制音调
  54. TL0 = timer0L;
  55. TR0 = 1; //启动T0, 由T0输出方波去发音
  56. delay(time); //控制时间长度
  57. }
  58. void main(void)
  59. {
  60. unsigned char k, i;
  61. TMOD = 1; //置T0定时工作方式1
  62. ET0 = 1; //开T0中断
  63. EA = 1; //开总中断
  64. while(1)
  65. {
  66. i = 0;
  67. time = 1;
  68. while(time)
  69. {
  70. k = song[i] + 7 * song[i + 1] - 1;//第i个是音符, 第i+1个是第几个八度
  71. timer0H = FREQH[k]; //从数据表中读出频率数值
  72. timer0L = FREQL[k]; //实际上, 是定时的时间长度
  73. time = song[i + 2]; //读出时间长度数值
  74. i += 3;
  75. sing(); //发出一个音符
  76. }
  77. }
  78. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/554336
推荐阅读
相关标签
  

闽ICP备14008679号