单片机:实现生日快乐歌(附带源码)

单片机实现《生日快乐歌》

实现一个"生日快乐歌"是单片机应用中的一个经典项目,通过它可以学习如何控制声音输出、使用定时器、以及如何处理按键输入等功能。本项目将利用单片机生成《生日快乐歌》的音频信号,并通过蜂鸣器播放出来。

项目目标

本项目的目标是设计并实现一个基于8051单片机的"生日快乐歌"播放系统。系统会通过蜂鸣器输出《生日快乐歌》的旋律,当按下一个按键时,系统播放这首歌。

一、硬件设计
1.1 单片机选择

本项目采用8051单片机,它具备丰富的I/O端口,可以与蜂鸣器连接,并且支持定时器,可以用来产生音频信号。

1.2 外部硬件
  • 蜂鸣器:作为输出设备,通过蜂鸣器发出不同频率的音符,模拟乐曲的旋律。
  • 按键:用于触发《生日快乐歌》的播放。假设使用一个简单的按键,按下时开始播放歌曲。
  • 定时器:用定时器来产生一定频率的脉冲信号,以控制蜂鸣器发出不同的音高。
  • 电源和电阻:用于电路的供电和保护。
1.3 硬件连接
  1. 蜂鸣器连接:蜂鸣器连接到P1.0端口,利用PWM信号驱动蜂鸣器发出声音。
  2. 按键连接:按键连接到P3.0端口,用来触发播放《生日快乐歌》。
二、系统设计
2.1 功能模块
  1. 音符生成模块:通过定时器产生不同频率的脉冲信号,驱动蜂鸣器发出不同频率的声音,形成音符。
  2. 按键触发模块:通过按键输入,触发歌曲的播放。
  3. 歌曲存储和播放模块:存储《生日快乐歌》中的音符频率和时长,依次播放。
2.2 数据结构
  • 音符频率:将歌曲中的每个音符频率(如C4、D4等)存储为一个数组,方便播放。
  • 音符时长:每个音符的时长也可以通过数组存储,控制每个音符的持续时间。
  • 当前音符:当前播放的音符。
2.3 歌曲结构

《生日快乐歌》的音符和时长如下(以C4为基础音符):

音符 频率(Hz) 时长(ms)
C4 261.63 400
C4 261.63 400
D4 293.66 400
C4 261.63 800
F4 349.23 400
F4 349.23 400
E4 329.63 400
C4 261.63 800
C4 261.63 400
C4 261.63 400
D4 293.66 400
C4 261.63 800
三、程序设计
3.1 定时器中断

利用定时器中断来生成频率对应的音符。通过设置定时器初值,可以生成一定频率的脉冲信号,从而控制蜂鸣器发出相应的音符。

3.2 主程序框架
  1. 初始化定时器和蜂鸣器
  2. 按键扫描:监听按键的输入,当按下按键时触发歌曲播放。
  3. 音符生成和播放:根据音符的频率和时长,通过定时器产生相应的脉冲信号,控制蜂鸣器的鸣响。
  4. 音符播放结束后继续播放下一音符,直到歌曲播放完毕。
3.3 代码实现
cpp 复制代码
#include <reg51.h>   // 包含8051的寄存器定义

// 定义蜂鸣器连接端口
#define BEEP P1_0

// 定义按键连接端口
#define BUTTON P3_0

// 定义音符的频率(单位:Hz)
#define C4 261
#define D4 293
#define E4 329
#define F4 349

// 定义音符时长(单位:毫秒)
#define NOTE_DURATION 400  // 默认音符时长

// 定义音符数组,按照《生日快乐歌》的音符顺序
unsigned int melody[] = {C4, C4, D4, C4, F4, F4, E4, C4, C4, C4, D4, C4};
unsigned int melody_duration[] = {NOTE_DURATION, NOTE_DURATION, NOTE_DURATION, NOTE_DURATION, NOTE_DURATION, NOTE_DURATION, NOTE_DURATION, NOTE_DURATION, NOTE_DURATION, NOTE_DURATION, NOTE_DURATION, NOTE_DURATION};

// 定时器初始化,产生固定频率的脉冲
void timer0_init() {
    TMOD = 0x01;  // 设置定时器0为模式1(16位定时器)
    IE = 0x82;    // 使能定时器中断
    TR0 = 1;      // 启动定时器0
}

