当前位置: 首页 > news >正文

【音视频|ALSA】SS528开发板编译Linux内核ALSA驱动、移植alsa-lib、采集与播放usb耳机声音

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭SS528开发板编译Linux内核ALSA驱动、移植alsa-lib、采集与播放usb耳机声音🍭
😎金句分享😎:🍭来忘掉错对,来怀念过去,曾共度患难日子总有乐趣 ——《友情岁月》🍭

目录

  • 一、概述
  • 二、编译ALSA驱动
    • 2.1 配置和编译ALSA驱动模块
    • 2.2 在ss528开发板插入ALSA驱动
  • 三、交叉编译 alsa-lib
    • 3.1 下载 alsa-lib
    • 3.2 交叉编译 alsa-lib
  • 四、开发ALSA应用层程序
    • 4.1 编写应用层代码 alsa-capture-playback.c
    • 4.2 运行程序 alsa-capture-playback
  • 五、总结


在这里插入图片描述

一、概述

上篇文章【音视频|ALSA】ALSA是什么?ALSA框架详细介绍 简单地介绍了ALSA驱动;这篇文章主要是一篇实战文章,通过ALSA架构,在SS528开发板实现播放usb耳机声音。整个操作大概分为三步:

  • 编译ALSA驱动
  • 交叉编译alsa-lib
  • 基于alsa-lib库开发采集、播放音频程序

本文使用开发环境:

  • 开发主机:Ubuntu18.04LTS
  • 交叉编译工具:aarch64-mix210-linux-gcc
  • 使用的Linux内核源码:ss528sdk自带的,SS528V100_SDK_V2.0.0.3/open_source/linux/linux-4.19.y
  • 使用的alsa-lib库:ALSA官网下载的 alsa-lib-1.2.10

在这里插入图片描述

二、编译ALSA驱动

在Linux系统中,要播放usb接口的音频,首先需要先有一个可以识别到这个usb耳机的驱动,然后再针对这个驱动编写应用层代码。自己写的话,耗时耗力不讨好,而ALSA架构就提供了这样的驱动和应用层的库,下面介绍怎样在Linux源码编译ALSA驱动,并将其编译成模块,插入到板子的Linux系统。

2.1 配置和编译ALSA驱动模块

首先进入Linux源码目录,配置启用ALSA驱动:

cd linux-4.19.y
make ARCH=arm64 CROSS_COMPILE=aarch64-mix210-linux- menuconfig

参考下面语句配置:

	Device Drivers  ---><M> Sound card support  ---><M>   Advanced Linux Sound Architecture  --->[*]   PCM timer interface (NEW)[*]   Support old ALSA API (NEW)[*]   Sound Proc FS Support (NEW)[*]     Verbose procfs contents (NEW)[*]   Generic sound devices (NEW)  ---> [*]   PCI sound devices (NEW)  ---> (2048) Pre-allocated buffer size for HD-audio driver[*]   SPI sound devices (NEW)  ----[*]   USB sound devices (NEW)  ---><M>   USB Audio/MIDI driver

配置完成后,保存退出,执行下面语句编译模块:

make ARCH=arm64 CROSS_COMPILE=aarch64-mix210-linux- modules

编译完成后,在sound目录下,有8个ko生成,将它们复制到开发板的文件系统即可:

