【音视频|ALSA】基于alsa-lib开发ALSA应用层程序--附带源码
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭基于alsa-lib开发ALSA应用层程序🍭
😎金句分享😎:🍭盖士人读书,第一要有志,第二要有识,第三要有恒。有志则断不甘为下流,有识则知学问无尽,不敢以一得自足,如河伯之观海,如井蛙之窥天,皆无识者也。有恒则断无不成之事,此三者缺一不可。 ——《曾国藩家书》🍭
【音视频|ALSA】ALSA是什么?ALSA框架详细介绍
【音视频|ALSA】SS528开发板编译Linux内核ALSA驱动、移植alsa-lib、采集与播放usb耳机声音
目录
- 一、ALSA应用层开发基础知识
- 二、alsa-lib常用函数
- 三、编写ALSA应用层程序
- 3.1 alsa播放程序开发--alsa-playback.c
- 3.2 alsa录制音频程序开发--alsa-capture.c
- 四、XRUN( underrun和overrun)
- 五、总结
一、ALSA应用层开发基础知识
sample
:样本,采样点。数字音频最小单位,其大小与位宽有关,一般为8bit(1个字节)、16bit(2个字节);channel
:声道,一般单声道(mono)和立体声(stereo),还有一些多声道如5.1声道。frame
:帧,一个完整的声音单元,即单次采样的所有声道的数据。frame=sample*channel
;
例如:48Khz、16位的立体声PCM流的1帧是4个字节。sample rate
:采样率,即每秒的采样次数。如果采样率为48kHz,则说明一秒采样48000帧。period size
:周期大小,是每次硬件中断之间的帧数。buffer size
:缓冲区大小,必须大于一个周期的大小。一般为周期大小的2倍。单位也是帧数。
例子:
结合上面的知识点,这里以48kHz、16bit的立体声音频流举例:
- 16bit则每个样本为2个字节,
- 立体声表示有2个声道,
- 48kHz 表示每秒有48000个音频帧。
由此可以计算出每秒钟传输的数据大小:
2 * 2 * 48000=192000
字节;
现在如果ALSA每秒钟产生一个硬件中断,在每秒结束时,我们需要准备好192000字节;
如果它每半秒中断一次,对于同一个流,我们需要在每次中断时准备好192000/2 = 96000字节;
如果每100毫秒发生一次中断,我们需要在每次中断时准备好192000*(0.1/1) = 19200字节。
我们可以通过设置周期大小(以帧为单位)来控制PCM中断的产生时间。
如果我们将48kHz、16bit的立体声音频流的period size
设置为4800帧(也就是480022=19200字节),则每19200字节就会产生一个中断,也就是100ms。
相应地,buffer size
至少应为2*period_size = 2*4800= 9600
帧(960022 = 38400字节)。
实际编程中,可能需要计算一个周期的总字节数
period bytes
,就是等于period size
乘以每一帧的大小。同样的,buffer的总字节数buffer bytes
等于buffer size
乘以一帧大小。
如果已知音频的采样率、通道数、位宽、周期数,则
buffer size
、buffer time
、period size
、period time
这四个值可以相互推断出来:
以48000Hz采样率、2声道、16bit、4周期来举例,这样的音频流一秒钟的帧数是48000帧,如果buffer size
是48000,则buffer time
刚好就是一秒;如果buffer time
是500ms,则buffer size
是24000帧。
而period size=buffer size/周期数
;period time=buffer time/周期数
二、alsa-lib常用函数
alsa-lib的函数声明在pcm.h,总共可以分为16个模块:
- PCM Interface
- Stream Information
- Hardware Parameters
- Software Parameters
- Access Mask Functions
- Format Mask Functions
- Subformat Mask Functions
- Status Functions
- Description Functions
- Debug Functions
- Direct Access (MMAP) Functions
- Helper Functions
- Hook Extension
- Scope Plugin Extension
- Simple setup functions
- Deprecated Functions
可以在官方文档查看对应的模块函数说明:
https://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html
下表介绍一些常用的函数:
函数 | 说明 |
---|---|
snd_pcm_open | 根据pcm设备名字打开一个pcm设备 |
snd_pcm_hw_params_malloc | 使用标准malloc分配无效的snd_pcm_hw_params_t |
snd_pcm_hw_params_any | 用PCM的完整配置空间填充参数。 |
snd_pcm_hw_params_set_access | 将配置空间限制为仅包含一种访问类型。 |
snd_pcm_hw_params_set_format | 将配置空间限制为仅包含一种格式。 |
snd_pcm_hw_params_set_channels | 将配置空间限制为仅包含一个通道计数。 |
snd_pcm_hw_params_set_rate_near | 将配置空间限制为具有最接近目标的速率。 |
snd_pcm_hw_params_get_buffer_time_max | 从配置空间中提取最大缓冲时间。 |
snd_pcm_stream | 获取PCM句柄的流 |
snd_pcm_hw_params_set_buffer_time_near | 限制配置空间以使缓冲时间最接近目标。 |
snd_pcm_hw_params_set_period_time_near | 限制配置空间以使周期时间最接近目标。 |
snd_pcm_hw_params | 安装从配置空间中选择的一个PCM硬件配置,并调用snd_pcm_prepare。 |
snd_pcm_nonblock | 设置非阻塞模式 |
snd_pcm_hw_params_get_period_size | 从配置空间中提取周期大小。 |
snd_pcm_hw_params_get_buffer_size | 从配置空间中提取周期大小。 |
snd_pcm_format_physical_width | 返回存储PCM样本所需的位。 |
更多函数说明参考:
https://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m___h_w___params.html
https://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html
三、编写ALSA应用层程序
这小节介绍简单的ALSA应用程序开发流程,以及给出例子源码。
在编写代码前,可以先使用cat /proc/asound/card0/stream0
查看ALSA设备支持的参数:
# cat /proc/asound/card0/stream0
Rapoo Gaming Headset at usb-10300000.xhci_0-1.1, full speed : USB AudioPlayback:Status: StopInterface 1Altset 1Format: S16_LEChannels: 2Endpoint: 1 OUT (ADAPTIVE)Rates: 48000, 44100Capture:Status: StopInterface 2Altset 1Format: S16_LEChannels: 1Endpoint: 2 IN (ASYNC)Rates: 48000, 44100
Playback:播放设备
Capture:录音设备
Interface:接口序号
Format:格式
Channels:通道数
Rates:支持的采样率
3.1 alsa播放程序开发–alsa-playback.c
开发流程:
- 1、打开设备:调用
snd_pcm_open
,指定类型为SND_PCM_STREAM_PLAYBACK
,以及设备名称,打开设备;- 2、设置硬件参数
设置存取方式、格式、通道数、采样率、缓冲时间、周期时间,最后将参数写入设备;
如果有一些参数不清楚怎么设置,可以使用命令cat /proc/asound/card0/stream0
查看支持的参数:- 3、播放音频
每次往alsa驱动写入一个周期大小的字节,不足一周期的要填0;- 4、释放资源,关闭设备
下面是一个非常简单的ALSA播放音频的代码,复制后保存为alsa-playback.c
,使用命令aarch64-mix210-linux-gcc alsa-playback.c -I /usr/lib/alsa-lib-1.2.10/include/ -L /usr/lib/alsa-lib-1.2.10/lib/ -l asound -lpthread -ldl -lm -o alsa-playback
已编译通过。
48000Hz-16bit-2ch-ChengDu.pcm 文件下载:https://download.csdn.net/download/wkd_007/88421282
// alsa-playback.c
// aarch64-mix210-linux-gcc alsa-playback.c -I /usr/lib/alsa-lib-1.2.10/include/ -L /usr/lib/alsa-lib-1.2.10/lib/ -l asound -lpthread -ldl -lm -o alsa-playback/*
* snd_pcm_hw_params_alloca 申请的内存在函数返回后会自动释放,不需要手动释放。这个函数会在栈上分配一块内存,函数返回后,栈上的内存会自动被回收。
*/
#include <stdio.h>
#include <alsa/asoundlib.h>#define PCM_NAME "hw:0,0"
#define PLAYBACK_FILE "48000Hz-16bit-2ch-ChengDu.pcm"snd_pcm_hw_params_t *hw_params;
static unsigned int rate = 48000; /* stream rate */int set_hw_params(snd_pcm_t *handle, int format, int channels, snd_pcm_uframes_t *period_frames)
{int err = -1;// 分配硬件参数空间,调用 alloca 在栈分配内存,函数结束后自动释放,不需要调用 snd_pcm_hw_params_freesnd_pcm_hw_params_alloca(&hw_params);//1、以默认值填充硬件参数if ((err = snd_pcm_hw_params_any(handle, hw_params)) < 0) {return err;}//2、 Restrict a configuration space to contain only real hardware rates.if ((err = snd_pcm_hw_params_set_rate_resample(handle, hw_params, 0)) < 0) {return err;}//3、设置存取方式为交叉存储if ((err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {return err;}//4、设置格式,S16_LE等if ((err = snd_pcm_hw_params_set_format(handle, hw_params, format)) < 0) {return err;}//5、设置通道if ((err = snd_pcm_hw_params_set_channels(handle, hw_params, channels)) < 0) {return err;}//6、大致设置采样率unsigned int rrate;rrate =rate;if ((err = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rrate, NULL)) < 0) {return err;}//7、设置缓冲时间unsigned int buffer_time, period_time;// 先获取缓存时间if((err = snd_pcm_hw_params_get_buffer_time_max(hw_params, &buffer_time, 0))<0){return err;}if (buffer_time > 500000){buffer_time = 500000; // 500ms读取完整个buffer,结合下面代码一个周期就是 buffer_time/4=125ms,每个周期会产生一个中断printf("[%s %d] buffer_time=%d, irq=%d\n",__FILE__,__LINE__,buffer_time, buffer_time/4);}// 设置缓冲时间if ((err = snd_pcm_hw_params_set_buffer_time_near(handle, hw_params, &buffer_time, 0)) < 0) {return err;}// 8、设置周期时间,也就是中断时间period_time = buffer_time / 4;if ((err = snd_pcm_hw_params_set_period_time_near(handle, hw_params, &period_time, 0)) < 0) {return err;}// 9、将参数写入设备if ((err = snd_pcm_hw_params(handle, hw_params)) < 0){return err;}snd_pcm_uframes_t buffer_frames;snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_frames);if(period_frames != NULL) {//获取一个周期有多少帧数据if((err =snd_pcm_hw_params_get_period_size(hw_params, period_frames, 0)) < 0){printf("cannot get period size (%s)\n", snd_strerror(err));return err;}}if(err = (snd_pcm_nonblock(handle, 1) < 0)){return err;}// 10、释放 snd_pcm_hw_params_malloc 分配的内存//snd_pcm_hw_params_free(hw_params);return 0;
}int main()
{int err = -1;snd_pcm_t *playback_handle;snd_pcm_uframes_t period_frames; // 一周期的帧数// 1、打开设备if((err = snd_pcm_open(&playback_handle, PCM_NAME, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {printf("cannot snd_pcm_open (%s)\n",snd_strerror(err));return -1;}// 2、设置硬件参数set_hw_params(playback_handle, SND_PCM_FORMAT_S16_LE, 2, &period_frames);// 3、播放音频// 3.1 打开pcm文件int fd = open(PLAYBACK_FILE,O_RDONLY,0644);if(fd < 0){printf("open %s error!!!\n",PLAYBACK_FILE);return -1;}// 3.2 获取一周期的字节数const int period_bytes = snd_pcm_frames_to_bytes(playback_handle,period_frames);char *playback_buf = malloc(period_bytes);// 3.3 循环播放音频int readframes = 0;while(readframes = read(fd, playback_buf, period_bytes)) {//解决最后一个周期数据问题if(readframes < period_bytes) {memset(playback_buf+readframes, 0, period_bytes-readframes);}//向PCM写入数据,播放err = snd_pcm_writei(playback_handle, playback_buf, period_frames);if(err == -EPIPE) {snd_pcm_prepare(playback_handle);fprintf(stderr, "<<< snd_pcm_writei --> Buffer Underrun >>> \n");err = snd_pcm_writei(playback_handle, playback_buf, period_frames);if(err != period_frames) {printf("write to audio interface failede err:%d (period_frames:%d)\n",err,period_frames);break;}}else if(err != period_frames) {printf("write to audio interface failede err:%d (period_frames:%d)\n",err,period_frames);break;}//printf("process:playback wrote %d frames\n",period_frames);//usleep(100*1000);usleep(130*1000); //测试用,超过 125ms,会报错 Underrun}// 4.释放资源,关闭设备free(playback_buf);close(fd);snd_pcm_close(playback_handle);return 0;
}
3.2 alsa录制音频程序开发–alsa-capture.c
开发流程:
- 1、打开设备:调用
snd_pcm_open
,指定类型为SND_PCM_STREAM_CAPTURE
,以及设备名称,打开设备;- 2、设置硬件参数
设置存取方式、格式、通道数、采样率、缓冲时间、周期时间,最后将参数写入设备;
如果有一些参数不清楚怎么设置,可以使用命令cat /proc/asound/card0/stream0
查看支持的参数:- 3、读取音频
每次从alsa驱动读取一个周期大小的字节;- 4、释放资源,关闭设备
// alsa-capture.c
// aarch64-mix210-linux-gcc alsa-capture.c -I /usr/lib/alsa-lib-1.2.10/include/ -L /usr/lib/alsa-lib-1.2.10/lib/ -l asound -lpthread -ldl -lm -o alsa-capture/*
* snd_pcm_hw_params_alloca 申请的内存在函数返回后会自动释放,不需要手动释放。这个函数会在栈上分配一块内存,函数返回后,栈上的内存会自动被回收。
*/
#include <stdio.h>
#include <alsa/asoundlib.h>#define PCM_NAME "hw:0,0"
#define CAPTURE_FILE "alsa-capture.pcm"snd_pcm_hw_params_t *hw_params;
static unsigned int rate = 48000; /* stream rate */int set_hw_params(snd_pcm_t *handle, int format, int channels, snd_pcm_uframes_t *period_frames)
{int err = -1;// 分配硬件参数空间,调用 alloca 在栈分配内存,函数结束后自动释放,不需要调用 snd_pcm_hw_params_freesnd_pcm_hw_params_alloca(&hw_params);//1、以默认值填充硬件参数if ((err = snd_pcm_hw_params_any(handle, hw_params)) < 0) {return err;}//2、 Restrict a configuration space to contain only real hardware rates.if ((err = snd_pcm_hw_params_set_rate_resample(handle, hw_params, 0)) < 0) {return err;}//3、设置存取方式为交叉存储if ((err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {return err;}//4、设置格式,S16_LE等if ((err = snd_pcm_hw_params_set_format(handle, hw_params, format)) < 0) {return err;}//5、设置通道if ((err = snd_pcm_hw_params_set_channels(handle, hw_params, channels)) < 0) {return err;}//6、大致设置采样率unsigned int rrate;rrate =rate;if ((err = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rrate, NULL)) < 0) {return err;}//7、设置缓冲时间unsigned int buffer_time, period_time;// 先获取缓存时间if((err = snd_pcm_hw_params_get_buffer_time_max(hw_params, &buffer_time, 0))<0){return err;}if (buffer_time > 500000){buffer_time = 500000; // 500ms写完整个buffer,结合下面代码一个周期就是 buffer_time/4=125ms,每个周期会产生一个中断printf("[%s %d] buffer_time=%d, irq=%d\n",__FILE__,__LINE__,buffer_time, buffer_time/4);}// 设置缓冲时间if ((err = snd_pcm_hw_params_set_buffer_time_near(handle, hw_params, &buffer_time, 0)) < 0) {return err;}// 8、设置周期时间,也就是中断时间period_time = buffer_time / 4;if ((err = snd_pcm_hw_params_set_period_time_near(handle, hw_params, &period_time, 0)) < 0) {return err;}// 9、将参数写入设备if ((err = snd_pcm_hw_params(handle, hw_params)) < 0){return err;}snd_pcm_uframes_t buffer_frames;snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_frames);if(period_frames != NULL) {//获取一个周期有多少帧数据if((err =snd_pcm_hw_params_get_period_size(hw_params, period_frames, 0)) < 0){printf("cannot get period size (%s)\n", snd_strerror(err));return err;}}if(err = (snd_pcm_nonblock(handle, 1) < 0)){return err;}// 10、释放 snd_pcm_hw_params_malloc 分配的内存//snd_pcm_hw_params_free(hw_params);return 0;
}int main()
{int err = -1;snd_pcm_t *capture_handle;snd_pcm_uframes_t period_frames; // 一周期的帧数// 1、打开设备if((err = snd_pcm_open(&capture_handle, PCM_NAME, SND_PCM_STREAM_CAPTURE, 0)) < 0) {printf("cannot snd_pcm_open (%s)\n",snd_strerror(err));return -1;}// 2、设置硬件参数set_hw_params(capture_handle, SND_PCM_FORMAT_S16_LE, 1, &period_frames);// 3、获取音频// 3.1 打开录制文件int fd = open(CAPTURE_FILE,O_RDWR | O_TRUNC | O_CREAT,0644);if(fd < 0){printf("open %s error!!!\n",CAPTURE_FILE);return -1;}// 3.2 获取一周期的字节数const int period_bytes = snd_pcm_frames_to_bytes(capture_handle,period_frames);char *capture_buf = malloc(period_bytes);int count = 100; // 捕获100个周期int readframes = 0;while(count--) {//向PCM读一周期数据memset(capture_buf,0,period_bytes);if((readframes = snd_pcm_readi(capture_handle, capture_buf, period_frames)) < 0) {if(readframes == -EPIPE)printf("read from audio interface failed (%d), overrun, Need to read faster\n",readframes);elseprintf("read from audio interface failed (%d)\n",readframes);break;}printf("--process:capture read %d frames\n",readframes);write(fd,capture_buf,snd_pcm_frames_to_bytes(capture_handle,readframes));usleep(100*1000); //usleep(130*1000); //测试用,超过 125ms,会报错 overrun}// 4、释放资源,关闭设备free(capture_buf);close(fd);snd_pcm_close(capture_handle);return 0;
}
四、XRUN( underrun和overrun)
在 ALSA 数据传输中,最容易出现的错误是 underrun 和 overrun。
underrun
:pcm 播放的时候,接口 snd_pcm_writei 返回 -EPIPE,为 underrun(不足)
出现这问题原因是应用准备的音频数据不够,比如,驱动需要播放需要 1026 帧数据,但应用只准备好了 1024 帧。可以根据采样率和buffer size
、period size
去调整;overrun
:录制音频的时候, 接口 snd_pcm_readi 返回 -EPIPE, 为 overrun(超载)
alsa驱动一直往buffer里面写,但应用程序却读取的很慢,例如:驱动写了1026帧,而应用层只读取了1024帧。需要加快读取速度。或者调整buffer size
、period size
。
五、总结
文章介绍了alsa的基础知识,以及基于alsa-lib开发ALSA应用层程序的开发流程和alsa开发过程钟常见的报错,提供了简单的alsa应用层代码。
参考资料:
ALSA官网资料——FramesPeriods:https://alsa-project.org/main/index.php/FramesPeriods
【Linux&音频】Alsa音频编程【精华】:https://blog.csdn.net/u012183924/article/details/53407668
ALSA 音频数据传输 underrun 和 overrun:https://blog.csdn.net/qq_38350702/article/details/111995039
Linux应用开发【第八章】ALSA应用开发:https://blog.csdn.net/thisway_diy/article/details/121809633
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁
相关文章:

