【C51】源码 4 -- 喇叭播放【寒蝉鸣泣之时】插曲 You

发布者:EuphoricMelody最新更新时间:2016-09-28 来源: eefocus关键字:C51  喇叭播放 手机看文章 扫描二维码
随时随地手机看文章
学单片机到喇叭部分,觉得挺好玩,编写了喇叭播放音乐的程序……

BGM 取自【寒蝉鸣泣之时】插曲 You,简谱由网络提供,感谢作者……先把简谱附上:

【C51】源码 4 -- 喇叭播放【寒蝉鸣泣之时】插曲 You - 灼眼のFate - 運命の始まり

还有一张自制的“钢琴按键频率分布”,没写那么全,只对应本程序,图如下:

【C51】源码 4 -- 喇叭播放【寒蝉鸣泣之时】插曲 You - 灼眼のFate - 運命の始まり

附上源码:(初出茅庐,难免有写的不好的地方,仅作备份之用,欢迎指点,喷子退散……)

/*******************************************************************
                               喇叭播放音乐

BGM 取自【寒蝉鸣泣之时】的插曲 You

缺点:

1、没有添加调节音量的功能
2、音高、节拍 都要自己提前写好,工作量大
      可以改进成:通过解析 midi 文件进行音乐播放
     (midi 里边就是音高、节拍信息)
********************************************************************/

#include 

sbit SPK = P1^0;    // 喇叭输入

/************************************************************************************************************************************
PIANO_F[ ]:是钢琴按键的频率,数组下标对应钢琴按键,如上图所示
               例:图上可以看出:8 号键对应钢琴的中央 C,正好是 PIANO_F[8],对应频率为 261.6 Hz
               注:PIANO_F[0] 不代表任何按键,为了方便计数,数组下标从 1 开始有意义
*************************************************************************************************************************************/

float code PIANO_F[ ] = {7.63, 
                                          130.8,  146.8,  164.8,  174.5,  196.0,  220.0,  247.1, 
                                          261.6,  293.6,  329.6,  349.0,  392.0,  440.0,  494.0, 
                                          523.2,  587.2,  659.2,  698.3,  784.0,  880.0,  988.0, 
                                          1046.4, 1174.4, 1318.4, 1396.8, 1567.7, 1760.0, 1975.3};

/******************************************************************************************************
PITCH[ ]:指的是 音高,对应上图中的按键号
          例:中音 do:如图对应 8 号键
                  高音 do:如图对应 15 号键
      好处:假如歌曲播放到了第 i 个音,那么 PITCH[i] 就是对应钢琴上的按键
                  那么 PIANO_F[ PITCH[i] ] 就是对应的琴键的频率,方便编程使用
          注:255 代表 音乐结束
                  0 代表 八分休止符
******************************************************************************************************/

unsigned char code PITCH[ ] = {16, 17, 16, 15, 16, 12, 17, 16, 15, 
                                                       16, 17, 16, 15, 15, 19, 16, 
                                                       16, 17, 16, 15, 16, 12, 17, 16, 15, 
                                                       16, 17, 16, 15, 15, 12, 
                                                       12, 10, 12, 15, 15, 
                                                       16, 16, 16, 17, 17, 12, 
                                                       12, 10, 12, 0,  15, 15, 16, 
                                                       16, 16, 16, 19, 17, 12, 
                                                       12, 10, 0,  12, 0,  15, 15, 15, 
                                                       16, 16, 16, 17, 17, 12, 
                                                       12, 10, 0,  12, 0,  15, 15, 16, 
                                                       16, 16, 16, 19, 17, 26, 
                                                       26, 24, 0,  26, 26, 22, 0,  23, 
                                                       23, 22, 23, 0,  24, 23, 24, 26, 
                                                       26, 24, 0,  26, 26, 22, 0,  23, 
                                                       23, 22, 0,  23, 22, 
                                                       255};

/***************************************************************************************************************
BEAT[ ]:指的是 节拍,数值代表基本节拍的倍数,这里基本节拍为 十六分音符 长
         例:8,代表 8 倍 十六分音符 长,即:二分音符
                4,代表 4 倍 十六分音符 长,即:四分音符
                2,代表 2 倍 十六分音符 长,即:八分音符
                1,代表 1 倍 十六分音符 长,即:十六分音符
                6,代表 6 倍 十六分音符 长,即:符点四分音符
***************************************************************************************************************/