$ find ./sound/ -name "*.ko"
./sound/core/snd.ko
./sound/core/snd-hwdep.ko
./sound/core/snd-rawmidi.ko
./sound/core/snd-timer.ko
./sound/core/snd-pcm.ko
./sound/usb/snd-usbmidi-lib.ko
./sound/usb/snd-usb-audio.ko
./sound/soundcore.ko
$ mkdir /nfsroot/sound
$ cd sound/
$ cp soundcore.ko core/*.ko usb/*.ko /nfsroot/sound -far

2.2 在ss528开发板插入ALSA驱动

说明:下面的打印都是在开发板文件系统的操作打印。

开发板在没用插入ALSA驱动之前,是没有/dev/snd目录、/prc/asound目录的:

/nfsroot/sound # ls /dev/snd
ls: /dev/snd: No such file or directory
/nfsroot/sound # ls /proc/asound
ls: /prc/asound: No such file or directory
/nfsroot/sound # 

插入ALSA驱动,参考下面命令:

insmod soundcore.ko
insmod snd.ko         
insmod snd-hwdep.ko   
insmod snd-timer.ko     
insmod snd-rawmidi.ko   
insmod snd-pcm.ko       
insmod snd-usbmidi-lib.ko
insmod snd-usb-audio.ko 

在这里插入图片描述
注意insmod的顺序,避免报错:insmod: can’t insert ‘snd.ko’: unknown symbol in module, or unknown parameter

插入成功后,可以看到/dev/snd目录、/prc/asound目录:
在这里插入图片描述

卸载ALSA驱动,参考下面语句:

rmmod snd-usb-audio
rmmod snd-usbmidi-lib
rmmod snd-pcm
rmmod snd-rawmidi
rmmod snd-timer
rmmod snd-hwdep
rmmod snd
rmmod soundcore

注意rmmod的顺序,避免报错:rmmod: can’t unload module ‘soundcore’: Resource temporarily unavailable

在这里插入图片描述

三、交叉编译 alsa-lib

3.1 下载 alsa-lib

在官网 https://www.alsa-project.org/files/pub/lib/ 可以下载到历史版本;
在Github https://github.com/alsa-project/alsa-lib/tags 可以下载到最新发布版本
本文下载的是 alsa-lib-1.2.10.tar.gz
在这里插入图片描述

3.2 交叉编译 alsa-lib

解压源码,如果里面没有configure文件,需要执行下面命令生成:

libtoolize --force --copy --automake
aclocal
autoheader
automake --foreign --copy --add-missing
autoconf

编译过程参考下面命令:

sudo mkdir /usr/lib/alsa-lib-1.2.10
sudo chown wkd:wkd /usr/lib/alsa-lib-1.2.10/ -R
tar zxf alsa-lib-1.2.10.tar.gz
cd alsa-lib-1.2.10/
./configure --prefix=/usr/lib/alsa-lib-1.2.10/ CC=aarch64-mix210-linux-gcc --host=aarch64-mix210-linux --enable-static=yes --enable-shared=no
make && make install

这里首先创建了/usr/lib/alsa-lib-1.2.10目录,因为链接了libasound.a后,程序需要到安装目录寻找配置文件share/alsa/alsa.conf,所以这里安装的目录需要和开发板存放的目录一致。

如果指定了--prefix为其他目录,就需要将share/alsa/alsa.conf复制到开发板同样的目录,否则运行程序会报错:Cannot access file /usr/lib/alsa-lib-1.2.10/share/alsa/alsa.conf,也可以通过选项--with-configdir来指定配置文件目录,它将影响 include/config.h中的 ALSA_CONFIG_DIR 目录。

在这里插入图片描述

四、开发ALSA应用层程序

4.1 编写应用层代码 alsa-capture-playback.c

代码参考:https://blog.csdn.net/u014056414/article/details/120989131

// alsa-capture-playback.c
// aarch64-mix210-linux-gcc alsa-capture-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-capture-playback#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <alsa/asoundlib.h>#define PLAYBACK_FILE "48000Hz-16bit-2ch-ChengDu.pcm"  // 采样率:48000 位深度:16bit 双通道
#define CAPTURE_FINE "capture.pcm"//#define PCM_NAME	"hw:CARD=mycodec,DEV=0"
#define PCM_NAME	"hw:0,0"
#define RATE 		48000
#define FORMAT		SND_PCM_FORMAT_S16_LE
#define CHANNELS	1snd_pcm_hw_params_t *hw_params;int print_all_pcm_name(void) {char **hints;/* Enumerate sound devices */int err = snd_device_name_hint(-1, "pcm", (void***)&hints);if(err != 0)return -1;char** n = hints;while(*n != NULL) {char *name = snd_device_name_get_hint(*n, "NAME");if(name != NULL && 0 != strcmp("null", name)) {printf("pcm name : %s\n",name);free(name);}n++;}snd_device_name_free_hint((void**)hints);return 0;
}snd_pcm_t *open_sound_dev(snd_pcm_stream_t type,const char *name, unsigned int rate, int format,int channels,snd_pcm_uframes_t *period_frames) {int err;snd_pcm_t *handle;int dir = 0;printf("rate=%d, format=%d, channels=%d\n",rate,format,channels);if((err = snd_pcm_open(&handle, name, type, 0)) < 0) {printf("cannot snd_pcm_open (%s)\n",snd_strerror(err));return NULL;}if((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) {printf("cannot allocate hardware parameter structure (%s)\n",snd_strerror(err));return NULL;}if((err = snd_pcm_hw_params_any(handle, hw_params)) < 0) {printf("cannot initialize hardware parameter structure (%s)\n",snd_strerror(err));return NULL;}if((err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {printf("cannot set access type (%s)\n",snd_strerror(err));return NULL;}if((err = snd_pcm_hw_params_set_format(handle, hw_params, format)) < 0) {printf("cannot set sample format (%s)\n",snd_strerror(err));return NULL;}if((err = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rate, 0)) < 0) {printf("cannot set sample rate (%s)\n",snd_strerror(err));return NULL;}if((err = snd_pcm_hw_params_set_channels(handle, hw_params, channels)) < 0) {printf("cannot set channel count (%s) channels=%d\n",snd_strerror(err),channels);if(channels==2){channels = 1;}if(channels==1){channels = 2;}if((err = snd_pcm_hw_params_set_channels(handle, hw_params, channels)) < 0) {printf("cannot set channel count (%s)\n",snd_strerror(err));return NULL;}}#if 1unsigned int buffer_time, period_time;if (snd_pcm_hw_params_get_buffer_time_max(hw_params, &buffer_time, 0) < 0) {fprintf(stderr, "Error snd_pcm_hw_params_get_buffer_time_max\n");return NULL;}if(snd_pcm_stream(handle) == SND_PCM_STREAM_PLAYBACK){if (buffer_time > 50000) buffer_time = 50000;	//50ms 这个数越小数据取的越快}period_time = buffer_time / 4;if (snd_pcm_hw_params_set_buffer_time_near(handle, hw_params, &buffer_time, 0) < 0) {fprintf(stderr, "Error snd_pcm_hw_params_set_buffer_time_near\n");return NULL;}if (snd_pcm_hw_params_set_period_time_near(handle, hw_params, &period_time, 0) < 0) {fprintf(stderr, "Error snd_pcm_hw_params_set_period_time_near\n");return NULL;}#endifif((err = snd_pcm_hw_params(handle, hw_params)) < 0) {printf("cannot set parameters (%s)\n",snd_strerror(err));return NULL;}if(period_frames != NULL) {//获取一个周期有多少帧数据if((err =snd_pcm_hw_params_get_period_size(hw_params, period_frames, &dir)) < 0){printf("cannot get period size (%s)\n",snd_strerror(err));return NULL;}}snd_pcm_hw_params_free(hw_params);return handle;
}int main(void) {int p,err;snd_pcm_t *playback_handle;snd_pcm_t *capture_handle;int pfd,cfd;snd_pcm_uframes_t period_frames;int size2frames;printf("program running ...\n");//查看所有pcm的nameprint_all_pcm_name();playback_handle = open_sound_dev(SND_PCM_STREAM_PLAYBACK,PCM_NAME,RATE,FORMAT,CHANNELS,&period_frames);if(!playback_handle) {printf("cannot open for playback\n");return -1;}usleep(5);capture_handle = open_sound_dev(SND_PCM_STREAM_CAPTURE,PCM_NAME,RATE,FORMAT,CHANNELS,NULL);if(!capture_handle) {printf("cannot open for capuure\n");snd_pcm_close(playback_handle);return -1;}if((err = snd_pcm_prepare(playback_handle)) < 0) {printf("cannot prepare audio interface for use (%s)\n",snd_strerror(err));goto out;}if((err = snd_pcm_prepare(capture_handle)) < 0) {printf("cannot prepare audio interface for use (%s)\n",snd_strerror(err));goto out;}//打开要播放的PCM文件pfd = open(PLAYBACK_FILE,O_RDONLY,0644);if(pfd < 0){printf("open %s error!!!\n",PLAYBACK_FILE);goto out;}//新建一个进程, 子进程播放, 父进程录音p = fork();if(p < 0) {printf("fork error!!!\n");goto out;}if(p==0) {char *pbuf;int size,period_bytes;period_bytes = snd_pcm_frames_to_bytes(playback_handle,period_frames);pbuf = malloc(period_bytes);int i = 0;for(; i<100; i++){printf("[%s %d]times = %d\n",__FILE__,__LINE__,i);lseek(pfd, 0, SEEK_SET);while( size = read(pfd, pbuf, period_bytes)) {//解决最后一个周期数据问题if(size < period_bytes) {memset(pbuf+size, 0, period_bytes-size);}//size2frames = snd_pcm_bytes_to_frames(playback_handle,size);size2frames = period_frames;//向PCM写入数据,播放err = snd_pcm_writei(playback_handle, pbuf, size2frames);if(err == -EPIPE) {snd_pcm_prepare(playback_handle);fprintf(stderr, "<<< snd_pcm_writei --> Buffer Underrun >>> \n");err = snd_pcm_writei(playback_handle, pbuf, size2frames);if(err != size2frames) {printf("write to audio interface failede err:%d (size2frames:%d)\n",err,size2frames);free(pbuf);close(pfd);exit(-1);}}else if(err != size2frames) {printf("write to audio interface failede err:%d (size2frames:%d)\n",err,size2frames);free(pbuf);close(pfd);exit(-1);}//printf("process:playback wrote %d frames\n",size2frames);usleep(100);}}free(pbuf);close(pfd);sleep(1);	//等待一下,给点时间父进程录音exit(0);}char *cbuf;const int frames_size = snd_pcm_frames_to_bytes(capture_handle,period_frames);cbuf = malloc(frames_size);memset(cbuf, 0, frames_size);//打开录音的保存文件cfd = open(CAPTURE_FINE,O_RDWR | O_TRUNC | O_CREAT,0644);if(cfd < 0){printf("open %s error!!!\n",CAPTURE_FINE);goto out;}while(waitpid(p, NULL, WNOHANG) == 0) {	//查看一下子进程是否已经退出//向PCM读一周期数据if((size2frames = snd_pcm_readi(capture_handle, cbuf, period_frames)) < 0) {printf("read from audio interface failed (%d)\n",size2frames);free(cbuf);close(cfd);goto out;}//printf("--process:capture read %d frames\n",size2frames);write(cfd,cbuf,snd_pcm_frames_to_bytes(capture_handle,size2frames));memset(cbuf,0,frames_size);usleep(100);}free(cbuf);close(cfd);out:snd_pcm_close(playback_handle);snd_pcm_close(capture_handle);printf("program finish ...\n");return 0;
}

复制上面代码保存为alsa-capture-playback.c,然后参考下面命令编译:

aarch64-mix210-linux-gcc alsa-capture-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-capture-playback

4.2 运行程序 alsa-capture-playback

首先,在开发板插入驱动,参考上面 2.2 节;

其次,复制alsa-lib交叉编译生成的 /usr/lib/alsa-lib-1.2.3.2/share/alsa/alsa.conf 文件到开发板同样的路径;

最后,复制应用程序 alsa-capture-playback 和任意 48KHZ的双通道16bit的pcm文件 48000Hz-16bit-2ch-ChengDu.pcm到开发板任一目录,执行alsa-capture-playback

顺利执行的话,可以在耳机听到播放的pcm文件声音,并且执行的目录下会生成record.pcm。我使用的pcm文件是48KHZ的双通道16bit的,点击 下载链接 可以下载,音频打开如下图:
在这里插入图片描述

在这里插入图片描述

五、总结

本篇文章介绍了在Linux开发板使用ALSA架构播放usb耳机声音的实例,包括了:编译安装ALSA驱动、交叉编译alsa-lib、实现ALSA应用层程序。
在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

相关文章:

【音视频|ALSA】SS528开发板编译Linux内核ALSA驱动、移植alsa-lib、采集与播放usb耳机声音

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…...

C/C++基础讲解(一百三十一)之经典篇(信息合并/平均分数存储)

C/C++基础讲解(一百三十一)之经典篇(信息合并/平均分数存储) 程序之美 前言 很多时候,特别是刚步入大学的学子们,对于刚刚开展的计算机课程基本上是一团迷雾,想要弄明白其中的奥秘,真的要花费一些功夫,我和大家一样都是这么啃过来的,从不知到知知,懵懂到入门,每一步…...

【ROS】使用vscode浏览navigation2源码时,提示:没有那个文件或目录

【ROS】郭老二博文之:ROS目录 1、问题描述 使用vscode浏览navigation2源码时,头文件下面有波浪线,并提示:没有那个文件或目录。比如没有:geometry_msgs/msg/polygon.h 错误信息: 无法打开源文件 “geometry_msgs/msg/polygon.h” (dependency of “nav2_controller/co…...

ARM-day9作业

main.c: #include "uart.h"#include "key_it.h"int main(){char c;char *s;uart4_init(); //串口初始化//中断初始化key_it_config();key3_it_config();//完成GPIO相关初始化all_led_init();//风扇初始化fs_init();//蜂鸣器初始化fmq_init();while(1){…...

ORA-00600: internal error code, arguments

通过rman将11g异机升级到19c时&#xff0c;应用归档时报错&#xff0c;报错如下 RMAN> recover database ; Starting recover at 2023-10-15 21:10:02 allocated channel: ORA_DISK_1 channel ORA_DISK_1: SID5776 device typeDISK starting media recovery media recove…...

C#里氏替换

在C#中&#xff0c;里氏替换原则是面向对象编程中的一个重要原则&#xff0c;它是关于继承和多态性的概念。 里氏替换原则的定义是&#xff1a;如果S是T的子类型&#xff08;或者T是S的基类型&#xff09;&#xff0c;那么程序中任意使用T类型的地方都可以替换为S类型而不会产…...

Java-使用sqlSessionTemplate实现批量更新-模拟mybatis 动态sql

环境准备&#xff08;非核心方法&#xff09; 创建表 创建表的sql(下表是基于Oracle创建的) CREATE TABLE "SYSTEM"."STUDENT" ("ID" NUMBER(10, 0),"NAME" VARCHAR2(20 BYTE),"ADDRES" CLOB,PRIMARY KEY ( …...

Eslint配置 Must use import to load ES Module(已解决)

最近在配置前端项目时&#xff0c;eslint经常会碰到各种报错&#xff08;灰常头疼~&#xff09; Syntax Error Error No ESLint configuration found.Syntax Error: Error: D:\dmq\dmq-ui.eslintrc.js: Environment key “es2021” is unknown at Array.forEach ()error in ./…...

正向代理(流量代理)

文章目录 正向代理与反向代理流量转发工具环境准备reGeorg 正向代理与反向代理 正向代理是客户端和其他所有服务器&#xff08;重点&#xff1a;所有&#xff09;的代理者 反向代理是客户端和所要代理的服务器之间的代理。 流量转发工具 需要放在拿到shell的服务器上可使用 …...

易天光通信推出100G BIDI ER光模块最新解决方案

随着数字信息时代的快速发展&#xff0c;网络通信技术的迅猛进步成为推动科技创新和产业升级的重要引擎之一。作为光通信行业的新秀&#xff0c;近期易天光通信推出了全新的100G BIDI ER1 Lite光模块和100G BIDI LR1 Lite光模块&#xff0c;助力崭新的未来网络建设。 易天光通…...

Flask框架配置celery-[1]:flask工厂模式集成使用celery,可在异步任务中使用flask应用上下文,即拿即用,无需更多配置

一、概述 1、celery框架和flask框架在运行时&#xff0c;是在不同的进程中&#xff0c;资源是独占的。 2、celery异步任务如果想使用flask中的功能&#xff0c;如orm&#xff0c;是需要在flask应用上下文管理器中执行orm操作的 3、使用celery是需要使用到中间件的&#xff0…...

合并二叉树

题目链接 合并二叉树 题目描述 注意点 如果两个节点重叠&#xff0c;那么将这两个节点的值相加作为合并后节点的新值&#xff1b;否则&#xff0c;不为 null 的节点将直接作为新二叉树的节点 解答思路 先序遍历二叉树&#xff0c;将重叠部分节点值相加作为新节点的值&…...

Sanic​——Python函数变成API的神器

今天给大家介绍一个超好用的框架&#xff0c;迅速将Python函数变成API&#xff0c;它就是最近越来越火的异步Web框架Sanic。 1. Sanic简介 Sanic 是 Python3.7 Web 服务器和 Web 框架&#xff0c;旨在提高性能。它允许使用 Python3.5 中添加的async/await语法&#xff0c;这使…...

Windows连接不上VMware,ping不通的问题

文章目录 防火墙问题Windows和虚拟机下的ip不一致导致的问题VMware Network Adapter (适配器)丢失的问题参考文档 防火墙问题 防火墙默认不会拦截ping命令&#xff0c;除非你个人设置了Linux防火墙Centos7的常用命令关闭防火墙 systemctl stop firewalld #停止Windows和虚拟机…...

24、Flink 的table api与sql之Catalogs(java api操作数据库、表)-2

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…...

【MySQL】深入了解索引的底层逻辑结构

文章目录 主键排序一. InnoDB的索引结构1. 单个page2. 多个page 二. 为什么选择B树三. 聚簇索引和非聚簇索引结束语 主键排序 我们创建一个user表&#xff0c;并乱序插入数据 mysql> create table if not exists user(-> id int primary key,-> age int not null,-&…...

Android之SpannableString使用

文章目录 前言一、效果图二、实现代码总结 前言 在开发中&#xff0c;往往有些需求是我们不愿意遇到的&#xff0c;但是也不得不处理的事情&#xff0c;比如一段文案&#xff0c;需要文案中某些文字变颜色或者点击跳转&#xff0c;所以简单写了几句代码实现&#xff0c;没什么…...

【Python】Python求均值、中值和众数

Python求均值、中值和众数 我们将讨论如何使用描述性统计数据进行数据分析&#xff0c;包括&#xff1a; 均值——一组值的平均值; 中值——当所有值按顺序排列时的中间值; 众数——最常出现的值。 以上这些都是集中趋势度量&#xff0c;每种都会产生一个值来表示一组值中的“…...

NPM 常用命令(十二)

目录 1、npm unpublish 1.1 使用语法 1.2 描述 2、npm unstar 2.1 使用语法 3、npm update 3.1 使用语法 3.2 描述 3.3 示例 插入符号依赖 波浪号依赖 低于 1.0.0 的插入符号依赖 子依赖 更新全局安装的包 4、npm version 4.1 使用语法 5、npm view 5.1 使用语…...

数据在内存中的存储(2)

文章目录 3. 浮点型在内存中的存储3.1 一个例子3.2 浮点数存储规则 3. 浮点型在内存中的存储 常见的浮点数&#xff1a; 3.14159 1E10 ------ 1.0 * 10^10 浮点数家族包括&#xff1a; float、double、long double 类型 浮点数表示的范围&#xff1a;float.h中定义 3.1 一个例…...

软件工程与计算总结(十三)详细设计中的模块化与信息隐藏

一.模块化与信息隐藏思想 1.设计质量 好的设计要着重满足以下3方面&#xff1a;可管理性、灵活性、可理解性好的设计需要侧重于间接性和可观察性——简洁性使得系统模块易于管理&#xff08;理解和分解&#xff09;、开发&#xff08;修改与调试&#xff09;和复用。实践者都…...

RF学习——器件的非线性失真分析

在大信号激励下的射频系统 在电路中,如果激励信号的幅度不可忽视,那么就会产生非线性失真。如二极管,晶体管等电路元件的特性在大信号激励下回变得非线性,输入和输出的形状不同,产生失真。 在功率放大器PA中,随着传输给负载的功率增大而迅速增大,传递功率的规格要始终考…...

SUB-1G SOC芯片DP4306F 32 位 ARM Cortex-M0+内核替代CMT2380F32

DP4306F是一款高性能低功耗的单片集成收发机&#xff0c;集成MO核MCU&#xff0c;工作频率可覆盖200MHiz^ 1000MHz。 支持230/408/433/470/868/915频段。该芯片集成了射频接收器、射频发射器、频率综合器、GFSK调制器、GFSK解调器等功能模块。通过SPI接口可以对输出功率、频道选…...

接收请求地址下载并输出文件流实现

代码: import httpxfrom datetime import datetime from io import BytesIO from fastapi.responses import StreamingResponse@router.get("/download", tags=["下载"]) async...

【iOS】——用单例类封装网络请求

文章目录 一、JSONModel1.JSONModel的简单介绍2.JSONModel的使用 二、单例类和Block传值 一、JSONModel 1.JSONModel的简单介绍 JSONModel一个第三方库&#xff0c;这个库用来将网络请求到的JSON格式的数据转化成Foundation框架下的Model类的属性&#xff0c;这样我们就可以直…...

再学Blazor——概述

简介 Blazor 是一种 .NET 前端 Web 框架&#xff0c;同时支持服务器端呈现和客户端交互性。 使用 C# 语言创建丰富的交互式 UI共享前后端应用逻辑可以生成混合桌面和移动应用受益于 .NET 的性能、可靠性和安全性需要有 HTML、CSS、JS 相关基础&#xff08;开发 UI 框架的话&a…...

Ceph运维笔记

Ceph运维笔记 一、基本操作 ceph osd tree //查看所有osd情况 其中里面的weight就是CRUSH算法要使用的weight&#xff0c;越大代表之后PG选择该osd的概率就越大 ceph -s //查看整体ceph情况 health_ok才是正常的 ceph osd out osd.1 //将osd.1踢出集群 ceph osd i…...

RTSP协议

1 前言 RTSP协议作为音视频实时监控一个非常重要的协议&#xff0c;具有非常广泛的应用。RTSP由RFC 2326规范化&#xff0c;它允许客户端通过请求不同的媒体资源来控制流媒体服务器。RTSP是一种应用层协议&#xff0c;通常基于TCP连接&#xff0c;用于建立和控制媒体会话。这使…...

Maven系列第6篇:生命周期和插件详解?

maven系列目标&#xff1a;从入门开始开始掌握一个高级开发所需要的maven技能。 这是maven系列第6篇。 整个maven系列的内容前后是有依赖的&#xff0c;如果之前没有接触过maven&#xff0c;建议从第一篇看起&#xff0c;本文尾部有maven完整系列的连接。 前面我们使用maven…...

【通义千问】大模型Qwen GitHub开源工程学习笔记(4)-- 模型的量化与离线部署

摘要: 量化方案基于AutoGPTQ,提供了Int4量化模型,其中包括Qwen-7B-Chat和Qwen-14B-Chat。更新承诺在模型评估效果几乎没有损失的情况下,降低存储要求并提高推理速度。量化是指将模型权重和激活的精度降低以节省存储空间并提高推理速度的过程。AutoGPTQ是一种专有量化工具。…...

手机游戏排行榜2020前十名/百度seo如何优化

http://www.cnblogs.com/85538649/archive/2011/12/05/2276901.html转载于:https://blog.51cto.com/5828666/1622841...

php网站开发说明文档/爱链网中可以进行链接买卖

8个动态数码管时钟显示#include#define uint unsigned int#define uchar unsigned charuchar i,temp,aa,miao,fen,shi,play0;/************************************************定义3个键&#xff0c;K1用于调节分&#xff0c;K2用于调节时&#xff0c;K3用于调节时**********…...

怎样做软件网站建设/精准营销推广

自从经朋友介绍PerfDog这款移动端测试神器后就一直在使用它测试大型游戏的流程度&#xff0c;前两天使用腾讯视频追剧分享到微信时发现发现的链接直接进入腾讯视频的小程序中&#xff0c;试了多个视频软件皆是如此&#xff0c;于是想要试试用PerfDog测试一下各家视频小程序实际…...

php做动态网站/seo搜索引擎优化技术

SQL Server 数据库启动过程&#xff0c;以及启动不起来的各种问题的分析及解决技巧参考文章&#xff1a; &#xff08;1&#xff09;SQL Server 数据库启动过程&#xff0c;以及启动不起来的各种问题的分析及解决技巧 &#xff08;2&#xff09;https://www.cnblogs.com/VicL…...

如何在宝塔中安装wordpress/北京网站建设公司哪家好

Runnable的缺陷 不能返回一个返回值也不能抛出checked Exception&#xff0c;只能trycatch Callable接口 类似于 Runnable&#xff0c;被其他线程执行的任务实现call方法有返回值 Future类 在并发编程中&#xff0c;我们经常用到非阻塞的模型&#xff0c;在之前的多线程的三…...

建设购物网站需要多少费用/企业全网推广公司

MySQL 保存 Boolean 值时&#xff0c;用 1 代表 TRUE&#xff0c;0 代表 FALSE&#xff1b;类似一个 bit 位&#xff0c;默认没有数据&#xff0c;即为 0&#xff0c;也即 Faslse MySQL 存储 Boolean 值的类型为 tinyint(1) 类型&#xff1b;MySQL 中有 true、false、TRUE、FAL…...