【音视频|ALSA】基于alsa-lib开发ALSA应用层程序--附带源码
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…...

嵌入式养成计划-43----QT QMainWindow中常用类的使用--ui界面文件--资源文件的添加--信号与槽
一百零九、QMainWindow中常用类的使用 109.1 菜单栏 QMenuBar 菜单栏 QMenuBar 最多只能有一个 109.2 工具栏 QToolBar 工具栏 QToolBar 可以有多个 109.3 状态栏QStatusBar 状态栏 QStatusBar 最多只能有一个 109.4 浮动窗口QDockWidget 浮动窗口 可以有多个 109.5 代…...
【Yarn】清除Yarn的缓存,更新Yarn本身、更新项目的依赖项
要清除Yarn的缓存,可以运行以下命令: yarn cache clean这将清除Yarn的缓存目录。 要更新Yarn本身,可以运行以下命令: yarn self-update这将下载并安装最新版本的Yarn。 如果要更新项目的依赖项,可以运行以下命令&a…...
点云从入门到精通技术详解100篇-雨雾环境下多传感器融合SLAM方法(续)
目录 4 基于球面投影的激光视觉融合里程计 4.1 引言 4.2 视觉惯性里程计 4.2.1特征点提取与匹配...
解决GET请求入参@NotNull验证不生效问题
一、问题 get请求NotNull验证不生效 二、解决方案 两个步骤: 在该方法的controller类上加Validated;在参数面前加NotNull; 三、其他注解 //被注释的元素必须为null Null //被注释的元素不能为null NotNull //被注释的元素必须为true Ass…...

