wahahaheihei 发表于 2025-8-16 21:40

如何用单片机模拟和弦铃声

要用单片机模拟和弦铃声,核心是同时生成多个不同频率的方波信号(模拟乐器音色),并通过混合电路输出。



原理概述

和弦本质:多个音符(不同频率)同时发声。
单片机实现:用定时器中断生成多个频率的方波,混合后驱动扬声器。
硬件连接:IO口 → 电阻网络 → 扬声器/蜂鸣器。



步骤与代码
1. 硬件准备
元器件:单片机、电阻(1kΩ×3)、扬声器(或蜂鸣器)。
电路连接:
将3个IO口(如P1.0、P1.1、P1.2)各接一个1kΩ电阻。
电阻另一端并联后接扬声器正极,扬声器负极接地。
目的:混合三个方波信号,防止IO口短路。

2. 频率计算
假设生成一个 C大调和弦(C4 + E4 + G4):
C4 = 261.63 Hz
E4 = 329.63 Hz
G4 = 392.00 Hz
定时器中断周期 = 1 / (2 × 目标频率)(方波半周期翻转一次)。




wahahaheihei 发表于 2025-8-16 21:41

#include <reg52.h>

// 定义三个音符的定时器重载值(12MHz晶振)
#define C4_HALF_PERIOD(65536 - (12000000 / (261.63 * 12 * 2))) // C4
#define E4_HALF_PERIOD(65536 - (12000000 / (329.63 * 12 * 2))) // E4
#define G4_HALF_PERIOD(65536 - (12000000 / (392.00 * 12 * 2))) // G4

// 引脚定义
sbit PIN_C = P1^0;
sbit PIN_E = P1^1;
sbit PIN_G = P1^2;

// 计数器变量
volatile unsigned int cnt_C = 0, cnt_E = 0, cnt_G = 0;

// 初始化定时器0(16位模式)
void Timer0_Init() {
    TMOD |= 0x01;    // 模式1
    TH0 = 0xFF;      // 初始值(快速触发首次中断)
    TL0 = 0xFF;
    ET0 = 1;         // 使能中断
    EA = 1;          // 全局中断
    TR0 = 1;         // 启动定时器
}

// 定时器0中断服务函数
void Timer0_ISR() interrupt 1 {
    TH0 = 0xFF;   // 重载初始值(短周期)
    TL0 = 0xFF;

    // 生成C4方波
    cnt_C++;
    if (cnt_C >= C4_HALF_PERIOD) {
      cnt_C = 0;
      PIN_C = !PIN_C;// 翻转电平
    }

    // 生成E4方波
    cnt_E++;
    if (cnt_E >= E4_HALF_PERIOD) {
      cnt_E = 0;
      PIN_E = !PIN_E;
    }

    // 生成G4方波
    cnt_G++;
    if (cnt_G >= G4_HALF_PERIOD) {
      cnt_G = 0;
      PIN_G = !PIN_G;
    }
}

void main() {
    Timer0_Init();
    while (1);       // 主循环保持运行
}
const float chord_major = {261.63, 329.63, 392.00}; // C大调
const float chord_minor = {261.63, 311.13, 392.00}; // C小调
if (timer1_count >= 1000) { // 播放1秒后停止
    TR0 = 0;               // 关闭定时器0
    P1 = 0x00;             // 关闭所有引脚
}

热爱浪漫 发表于 2025-9-27 15:52

用单片机模拟和弦铃声,需利用 PWM 输出不同频率音频,通过定时器精准控制各频率占空比。将和弦分解为单音,按音符时序分配多个 PWM 通道,同步输出叠加,配合延时函数控制音长,结合查表法存储音符频率与节拍,实现多音叠加的和弦效果,需注意通道资源与频率精度匹配。
页: [1]
查看完整版本: 如何用单片机模拟和弦铃声