[PIC®/AVR®/dsPIC®产品] 如何用单片机模拟和弦铃声

[复制链接]
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 | 显示全部楼层
  1. #include <reg52.h>

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

  6. // 引脚定义
  7. sbit PIN_C = P1^0;
  8. sbit PIN_E = P1^1;
  9. sbit PIN_G = P1^2;

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

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

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

  25.     // 生成C4方波
  26.     cnt_C++;
  27.     if (cnt_C >= C4_HALF_PERIOD) {
  28.         cnt_C = 0;
  29.         PIN_C = !PIN_C;  // 翻转电平
  30.     }

  31.     // 生成E4方波
  32.     cnt_E++;
  33.     if (cnt_E >= E4_HALF_PERIOD) {
  34.         cnt_E = 0;
  35.         PIN_E = !PIN_E;
  36.     }

  37.     // 生成G4方波
  38.     cnt_G++;
  39.     if (cnt_G >= G4_HALF_PERIOD) {
  40.         cnt_G = 0;
  41.         PIN_G = !PIN_G;
  42.     }
  43. }

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


您需要登录后才可以回帖 登录 | 注册

本版积分规则

231

主题

3196

帖子

12

粉丝
快速回复 在线客服 返回列表 返回顶部