《golang设计模式》第三部分·行为型模式-01-责任链模式(Chain of Responsibility)
文章目录 1 概念1.1 角色1.2 类图 2. 代码示例2.1 设计2.2 代码2.3 类图 1 概念 责任链(Chain of Responsibility)是指将客户端请求处理的不同职责对象组成请求处理链。 客户端只需要将请求交付到该链上,而不需要关心链上含有哪些对象。请求…...

环境变量【使用命令行参数引出环境变量】
前提:命令行参数 大家在写C/C程序的时候肯定见过下面这种情况: main函数里面携带的参数,平常写代码过程中很少用到这两个参数,接下来我们就研究一下 我们也不知道 指针数组argv里面到底保存的是什么,也不知道这个a…...

【Java 进阶篇】JavaScript BOM History 详解
当用户浏览网页时,可以使用JavaScript的BOM (Browser Object Model)中的History对象来访问浏览器的历史记录。这个对象允许您在不更改页面的情况下导航到不同的历史记录项,或者查看有关用户访问过的页面的信息。 在本篇博客中,我们将围绕Jav…...

【计算机网络】https协议
文章目录 1 :peach:基本概念:peach:1.1 :apple:什么是HTTPS?:apple:1.2 :apple:什么是加密?:apple:1.3 :apple:常见的加密方式:apple:1.3.1 :lemon:对称加密:lemon:1.3.2 :lemon:⾮对称加密:lemon: 1.4 :lemon:数据指纹:lemon: 2 :peach:HTTPS的⼯作过程…...