// 延时函数(单位:毫秒)
void delay_ms(unsigned int ms) {
    unsigned int i, j;
    for (i = 0; i < ms; i++) {
        for (j = 0; j < 120; j++) {
            // 空循环,产生延时
        }
    }
}

// 播放音符
void play_tone(unsigned int frequency, unsigned int duration) {
    unsigned int i;
    unsigned int delay_time = 1000000 / frequency;  // 计算每个周期的延时
    unsigned int cycles = frequency * duration / 1000;  // 计算音符持续的周期数
    
    for (i = 0; i < cycles; i++) {
        BEEP = 1;  // 启动蜂鸣器
        delay_ms(delay_time / 2);  // 延时一半周期
        BEEP = 0;  // 关闭蜂鸣器
        delay_ms(delay_time / 2);  // 延时另一半周期
    }
}

// 按键扫描函数
unsigned char key_scan() {
    if (BUTTON == 0) {
        delay_ms(20);  // 去抖动
        return 1;  // 按键被按下
    }
    return 0;
}

// 主程序
void main() {
    unsigned int i;
    timer0_init();  // 初始化定时器
    
    while (1) {
        if (key_scan()) {  // 如果按键被按下
            for (i = 0; i < sizeof(melody) / sizeof(melody[0]); i++) {
                play_tone(melody[i], melody_duration[i]);  // 播放音符
                delay_ms(100);  // 音符之间的间隔
            }
        }
    }
}
四、程序说明
  1. 定时器初始化timer0_init()函数初始化定时器0为模式1(16位定时器),启用定时器中断来产生音频信号。
  2. 按键扫描key_scan()函数用来检测按键是否被按下,若按键按下,则启动播放《生日快乐歌》。
  3. 音符播放play_tone()函数根据音符的频率和时长,生成脉冲信号,控制蜂鸣器发出相应的音符。
  4. 音符和时长数组melody[]数组存储《生日快乐歌》的音符,melody_duration[]数组存储每个音符的时长。
五、优化与扩展
  1. 多音符支持:可以扩展音符数组,增加更多的音符和歌曲。
  2. 使用LCD显示:通过LCD显示屏显示歌曲的进度或歌曲名。
  3. 音量调节:通过PWM信号控制蜂鸣器的音量,提供音量调节功能。
  4. 多段歌曲支持:将不同的歌曲分段存储,增加多种歌曲选择功能。
六、总结

通过本项目,我们学习了如何通过单片机控制蜂鸣器发出不同频率的声音,模拟乐曲的旋律。同时,这个项目也展示了如何用8051单片机处理定时器、按键输入和音符生成等基本功能。

相关推荐
Uitwaaien5418 分钟前
单片机数码管动态显示
单片机·嵌入式硬件
末时清3 小时前
电机驱动-标准库和HAL库
单片机·嵌入式硬件
电鱼智能的电小鱼4 小时前
基于SAIL-RK3576核心板的AI边缘计算网关设计方案——智慧家庭新突破
linux·人工智能·嵌入式硬件·边缘计算
嵌入式-老费5 小时前
基于海思soc的智能产品开发(高、中、低soc、以及和fpga的搭配)
嵌入式硬件
BuiderCodes7 小时前
STM32 中 GPIO 的八种工作模式介绍
stm32·单片机·嵌入式硬件
Ronin-Lotus8 小时前
嵌入式硬件篇---PWM&电机&舵机
c语言·stm32·单片机·嵌入式硬件·学习·51单片机·硬件工程
Tony小周19 小时前
HC32L136K8TA单片机输出互为反相双路PWM
单片机·嵌入式硬件
DarrenPig19 小时前
NEC纪实 :2024全国机器人大赛 Robocon 常州工学院团队首战国三
人工智能·嵌入式硬件·机器人·开源·开放原子·智能硬件·robocon
甜甜的大香瓜20 小时前
【CC2640R2F】香瓜CC2640R2F之SPI读写W25Q80
单片机
易板21 小时前
推荐单通道有刷直流电机驱动芯片AT8236
单片机·嵌入式硬件·h桥·直流电机驱动