unsigned char code BEAT[ ] = {4, 1, 1, 2, 2, 2, 1, 1, 2,    4, 1, 1, 2, 2, 2, 4, 
                                                      4, 1, 1, 2, 2, 2, 1, 1, 2,    4, 1, 1, 2, 6, 2, 
                                                      2, 4, 2, 6, 2,                    2, 2, 2, 2, 6, 2, 
                                                      2, 2, 4, 2, 2, 2, 2,            2, 2, 2, 2, 6, 2, 
                                                      2, 2, 2, 2, 2, 2, 2, 2,        2, 2, 2, 2, 6, 2, 
                                                      2, 2, 2, 2, 2, 2, 2, 2,        2, 2, 2, 2, 6, 2, 
                                                      2, 2, 2, 2, 2, 2, 2, 2,        2, 2, 2, 2, 2, 2, 2, 2, 
                                                      2, 2, 2, 2, 2, 2, 2, 2,        2, 2, 2, 2, 8, 
                                                      255};

unsigned char time_h = 0;      // 用于向定时器中断程序传递下一步定时信息
unsigned char time_l = 0;

unsigned int time = 0;             // 根据按键频率,换算出应该定时多长时间
unsigned char i;

void Init_Timer0(void);                   // 初始化 定时器 0
void Delay(unsigned int t);            // 普通延时
void Delay_ms(unsigned int t);     // 相当近似的延迟 t ms

void main (void)
{
    Init_Timer0();       

    for (i = 0; PITCH[i] != 255; i++) {         // 顺序播放,255 为音乐结束

        TR0 = 0;          // 关 定时器0

        Delay_ms(20);          // 延时一段时间,保证按键与按键之间能分得清楚

       /*********************************************************************************************************************
        定时时间 time 的计算:

        以 中央 C 为例:频率为 261.6 Hz,就是每秒 261.6 下,倒数就是 每下 1/261.6 s,
                                      换成 us 就是 1,000,000/261.6,每响一次是一个上升沿加一个下降沿,
                                      因此,变换的次数应该是 2 倍,每次变换所花时间是一半,
                                      即:1,000,000/(2*261.6)
        **********************************************************************************************************************/

        time = (unsigned int)(1000000 / (2 * PIANO_F[PITCH[i]]));

        time_h = (65536 - time) / 256;
        time_l = (65536 - time) % 256;

        TH0 = time_h;         // 定时器赋值 
        TL0 = time_l;

        TR0 = 1;                   // 开 定时器0

       /****************************************************************************************************************
        如果音高是 0,说明是 八分休止符,关定时器,定时器不驱动喇叭,也就没有声音了
        ****************************************************************************************************************/

        if (PITCH[i] == 0) TR0 = 0;

       /********************************************************************************************************
        相当重要的延时!节拍全部由它控制,不是很精确,其实用 定时器 1 可能更好
        ********************************************************************************************************/

        Delay_ms(BEAT[i] * 30);
    }

    TR0 = 0;        // 音乐播放完后,关定时器,收尾

    /*****************************************************************************************************************
    相当重要!没有此语句将导致循环执行 main 函数!

    详细讨论参见:http://gaebolg.blog.163.com/blog/static/19826906820122254823928/
    *****************************************************************************************************************/

    while (1);
}

void Init_Timer0(void)
{
    TMOD = 0x01;       // 定时器 0,模式1
    EA = 1;                   // 开 总中断
    ET0 = 1;                 // 开 定时器 0 中断 
}

void Timer0_ISR(void) interrupt 1
{
    TH0 = time_h;      // 重装初值
    TL0 = time_l;

    SPK = !SPK;         // 产生方波,驱动喇叭发声
}

void Delay(unsigned int t)
{
    while (t--);
}

void Delay_ms(unsigned int t)       // 根据测试,可以相当近似的表示 t ms
{
    while (t--) {
        Delay(245);
        Delay(245);
    }
}

关键字:C51  喇叭播放 引用地址:【C51】源码 4 -- 喇叭播放【寒蝉鸣泣之时】插曲 You

上一篇:【C51】源码 5 -- LCD 1602 显示字符
下一篇:【C51】源码 3 -- 电子时钟(独立按键、8 位数码管、定时器)

推荐阅读最新更新时间:2024-03-16 15:12

