ESP32 I2S音频总线学习笔记(一):初识I2S通信与配置基础
文章目录
- 简介
- 为什么需要I2S?
- 关于音频信号
- 采样率
- 分辨率
- 音频声道
- 怎样使用I2S传输音频?
- 位时钟BCLK
- 字时钟WS
- 串行数据SD
- I2S传输模型
- I2S通信格式
- I2S格式
- 左对齐格式
- 右对齐格式
- i2s基本配置
- i2s 底层API
- 加载I2S驱动
- 设置I2S使用的引脚
- I2S读取数据
- I2S发送数据
- 卸载I2S驱动
- 总结
简介
在音频处理领域,I2S是一种广泛使用的通信协议,它专门用于芯片之间的音频数据传输。ESP32 作为一款高性能的微控制器,不仅支持 I2S 通信,还提供了强大的硬件接口和灵活的软件库,使其成为音频项目开发的理想选择。本篇文章将介绍I2S的相关知识和使用ESP32驱动I2S音频设备时比较常用的相关底层API函数。
I2S即Inter-IC Sound, 简称I2S,意思是芯片间音频总线,它是由飞利浦开发的一种用于数字音频设备的通信协议,常用于麦克风、扬声器、音频处理器等设备之间的音频数据传输。
为什么需要I2S?
传统的音频设备,像模拟电路,传递的是电压信号,这种方式容易受到干扰,比如噪声或者信号衰减。而数字音频需要传输数据,通常是二进制的“0”和“1”,直接用模拟接口传输会很麻烦。而 I2S就是为了解决这个问题的一种数字音频接口,它让音频数据的传输变得简单、高效、而且抗干扰能力强。 使用 I2S可以很方便地把数字音频信号从一个芯片传递到另一个芯片,对于开发者来讲只需要配置好芯片的 I2S 模块,就可以实现数字音频数据的传输了。
关于音频信号
在自然界中音频信号是以模拟量的形式存在的,它是一种随时间连续变化的物理量,为了减少外界的干扰我们需要把它变成数字量,我们一般可以通过一个模数转换器把它变成数字信号(图1),数字信号在计算机或数字设备中以离散的数值形式表示和处理,比如用0和1的组合去表示,这里可以了解下PCM编码,它是一种模拟信号数字化的方法
(图1)
当然我们也能通过一个数模转换器把数字信号还原成模拟信号,以便在扬声器上播放音频(图2)。
(图2)
这样音频信号之间的传递就可以通过数字信号来进行了(图3),可以减少外界对信号的干扰。
(图3)
在音频信号处理和传输中,有三个非常重要的参数决定了音频质量和设备性能:采样率、分辨率和 音频声道。
采样率
采样率就是每秒采集声音样本的频率,这个频率越快,采样的数字信号就越接近原始的声音的信号,因为采样的越快,离散数字曲线每个样本值之间的过渡就越接近,曲线就会越平滑。这个过程和录像是类似的,一个是采样光,一个采样振动。我们知道录像其实就是一帧一帧的图像快速播放,这个采样速度很快,我们肉眼分辨不了,看起来就是连续的。如果录像时采样的速度很慢,比如1秒采样3次,那我们就会丢失掉很多画面细节。采集声音的时候也是如此,大家可以想象一下,如果采集频率很慢,听到的声音会是什么样子,会明显感到声音听起来失真不连贯甚至变样。
每秒钟采集的音频样本数,常见的有8K、16K、44.1K等,采样率越高,信号还原越精细,一般使用44.1KHz采样频率就可以得到比较高保真的声音。
分辨率
对声音数据采样后,我们将得到一些离散的样本点,那我们在一些数字设备是如何存储这些样本点的呢?我们采样的数据是以二进制的形式存储的,比如对于每一个采样点我们用3位二进制来表示(图4),那么它可以表示的范围就是2^3=8 即8种量化电平信号(图5),可以简单理解为:每个采样点可以存储 8种情况的声音。如果量化位数越多,根据我们高中学过的排列组合知道,得到的样本值就会越多,那它可以表示自然界声音的细节就越多,或者说能表示的声音就越丰富。
音频数据的量化位数或量化深度,常见的有8bit、16bit、24bit、32bit等,位数越高,信号的动态范围和精细程度越好
(图4)
(图5)
音频声道
分为单声道,双声道,单声道是一种只有一个音频信号通道,所有声音都合并到一个通道中输出,无论是通过一个扬声器还是两个扬声器,听到的声音是完全相同的。双声道分为左声道和右声道,具有两个独立音频通道,左声道和右声道可以传递不同的声音信号,具有空间感和方向感,也就是我们平常说的立体声。
怎样使用I2S传输音频?
使用I2S传输音频的时候,需要用到时钟信号、控制信号以及数据信号(图6),它们之间是分开传输的。对于标准通信模式下的 I2S 总线主要包含以下几个信号:位时钟BCLK,字时钟WS,串行数据SD。有的时候还需要MCLK:主时钟线,该信号线可选,具体取决于从机,主要用于向 I2S 从机提供参考时钟。
(注意这几种信号有几种其它叫法,这里结合英文选择了这几个名称,大家只要在使用能区分就行)~
图(6)
位时钟BCLK
BCLK(Bit Clock,位时钟)
也叫BCK, SCLK(Serial Clock),对应数字音频的每一位数据,是模块内的同步信号BCLK 定义了数据传输的速率,用来控制数据的传输节奏。它的频率通常是采样率乘以每个采样的位数再乘以声道数量。例如,对于 44.1kHz 的采样率、16 位双声道音频,BCLK 的频率为 44.1kHz × 16 × 2= 1.4112 MHz。所以对于双声道来说,BCLK的频率=2×采样频率×采样位数。
字时钟WS
WS(Word Select , 字选择时钟)
也叫 LRCLK (Left Right Clock)即左右声道时钟, 用于标识当前正在传输的是左声道数据还是右声道数据。对于飞利浦公司定义的I2S标准,当 WS 为低电平时表示左声道,高电平时表示右声道。一个完整的 WS 信号周期包含两个声道的数据(左声道和右声道)WS 信号的频率等于音频的采样率。
例如,如果音频采样率是 44.1kHz,那么 WS 的频率也是 44.1kHz。
串行数据SD
SD(Serial Data,串行数据)
i2s传输时的音频数据,是用二进制补码表示的,具体数据传输的格式主要包括:I2S格式,左对齐格式,右对齐格式,每个 BCK 周期会传输一位数据。数据发送端和接收端会根据 BCK 信号的跳变(上升沿或下降沿)同步数据的发送和接收。当 WS 为低电平时,SD 传输左声道数据;当 WS 为高电平时,SD 传输右声道数据。
比如我们传输16 位双声道音频,SD数据为1 0 1 0 1 1 0 1 1 0 0 0 1 0 0 1 1 1 0 0 1 0 0 1 1 0 0 0 1 0 0 1
它表示
- 每个 BCK 周期传输一位音频数据。
- 当 WS 为低电平时,SD 按位传输左声道的 16 位数据1 0 1 0 1 1 0 1 1 0 0 0 1 0 0 1
- 当 WS 为高电平时,SD 按位传输右声道的 16 位数据 1 1 0 0 1 0 0 1 1 0 0 0 1 0 0 1,
个人总结
字时钟:高低电平翻转,总线在传输双声道音频 0为左, 1为右,字时钟的频率=采样率
位时钟:串行数据线的信号会在位时钟上升沿被采样,位时钟的频率=2×采样率×采样位数。
串行数据:用二进制补码表示的音频数据,先传输高位,再传输低位,
Tips:字时钟和位时钟都是由主机发送
了解了I2S是如何传输后,我们再来看看他的传输模型和通信格式。
I2S传输模型
I2S通信支持全双工和半双工通信,支持主/从模式。主设备就是发送时钟的,从设备在时钟的控制下发送或者接收数据。
连接到I2S总线的设备可以分为两类:
控制器——控制 SCK 和 WS 信号。
目标设备——接收 SCK 和 WS 信号
总线上只能有一个控制器,但是总线可以有多个目标设备。
音频设备,可以分为三类:
发射器——发送音频信号。
接收器——接收音频信号。
控制器——控制音频信号
这里我们至少需要一个发射器和接收器,控制器是可选的,主要用于向 I2S 从机提供参考时钟
根据I2S总线谁作为控制器,谁作为目标设备,我们可以有三种I2S传输模型:
- 发射器作为控制器, 接收器作为目标设备
- 发射器作为目标设备,接收器作为控制器
- 发射器和接收器都作为目标设备,其他I2S控制器作为控制器
总结:三种经典I2S传输模型
I2S通信格式
PCM510xA 支持行业标准的音频数据格式,包括标准 I2S 和 左对齐(Left-justified) 格式等。
I2S格式
I2S格式:又称飞利浦格式(图7),数据最高位总是出现在字时钟变化后的第二个位时钟脉冲处(滞后一个位时钟),这种格式下数据MSB的位置是确定的,LSB的位置取决于字长。
图(7)
左对齐格式
左对齐格式(图8):数据最高位出现在字时钟变化后的第一个位时钟脉冲处(无滞后位时钟)
图(8)
右对齐格式
右对齐格式:又称日本格式,这种格式和左对齐差不多,只不过整体是靠右对齐的,即数据LSB与WCLK跳变沿对齐。
图(9)
i2s基本配置
①,i2s的时钟使能和GPIO口配置 ②,配置为i2s模式
③,i2s标准,无论有多少位有效数据,即数据的最高位总是出现在WS变化(也就是一帧开始)后的第2个CK脉冲处。
④,i2s数据长度,包括16位,16位扩展(16位数据以32位包发送),24位,32位。 ⑤,设置i2s时钟
⑥,设置i2s空闲状态下时钟电平 ⑦,i2s使能
i2s 底层API
这里我们以ESP32 I2S通信为例,开发环境是Arduino IDE,介绍它的相关底层API,在我们调库的时候下面这些函数会被调用,我们看一下它的实现过程。
加载I2S驱动
函数原型:
esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void *i2s_queue)
参数说明::
i2s_port_t i2s_num:指定使用的 I2S 外设端口。i2s_port_t 是 I2S 外设端口的枚举类型,有两个端口可用:I2S_NUM_0 和 I2S_NUM_1,对应 ESP32 的第一个和第二个 I2S 外设。
typedef enum {I2S_NUM_0 = 0, /*!< I2S port 0 */
#if SOC_I2S_NUM > 1I2S_NUM_1 = 1, /*!< I2S port 1 */
#endifI2S_NUM_MAX, /*!< I2S port max */
} i2s_port_t;
const i2s_config_t * i2s_config : 设置I2S 外设的配置参数。其中i2s_config_t 是一个结构体,定义了 I2S 外设的配置选项,这里我们只看常用的配置选项就可以了,主要包括mode、 sample_rate、bits_per_sample等,如下:
typedef struct {i2s_mode_t mode; /*< 设置 I2S 的工作模式 */uint32_t sample_rate; /*!< 设置音频采样率 */i2s_bits_per_sample_t bits_per_sample; /*!< 设置采样位数 */i2s_channel_fmt_t channel_format; /*!< 设置数据通道格式.*/i2s_comm_format_t communication_format; /*!< 设置I2C数据传输格式 */int intr_alloc_flags; /*!< 设置中断相关标志位*/int dma_buf_count; dma缓存个数, int dma_buf_len;
} i2s_driver_config_t;typedef i2s_driver_config_t i2s_config_t;
int queue_size: 数据传输的队列的大小
void * i2s_queue:存放和管理 I2S 传输的数据。
这个函数有一个esp_err_t 的返回值,如果返回ESP_OK表示加载I2S驱动成功。
设置I2S使用的引脚
函数原型:
esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin)
参数说明:
i2s_port_t i2s_num:指定使用的 I2S 外设端口,I2S_NUM_0 或I2S_NUM_1。
i2s_pin_config_t * pin:配置I2S接口的各个引脚,i2s_pin_config_t 是一个结构体,里面是关于I2S引脚,如时钟引脚,左右声道选择引脚,数据输入引脚等引脚的配置。如下:
typedef struct {int mck_io_num; /*!< MCK in out pin. Note that ESP32 supports setting MCK on GPIO0/GPIO1/GPIO3 only*/int bck_io_num; /*!< BCK in out pin*/int ws_io_num; /*!< WS in out pin*/int data_out_num; /*!< DATA out pin*/int data_in_num; /*!< DATA in pin*/
} i2s_pin_config_t
I2S读取数据
函数原型:
esp_err_t i2s_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_read, TickType_t ticks_to_wait);*/用于从 I2S接口读取音频数据
参数说明:
i2s_port_t i2s_num:I2S_NUM_0 或I2S_NUM_1。
void * dest:读取目标数据的缓存区
size_t size:要读取的数据大小,单位是字节
size_t * bytes_read:实际读取到的字节数
TickType_t ticks_to_wait:超时等待时间,因为I2S是按一定频率读取数据的,如果一次传输的数据很多就需要等待,这个参数一般写入portMAX_DELAY 表示无限等待。
如果返回ESP_OK表示I2S读取数据成功。
I2S发送数据
函数原型:
esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *bytes_written, TickType_t ticks_to_wait);*/用于向 I2S 接口写入音频数据
参数说明:
i2s_port_t i2s_num:I2S_NUM_0 或I2S_NUM_1。
const void *src:写入源数据的缓存区
size_t size:要写入的数据大小,单位是字节
size_t *bytes_written:实际写入的字节数
TickType_t ticks_to_wait:超时等待时间,因为I2S是按一定频率发送数据的,如果一次传输的数据很多就需要等待,这个参数一般写入portMAX_DELAY 表示无限等待。
卸载I2S驱动
函数原型:
esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num);
参数说明:
卸载I2S驱动的话我们只需要传入I2S端口就行了。
i2s_port_t i2s_num:指定使用的 I2S 外设端口。i2s_port_t 是 I2S 外设端口的枚举类型,有两个端口可用:I2S_NUM_0 和 I2S_NUM_1,对应 ESP32 的第一个和第二个 I2S 外设。
总结
以上我们介绍了I2S的相关知识和配置的相关函数,下篇文章我们来看一下一个使用ESP32驱动I2S设备的小案例!这系列的文章主要是分享一下本人学习过程的相关知识,如果有错误可以交流学习下!
相关文章:

ESP32 I2S音频总线学习笔记(一):初识I2S通信与配置基础
文章目录 简介为什么需要I2S?关于音频信号采样率分辨率音频声道 怎样使用I2S传输音频?位时钟BCLK字时钟WS串行数据SD I2S传输模型I2S通信格式I2S格式左对齐格式右对齐格式 i2s基本配置i2s 底层API加载I2S驱动设置I2S使用的引脚I2S读取数据I2S发送数据卸载…...
25上半年软考高级系统分析师易混淆知识点
第1章 系统工程与信息系统基础 易混淆点1:系统工程生命周期与信息系统的生命周期 1、系统工程生命周期阶段 探索性研究→概念阶段→开发阶段→生产阶段→使用阶段→保障阶段→退役阶段 2、信息系统的生命周期 产生阶段→开发阶段(单个系统开发&…...
采集JSON解析错误的修复
两段采集来的JSON格式: 一: {"hwgOnlineId":"554312", "jiwuChatId":"", "phoneCategoryId":"20006", "cuxiaoSeq":{voucherTitle:1,lh 二: {"pic":&q…...
Java中实现对象的深拷贝(Deep Copy)
在Java中实现对象的深拷贝(Deep Copy)意味着创建一个对象的副本,使得原对象和副本对象完全分离,对副本对象的任何修改都不会影响到原对象。以下是几种实现深拷贝的方法: 1. 手动实现深拷贝 对于自定义类,…...

位置编码-APE
Transformer 中的绝对位置编码 (以下由gpt 生成) Transformer 的绝对位置编码(Absolute Position Encoding, APE)是用于对序列数据中的位置信息进行建模的一种方法。在 Transformer 的架构中,输入数据(如句…...
MySQL有哪些锁?
1.MySQL有哪些锁? 全局锁表级锁 表锁元数据锁意向锁 行级锁 记录锁间隙锁临键锁临时意向锁 我了解的是MySQL的锁可以分为全局锁、表级锁、行级锁。 我比较熟悉的是表级锁和行级锁,如果我们对表结构进行修改时,MySQL就会对这个表结构加一个…...

Everything实现,快速搜索文件
最近编写NTFS文件实时搜索工具, 类似 Everything 这样, 翻阅了很多博客, 结果大致如下: 1.分析比较肤浅, 采用USN日志枚举来获取文件记录 速度一言难尽, 因为日志枚举的是全盘所有文件的所有日志, 记录比文件记录还多, 速度当然很慢, 还有的甚至于是 使用 DeviceIoControl 函数…...

[硬件] DELL BIOS 相关注意事项
前言 前段时间重装系统. DELL BIOS属实资料少, 又难用. 这里给出相关的注意事项, 并且配上图片. BIOS相关注意事项 进入BIOS ESC/F2/ F12. 都可以进入BIOS, 当进U盘的入Win PE系统时, 使用F12 效果更佳. 关闭安全模式 切换到Boot Configuration选项,将Secure Boot选项off选…...

Rocky Linux 下安装Liboffice
Rocky Linux下安装Liboffice。 Step1: 在桌面,单击击键盘的Window键,点击出现的白色software按钮图标; Step2: 输入lib,即可自动跳出libre Office, 进行安装; Step3: Have fun with Rocky Linux....
【每日学点鸿蒙知识】长时任务、HarmonyAppProvision申请、preferences、Testing工具、应用保活
1、HarmonyOS 如何解决语音聊天、通信app退后台系统采集播放回调就会停止,回前台未恢复? 关于应用切到后台系统采集播放回调停止的问题原因如下:为了降低设备耗电速度、保障用户使用流畅度,系统会对退至后台的应用进行管控&#…...

步进电机驱动算法——S形加减速算法原理
1. 前言: 最近项目又用到了步进电机,为了在运动中加减速更加平稳决定研究一下S型加减速,原来用过野火的s型加减速程序,云里雾里的移植成功了,今天再翻来程序看一脸懵逼,重新学习了一下发现所有公式都能看懂…...
【图像去噪】论文复现:大道至简!ZS-N2N的Pytorch源码复现,跑通源码,获得指标计算结果,补充保存去噪结果图像代码,代码实现与论文理论对应!
请先看【专栏介绍文章】:【图像去噪(Image Denoising)】关于【图像去噪】专栏的相关说明,包含适配人群、专栏简介、专栏亮点、阅读方法、定价理由、品质承诺、关于更新、去噪概述、文章目录、资料汇总、问题汇总(更新中) 完整代码和训练好的模型权重文件下载链接见本文底…...

2024年中国新能源汽车用车发展怎么样 PaperGPT(一)
概述 在国家政策的强力扶持下,2024年中国新能源汽车市场迎来了新的发展机遇。本文将基于《中国新能源汽车用车报告(2024年)》的数据,对新能源汽车的市场发展和用车趋势概述。 新能源汽车市场发展 政策推动:国家和地…...
数据结构-排序思想
直接插入排序 将后面的无序区中的元素挨个向前面的有序区中插入。 1.将顺序表中R[0]用作哨兵,按索引i2...n的次序,将R[i]向有序区R[1...i-1]中执行插入操作。 2.插入操作可采取在有序区中从后向前的查找比较和移动的方法。 3.此操作中比较的次数与原序列…...
python 快速排序(Quick Sort)
快速排序(Quick Sort) 快速排序是一种高效的排序算法,采用分治法(Divide and Conquer)策略。它的基本思想是:选择一个基准元素(pivot),将数组分为两部分,使得…...

MySQL数据库——常见慢查询优化方式
本文详细介绍MySQL的慢查询相关概念,分析步骤及其优化方案等。 文章目录 什么是慢查询日志?慢查询日志的相关参数如何启用慢查询日志?方式一:修改配置文件方式二:通过命令动态启用 分析慢查询日志方式一:直…...

【AIGC篇】AIGC 引擎:点燃创作自动化的未来之火
:羑悻的小杀马特.-CSDN博客 未来都是惊喜。你生来本应为高山。并非草芥。 引言: 在当今数字化的时代,人工智能生成内容(AIGC)正以一种前所未有的力量改变着我们的创作领域。它就像一个神秘而强大的魔法师,…...

C语言性能优化:从基础到高级的全面指南
引言 C 语言以其高效、灵活和功能强大而著称,被广泛应用于系统编程、嵌入式开发、游戏开发等领域。然而,要写出高性能的 C 语言代码,需要对 C 语言的特性和底层硬件有深入的了解。本文将详细介绍 C 语言性能优化的背后技术,并通过…...
常用的公共 NTP(网络时间协议)服务器
公共 NTP 服务列表 以下是一些常用的公共 NTP(网络时间协议)服务器,供您参考: 中国地区公共 NTP 服务器 国家授时中心 NTP 服务器:ntp.ntsc.ac.cn中国 NTP 快速授时服务:cn.ntp.org.cn阿里云公共 NTP 服务…...

Kafka中的Topic和Partition有什么关系?
大家好,我是锋哥。今天分享关于【Kafka中的Topic和Partition有什么关系?】面试题。希望对大家有帮助; Kafka中的Topic和Partition有什么关系? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 Apache Kafka 中&#…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...

Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...

ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...

力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...