作为学习I2S通讯的第一个例子,使用STC的Ai8051U单片机,在生成三角波形例程的基础上进行改造,程序代码如下:
/************* 功能说明 **************
本例程基于AI8051U为主控芯片的实验箱进行编写测试.
使用Keil C251编译器,Memory Model推荐设置XSmall模式,默认定义变量在edata,单时钟存取访问速度快。
edata建议保留1K给堆栈使用,空间不够时可将大数组、不常用变量加xdata关键字定义到xdata空间。
测试工作频率为 45.1584MHz
******************************************/
#include "../../comm/AI8051U.h"
#include "stdio.h"
#include "intrins.h"
typedef unsigned charu8;
typedef unsigned intu16;
typedef unsigned longu32;
#define FOSC 45158400UL // 定义主时钟
#define SampleRate 44100 // 定义采样率
#define MCKOE 1 // I2S 主时钟输出控制 , 0:禁止 I2S 主时钟输出, 1:允许 I2S 主时钟输出
#define I2SEN 0x04 // I2S 模块使能 0x00:禁止, 0x04:允许
//0:从机发送模式
//1:从机接收模式
//2:主机发送模式
//3:主机接收模式,
#define I2S_MODE 2 // I2S 模式
//0:短帧同步
//1:长帧同步
#define PCMSYNC 0 //PCM 帧同步
//0: I2S 飞利浦标准
//1: MSB 左对齐标准
//2:LSB 右对齐标准
//3:PCM 标准
#define STD_MODE 1 //I2S 标准选择
//0:时钟稳定状态为低电平
//1:时钟稳定状态为高电平
#define CKPOL 0 //I2S 稳态时钟极性
//0:16 位
//1:24 位
//2:32 位
//3:保留
#define DATLEN 0 //数据长度
//0:16 位
//1: 32 位
#define CHLEN 0 //通道长度(每个音频通道的位数)
#if (MCKOE == 1) //允许主时钟输出
#define I2SDIV FOSC/(16*2*8*SampleRate) //对于双声道允许主时钟输出 16bit 256fs
//则 2*DIV + ODD = I2S 时钟 / 256fs
//必要需要 DIV >= 2, 即分频系数 >=4.
#endif
#if (MCKOE == 0) //禁止主时钟输出
#define I2SDIV FOSC/(16*2*SampleRate) //对于双声道禁止主时钟输出 16bit
//则 2*DIV + ODD = I2S 时钟 / 32fs
//必要需要 DIV >= 2, 即分频系数 >=4.
#endif
u8 dac_index; //输出计数索引
// 延时处理,LED闪烁用
void delay_ms(u16 ms) {
u16 i;
do {
i = FOSC / 6000;
while(--i);
}while(--ms);
}
void main(void) {
EAXFR = 1; //允许访问扩展的特殊寄存器,XFR
//(32 位模式请使用这句,注释下一句)
// P_SW2 |= 0x80; //允许访问扩展的特殊寄存器,XFR
//(8 位模式请使用这句,注释上一句)
WTST = 0; // 设置取程序代码等待时间, 赋值为 0 表示不等待,程序以最快速度运行
CKCON = 0; // 设置访问片内的 xdata 速度,赋值为 0 表示用最快速度访问,不增加额外的等待时间
// 配置端口模式,全都设置为准双向口模式
P0M0 = 0x00; P0M1 = 0x00;
P1M0 = 0x00; P1M1 = 0x00;
P2M0 = 0x00; P2M1 = 0x00;
P3M0 = 0x00; P3M1 = 0x00;
P4M0 = 0x00; P4M1 = 0x00;
P5M0 = 0x00; P5M1 = 0x00;
I2SMD = 0xff; //内部保留字节,需设置为 FFH
I2SCR = 0x80; //使能发送缓冲区空中断(0x80)
// 设置 I2S 主时钟输出(I2SMCK), 设置 ODD
I2SPRH = (MCKOE << 1) + (I2SDIV & 1);
I2SPRL = I2SDIV/2; //设置 I2S 时钟分频
I2SCFGH = I2S_MODE; //设置 I2S 模式为主机发送模式
I2SCFGL = (PCMSYNC << 7) + (STD_MODE << 4) + (CKPOL << 3) + (DATLEN << 1) + CHLEN;
//0: P3.2(BCLK) P3.4(SD) P5.4(MCLK) P3.5(WS)
P_SW3 = (P_SW3 & 0x3f) | (0<<6); //I2S 端口切换
I2SCFGH |= I2SEN; // 使能 I2S 模块
// 开中断
EA = 1;
dac_index = 0;
while (1) {
// 闪烁P00所在LED,仅仅是为了证明程序已经工作
P00 = 0;//LED On
delay_ms(500);
P00 = 1;//LED Off
delay_ms(500);
}
}
// I2S发送完成中断
void I2S_ISR(void) interrupt 62 {
u8 i;
// 发送缓冲区空
if (I2SSR & 0x02) {
// 哪个通道的发送通道的数据为空
if (I2SSR & 0x04) {
// 右声道发送完成,准备左通道的
i = dac_index;
I2SDRL = i; //发送下一帧音频数据
I2SDRH = 0;
} else {
// 左声道发送完成,准备右通道的
i = dac_index;
I2SDRL = i^255; //发送下一帧音频数据
I2SDRH = 0;
dac_index++;
}
}
}代码说明:
1、设置I2SCR

