Linux驅動開發之音頻驅動與基礎應用編程

目錄

CODEC芯片

音頻編碼

I2S總線接口

數字音頻接口(DAI)

設備樹配置

ALSA

音頻相關概念

應用程序編寫

運行測試

CODEC芯片

音頻若想被CPU“聽到”,就必須轉換為CPU能夠“聽懂”的語言,即二進制數據的0和1。在信號處理領域,聲音是模擬信號而二進制數據是數字信號,因此需要一個將模擬信號轉化為數字信號的器件,而完成這個功能的就是ADC芯片。同理,CPU若想向外傳達聲音,就需要將數字信號轉化為模擬信號,而完成這個功能的則是 DAC 芯片。將ADC和DAC芯片以及一系列其他單元疊加到一起就形成了專門用于音頻處理的芯片,即音頻編解碼芯片(Audio CODEC),如ES8388,ES7202和rt5640等。不同CODEC芯片支持的錄音/放音功能有所不同,其對應的引腳接口也會不同,但總體上CODEC對外接口可分為控制接口和數據接口兩大部分,一般對應I2C和I2S。榮品RK3588開發板上使用的是rt5640,其原理圖對應部分如下:

可以看出該CODEC通過AUDIO_SCL和AUDIO_SDA與CPU的I2C相連,通過I2C對其進行配置,并通過I2S接口進行數據傳輸。具有兩路輸入,兩路揚聲器輸出以及一路耳機輸出。

音頻編碼

音頻編碼一般采用脈沖編碼調制(PCM)的方法,PCM是Pulse Code Modulation的縮寫,該編碼方法是對語音信號進行采樣,然后對每個采樣值進行量化編碼,我們所熟知的CD音頻即是使用PCM編碼。使用PCM編碼的音頻文件在windows下的保存格式也是我們所熟知的WAV格式。

在PCM基礎上發展起來的還有自適應差分脈沖編碼調制ADPCM,其編碼的方法是對輸入樣值進行自適應預測,然后對預測誤差進行量化編碼。除此之外,其他編碼方式還有線性預測編碼LPC,低延遲碼激勵線性預測編碼LD-CELP等。而除了WAV格式,還有MP3,WMA和RAW等編碼格式。

I2S總線接口

I2S(Inter-IC Sound)總線有時候也寫作IIS,是飛利浦公司提出的一種用于數字音頻設備之間進行音頻數據傳輸的總線。和I2C、SPI這些常見的通信協議一樣,I2S總線用于主控制器和音頻CODEC芯片之間傳輸音頻數據。因此,要想使用I2S協議,主控制器和音頻CODEC 都得支持I2S協議。作為一種數字音頻設備之間進行音頻數據傳輸的總線標準,I2S一般有3~5根物理連接線:

  • SCK:串行時鐘信號,為串行數據提供位時鐘(BCLK),音頻數據的每一位數據都對應一個SCK,而立體聲都是雙聲道的,因此 SCK=2×采樣率×采樣位數。
  • WS:字段(聲道)選擇信號,也叫做LRCK,用于切換左右聲道數據幀,WS為“1”表示正在傳輸左聲道的數據,WS為“0”表示正在傳輸右聲道的數據,其頻率等于采樣率。
  • SD:串行數據信號,也就是實際傳輸的音頻數據,如果要同時實現放音和錄音,那么就需要2根數據線IISDI和IISDO,分別用于錄音和放音。
  • MCLK:為了使音頻 CODEC 芯片與主控制器之間能夠更好的同步而引入的信號,也叫做同步時鐘或編碼器時鐘,一般是采樣率的256倍或384倍。

數據的發送方和接收方需要有一個時鐘信號來控制數據的傳輸,因此數據發送方(主設備)必須提供字段選擇信號、時鐘信號和數據信號。當有多個發送方和接收方,系統需引入控制模塊,用于控制數字音頻數據在不同設備之間的傳輸。傳輸模式示意圖如下:

I2S總線協議也即音頻數據時序圖如下:

隨著技術的發展,在統一的I2S接口下,出現了不同的數據格式,根據音頻數據相對于LRCK 和SCK位置的不同,可分為LeftJustified(左對齊)和 RightJustified(右對齊)兩種格式

數字音頻接口(DAI)

音頻CODEC支持I2S協議,那么主控制器也必須支持I2S協議,而主控制器則是通過音頻接口來連接CODEC,這個接口在RK平臺上的外設則為數字音頻接口(DAI)。RK平臺有兩種I2S控制器:I2S和I2S-TDM。I2S控制器支持I2S, PCM協議;I2S-TDM控制器支持 I2S,PCM, TDM 協議。除此之外,RK平臺還具有PDM控制器,支持PDM協議的數字麥或者ADC;支持數字CODEC接口,可對接支持該協議的模擬CODEC組合成完整CODEC;支持語音活性檢測 (Voice Activity Detection),VAD接收來自DAI的數據,處理統計分析,達到預設閾值時,觸發中斷,喚醒系統;還支持支持 SPDIF Transmitter 接口協議等。并且RK 平臺支持任意 DAI 的組合使用,重組 DAI 生成 Combo DAI,如下圖所示:

一般來說,RK發布的SDK中已經完成了DAI驅動的編寫,開發者只需要根據應用場景配置屬性啟用相應功能即可。相關驅動文件基本都在目錄kernel/sound/soc/rockchip下。而machine驅動部分主要涉及聲卡的添加,其中Simple Card是ASoC通用的machine driver,可支持大部分標準聲卡的添加。

設備樹配置

榮品RK3588開發板上使用的是rt5640,其相關設備樹配置如下:

