用【STCAI-万能实验板】做实验 用I2S音频播放方式实现八音盒
最新成果,读纸带的电子八音盒。再也不怕弹错键了{:4_174:}--------------------------------------------
一直想做一个可以自定义音色,并且可以发出和弦声音的简易电子琴,看到STC32G144K246特别加大了程序存储空间,
正好赶上论坛鼓励大家学习新的芯片,组织了使用万能实验板做实验的活动,我用论坛签到积分兑换了三块实验板,申请了2个芯片,开始行动。
官方更新了脚位图,大家注意一下。
为了方便试验,我做了简易的标签贴纸,放在附件了,需要的朋友可以自行打印
用纸带谱曲实现了八音盒模式,再也不拍弹错键了
今天完成了单一的音乐播放,烧录完即可循环播放,借鉴了之前AI8051上例程,但是有一点不一样的地方就是STC32G144K246必须使用PLL时钟,我是个菜鸟,弄明白这些花费了一点时间。但终于出声音了。
文件见附件,程序如下:
//=================== 头文件包含 ============================================
#include "STC32G144K246.H"
#include "intrins.h"
#include "yinyue.h"
//=================== 主时钟和采样率定义宏 =================================
#define FOSC 56000000UL // 系统主时钟 96MHz (由PLL产生)
#define PLL_CLK 480000000UL// PLL输出时钟 480MHz
#define SampleRate 8000 // 定义采样率
//=================== I2S配置 ============================================
#define MCKOE 0 // I2S主时钟输出使能, 0:禁止I2S主时钟输出, 1:允许I2S主时钟输出
#define I2SEN 0x04 // I2S使能位, 0x00:关闭, 0x04:使能
#define I2S_MODE 2 // I2S模式, 0:从发送, 1:从接收, 2:主发送, 3:主接收,
#define PCMSYNC 0// PCM同步模式, 0: 长同步, 1: 短同步
#define STD_MODE 0 // I2S标准模式, 0: I2S标准格式, 1: MSB对齐格式, 2:LSB对齐格式, 3:PCM模式, CS4334或CS4344选择0:I2S标准格式,PT8211选择1: MSB对齐格式
#define CKPOL 0 // I2S时钟极性, 0:SCLK空闲时为低电平, 1:SCLK空闲时为高电平
#define DATLEN 0 // 数据长度, 0:16位, 1:24位, 2:32位, 3:保留
#define CHLEN 0 // 声道长度(在PCM模式下), 0:16位, 1: 32位
// 分频系数计算
#define I2S_MCLKDIV (FOSC / (8 * 16 * 2 * SampleRate))// MCLK分频系数
#define I2S_BCLKDIV (FOSC / (16 * 2 * SampleRate)) // BCLK分频系数
//=================== 类型定义 ============================================
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
typedef signed int s16;
// 扩展音频索引变量
u32 yinyue_index;
// 扩展音频播放状态
bit yinyue;
u16 buffer;
bit flip;
bit flip_local;
//=================== 延时函数 ==============================================
void delay_ms(u16 ms)
{
u16 i;
while(ms--)
{
i = 4000;
while(i--);
}
}
//=================== PLL时钟初始化 ==========================================
void pll_init(void)
{
// STC32G的PLL初始化
HPLLCR = 0x10; // 选择HIRC作为PLL输入
HPLLPDIV = 8; // 预分频8, HIRC 48MHz/8 = 6MHz
HPLLCR |= 0x0e; // 倍频80, 6MHz*80 = 480MHz
HPLLCR |= 0x80; // 使能HPLL
delay_ms(10); // 等待PLL稳定
CLKDIV = 5; // 系统时钟分频: 480MHz/5 = 96MHz
CLKSEL = 0x04; // 选择HPLL/2作为主时钟源
delay_ms(10); // 等待时钟切换完成
}
//=================== 系统初始化 ============================================
void system_init(void)
{
WTST = 0x00;
CKCON = 0x00;
EAXFR = 1;
// 初始化IO口
P0M0 = 0x00;
P0M1 = 0x00;
P1M0 = 0x00;
P1M1 = 0x00;
P2M0 = 0x00;
P2M1 = 0x00;
P2PU = 0xff;
P3M0 = 0x00;
P3M1 = 0x00;
P3PU = 0xff;
P4M0 = 0x00;
P4M1 = 0x00;
P5M0 = 0x00;
P5M1 = 0x00;
}
//=================== I2S初始化 ============================================
void i2s_init(void)
{
I2SMD = 0xff; // 模块使能寄存器,初始化为FFH
I2SSR = 0x00; // 状态寄存器清零
I2SCR = 0x80 + 0x00; // 使能I2S模块(0x80), +0x00:Motorola格式, +0x10:TI格式
HSCLKDIV = 1; // 高速时钟分频 1~255 (默认为2)
I2S_CLKDIV = 1; // I2S时钟分频
I2SMCKDIV = I2S_MCLKDIV; // I2S主时钟分频,I2SMCLK = 系统时钟/2/I2S_CLKDIV/HSCLKDIV/I2SMCKDIV, 或I2SMCLK = PLLCLK/2/I2S_CLKDIV/HSCLKDIV/I2SMCKDIV
I2SPRH = (MCKOE << 1) + (I2S_BCLKDIV & 1);// 高字节:bit1控制I2S_BMCLK输出使能, bit0为BCLK分频系数的bit0, 同时控制是否输出MCLK
I2SPRL = I2S_BCLKDIV / 2; // 低字节:BCLK分频系数的bit8~bit1
I2SCFGH = I2S_MODE; // 配置I2S工作模式
I2SCFGL = (PCMSYNC << 7) + (STD_MODE << 4) + (CKPOL << 3) + (DATLEN << 1) + CHLEN;
P_SW3 = (P_SW3 & 0x3f) | (2 << 6); // I2S引脚切换,
// 00: P3.2(BCLK) P3.3(MCLK) P3.4(SD) P3.5(LRCK),
// 01: P1.7(BCLK) P1.6(MCLK) P1.5(SD) P1.4(LRCK),
// 10: P2.3(BCLK) P2.2(MCLK) P2.1(SD) P2.0(LRCK),
// 11: P4.3(BCLK) P1.6(MCLK) P4.1(SD) P4.0(LRCK)
}
//=================== 音频初始化 ==============================================
void audio_init(void)
{
yinyue_index = 0;
buffer = 128;
buffer = 128;
flip = 0;
flip_local = 0;
}
//=================== I2S中断服务程序 ================================
void I2S_ISR(void) interrupt 62
{
if (I2SSR & 0x02)// 发送缓冲区空
{
s16 audio_data;
// 正确的8位转16位转换
// 减去128去除直流偏置,左移7位得到16位有符号值
audio_data = ((s16)buffer - 128) << 7;
// 音量调节选项(取消注释其中一个):
// audio_data = ((s16)buffer - 128) << 6;// 最小音量
// audio_data = ((s16)buffer - 128) << 7;// 中等音量
// audio_data = ((s16)buffer - 128) << 8;// 最大音量
// 发送16位数据
I2SDRH = (u8)(audio_data >> 8); // 高8位
I2SDRL = (u8)audio_data; // 低8位
// 左声道切换缓冲区
if (!(I2SSR & 0x04))
{
flip = !flip;
}
}
}
//=================== 主函数 ==============================================
void main(void)
{
system_init(); // 系统初始化
pll_init(); // PLL时钟初始化
i2s_init(); // I2S初始化
audio_init(); // 音频初始化
I2SCFGH |= I2SEN;// 使能I2S
EA = 1; // 使能全局中断
while (1)
{
if (flip_local != flip)
{
buffer = yinyue_pcm;
yinyue_index++;
if (yinyue_index >= yinyue_pcm_len)
{
yinyue_index = 0;
}
flip_local = flip;
}
_nop_();
}
}
attach://132743.mp4
后续重新用新版本万能实验板做了,能正常播放了。下一步添加7个按键实现7个音节。
灰太狼8888 发表于 2026-3-1 23:51
今天完成了单一的音乐播放,烧录完即可循环播放,借鉴了之前AI8051上例程,但是有一点不一样的地方就是STC3 ...
5V电源有无稳压滤波 狂热主宰 发表于 2026-3-2 14:56
5V电源有无稳压滤波
我回来加个滤波电容试一下
已更新设计
今天用之前AI8051U的程序修改的可以播放四个音的程序,需要注意的是这两个单片机I2S接口引脚不同,还有就是STC32G144K246必须使用PLL时钟才可以。
//=================== 头文件包含 ============================================
#include "STC32G144K246.H"
#include "intrins.h"
#include "yinxiao1.h"
#include "yinxiao2.h"
#include "yinxiao3.h"
#include "yinxiao4.h"
//=================== 主时钟和采样率定义宏 =================================
#define FOSC 96000000UL // 系统主时钟 96MHz (由PLL产生)
#define PLL_CLK 480000000UL// PLL输出时钟 480MHz
#define SampleRate 16000 // 定义采样率
//=================== I2S配置 ============================================
#define MCKOE 0 // I2S主时钟输出使能, 0:禁止I2S主时钟输出, 1:允许I2S主时钟输出
#define I2SEN 0x04 // I2S使能位, 0x00:关闭, 0x04:使能
#define I2S_MODE 2 // I2S模式, 0:从发送, 1:从接收, 2:主发送, 3:主接收,
#define PCMSYNC 0// PCM同步模式, 0: 长同步, 1: 短同步
#define STD_MODE 0 // I2S标准模式, 0: I2S标准格式, 1: MSB对齐格式, 2:LSB对齐格式, 3:PCM模式, CS4334或CS4344选择0:I2S标准格式,PT8211选择1: MSB对齐格式
#define CKPOL 0 // I2S时钟极性, 0:SCLK空闲时为低电平, 1:SCLK空闲时为高电平
#define DATLEN 0 // 数据长度, 0:16位, 1:24位, 2:32位, 3:保留
#define CHLEN 0 // 声道长度(在PCM模式下), 0:16位, 1: 32位
//#define I2S_MCLKDIV (FOSC / (8 * 16 * 2 * SampleRate)) // MCLK分频系数, 支持16bit.
//#define I2S_BCLKDIV (FOSC / (16 * 2 * SampleRate)) // BCLK分频系数, 支持16bit.
///2#define I2S_MCLKDIV (FOSC / (8 * 16 * 2 * SampleRate)) // MCLK分频系数, 支持16bit.
///2#define I2S_BCLKDIV (FOSC / (16 * SampleRate)) // BCLK分频系数, 支持16bit.
// 分频系数计算
#define I2S_MCLKDIV (FOSC / (8 * 16 * 2 * SampleRate))// MCLK分频系数
#define I2S_BCLKDIV (FOSC / (16 * 2 * SampleRate)) // BCLK分频系数
//=================== 类型定义 ============================================
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
u16 yinxiao1_index;
u16 yinxiao2_index;
u16 yinxiao3_index;
u16 yinxiao4_index;
bit yinxiao1;
bit yinxiao2;
bit yinxiao3;
bit yinxiao4;
// 时间戳变量 - 用于记录音频开始播放的时间,实现"挤掉最先播放的"逻辑
u16 start_time1;
u16 start_time2;
u16 start_time3;
u16 start_time4;
u16 current_time;// 当前时间计数器
// 按键状态变量 - 用于检测按键按下事件
bit key1_pressed;
bit key2_pressed;
bit key3_pressed;
bit key4_pressed;
u16 buffer;
bit flip;
bit flip_local;
//=================== 延时函数 ==============================================
void delay_ms(u16 ms)
{
u16 i;
while(ms--)
{
i = 4000;
while(i--);
}
}
//=================== PLL时钟初始化 ==========================================
void pll_init(void)
{
// STC32G的PLL初始化
HPLLCR = 0x10; // 选择HIRC作为PLL输入
HPLLPDIV = 8; // 预分频8, HIRC 48MHz/8 = 6MHz
HPLLCR |= 0x0e; // 倍频80, 6MHz*80 = 480MHz
HPLLCR |= 0x80; // 使能HPLL
delay_ms(10); // 等待PLL稳定
CLKDIV = 5; // 系统时钟分频: 480MHz/5 = 96MHz
CLKSEL = 0x04; // 选择HPLL/2作为主时钟源
delay_ms(10); // 等待时钟切换完成
}
//=================== 主函数 ==============================================
void main(void)
{
// 初始化系统
WTST = 0x00;
CKCON = 0x00;
EAXFR = 1;
// 初始化PLL时钟
pll_init();
// 初始化IO口
P0M0 = 0x00;
P0M1 = 0x00;
P1M0 = 0x00;
P1M1 = 0x00;
P2M0 = 0x00;
P2M1 = 0x00;
P2PU = 0xff;
P3M0 = 0x00;
P3M1 = 0x00;
P3PU = 0xff;
P4M0 = 0x00;
P4M1 = 0x00;
P5M0 = 0x00;
P5M1 = 0x00;
I2SMD = 0xff; // 模块使能寄存器,初始化为FFH
I2SSR = 0x00; // 状态寄存器清零
I2SCR = 0x80 + 0x00; // 使能I2S模块(0x80), +0x00:Motorola格式, +0x10:TI格式
HSCLKDIV = 1; // 高速时钟分频 1~255 (默认为2)
I2S_CLKDIV = 1; // I2S时钟分频
I2SMCKDIV = I2S_MCLKDIV; // I2S主时钟分频,I2SMCLK = 系统时钟/2/I2S_CLKDIV/HSCLKDIV/I2SMCKDIV, 或I2SMCLK = PLLCLK/2/I2S_CLKDIV/HSCLKDIV/I2SMCKDIV
I2SPRH = (MCKOE << 1) + (I2S_BCLKDIV & 1); // 高字节:bit1控制I2S_BMCLK输出使能, bit0为BCLK分频系数的bit0, 同时控制是否输出MCLK
I2SPRL = I2S_BCLKDIV / 2; // 低字节:BCLK分频系数的bit8~bit1
I2SCFGH = I2S_MODE; // 配置I2S工作模式
I2SCFGL = (PCMSYNC << 7) + (STD_MODE << 4) + (CKPOL << 3) + (DATLEN << 1) + CHLEN;
P_SW3 = (P_SW3 & 0x3f) | (2 << 6); // I2S引脚切换,
音效文件在头文件里,
我用AI写了个将MP3转化为头文件的网页版转换程序,可以方便的进行转换
666,i3s和i2c有啥区别?对于本单片机来说? guojun0718 发表于 2026-3-8 14:40
666,i3s和i2c有啥区别?对于本单片机来说?
简单来说,I2C是设备间用于传输数据的“控制总线”,I2S是传输数字音频的“数据总线”。 灰太狼8888 发表于 2026-3-8 19:42
简单来说,I2C是设备间用于传输数据的“控制总线”,I2S是传输数字音频的“数据总线”。 ...
收到,谢谢。 感谢版主{:4_196:},寄来了新版本的万能板。焊接好基础元件,开始继续研究。
页:
[1]
2