I2SCR = 0x80; //使能发送缓冲区空中断(0x80)
TXEIE : B7 = 1,表示当发送缓冲区数据被发送完成后,会产生中断。在本例中,I2S外设是被当做主设备使用的,向外发送数据。
2、设置I2SPRH 和 I2SPRL

#define FOSC 45158400UL // 定义主时钟 #define SampleRate 44100 // 定义采样率44.1KHz #define MCKOE 1 // I2S 主时钟输出控制 , 0:禁止 I2S 主时钟输出, 1:允许 I2S 主时钟输出 #if (MCKOE == 1) //允许主时钟输出 #define I2SDIV FOSC/(16*2*8*SampleRate) //对于双声道允许主时钟输出 16bit 256fs //则 2*DIV + ODD = I2S 时钟 / 256fs , 需要 DIV >= 2, 即分频系数 >=4. // 根据计算 I2SDIV=45158400/(16*2*8*44100)=4 #endif // 设置 I2S 主时钟输出(I2SMCK), 设置 ODD=0,MCKOE=1 I2SPRH = (MCKOE << 1) + (I2SDIV & 1); // =2 I2SPRL = I2SDIV/2; // 设置 I2S 时钟分频 =2 当 I2S 主时钟输出使能时(MCKOE 设置为 1)、当信道帧宽度为 16 位时,音频采样频率 FS=I2S 时钟÷[(16×2)×(2×DIV+ODD)×8)]
3、设置I2SCFGH 和 I2SCFGL

#define I2SEN 0x04 // I2S 模块使能 0x00:禁止, 0x04:允许 //0:从机发送模式 //1:从机接收模式 //2:主机发送模式 //3:主机接收模式, #define I2S_MODE 2 // I2S 模式 //0:短帧同步 //1:长帧同步 #define PCMSYNC 0 //PCM 帧同步 //0: I2S 飞利浦标准 //1: MSB 左对齐标准 //2:LSB 右对齐标准 //3:PCM 标准 #define STD_MODE 1 // I2S 标准选择 //0:时钟稳定状态为低电平 //1:时钟稳定状态为高电平 #define CKPOL 0 //I2S 稳态时钟极性 //0:16 位 //1:24 位 //2:32 位 //3:保留 #define DATLEN 0 //数据长度 //0:16 位 //1: 32 位 #define CHLEN 0 //通道长度(每个音频通道的位数) I2SCFGH = I2S_MODE; //设置 I2S 模式为主机发送模式 I2SCFGL = (PCMSYNC << 7) + (STD_MODE << 4) + (CKPOL << 3) + (DATLEN << 1) + CHLEN; // //0: P3.2(BCLK) P3.4(SD) P5.4(MCLK) P3.5(WS) P_SW3 = (P_SW3 & 0x3f) | (0<<6); //I2S 端口切换 I2SCFGH |= I2SEN; // 使能 I2S 模块
4、数据发送过程中,通道的判断处理

TXE :发送完成标志
CHSID : 0:左通道正在发送或接收数据;1:右通道正在发送或接收数据
程序中为了明显区别左右声道数据的不同,特意做了取反处理,运行起来后用逻辑分析仪测量到的波形:



从波形上看,左声道数据在前,右声道数据在后,数据为16位长度,高位在前,低位在后。

与左对齐模式 Left Justified Standard是一致的。
标准左对齐格式的数据的MSB没有相对于BCLK延迟一个时钟。左对齐格式的左右声道数据的MSB在LRCK边沿变化后BCLK的第一个上升沿有效。左对齐格式的优点在于,由于在LRCK变化后的第一个SCK上升沿就开始采样,它不需要关心左右声道数据的字长。

BLCK的时钟频率:

从波形上看,为5.56MHz的样子,根据公式《SCLK的频率=2×采样频率×采样位数》的计算结果看,出入比较大啊。
工程文件:
我要赚赏金