React之受控组件和非受控组件以及高阶组件
一、受控组件 受控组件,简单来讲,就是受我们控制的组件,组件的状态全程响应外部数据 举个简单的例子: class TestComponent extends React.Component {constructor (props) {super(props);this.state { username: lindaidai }…...

中国移动集采120万部,助推国产5G赶超iPhone15
近期媒体纷纷传出消息指中国移动将大规模集采,预计将采购国产5G手机120万台,加上另外两家运营商的集采数量,估计集采数量可能达到300万部,如此将有助于它在国内高端手机市场赶超苹果。 国产5G手机在8月底突然上市,获益…...

华为云HECS服务器下docker可视化(portainer)
一、docker安装 华为云HECS安装docker-CSDN博客 二、portainer安装 portainer地址:Portainer: Docker and Kubernetes Management Platform 当前portainer分CE(开源版) 和 BE(商业版),用CE即可 1 创建…...

postman发送soap报文示例
一、soap简介 soap是一种基于XML的协议 二、postman发送soap请求 1、发送post请求,url: https://www.dataaccess.com/webservicesserver/NumberConversion.wso 2、headers设置,添加Content-Type,值为text/xml 添加SOAP…...

力扣-python-两数之和
题解: class Solution(object):def twoSum(self, nums, target):# 遍历列表for i in range(len(nums)):# 计算需要找到的下一个目标数字res target-nums[i]# 遍历剩下的元素,查找是否存在该数字if res in nums[i1:]:# 若存在,返回答案。这里…...

算水质TDS加温度补偿
先上图,就图里这款水质检测,用树莓派3/4的话,要配个温度检测作为温度校正,以及一个adc 元器件。我选ds18b20和ads1115。 再把模拟数据计算过程放一下: 温度检测元器件在农历钟那里提过,就是同款。此处先测个…...

wps/word 如何让表格的标题和表格名称文本(表1-1 xxx)跨页显示(已解决)
第一步: 打开wps 创建一个跨页的表格表格,如下图 第二步 大家都知道 表格标题跨页 就是1)在菜单表格工具 点击重复标题 或者 2)表格属性--》行--》在各页顶端以标题行形式出现,详细如下图。 1) 第一…...

攻防世界web篇-PHP2
直接点击进入到http网页中,会得到这样一个界面 这里,我最开始使用了burp什么包也没有抓到,然后接着又用nikto进行探测,得到的只有两个目录,当时两个目录打开后,一个是fond界面,一个是这个网页的…...
Kotlin中的步长
步长是 Kotlin 中用于迭代区间或集合时控制迭代步进的概念。在 Kotlin 中,我们可以使用 step 关键字来指定迭代时的步长。 在 Kotlin 中,有多种方式可以定义一个区间(Range)。我们将通过以下示例代码来展示不同类型的区间以及如何…...
3. 无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。示例 2: 输入: s "bbbbb" 输出: 1 解释: 因为无…...

通过SPI传输BMI160数据到nrf528xx
目录 主控和外设之间的联系关键示例可能的bug 主控和外设之间的联系 在完成代码之前,我们手里会有两份代码,一份是nrf528xx的SDK,一份是BMI160传感器的SDK,怎么利用SDK完成我们的需求呢?首先我们要搞明白,…...

地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...

C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...

使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...

Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...

C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...