/ {rt5640-sound {compatible = "simple-audio-card";simple-audio-card,format = "i2s";simple-audio-card,name = "rockchip,rt5640-codec";simple-audio-card,mclk-fs = <256>;simple-audio-card,widgets ="Microphone", "Mic Jack","Headphone", "Headphone Jack";simple-audio-card,routing ="Mic Jack", "MICBIAS1","IN1P", "Mic Jack","Headphone Jack", "HPOL","Headphone Jack", "HPOR";simple-audio-card,cpu {sound-dai = <&i2s0_8ch>;};simple-audio-card,codec {sound-dai = <&rt5640>;};};rk_headset: rk-headset {status = "okay";compatible = "rockchip_headset";headset_gpio = <&gpio1 RK_PC4 GPIO_ACTIVE_HIGH>;pinctrl-names = "default";pinctrl-0 = <&hp_det>;};
};&i2s0_8ch {status = "okay";
};&i2c7 {status = "okay";pinctrl-names = "default";pinctrl-0 = <&i2c7m0_xfer>;rt5640: rt5640@1c {#sound-dai-cells = <0>;compatible = "realtek,rt5640";reg = <0x1c>;clocks = <&mclkout_i2s0>;clock-names = "mclk";realtek,in1-differential;pinctrl-names = "default";pinctrl-0 = <&i2s0_mclk>;io-channels = <&saradc 4>;hp-det-adc-value = <500>;spk-play-volume = <7>;       63-0 min-maxhp-play-volume = <15>;       63-0 min-maxcapture-volume = <127>; //0-127 min-max};
};&pinctrl {rt5640_pinctrl {hp_det:hp_det {rockchip,pins = <1 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;};};
};

結合原理圖可知rt5640掛載在i2c7下,也即其codec節點添加在i2c7節點之下。驅動文件在目錄kernel/sound/soc/codecs下,為rt5640.c,該驅動文件為廠家所編寫,一般直接移植即可。在rt5640該codec節點添加完成后,需添加并使能sound節點,這里為sound-rt5640節點,其與Simple Card該通用machine driver相配對。最后根據硬件連接情況使能對應的i2s節點,這里為i2s0,與原理圖一致。其余配置為開發板針對耳機的相關節點配置以及耳機插入檢測所需的gpio資源配置等,在驅動中實現耳機插入檢測后從揚聲器切換為耳機的功能。最后通過圖形化配置界面使能相關配置,如I2S,新添加的rt5640驅動等。

重新編譯并燒寫內核,使用cat /proc/asound/cards命令查看系統聲卡,確認驅動是否移植成功。

ALSA

ALSA是Advanced Linux Sound Architecture(高級的 Linux 聲音體系)的縮寫,目前已經成為了linux下的主流音頻體系架構,采用分離、分層思想設計,提供了音頻和MIDI的支持,替代了原先舊版本中的OSS(開發聲音系統)。在應用層,ALSA提供了一套標準的API,應用程序只需要調用這些API就可完成對底層音頻硬件設備的控制,如播放、錄音等,這一套 API稱為alsa-lib,關系示意圖如下。在Linux內核設備驅動層,基于ALSA音頻驅動框架注冊的sound設備會在/dev/snd 目錄下生成相應的設備節點文件。

由于alsa-lib是ALSA提供的一套在Linux下的C語言函數庫,因此需要將alsa-lib交叉編譯移植到開發板上,這樣基于alsa-lib編寫的應用程序才能成功運行。除了移植alsa-lib庫之外,通常還需要移植alsa-utils,alsa-utils包含了一些用于測試、配置聲卡的命令和工具,譬如aplay、arecord、alsactl、alsaloop、alsamixer、amixer等。其中,aplay命令用于播放.wav格式的音頻文件;arecord命令用于錄音測試,其生成.wav格式的音頻文件;alsaloop命令用于回環測試,可實現邊錄音邊播放;alsamixer和amixer用于配置聲卡的混音器,區別在于前者是圖形化界面后者是命令行形式;alsactl則用來保存對聲卡的配置。在ALSA官網有這些工具的詳細介紹及大量資料參考。

音頻相關概念

基于alsa-lib的應用編程中會涉及一系列音頻相關概念,如樣本長度,聲道數和采樣率等。

  • 樣本(sample)是記錄音頻數據最基本的單元,樣本長度就是采樣位數,也稱為位深度(Bit Depth、Sample Size、Sample Width)。指計算機在采集和播放聲音文件時,所使用數字聲音信號的二進制位數,或者說每個采樣樣本所包含的位數(計算機對每個通道采樣量化時數字比特位數),通常有8bit、16bit、24bit等。
  • 聲道數(channel)分為單聲道(Mono)和雙聲道/立體聲(Stereo)1 表示單聲道、2 表示立體聲。
  • 幀(frame)表示一個聲音單元,其長度為樣本長度與聲道數的乘積,一段音頻數據就是由苦干幀組成的。把所有聲道中的數據加在一起叫做一幀,對于單聲道:一幀 = 樣本長度 * 1;雙聲道:一幀 = 樣本長度 * 2。譬如對于樣本長度為 16bit 的雙聲道來說,一幀的大小等于:16 * 2 / 8 = 4 個字節。
  • 采樣率(sample rate)指每秒鐘采樣次數,該次數是針對而言。常見的采樣率有:8KHz,44.1KHz等。
  • 交錯模式(interleaved)是一種音頻數據的記錄方式,分為交錯模式和非交錯模式。在交錯模式下,數據以連續楨的形式存放,即首先記錄完楨 1 的左聲道樣本和右聲道樣本(假設為立體聲格式),再記錄楨 2 的左聲道樣本和右聲道樣本。而在非交錯模式下,首先記錄的是一個周期內所有楨的左聲道樣本,再記錄右聲道樣本,數據是以連續通道的方式存儲。多數情況下都是使用交錯模式。
  • 周期(period)是音頻設備處理(讀、寫)數據的單位,每一次讀或寫一個周期的數據,一個周期包含若干個幀;譬如周期的大小為 1024 幀,則表示音頻設備進行一次讀或寫操作的數據量大小為 1024 幀,假設一幀為 4 個字節,那么也就是 1024*4=4096 個字節數據。一個周期其實就是兩次硬件中斷之間的幀數,音頻設備每處理(讀或寫)完一個周期的數據就會產生一個中斷,所以兩個中斷之間相差一個周期
  • 數據緩沖區(buffer),一個緩沖區包含若干個周期,所以buffer是由若干個周期所組成的一塊空間。

它們之間的關系如下:

音頻設備底層驅動程序使用DMA來搬運數據,buffer中有4個period,每當DMA搬運完一個period的數據就會觸發一次中斷,因此搬運整個buffer中的數據將產生4次中斷。為了延遲問題,ALSA把緩存區拆分成多個周期,以周期為傳輸單元進行傳輸數據。所以,周期不宜設置過大,周期過大會導致延遲過高;但周期也不能太小,周期太小會導致頻繁觸發中斷,這樣會使得CPU被頻繁中斷而無法執行其它的任務,使得效率降低。

應用程序編寫

基于alsa-lib編寫簡單的音頻播放程序,通過WAV音頻文件相關數據結構實現對音頻文件的信息解析并進行打印顯示。

#include?<stdio.h>
#include?<stdlib.h>
#include?<errno.h>
#include?<string.h>
#include?<alsa/asoundlib.h>#define?PCM_PLAYBACK_DEV?"hw:0,0"//WAV?音頻文件解析相關數據結構申明typedef?struct?WAV_RIFF?{char?ChunkID[4];?/*?"RIFF"?*/u_int32_t?ChunkSize;?/*?從下一個地址開始到文件末尾的總字節數?*/char?Format[4];?/*?"WAVE"?*/
}?__attribute__?((packed))?RIFF_t;typedef?struct?WAV_FMT?{char?Subchunk1ID[4];?/*?"fmt?"?*/u_int32_t?Subchunk1Size;?/*?16?for?PCM?*/u_int16_t?AudioFormat;?/*?PCM?=?1*/u_int16_t?NumChannels;?/*?Mono?=?1,?Stereo?=?2,?etc.?*/u_int32_t?SampleRate;?/*?8000,?44100,?etc.?*/u_int32_t?ByteRate;?/*?=?SampleRate?*?NumChannels?*?BitsPerSample/8?*/u_int16_t?BlockAlign;?/*?=?NumChannels?*?BitsPerSample/8?*/u_int16_t?BitsPerSample;?/*?8bits,?16bits,?etc.?*/
}?__attribute__?((packed))?FMT_t;static?FMT_t?wav_fmt;typedef?struct?WAV_DATA?{char?Subchunk2ID[4];?/*?"data"?*/u_int32_t?Subchunk2Size;?/*?data?size?*/
}?__attribute__?((packed))?DATA_t;static?snd_pcm_t?*pcm?=?NULL;?//pcm?句柄
static?unsigned?int?buf_bytes;?//應用程序緩沖區的大小(字節為單位)
static?void?*buf?=?NULL;?//指向應用程序緩沖區的指針
static?int?fd?=?-1;?//指向?WAV?音頻文件的文件描述符
static?snd_pcm_uframes_t?period_size?=?1024;?//周期大小(單位:?幀)
static?unsigned?int?periods?=?16;?//周期數(設備驅動層?buffer?的大小)static?int?snd_pcm_init(void)
{snd_pcm_hw_params_t?*hwparams?=?NULL;int?ret;/*?打開?PCM?設備?*/ret?=?snd_pcm_open(&pcm,?PCM_PLAYBACK_DEV,?SND_PCM_STREAM_PLAYBACK,?0);if?(0?>?ret)?{fprintf(stderr,?"snd_pcm_open?error:?%s:?%s\n",PCM_PLAYBACK_DEV,?snd_strerror(ret));return?-1;}/*?申請hwparams */snd_pcm_hw_params_malloc(&hwparams);/*?初始化hwparams?*/ret?=?snd_pcm_hw_params_any(pcm,?hwparams);if?(0?>?ret)?{fprintf(stderr,?"snd_pcm_hw_params_any?error:?%s\n",?snd_strerror(ret));goto?err2;}/*?設交錯模式?*/ret?=?snd_pcm_hw_params_set_access(pcm,?hwparams,?SND_PCM_ACCESS_RW_INTERLEAVED);if?(0?>?ret)?{fprintf(stderr,?"snd_pcm_hw_params_set_access?error:?%s\n",?snd_strerror(ret));goto?err2;}/*?設置數據格式:?有符號?16?位、小端模式?*/ret?=?snd_pcm_hw_params_set_format(pcm,?hwparams,?SND_PCM_FORMAT_S16_LE);if?(0?>?ret)?{fprintf(stderr,?"snd_pcm_hw_params_set_format?error:?%s\n",?snd_strerror(ret));goto?err2;}/*?設置采樣率?*/ret?=?snd_pcm_hw_params_set_rate(pcm,?hwparams,?wav_fmt.SampleRate,?0);if?(0?>?ret)?{fprintf(stderr,?"snd_pcm_hw_params_set_rate?error:?%s\n",?snd_strerror(ret));goto?err2;}/*?設置聲道數:?雙聲道?*/ret?=?snd_pcm_hw_params_set_channels(pcm,?hwparams,?wav_fmt.NumChannels);if?(0?>?ret)?{fprintf(stderr,?"snd_pcm_hw_params_set_channels?error:?%s\n",?snd_strerror(ret));goto?err2;}/*?設置周期大小?*/ret?=?snd_pcm_hw_params_set_period_size(pcm,?hwparams,?period_size,?0);if?(0?>?ret)?{fprintf(stderr,?"snd_pcm_hw_params_set_period_size?error:?%s\n",?snd_strerror(ret));goto?err2;}/*?設置周期數(驅動層?buffer?的大小)?*/ret?=?snd_pcm_hw_params_set_periods(pcm,?hwparams,?periods,?0);if?(0?>?ret)?{fprintf(stderr,?"snd_pcm_hw_params_set_periods?error:?%s\n",?snd_strerror(ret));goto?err2;}/*?使配置生效?*/ret?=?snd_pcm_hw_params(pcm,?hwparams);snd_pcm_hw_params_free(hwparams);?//釋放?hwparams?對象占用的內存if?(0?>?ret)?{fprintf(stderr,?"snd_pcm_hw_params?error:?%s\n",?snd_strerror(ret));goto?err1;}buf_bytes?=?period_size?*?wav_fmt.BlockAlign;?//變量賦值,一個周期的字節大小return?0;
err2:snd_pcm_hw_params_free(hwparams);?//釋放內存
err1:snd_pcm_close(pcm);?//關閉?pcm?設備return?-1;
}
static?int?open_wav_file(const?char?*file)
{RIFF_t?wav_riff;DATA_t?wav_data;int?ret;fd?=?open(file,?O_RDONLY);if?(0?>?fd)?{fprintf(stderr,?"open?error:?%s:?%s\n",?file,?strerror(errno));return?-1;}/*?讀取?RIFF?chunk?*/ret?=?read(fd,?&wav_riff,?sizeof(RIFF_t));if?(sizeof(RIFF_t)?!=?ret)?{if?(0?>?ret)perror("read?error");elsefprintf(stderr,?"check?error:?%s\n",?file);close(fd);return?-1;}if?(strncmp("RIFF",?wav_riff.ChunkID,?4)?||//校驗strncmp("WAVE",?wav_riff.Format,?4))?{fprintf(stderr,?"check?error:?%s\n",?file);close(fd);return?-1;}/*?讀取?sub-chunk-fmt?*/ret?=?read(fd,?&wav_fmt,?sizeof(FMT_t));if?(sizeof(FMT_t)?!=?ret)?{if?(0?>?ret)perror("read?error");elsefprintf(stderr,?"check?error:?%s\n",?file);close(fd);return?-1;}if?(strncmp("fmt?",?wav_fmt.Subchunk1ID,?4))?{//校驗fprintf(stderr,?"check?error:?%s\n",?file);close(fd);return?-1;}/*?打印音頻文件的信息?*/printf("<<<<音頻文件格式信息>>>>\n\n");printf("?file?name:?%s\n",?file);printf("?Subchunk1Size:?%u\n",?wav_fmt.Subchunk1Size);printf("?AudioFormat:?%u\n",?wav_fmt.AudioFormat);printf("?NumChannels:?%u\n",?wav_fmt.NumChannels);printf("?SampleRate:?%u\n",?wav_fmt.SampleRate);printf("?ByteRate:?%u\n",?wav_fmt.ByteRate);printf("?BlockAlign:?%u\n",?wav_fmt.BlockAlign);printf("?BitsPerSample:?%u\n\n",?wav_fmt.BitsPerSample);/*?sub-chunk-data?*/if?(0?>?lseek(fd,?sizeof(RIFF_t)?+?8?+?wav_fmt.Subchunk1Size,SEEK_SET))?{perror("lseek?error");close(fd);return?-1;}while(sizeof(DATA_t)?==?read(fd,?&wav_data,?sizeof(DATA_t)))?{/*?找到?sub-chunk-data?*/if?(!strncmp("data",?wav_data.Subchunk2ID,?4))//校驗return?0;if?(0?>?lseek(fd,?wav_data.Subchunk2Size,?SEEK_CUR))?{perror("lseek?error");close(fd);return?-1;}}fprintf(stderr,?"check?error:?%s\n",?file);return?-1;
}int?main(int?argc,?char?*argv[])
{int?ret;if?(2?!=?argc)?{fprintf(stderr,?"Usage:?%s?<audio_file>\n",?argv[0]);exit(EXIT_FAILURE);}/*?打開?WAV?音頻文件?*/if?(open_wav_file(argv[1]))exit(EXIT_FAILURE);/*?初始化?PCM?Playback?設備?*/if?(snd_pcm_init())goto?err1;/*?申請讀緩沖區?*/buf?=?malloc(buf_bytes);if?(NULL?==?buf)?{perror("malloc?error");goto?err2;}/*?播放?*/for?(?;?;?)?{memset(buf,?0x00,?buf_bytes);?ret?=?read(fd,?buf,?buf_bytes);?if?(0?>=?ret)?goto?err3;ret?=?snd_pcm_writei(pcm,?buf,?period_size);if?(0?>?ret)?{fprintf(stderr,?"snd_pcm_writei?error:?%s\n",?snd_strerror(ret));goto?err3;}else?if?(ret?<?period_size)?{if?(0?>?lseek(fd,?(ret-period_size)?*?wav_fmt.BlockAlign,?SEEK_CUR))?{perror("lseek?error");goto?err3;}}}
err3:free(buf);?
err2:snd_pcm_close(pcm);?
err1:close(fd);?exit(EXIT_FAILURE);
}

運行測試

這里采用龍芯2K0300久久派開發板進行測試,同時也是驗證只要開發板移植了alsa-lib就能運行基于alsa-lib所編寫的音頻應用程序。交叉編譯得到pcm_playback,拷入開發板運行播放音頻文件,插入耳機能聽到聲音,并將程序運行的打印信息與文件信息作對比。

總結:本篇詳細介紹了音頻驅動相關概念,RK平臺音頻相關配置以及ALSA編程相關概念等,最后基于alsa-lib編寫了簡單的音頻播放程序并在開發板上進行了驗證。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/70525.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/70525.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/70525.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在 Java 中解析 JSON 數據

例子解析以下JSON數據 {"code":0,"msg":"成功","data": [{ "host":"1068222.com", "port":"", "m_token":"490e20e70e7de5f21a24b14c12a393f6", "categ…

python——集合(一)

文章目錄 集合 set創建集合訪問集合項in關鍵字添加集合元素刪除集合元素復制集合使用操作符對集合進行交集、并集、差集、對稱差集使用方法對集合進行交集、并集、差集、對稱差集子集和超集 frozenset 凍結集合&#xff1f; 不可變集合&#xff01; 集合 set 什么是集合&#…

DeepSeek 與網絡安全:AI 在網絡安全領域的應用與挑戰

&#x1f4dd;個人主頁&#x1f339;&#xff1a;一ge科研小菜雞-CSDN博客 &#x1f339;&#x1f339;期待您的關注 &#x1f339;&#x1f339; 1. 引言 在當今數字化時代&#xff0c;網絡安全已成為國家、企業和個人面臨的重要挑戰。從傳統的病毒、木馬攻擊&#xff0c;到高…

【Blender】二、建模篇--05,陣列修改器與晶格形變

陣列修改器是bender里面一個比較常用的修改器,所以我們單獨開口來講,我們會先從幾片樹葉出發,然后我們用陣列修改器把這幾片樹葉變成這樣的造型和這樣的造型。這兩個造型分別就代表著陣列修改器最常用的兩種偏移方法,我們現在就開始我們先來做幾個樹葉。 1.樹葉建模 首先…

【Python 專題】數據結構 樹

LeetCode 題目104. 二叉樹的最大深度(gif 圖解)方法一:后序遍歷(DFS)方法二:層序遍歷(BFS)872. 葉子相似的樹(DFS 遍歷)1448. 統計二叉樹中好節點的數目(DFS 遍歷)437. 路徑總和 III(前綴和 + DFS 回溯)1372. 二叉樹中的最長交錯路徑(DFS)236. 二叉樹的最近公共…

Linux下基本指令(4)

Linux權限的概念 Linux下有兩種用戶&#xff1a;超級用戶&#xff08;root&#xff09;、普通用戶。 超級用戶&#xff1a;可以再linux系統下做任何事情&#xff0c;不受限制 普通用戶&#xff1a;在linux下做有限的事情。 超級用戶的命令提示符是“#”&#xff0c;普通用戶…

ubuntu部署小筆記-采坑

ubuntu部署小筆記 搭建前端控制端后端前端nginx反向代理使用ubuntu部署nextjs項目問題一 如何訪問端口號配置后臺運行該進程pm2 問題二 包體過大生產環境下所需文件 問題三 部署在vercel時出現的問題需要魔法訪問后端api時&#xff0c;必須使用https協議電腦端訪問正常&#xf…

【聯盛德 W803-Pico 試用】簡介、工程測試

【聯盛德 W803-Pico 試用】簡介、工程測試 本文介紹了聯盛德微電子 W803-Pico 開發板的基本信息、環境搭建、工程測試等內容。簡介包含開發板功能、主控參數及特點、開發板原理圖等信息&#xff0c;工程測試包括 Blink、串口打印等方案的演示。 活動詳情&#xff1a;聯盛德問答…

cursor使用記錄

一、如何查看自己登錄的是哪個賬號 操作路徑&#xff1a;Cursor -- 首選項 -- Cursor Setting &#xff08;有快捷鍵&#xff09; 二、狀態修改為豎排&#xff08;默認是橫排&#xff09; 默認如圖展示&#xff0c;想要像vscode、idea等等在左側豎著展示 操作路徑&#xff1…

gitlab 解決雙重認證無法登錄remote: HTTP Basic: Access denied.

問題&#xff1a;gitlab開啟了雙因素認證 如進行了 OAuth configuration 在進行git操作時如下提示 remote: HTTP Basic: Access denied. The provided password or token is incorrect or your account has 2FA enabled and you must use a personal access token instead o…

C語言基礎學習指南:從零入門到實戰應用——適合零基礎學習者與進階鞏固

目錄 一、C語言概述與開發環境搭建 二、核心語法與數據類型 三、控制結構與運算符 四、函數與模塊化編程 五、指針與內存管理 六、實踐建議與資源推薦 結語 一、C語言概述與開發環境搭建 C語言是一種高效、靈活的通用編程語言&#xff0c;廣泛應用于系統開發、嵌入式系…

C# 委托——lambda

lambda表達式不簡化寫起來和匿名函數很像&#xff0c;而匿名函數通常賦值給委托&#xff0c;通過委托進行調用。以下我們對lambda和委托的基本規則與使用進行整理&#xff0c;同時為了加深理解和記憶&#xff0c;我們整理了委托是如何一步步演化到lambda。 1. 委托 委托是一個…

【每日論文】TESS 2: A Large-Scale Generalist Diffusion Language Model

下載PDF或閱讀論文&#xff0c;請點擊&#xff1a;LlamaFactory - huggingface daily paper - 每日論文解讀 | LlamaFactory | LlamaFactory 摘要 我們推出了TESS 2&#xff0c;這是一種通用的指令跟隨擴散語言模型&#xff0c;其性能優于當代的指令調整擴散模型&#xff0c;有…

conda 配置源

無論是Anaconda vs Miniconda vs Miniforge 中的哪個&#xff0c;只要使用conda就涉及源&#xff0c;換源的目的是為了加速包的獲取 修改配置文件 通過修改用戶目錄下的 .condarc 文件來使用 不同系統下的 .condarc 目錄如下&#xff1a; Linux: ${HOME}/.condarcmacOS: ${…

AI大模型發展對語音直播交友系統源碼開發搭建的影響

近年來&#xff0c;AI大模型技術突飛猛進&#xff0c;為語音直播交友系統的源碼開發搭建帶來了深遠影響。本文將從技術發展層面&#xff0c;探討AI大模型如何賦能語音直播交友系統&#xff0c;并分析其對開發流程、功能實現和用戶體驗等方面帶來的變革。 一、技術賦能&#xff…

C++面試題,TCP和UDP方面(1)

個人主頁 &#xff1a; 個人主頁 個人專欄 &#xff1a; 《數據結構》 《C語言》《C》《Linux》《網絡》 《redis學習筆記》 文章目錄 前言TCP和UDP的區別UDP如何實現可靠TCP滑動窗口原理TCP流量控制TCP超時重傳總結 前言 這是個人總結的C方向的面試題,TCP和UDP方面&#xff0…

Huatuo熱更新--如何使用

在安裝完huatuo熱更新插件后就要開始學習如何使用了。 1.創建主框漸Main 新建文件夾Main&#xff08;可自定義&#xff09;&#xff0c;然后按下圖創建文件&#xff0c;注意名稱與文件夾名稱保持一致 然后新建場景&#xff08;Init場景&#xff09;&#xff0c;添加3個空物體…

Springboot + Ollama + IDEA + DeepSeek 搭建本地deepseek簡單調用示例

1. 版本說明 springboot 版本 3.3.8 Java 版本 17 spring-ai 版本 1.0.0-M5 deepseek 模型 deepseek-r1:7b 需要注意一下Ollama的使用版本&#xff1a; 2. springboot項目搭建 可以集成在自己的項目里&#xff0c;也可以到 spring.io 生成一個項目 生成的話&#xff0c;如下…

如何在 macOS 上配置 MySQL 環境變量

如何在 macOS 上配置 MySQL 環境變量 步驟 1: 查找 MySQL 安裝路徑 打開終端&#xff0c;使用以下命令查找 mysql 的可執行文件路徑&#xff1a; which mysql如果該命令沒有返回結果&#xff0c;可以使用 find 命令&#xff1a; sudo find / -name "mysql" 2>/de…

Unity Excel導表工具轉Lua文件

思路介紹 借助EPPlus讀取Excel文件中的配置數據&#xff0c;根據指定的不同類型的數據配置規則來解析成對應的代碼文本&#xff0c;將解析出的字符串內容寫入到XXX.lua.txt文件中即可 EPPlus常用API //命名空間 using OfficeOpenXml;//Excel文件路徑 var fileExcel new File…