C51驱动步进电机
代码: 采用1-2相励磁的方式使步进电机正向转动起来 #include reg52.h #define uint unsigned int #define uchar unsigned char sbit dula=P2^6; 数码管段选定义 uchar code step_table ={0xc4,0xcc,0xc8,0xd8,0xd0,0xf0,0xe0,0xe4}; void delay(uint t) void main() { uint i; P0=00; 关掉数码管避免乱显示,因为没有用到 delay(500); dula=1; delay(500); dula=0;
[单片机]
<font color='red'>C51</font>驱动步进电机
PS/2处理C51头文件
/**********************中文版本*******************************/ /*****功能描述 : PS/2键盘应用头文件(中断处理) *****/ /*****调试平台 : 51单片机 11.0592M晶振 *****/ /*****作 者 : 郑文(ClimberWin) *****/ /*****编写日期 : 2009年10月5日 *****/ /*****版本信息 : V1.0 *****/ /*****修改日期 : *****/ /
[单片机]
基于C51单片机的MP3播放器设计与实现
0 引言     便携式MP3播放器作为一种集音频播放、数据存储为一身的数码产品,其功能结构为电子设计人员所津津乐道。MP3是MPEG一1音频III(1ayerIII)的简称。MPEG一1音频(ISO/IECll 172—3)是目前普遍应用的音频压缩标准,其中层III的算法最为复杂,但压缩比最大,效果也最好,在低码率的条件下基本能达到CD的音质效果。MP3标准用尽可能低的码流实现CD音质的声音而不会产生数据损失。如果对于一段声音不进行压缩的话,那么每存储一秒钟的立体声CD音质音乐必须用1.4Mbit,这是个十分大的开销。通过运用MPEG音频标准的压缩技术,我们可以把存储空间压缩到原来的1/12而不会降低声音的音质。即使使用1/
[嵌入式]
LCD1602液晶秒表C51程序
此程序是基于51hei单片机开发板上面写的,如需要移植到自己的电路上,修改相应的端口即可 *********************************************************************** * @file main.c * @author xr * @date 2014年5月8日22:11:33 -- 2014年5月9日12:03:49 * @version V1.2.3 * @brief LCD1602液晶跑表 单片机STC89C52RC MCU 晶振 11.0592MHZ **************************************
[单片机]
C51 手动计算定时器 中断简介
以下由软件计算得出12M晶振,定时器模式16位在12T下1毫秒的时间 void Timer0Init(void) //1毫秒@12.000MHz{ AUXR &= 0x7F; //定时器时钟12T模式 TMOD &= 0xF0; //设置定时器模式 TMOD |= 0x01; //设置定时器模式 TL0 = 0x18; //设置定时初值 TH0 = 0xFC; //设置定时初值 TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时}1.2.3.4.5.6.7.8.9.10. 验证软件的结果: 晶振为12M,一个震荡用时为(1/12M)秒 12T的单片机一个机器
[单片机]
<font color='red'>C51</font> 手动计算定时器 中断简介
Keil C51软件使用详解
第一节 Keil C51编译器的控制指令 C51编译器的控制指令分为三类:源文件控制类,目标文件控制类及列表控制类。 1. 源文件控制类 NOEXTEND:C51源文件不允许使用ANSI C扩展功能。 DEFINE(DF):定义预处理(在C51命令行)。 2. 目标文件(Object)控制类: COMPACT LARGE SMALL 选编译模式 DEBUG(DB) 包含调试信息,以供仿真器或dSCope51使用。 NOAMAKE(NOAM) 禁止AutoMake信息记录 NOREGPARMS 禁止用寄存器传递参数 OBJECTEXTEND(OE) Object文件包含附加变量类型信息 OPTIMIZE(OT) 指
[单片机]
C51编程总结-单片机的奇怪知识1(IC输入输出电压)
在使用单片机中过程,我们肯定对数字信号的“0”与“1”,有了深刻的影响,一般来说高电平位“1”为5V(对于5V VCC的单片机来来说),低电平“0”是0V。 实际上我们可能使用供电电压3.3V的芯片,高电平“1”的电压是3.3V。使其与单片机进行交换数据,,这个时候5V单片机能够正常识别到3.3V芯片的 “1”吗? 3.3V芯片与5V单片能不能正常交换数据 IC输入输出电压(也常被成为I/O识别电压),不是看VCC。而是看输入输出电压 我们可以在IC的规格书上查看到相关的参数。以下是CH340部分电气参数。 从表格可以知道,相关输入输出电压有四个参数,分别是 注:看输入输出电压,需要看两个芯片的输入输出电压,
[单片机]
<font color='red'>C51</font>编程总结-单片机的奇怪知识1(IC输入输出电压)
C51单片机的IO口介绍(下)
上一篇文章我们对C51的IO简单的介绍了一下,现在我们来简单了解C51的IO的结构 这里我们学习一下比较常见的单片机的IO模式,分别是准双向,开漏输出和推挽输出 (这里要提一嘴,我们用的STC88C52RC是没有推挽输出功能的,STC公司后续推出的一些机型才有推挽输出功能) 接下来我们来看看这几种模式 1.准双向 看看下面的原理图,机内信号通过一个非门取反后送入一个MOS管,MOS管负责控制这个IO的高低电平,配合内部上拉电阻完成高低电平的输出 为了方便我们分析,我们把这个MOS管看成一只NPN三极管。区别是三极管靠电流导通,MOS管靠电压导通 结合前面我们讲过的知识,对于一只NPN三极管,基极b电压比集电极c电压
[单片机]
<font color='red'>C51</font>单片机的IO口介绍(下)
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
热门活动
换一批
更多
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

更多精选电路图
换一换 更多 相关热搜器件
更多每日新闻
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved