不用定时器的单片机音乐教程

初学单片机的时候不会定时器,刚学了蜂鸣器想搞音乐但调全崩了,研究了半天研究出了一个计算用

while(i--);

的操作搞相对准确的音调;

先说下我计算的过程吧

(本作者单片机也没学多深,文章里肯定会有错误或不准确的请指出,谢谢)

先来一小段代码

#include<reg52.h>

typedef unsigned int uint;
typedef unsigned char uchar;

sbit beep = P1^5; //蜂鸣器引脚

void delay(uint i){
	while(i--);
    beep = !beep;//这里设置一个断点
}

void main(){
	while(1){
        delay(scale[0]);
        
	}
}

先将keil晶振设置为12(我实验板子上的),用keil的调试和断点功能和模拟功能,根据这位大佬的

------------------------------------

         音符频率对照表

------------------------------------

假设表是十分准确的

中 1 DO 频率 523HZ     半周期 0956 微秒

断点设置在

用delay(104);

我们可以测试出(sec)

运行前    0.00133900     运行一次     0.00229400      运行两次    0.00324900

差都为

0.00095500

delay(104);

我们可以测试出(sec)

运行前    0.00133900     运行一次     0.00229400      运行两次    0.00324900

差都为

0.00095500

和半周期标准值956()差一点点

delay(105);

我们可以测试出(sec)

运行前    0.00134800     运行一次     0.00231200      运行两次    0.00327600

差都为

0.00096400

所以按照标准值为956的情况下,要想得到准确的延迟956,delay内应该为104+1/9

假设存在一个系数使 delay内系数 = 半周期

可求得系数约为

9.182497331910353‬

用 中 2 RE 频率 578 HZ     半周期 0842  微妙

来测试

得到 delay内 为 91.69618781961877‬ 约为 92

带回上面那串代码测试

delay(92);

我们可以测试出(sec)

运行前    0.00123100     运行一次     0.00207800      运行两次    0.00292500

差都为

0.00084700

 

delay(91);

我们可以测试出(sec)

运行前    0.00122200     运行一次     0.00206000      运行两次    0.00289800

差都为

0.00083800

与标准值接近

根据此操作可以算出如下延时操作时,每个音对应delay内部的数

void delay(uint i){
	while(i--);
    beep = !beep;//这里设置一个断点
}

以下为根据如上操作计算结果

不用定时器如果代码不同会导致时间不同,因为运行代码计算会消耗时间,所以建议写的时候自己计算下时间,如果用一下数据请确保delay内部和上面那代码栏内的一样,不然会崩的

----------------------------------------------------

低 208,185,165,156,139,123,110

中 104,92,83,78,69,62,55,

高 52,46,41,39,35,31,27

----------------------------------------------------

还有种操作根据频率计算的这里就不讲了。

附上根据频率计算系数搞出来的极乐净土乐谱

(我写的太占空间了,原本是写两只老虎就没用数组写直接硬写,后来改极乐净土肝到一半才觉得有点不对劲。。。。不想浪费劳动成果,就直接硬写下去了,懒得再改用数组再写了)

极乐净土乐谱
极乐净土

以下为成品代码

#include<reg52.h>
typedef unsigned int uint;
typedef unsigned char uchar;

sbit beep = P1^5; 
uint scale[] = {108, 102,93,81,77,68,61,54, 51,46,41,38,34,30,27};/中高部分,最前面那个是为了凑数,毕竟每个调对应相应的简谱数字比较好检查,我测试是直接用这里的代码测试出来的,所以数字会有差别,毕竟不用定时器代码不同会占用计算,导致时间不同所以建议写的时候自己计算下时间
uint scalel[] = {204, 204,182,162,153,137,122,108};//低音部分

void delay(uint i){
	while(i--);
}

void tone(uchar tone,uchar time,uchar stop){
	uint Time = time*12500/scale[tone];
	uint Stop = stop * 1250;
	while(Time--){
		beep = ~beep;
		delay(scale[tone]);
	}
	delay(Stop);
}

void tonel(uchar tone,uchar time,uchar stop){
	uint Time = time*12500/scalel[tone];
	uint Stop = stop * 1250;
	while(Time--){
		beep = ~beep;
		delay(scalel[tone]);
	}
	delay(Stop);
}

void main(){
    uchar a = 2;
	while(1){
		//1
		tone(3,2,2);
		tone(5,2,2);
		
		tone(6,2,20);
		tone(5,2,2);
		tone(6,2,20);
		tone(5,2,2);
		
		tone(6,2,2);
		tone(8,2,2);
		tone(5,2,2);
		tone(6,2,2);
		tone(3,2,10);
		tone(3,2,2);
		tone(5,2,2);
		
		tone(6,2,20);
		tone(5,2,2);
		tone(6,2,20);
		tone(5,2,2);
		
		tone(6,2,2);
		tone(10,2,2);
		tone(8,2,2);
		tone(9,2,2);
		tone(6,2,10);
		tone(3,2,2);
		tone(5,2,2);
		
		//2
		tone(6,2,20);
		tone(5,2,2); 
		tone(6,2,20);
		tone(5,2,2);
		
		tone(6,2,2);
		tone(8,2,2);
		tone(5,2,2);
		tone(6,2,2);
		tone(3,2,2);
		tone(5,2,2);
		tone(1,2,2);
		tone(2,2,2);
		
		tone(3,4,2);
		tone(8,4,2);
		tone(6,4,2);
		tone(10,4,2);
		
		tone(9,2,2);
		tone(10,1,2);
		tone(9,1,2);
		tone(8,2,2);
		tone(9,2,2);
		tone(6,4,20);
		
		//3
		tone(6,4,2);
		tone(6,4,2);
		tone(6,4,2);
		tone(6,1,2);
		tone(8,1,2);
		tone(9,1,2);
		tone(10,1,2);
		
		tone(6,4,2);
		tone(6,4,2);
		tone(6,2,2);
		tone(5,2,2);
		tone(5,2,2);
		tone(6,2,2);
		
		tone(6,4,2);
		tone(6,4,2);
		tone(6,4,2);
		tone(6,1,2);
		tone(8,1,2);
		tone(9,1,2);
		tone(10,1,2);
		
		tone(6,4,2);
		tone(6,4,2);
		tone(6,2,2);
		tone(11,2,2);
		tone(11,2,2);
		tone(10,2,2);
		
    while(a--){
		//4
		tone(6,4,2);
		tone(6,4,2);
		tone(6,4,2);
		tone(6,1,2);
		tone(8,1,2);
		tone(9,1,2);
		tone(10,1,2);
		
		tone(6,4,2);
		tone(6,4,2);
		tone(6,2,2);
		tone(5,2,2);
		tone(5,2,2);
		tone(6,2,2);
		
		tone(6,4,2);
		tone(6,4,2);
		tone(6,4,2);
		tone(6,1,2);
		tone(8,1,2);
		tone(9,1,2);
		tone(10,1,2);
		
		tone(13,4,2);
		tone(5,2,2);
		tone(5,2,2);
		tone(6,2,2);
		tone(6,4,30);
		
		//5
        tone(6,2,2);
		tone(6,2,2);
		tone(5,1,2);
		tone(5,1,2);
		tone(5,2,2);
        tone(6,2,2);
        
		tone(5,2,2);
		tone(3,2,2);
        tone(3,2,2);
		tone(5,1,2);
        tone(3,1,2);
		tone(3,4,50);
        
        tone(6,2,2);
		tone(6,2,2);
        tone(5,2,2);
		tone(6,2,2);
        tone(7,2,2);
        
        tone(8,4,2);
		tone(7,4,2);
        tone(6,2,2);
		tone(7,1,2);
        tone(6,1,2);
		tone(5,4,30);
        
        //6
        tone(6,2,2);
		tone(6,2,2);
		tone(5,2,2);
		tone(5,2,2);
		tone(6,1,2);
        tone(5,1,2);
        
		tone(5,2,2);
		tone(3,2,2);
        tone(3,2,2);
		tone(5,1,2);
        tone(3,1,2);
		tone(3,4,10);
        tone(5,2,2);
        
        tone(5,2,2);
		tone(6,2,10);
        tone(5,2,2);
        tone(5,2,2);
        tone(6,2,10);
		tone(6,1,2);
        tone(7,1,2);
        
        tone(8,4,2);
		tone(9,4,2);
        tone(6,2,2);
		tone(3,2,2);
        tone(3,2,2);
		tone(5,2,2);
        
        //7
        tone(5,2,2);
		tone(6,2,10);
        tone(10,2,2);
		tone(9,4,10);
        tone(6,2,10);
        
		tone(6,2,2);
        tone(6,2,2);
		tone(10,2,2);
        tone(9,4,30);
        
        tone(9,2,2);
		tone(9,2,2);
        tone(8,2,2);
		tone(9,2,2);
        tone(8,1,2);
        tone(6,1,2);
		tone(6,2,2);
        tone(5,2,2);
        
        tone(5,2,2);
		tone(5,2,2);
        tone(5,2,2);
		tone(6,2,2);
        tone(6,2,2);
        tone(3,2,2);
		tone(3,2,2);
        tone(5,2,2);
        
        //8
        tone(5,2,2);
		tone(6,2,10);
        tone(10,2,2);
		tone(9,4,10);
        tone(6,2,10);
        
		tone(6,2,2);
        tone(6,2,2);
		tone(10,2,2);
        tone(9,4,30);
        
        tone(9,2,2);
		tone(9,2,2);
        tone(8,2,2);
		tone(9,2,2);
        tone(8,1,2);
        tone(6,1,2);
		tone(6,1,2);
        tone(3,1,2);
        tone(5,2,2);
        
        tone(5,2,2);
		tone(6,2,2);
        tone(6,2,2);
		tone(5,2,2);
        tone(6,4,10);
		tone(3,1,2);
        tone(5,1,2);
        
        //9
        tone(6,2,2);
		tone(6,2,2);
        tone(6,2,2);
		tone(10,2,2);
        tone(10,4,10);
		tone(7,1,2);
        tone(8,1,2);
        
        tone(9,2,2);
		tone(8,1,2);
        tone(9,1,2);
		tone(9,2,2);
        tone(10,2,2);
		tone(6,4,10);
        tone(5,2,2);
        tone(5,2,2);
        
        tone(6,4,2);
		tone(10,2,2);
        tone(10,1,2);
		tone(9,2,2);
        tone(8,2,2);
		tone(6,2,2);
        tone(5,2,2);
        
        tone(6,2,2);
		tone(6,1,2);
        tone(6,2,2);
		tone(8,2,2);
        tone(9,4,20);
        
        //10
        tone(6,2,2);
		tone(6,1,2);
        tone(6,1,2);
		tone(6,2,2);
        tone(5,1,2);
		tone(5,1,2);
        tone(6,2,2);
		tone(10,2,10);
        tone(8,2,2);
        
        tone(9,2,2);
		tone(8,1,2);
        tone(9,1,2);
		tone(9,2,2);
        tone(10,2,2);
		tone(10,4,10);
        tone(5,2,2);
        
        tone(6,2,2);
		tone(8,2,10);
        tone(5,2,2);
		tone(6,2,2);
        tone(10,2,10);
		tone(10,1,2);
        tone(9,1,2);
        
        tone(8,2,2);
		tone(7,2,2);
        tone(6,2,2);
		tone(5,2,2);
        tone(5,2,2);
        tone(6,4,10);
    }
        
        //11
        tone(6,2,2);
		tone(5,2,2);
        tone(3,2,2);
		tone(2,2,2);
        tone(3,2,2);
		tone(1,2,2);
        tonel(5,2,2);
        
        tonel(6,2,2);
		tonel(5,2,2);
        tonel(6,2,10);
		tonel(6,4,20);

        tonel(6,4,20);
		tonel(7,4,00);

        tonel(6,1,2);
		tonel(7,1,2);
        tonel(6,2,2);
		tonel(6,1,2);
        tonel(7,1,2);
        tonel(6,2,2);
        tone(1,4,20);
        
        tonel(7,2,2);
		tone(6,2,2);
        tone(5,2,2);
		tone(3,2,2);
        tone(2,2,2);
        tone(3,2,2);
        tone(1,2,2);
        tonel(5,2,2);
	}
}

 

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个基于51单片机定时器的简易音乐播放代码: ```c #include <reg51.h> typedef unsigned char uchar; typedef unsigned int uint; // 音乐节拍数组,每个元素表示占空比,范围0~255 uchar music[] = { 100, 100, 100, 50, 150, 150, 150, 50, 100, 100, 100, 50, 150, 150, 150, 50 }; // 每个音符的持续时间,单位为20ms uchar duration[] = { 10, 10, 10, 5, 15, 15, 15, 5, 10, 10, 10, 5, 15, 15, 15, 5 }; uchar index = 0; // 当前播放的音符索引 void timer0_init() { TMOD |= 0x01; // 设置为工作模式1 TH0 = (65536 - 50000) / 256; // 定时器初值,定时20ms TL0 = (65536 - 50000) % 256; EA = 1; // 打开总中断开关 ET0 = 1; // 打开定时器0中断开关 TR0 = 1; // 启动定时器0 } void main() { timer0_init(); while(1); } void timer0_isr() interrupt 1 { static uchar count = 0; TH0 = (65536 - 50000) / 256; // 重新赋初值 TL0 = (65536 - 50000) % 256; P1 = (count < music[index] ? 0x01 : 0x00); // 控制P1.0输出高电平或低电平 count++; if (count >= duration[index]) // 当前音符播放结束 { count = 0; index++; if (index >= sizeof(music)) // 播放完毕,从头开始 { index = 0; } } } ``` 该代码使用定时器0产生20ms的中断,每次中断时控制P1.0输出高电平或低电平,从而产生音乐声音。音乐节拍和每个音符的持续时间以数组的形式存储,通过index来控制当前播放的音符。当当前音符播放结束时,index自增,如果已经播放完毕,则从头开始播放

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值