我今天收拾东西找到了几个IIS的传感器,看了下都是音频的器件。以前使用是ESP32 自带的IIS,因为时间的原因没有研究很多,这篇文章做下简单的总结。
I²S(Inter-IC Sound或Integrated Interchip Sound)是飞利浦公司制定的一种数字音频标准,于1986年发布,最近的一次修改是1996年。该总线适用于音频设备之间的数据传输,现已广泛应用于各种多媒体系统。它的时钟信号与音频数据流分离,与需要时钟恢复的系统相比,抖动比较低,为用户节省了购买抵抗音频抖动的专业设备的费用。
I²S总线规范
I²S至少有三条信号线:
SCK: (continuous serial clock) 串行时钟, 对应数字音频的每一位数据,SCK都有1个脉冲。SCK的频率=2×采样频率×采样位数。
WS: (word select) 字段(声道)选择,用于切换左右声道的数据。WS的频率等于采样频率。声道选择线表明了正在被传输的声道。
WS为“1”表示正在传输的是左声道的数据。
WS为“0”表示正在传输的是右声道的数据。
WS可以在串行时钟的上升沿或者下降沿发生改变,并且WS信号不需要一定是对称的。在从属设备端,WS在时钟信号的上升沿发生改变。
WS总是在最高位传输前的一个时钟周期发生改变,这样可以使从属设备得到与被传输的串行数据同步的时间,并且使接收端存储当前的命令以及为下次的命令清除空间。
SD: (serial data) 串行数据,用二进制补码表示的音频数据。I²S格式的信号无论有多少位有效数据,数据的最高位总是被最先传输(在WS变化(也就是一帧开始)后的第2个SCK脉冲处),因此最高位拥有固定的位置,而最低位的位置则是依赖于数据的有效位数。
这就使得接收端与发送端的有效位数可以不同。如果接收端能处理的有效位数少于发送端,可以放弃数据帧中多余的低位数据;如果接收端能处理的有效位数多于发送端,可以自行补足剩余的位(常补足为零)。
这种同步机制使得数字音频设备的互连更加方便,而且不会造成数据错位。为了保证数字音频信号的正确传输,发送端和接收端应该采用相同的数据格式和长度。当然,对I²S格式来说数据长度可以不同。
对于系统而言,产生SCK和WS的信号端就是主设备,用MASTER表示,简单系统示意图如下图所示:
系统示意图
此标准是Philips (后来为NXP,现在位Qualcomm)于1986年推出的,最后一个版本修订于1996年.现在是22年,大概就是26年了。
其实很简单,就是一个协议而已.现在好像是可以控制灯光了。
下面是参考文末的文章,使用ESP32 Cam实现:
代码语言:javascript复制from machine import I2S
from machine import Pin
import time
# 初始化引脚定义
sck_pin = Pin(14) # 串行时钟输出
ws_pin = Pin(13) # 字时钟
sd_pin = Pin(12) # 串行数据输出
# 初始化i2s
audio_out = I2S(1,sck=sck_pin,
ws=ws_pin,
sd=sd_pin,
mode=I2S.TX,
bits=16,
format=I2S.MONO,
rate=16000,
ibuf=20000)
使用microPython就是这样
代码语言:javascript复制sck 是串行时钟线的引脚对象
ws 是单词选择行的引脚对象
sd 是串行数据线的引脚对象
mode 指定接收或发送
bits 指定样本大小(位),16 或 32
format 指定通道格式,STEREO(左右声道) 或 MONO(单声道)
rate 指定音频采样率(样本/秒)
ibuf 指定内部缓冲区长度(字节)
这些是参数的意思
代码语言:javascript复制from machine import I2S
from machine import Pin
import time
# 初始化引脚定义
sck_pin = Pin(14) # 串行时钟输出
ws_pin = Pin(13) # 字时钟
sd_pin = Pin(12) # 串行数据输出
# 初始化i2s
audio_out = I2S(1, sck=sck_pin,
ws=ws_pin,
sd=sd_pin,
mode=I2S.TX,
bits=16,
format=I2S.MONO,
rate=16000,
ibuf=20000)
wavtempfile = "temp.wav"
wav = open(wavtempfile, 'rb')
# 前进到WAV文件中数据段的第一个字节
pos = wav.seek(44)
# 分配样本数组
# 用于减少while循环中堆分配的内存视图
wav_samples = bytearray(1024)
wav_samples_mv = memoryview(wav_samples)
print('播放音频')
# 下面的0.016得来的方法:16000(采样率) x 8(采样位宽,我用的是8位音频,单位bit) x1(通道数,单声道1,立体声n) ÷ 8(1字节=8bit) ÷ 1000000(秒换算成微秒)
# 上方的参数我都是使用的固定参数,我通过音频软件得出的,最好是从wav文件头中得出所有参数,就比较准确
# 音频总时长 us(微秒)
all_time = (len(wav)-44) / 0.016
# 从WAV文件中连续读取音频样本
# 并将其写入I2S DAC
while True:
try:
num_read = wav.readinto(wav_samples_mv)
num_written = 0
# WAV文件结束
if num_read == 0:
break
# 前进到数据段的第一个字节
# pos = wav.seek(44)
# 在首次执行的时候记录开始时间
if num_written == 0:
# 记录播放开始时间
start_time = time.ticks_us()
# 循环,直到所有样本都写入I2S外围设备
while num_written < num_read:
num_written = audio_out.write(
wav_samples_mv[num_written:num_read])
except Exception as e:
print('错误,', e)
break
从SD卡中读取音频播放,之后注销:
代码语言:javascript复制# 等待音频播放完毕
while 1:
# 播放结束时间
end_time = time.ticks_us()
# 如果当前时间减去开始播放的时间大于音频时长
if (end_time - start_time) > all_time:
# 取消初始化 I2S 总线
audio_out.deinit()
# 停止等待
break
# 播放完毕
# 关闭文件
wav.close()
以上的的代码有毛病,ESP32 Cam的IO少,SD和IIS器件公用了引脚,所以效果不好。
代码语言:javascript复制import machine
print('挂载sd卡...')
try:
os.mount(machine.SDCard(), "/sd")
print('挂载成功,路径为:"/sd"')
# 卸载
# os.umount("/sd")
except Exception as e:
print(e)
# I2S
from machine import I2S
sck_pin = Pin(14)
ws_pin = Pin(13)
sd_pin = Pin(12)
audio_out = I2S(
1,
sck=sck_pin,
ws=ws_pin,
sd=sd_pin,
mode=I2S.TX,
bits=16,
format=I2S.MONO,
rate=16000,
ibuf=20000
那就可以设计成这样:
挂载SD卡->读取音频文件到内存->注销挂载SD卡->实例化I2S->播放音频->注销I2S->挂载SD卡。
代码语言:javascript复制import io
import urequests
# 音频文件
wavname = 'test.wav'
# 请求音频文件
wavbuf = urequests.get('http://www.xxx.com/music/%s' % wavname).content
# 数据存到内存
wav = io.BytesIO(wavbuf)
# 以打开文件的方式读取内存数据
buf = wav.read()
不过更好的方式,应该是使用网络实时的传输了。
代码语言:javascript复制https://blog.csdn.net/qq_33130395/article/details/120117741?ops_request_misc=%7B%22request%5Fid%22%3A%22164923611516780366517961%22%2C%22scm%22%3A%2220140713.130102334.pc%5Fall.%22%7D&request_id=164923611516780366517961&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-6-120117741.142^v5^pc_search_result_control_group,157^v4^control&utm_term=ESP32 IIS&spm=1018.2226.3001.418
代码语言:javascript复制https://www.stepfpga.com/doc/i2s