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

STM32 SAI 通讯原理与 TDM 应用

一、SAI 通讯原理基础

1.1 SAI 概述

SAI(Serial Audio Interface)串行音频接口是 STM32 系列单片机中专门为音频和高精度传感器应用设计的高性能外设。它提供了两个完全独立的音频子块 (SAI_A 和 SAI_B),每个子块都可以独立配置为主机或从机,支持全双工通信。

SAI 相比传统 I2S 接口的核心优势:

  • 支持TDM 时分复用模式,最多可连接 16 个设备
  • 更灵活的帧和时隙配置
  • 支持 8/10/16/20/24/32 位数据宽度
  • 内置 FIFO 缓冲区 (8 个 32 位字)
  • 支持 DMA 传输,减轻 CPU 负担

1.2 SAI 核心架构

每个 SAI 子块包含以下关键组件:

  • 时钟生成单元:产生串行时钟 (SCK) 和帧同步信号 (FS)
  • 帧同步单元:生成和检测帧同步信号
  • 数据串行化 / 反串行化单元:并行数据与串行数据转换
  • FIFO 缓冲区:8 个 32 位深度,用于数据缓存
  • DMA 接口:支持高速数据传输
  • 中断控制器:提供多种中断源

1.3 SAI 工作模式详解

SAI 支持五种主要工作模式:

模式描述典型应用
Free 协议模式最灵活的模式,可配置为任何自定义协议TDM 接口传感器、自定义音频协议
I2S 模式标准 I2S 协议,支持 Philips、MSB、LSB 对齐立体声麦克风、音频编解码器
PCM 模式脉冲编码调制模式,支持短帧和长帧单声道麦克风、电话系统
AC'97 模式音频编解码器接口传统音频 Codec
SPDIF 模式索尼 / 飞利浦数字接口数字音频传输

1.4 TDM 模式核心原理

TDM(Time Division Multiplexing)时分复用模式是 SAI 最强大的功能,它允许在同一根串行数据线上传输多个通道的数据

TDM 工作机制

  1. 数据传输以帧 (Frame)为单位
  2. 每个帧包含多个时隙 (Slot)
  3. 每个时隙对应一个物理设备 (传感器 / 麦克风)
  4. 帧同步信号 (FS) 在每个帧开始时触发
  5. 数据在串行时钟 (SCK) 的边沿被采样
  6. 每个设备只在自己的时隙内发送 / 接收数据

TDM 关键参数

  • 帧长度 (FRL):一个帧包含的总位数
  • 时隙数量 (NBSLOT):一个帧包含的时隙数 (最多 16 个)
  • 时隙大小 (SLOTSZ):每个时隙的位数 (8/16/32 位)
  • 帧同步活动长度 (FSALL):FS 信号有效持续的位数
  • 帧同步偏移 (FSOFF):FS 信号与第一个数据位的偏移量

二、SAI 关键寄存器详解

2.1 全局配置寄存器 (SAI_GCR)

地址偏移: 0x00 复位值: 0x00000000
  • SYNCOUT[1:0](位 1-0): 同步输出选择
    • 00: 无同步输出
    • 01: SAI_A 作为同步主
    • 10: SAI_B 作为同步主
  • SYNCIN[1:0](位 3-2): 同步输入选择
    • 00: 无同步输入
    • 01: 同步于 SAI_A
    • 10: 同步于 SAI_B

2.2 子块配置寄存器 1 (SAI_xCR1)

地址偏移: 0x04 + 0x0400 * x (x=A/B) 复位值: 0x00000040
  • MODE[1:0](位 1-0): 模式选择
    • 00: 主发送器 (Master Transmitter)
    • 01: 主接收器 (Master Receiver)
    • 10: 从发送器 (Slave Transmitter)
    • 11: 从接收器 (Slave Receiver)
  • PRTCFG[1:0](位 3-2): 协议配置
    • 00: Free 协议 (用于 TDM)
    • 01: SPDIF 协议
    • 10: AC'97 协议
    • 11: 保留
  • DS[3:0](位 7-4): 数据大小
    • 0000: 8 位
    • 0001: 10 位
    • 0010: 16 位
    • 0011: 20 位
    • 0100: 24 位
    • 0101: 32 位
  • LSBFIRST(位 8): 最低位优先
    • 0: MSB 优先 (默认)
    • 1: LSB 优先
  • CKSTR(位 9): 时钟极性
    • 0: 数据在 SCK 下降沿发送,上升沿采样
    • 1: 数据在 SCK 上升沿发送,下降沿采样
  • SYNCEN[1:0](位 11-10): 同步使能
    • 00: 异步模式
    • 01: 内部同步
    • 10: 外部同步
  • MONO(位 12): 单声道模式
    • 0: 立体声
    • 1: 单声道
  • SAICLK[2:0](位 18-16): SAI 时钟源选择
    • 000: PLLSAI1_P
    • 001: PLLSAI2_P
    • 010: PLL3_P
    • 011: I2S_CKIN
    • 100: HSI
  • MCKDIV[5:0](位 23-19): 主时钟分频系数
    • 0-63: 分频值

2.3 子块配置寄存器 2 (SAI_xCR2)

地址偏移: 0x08 + 0x0400 * x (x=A/B) 复位值: 0x00000000
  • FTH[2:0](位 2-0): FIFO 阈值
    • 000: FIFO 空
    • 001: 1/4 FIFO
    • 010: 1/2 FIFO
    • 011: 3/4 FIFO
    • 100: FIFO 满
  • FFLUS(位 3): FIFO 刷新
    • 0: 无操作
    • 1: 刷新 FIFO
  • TRIS(位 4): 三态管理
    • 0: 数据引脚在非活动时隙保持驱动
    • 1: 数据引脚在非活动时隙进入高阻
  • MUTE(位 5): 静音使能
    • 0: 正常操作
    • 1: 发送静音值

2.4 帧配置寄存器 (SAI_xFRCR)

地址偏移: 0x0C + 0x0400 * x (x=A/B) 复位值: 0x00000007
  • FRL[7:0](位 7-0): 帧长度
    • 0-255: 帧长度 = FRL + 1 位
  • FSALL[6:0](位 14-8): 帧同步活动长度
    • 0-127: FS 有效长度 = FSALL + 1 位
  • FSDEF(位 16): 帧同步定义
    • 0: FS 是开始信号
    • 1: FS 是通道识别信号
  • FSPOL(位 17): 帧同步极性
    • 0: FS 低电平有效
    • 1: FS 高电平有效
  • FSOFF(位 18): 帧同步偏移
    • 0: FS 与第一个数据位同时开始
    • 1: FS 比第一个数据位提前一个 SCK 周期

2.5 时隙配置寄存器 (SAI_xSLOTR)

地址偏移: 0x10 + 0x0400 * x (x=A/B) 复位值: 0x00000000
  • FBOFF[4:0](位 4-0): 第一个位偏移
    • 0-31: 第一个数据位的偏移量
  • SLOTSZ[1:0](位 7-6): 时隙大小
    • 00: 与数据大小 (DS) 相同
    • 01: 16 位
    • 10: 32 位
    • 11: 保留
  • NBSLOT[3:0](位 11-8): 时隙数量
    • 0-15: 时隙数量 = NBSLOT + 1
  • SLOTEN[15:0](位 31-16): 时隙使能
    • 每一位对应一个时隙,1 表示使能

2.6 数据寄存器 (SAI_xDR)

地址偏移: 0x14 + 0x0400 * x (x=A/B) 复位值: 0x00000000
  • 32 位读写寄存器,用于发送和接收数据
  • 写入数据会被放入发送 FIFO
  • 读取数据会从接收 FIFO 中取出

2.7 状态寄存器 (SAI_xSR)

地址偏移: 0x18 + 0x0400 * x (x=A/B) 复位值: 0x00000008
  • OVRUDR(位 0): 溢出 / 下溢标志
    • 接收模式: 1 表示 FIFO 满时又收到数据 (溢出)
    • 发送模式: 1 表示 FIFO 空时需要发送数据 (下溢)
  • FREQ(位 3): FIFO 请求标志
    • 1 表示 FIFO 达到阈值
  • FLVL[2:0](位 9-7): FIFO 级别
    • 000: FIFO 空
    • 001: FIFO 中有 1-2 个字
    • 010: FIFO 中有 3-4 个字
    • 011: FIFO 中有 5-6 个字
    • 100: FIFO 中有 7-8 个字

三、STM32CubeMX SAI 配置步骤

3.1 系统时钟配置

SAI 对时钟精度要求很高,必须正确配置:

  1. 在 "Clock Configuration" 中找到 SAI 时钟源
  2. 通常选择PLLSAI1_PPLL3_P作为 SAI 时钟源
  3. 配置 PLL 分频系数,使 SAI 内核时钟为49.152MHz(48kHz 采样率) 或45.1584MHz(44.1kHz 采样率)
  4. 确保 MCLK 频率 = 采样率 × 256 (标准音频时钟)

3.2 SAI 基本配置

  1. 在 "Connectivity" 中找到 SAI 并启用
  2. 选择要使用的子块 (SAI_A 或 SAI_B)
  3. 配置模式(主发送 / 主接收 / 从发送 / 从接收)
  4. 配置协议(Free 协议用于 TDM)
  5. 配置数据大小(通常 24 位用于 MEMS 传感器)
  6. 配置时钟极性(根据设备手册)
  7. 配置帧同步参数
  8. 配置时隙参数
  9. 配置FIFO 阈值
  10. 启用DMA(推荐) 或中断

3.3 DMA 配置

  1. 点击 "Add" 添加 DMA 通道
  2. 方向选择Peripheral to Memory(接收) 或Memory to Peripheral(发送)
  3. 优先级选择HighVery High
  4. 数据宽度选择Word(32 位)
  5. 启用循环模式(Circular Mode)
  6. 启用内存增量模式(Memory Increment)
  7. 禁用外设增量模式(Peripheral Increment)

四、TDM 接口 MEMS 加速度计读写实现

4.1 硬件连接

ADXL355-TDM三轴加速度计为例:

  • SAI_SCK → ADXL355_SCLK
  • SAI_FS → ADXL355_FSYNC
  • SAI_SD → ADXL355_SDO
  • SAI_MCLK → ADXL355_MCLK (可选)
  • VCC → 3.3V
  • GND → GND

注意:ADXL355-TDM 支持最多 4 个传感器共享同一总线,每个传感器占用一个时隙。

4.2 STM32CubeMX 配置

  1. 启用 SAI,选择SAI1 Block A
  2. 模式Master Receive(主接收)
  3. ProtocolFree Protocol(自由协议)
  4. Data Size24 Bits
  5. First BitMSB First
  6. Clock Strobing EdgeFalling Edge(数据在下降沿发送,上升沿采样)
  7. SynchronizationAsynchronous(异步)
  8. MCLK OutputEnabled(如果需要提供主时钟)
  9. Frame Configuration
    • Frame Length:31(32 位 / 帧)
    • Frame Sync Active Length:0(1 位有效)
    • Frame Sync Definition:Start of Frame
    • Frame Sync Polarity:Active High
    • Frame Sync Offset:No Offset
  10. Slot Configuration
    • First Bit Offset:0
    • Slot Size:32 Bits
    • Number of Slots:3(4 个时隙)
    • Slot Enable:0x000F(使能前 4 个时隙)
  11. FIFO Threshold4 FIFO
  12. DMA 配置:添加 DMA 通道,循环模式,32 位数据宽度

4.3 完整代码实现

#include "stm32h7xx_hal.h" #include <stdio.h> // 全局变量 SAI_HandleTypeDef hsai_BlockA1; DMA_HandleTypeDef hdma_sai1_a; #define ACCEL_CHANNELS 4 #define ACCEL_BUFFER_SIZE ACCEL_CHANNELS * 2 // 双缓冲 uint32_t accel_tdm_buffer[ACCEL_BUFFER_SIZE]; int32_t accel_data[ACCEL_CHANNELS][3]; // [通道][X/Y/Z] uint8_t accel_data_ready = 0; // SAI接收完成回调函数 void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai) { if(hsai->Instance == SAI1_Block_A) { accel_data_ready = 1; } } // 初始化SAI TDM加速度计 void SAI_TDM_Accel_Init(void) { // 启动DMA循环接收 HAL_SAI_Receive_DMA(&hsai_BlockA1, (uint8_t*)accel_tdm_buffer, ACCEL_BUFFER_SIZE); } // 解析加速度数据 void Parse_Accel_Data(void) { if(!accel_data_ready) return; accel_data_ready = 0; // 处理每个通道 for(int ch=0; ch<ACCEL_CHANNELS; ch++) { // ADXL355输出20位有符号数,左对齐在32位时隙中 // 数据格式: [20位数据][12位0] int32_t raw_data = (int32_t)(accel_tdm_buffer[ch] << 4) >> 12; // 分解X/Y/Z轴数据(ADXL355在一个时隙内连续发送X/Y/Z) // 注意:不同传感器的数据格式可能不同,请参考手册 accel_data[ch][0] = raw_data & 0xFFFFF; // X轴 accel_data[ch][1] = (raw_data >> 20) & 0xFFFFF; // Y轴 accel_data[ch][2] = (raw_data >> 40) & 0xFFFFF; // Z轴 // 符号扩展 if(accel_data[ch][0] & 0x80000) accel_data[ch][0] |= 0xFFF00000; if(accel_data[ch][1] & 0x80000) accel_data[ch][1] |= 0xFFF00000; if(accel_data[ch][2] & 0x80000) accel_data[ch][2] |= 0xFFF00000; // 转换为g值(ADXL355 ±8g范围: 4μg/LSB) float x_g = accel_data[ch][0] * 0.000004f; float y_g = accel_data[ch][1] * 0.000004f; float z_g = accel_data[ch][2] * 0.000004f; printf("Channel %d: X=%.3fg, Y=%.3fg, Z=%.3fg\r\n", ch, x_g, y_g, z_g); } } // 主函数 int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_DMA_Init(); MX_SAI1_Init(); SAI_TDM_Accel_Init(); while(1) { Parse_Accel_Data(); HAL_Delay(10); } }

五、TDM 接口 MEMS 麦克风拾音实现

5.1 硬件连接

INMP441-TDM数字 MEMS 麦克风为例:

  • SAI_SCK → INMP441_SCK
  • SAI_FS → INMP441_WS
  • SAI_SD → INMP441_SD
  • SAI_MCLK → INMP441_MCLK (可选)
  • VCC → 3.3V
  • GND → GND
  • L/R → GND (左声道) 或 VCC (右声道)

注意:INMP441-TDM 支持最多 8 个麦克风共享同一总线,每个麦克风占用一个时隙。

5.2 STM32CubeMX 配置

  1. 启用 SAI,选择SAI1 Block A
  2. 模式Master Receive(主接收)
  3. ProtocolFree Protocol(自由协议)
  4. Data Size24 Bits
  5. First BitMSB First
  6. Clock Strobing EdgeRising Edge(数据在上升沿发送,下降沿采样)
  7. SynchronizationAsynchronous(异步)
  8. MCLK OutputEnabled
  9. Frame Configuration
    • Frame Length:255(256 位 / 帧)
    • Frame Sync Active Length:0(1 位有效)
    • Frame Sync Definition:Start of Frame
    • Frame Sync Polarity:Active High
    • Frame Sync Offset:No Offset
  10. Slot Configuration
    • First Bit Offset:0
    • Slot Size:32 Bits
    • Number of Slots:7(8 个时隙)
    • Slot Enable:0x00FF(使能前 8 个时隙)
  11. FIFO Threshold8 FIFO
  12. DMA 配置:添加 DMA 通道,循环模式,32 位数据宽度

5.3 完整代码实现

#include "stm32h7xx_hal.h" #include <stdio.h> #include <string.h> // 全局变量 SAI_HandleTypeDef hsai_BlockA1; DMA_HandleTypeDef hdma_sai1_a; #define MIC_CHANNELS 8 #define AUDIO_SAMPLE_RATE 48000 #define AUDIO_BUFFER_SIZE 1024 // 每个通道的采样点数 #define TOTAL_BUFFER_SIZE MIC_CHANNELS * AUDIO_BUFFER_SIZE uint32_t mic_tdm_buffer[TOTAL_BUFFER_SIZE]; int32_t audio_buffer[MIC_CHANNELS][AUDIO_BUFFER_SIZE]; uint8_t audio_buffer_ready = 0; uint8_t audio_buffer_half = 0; // 1: 前半部分, 2: 后半部分 // SAI半接收完成回调函数 void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai) { if(hsai->Instance == SAI1_Block_A) { audio_buffer_half = 1; audio_buffer_ready = 1; } } // SAI接收完成回调函数 void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai) { if(hsai->Instance == SAI1_Block_A) { audio_buffer_half = 2; audio_buffer_ready = 1; } } // 初始化SAI TDM麦克风 void SAI_TDM_Mic_Init(void) { // 启动DMA循环接收 HAL_SAI_Receive_DMA(&hsai_BlockA1, (uint8_t*)mic_tdm_buffer, TOTAL_BUFFER_SIZE); } // 处理音频数据 void Process_Audio_Data(void) { if(!audio_buffer_ready) return; audio_buffer_ready = 0; uint32_t *src_ptr; uint32_t start_idx; uint32_t end_idx; // 确定处理哪一部分缓冲区 if(audio_buffer_half == 1) { src_ptr = mic_tdm_buffer; start_idx = 0; end_idx = AUDIO_BUFFER_SIZE / 2; } else { src_ptr = mic_tdm_buffer + TOTAL_BUFFER_SIZE / 2; start_idx = AUDIO_BUFFER_SIZE / 2; end_idx = AUDIO_BUFFER_SIZE; } // 解析TDM数据 for(int sample=0; sample < AUDIO_BUFFER_SIZE/2; sample++) { for(int ch=0; ch<MIC_CHANNELS; ch++) { // INMP441输出24位有符号数,左对齐在32位时隙中 // 数据格式: [24位数据][8位0] int32_t raw_sample = (int32_t)(src_ptr[sample * MIC_CHANNELS + ch] << 8) >> 8; // 存储到音频缓冲区 audio_buffer[ch][start_idx + sample] = raw_sample; } } // 音频处理示例:计算每个通道的RMS值 for(int ch=0; ch<MIC_CHANNELS; ch++) { int64_t sum_sq = 0; for(int i=start_idx; i<end_idx; i++) { sum_sq += (int64_t)audio_buffer[ch][i] * audio_buffer[ch][i]; } float rms = sqrtf((float)sum_sq / (AUDIO_BUFFER_SIZE / 2)); // 转换为dBFS(满量程分贝) float dbfs = 20.0f * log10f(rms / 8388608.0f); printf("Channel %d RMS: %.1f dBFS\r\n", ch, dbfs); } } // 主函数 int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_DMA_Init(); MX_SAI1_Init(); SAI_TDM_Mic_Init(); while(1) { Process_Audio_Data(); } }

六、SAI 各种模式完整应用示例

6.1 I2S 模式 (立体声麦克风)

CubeMX 配置

  • 模式: Master Receive
  • 协议: I2S Philips
  • 数据大小: 16 Bits
  • 标准: I2S Philips
  • 采样率: 44100 Hz
  • 时钟极性: Low

代码实现

#define I2S_BUFFER_SIZE 1024 uint16_t i2s_stereo_buffer[I2S_BUFFER_SIZE]; int16_t left_channel[I2S_BUFFER_SIZE/2]; int16_t right_channel[I2S_BUFFER_SIZE/2]; void I2S_Stereo_Init(void) { HAL_SAI_Receive_DMA(&hsai_BlockA1, (uint8_t*)i2s_stereo_buffer, I2S_BUFFER_SIZE); } void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai) { // 分离左右声道 for(int i=0; i<I2S_BUFFER_SIZE/2; i++) { left_channel[i] = i2s_stereo_buffer[2*i]; right_channel[i] = i2s_stereo_buffer[2*i+1]; } }

6.2 PCM 模式 (单声道麦克风)

CubeMX 配置

  • 模式: Master Receive
  • 协议: PCM
  • 数据大小: 16 Bits
  • 标准: PCM Short
  • 采样率: 16000 Hz
  • 时钟极性: High

代码实现

#define PCM_BUFFER_SIZE 512 uint16_t pcm_mono_buffer[PCM_BUFFER_SIZE]; void PCM_Mono_Init(void) { HAL_SAI_Receive_DMA(&hsai_BlockA1, (uint8_t*)pcm_mono_buffer, PCM_BUFFER_SIZE); } void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai) { // 处理PCM数据 for(int i=0; i<PCM_BUFFER_SIZE; i++) { int16_t sample = (int16_t)pcm_mono_buffer[i]; // 处理采样点... } }

6.3 全双工模式 (音频编解码器)

CubeMX 配置

  • SAI_A: Master Transmit
  • SAI_B: Master Receive
  • 协议: I2S Philips
  • 数据大小: 16 Bits
  • 采样率: 44100 Hz
  • 同步: SAI_B 同步到 SAI_A

代码实现

#define AUDIO_BUFFER_SIZE 1024 uint16_t tx_buffer[AUDIO_BUFFER_SIZE]; uint16_t rx_buffer[AUDIO_BUFFER_SIZE]; void SAI_FullDuplex_Init(void) { // 先启动发送,再启动接收 HAL_SAI_Transmit_DMA(&hsai_BlockA1, (uint8_t*)tx_buffer, AUDIO_BUFFER_SIZE); HAL_SAI_Receive_DMA(&hsai_BlockB1, (uint8_t*)rx_buffer, AUDIO_BUFFER_SIZE); } void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai) { // 填充发送缓冲区 for(int i=0; i<AUDIO_BUFFER_SIZE; i++) { tx_buffer[i] = 0; // 静音 } } void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai) { // 处理接收数据 memcpy(tx_buffer, rx_buffer, AUDIO_BUFFER_SIZE * 2); // 回环 }

6.4 主从同步模式 (多 SAI 同步)

CubeMX 配置

  • SAI1_A: Master Transmit (同步主)
  • SAI2_A: Slave Receive (同步从)
  • 全局配置: SAI1 SYNCOUT=01, SAI2 SYNCIN=01

代码实现

void SAI_Sync_Init(void) { // 先启动从设备,再启动主设备 HAL_SAI_Receive_DMA(&hsai2_BlockA1, (uint8_t*)rx_buffer, BUFFER_SIZE); HAL_SAI_Transmit_DMA(&hsai1_BlockA1, (uint8_t*)tx_buffer, BUFFER_SIZE); }

七、常见问题与解决方案

7.1 数据丢失 / 溢出问题

现象:SAI_SR 寄存器的 OVRUDR 位被置 1解决方案

  1. 提高 DMA 优先级到最高
  2. 增加 FIFO 阈值 (推荐使用 FIFO 满)
  3. 使用双缓冲或循环缓冲
  4. 避免在中断中执行耗时操作
  5. 检查 SAI 时钟频率是否正确

7.2 数据错位 / 乱序问题

现象:接收到的数据与预期不符解决方案

  1. 检查帧同步极性和偏移
  2. 确认时钟极性 (CKSTR) 设置正确
  3. 检查数据大小和时隙大小是否匹配
  4. 确认第一个位偏移 (FBOFF) 设置正确
  5. 检查硬件连接是否正确

7.3 符号扩展问题

现象:负数显示为很大的正数解决方案

// 24位数据符号扩展 int32_t sample_24 = (int32_t)(raw_data << 8) >> 8; // 20位数据符号扩展 int32_t sample_20 = (int32_t)(raw_data << 12) >> 12; // 16位数据符号扩展 int16_t sample_16 = (int16_t)raw_data;

7.4 时钟同步问题

现象:音频有杂音或周期性失真解决方案

  1. 使用高精度的外部晶振
  2. 配置 PLLSAI 专门用于 SAI 时钟
  3. 确保主从设备使用相同的时钟源
  4. 避免在运行时修改 SAI 配置

八、最佳实践总结

  1. 时钟配置:优先使用 PLLSAI 作为 SAI 时钟源,确保时钟精度
  2. DMA 传输:始终使用 DMA 传输 SAI 数据,避免 CPU 轮询
  3. 双缓冲机制:使用半传输和全传输中断实现双缓冲
  4. FIFO 配置:FIFO 阈值设置为 FIFO 满,减少 DMA 请求次数
  5. 数据处理:在主循环中处理数据,避免在中断中处理
  6. 错误处理:定期检查 SAI 状态寄存器,处理溢出和错误
  7. 硬件设计:SAI 信号线尽量短,避免干扰,使用差分信号
http://www.jsqmd.com/news/928254/

相关文章:

  • 第四章:暗礁
  • 【个人记账理财助手】手动新增账单功能
  • 2026年最新三亚市金银首饰回收+金条金币+铂金K金 高价回收;实体老店回收黄金 多年口碑 交易放心;TOP5实力权威排行榜推荐+联系方式 - 亦辰小黄鸭
  • 2026最新指南|Codex 接入 MiniMax 模型全攻略:利用 CC Switch 本地路由零基础配置
  • 从一次线上GC故障排查说起:我为什么最终把生产环境从OracleJDK 11换成了Amazon Corretto 11
  • 医疗营销实战:生成式AI在聊天机器人、内容创作与社交媒体中的应用
  • 第1篇 | 政治思维生存逻辑解析
  • 二分查找模板(binary_search)
  • Web应用技术第一次和第二次作业
  • 无人机红外数据集 深度学习框架 无人机高空红外检测系统pyqt5界面 无人机高空红外数据集 无人机高空红外行人车辆检测数据集
  • 【多Agent 协作深度解析】Claude 官方 5 种协调模式的原理、选择与工程实践
  • 微服务架构(MSA)是如何诞生的?
  • 聊天机器人的搭建(一)
  • AI销售助理:1700万美元融资背后的技术架构与落地实践
  • AI内容运营成为大学生就业热门方向,越来越多年轻人开始学习AI营销
  • 单向循环链表超详细精讲 | 带头节点带头指针 + 完整可运行c语言代码
  • 车载AI Agent Harness:行车安全与交互管控
  • 生成式AI赋能无障碍开发:从设计到测试的实践指南
  • 波普尔主义百年灾难清单:系统性尸检报告
  • GPT-Image-2迭代亮点解析
  • 保姆级教程:在Ubuntu 20.04上从源码编译运行ORB-SLAM3(含ROS1/ROS2配置)
  • 设计模式深度解析:从六大原则到Spring源码,面试通关全攻略
  • 山东大学创新实训(六)--基于Multi-Agent的剧本杀平台博客
  • 第三周进度
  • 2026年最新厦门市金银首饰回收+金条金币+铂金K金 高价回收;实体老店回收黄金 多年口碑 交易放心;TOP5实力权威排行榜推荐+联系方式 - 亦辰小黄鸭
  • 2026年最新汕头市金银首饰回收+金条金币+铂金K金 高价回收;实体老店回收黄金 多年口碑 交易放心;TOP5实力权威排行榜推荐+联系方式 - 亦辰小黄鸭
  • 第五章:年终
  • Product Hunt 每日热榜 | 2026-05-31
  • 10. JavaArrayList 核心笔记
  • 扔掉塑料尺:给未来孤勇者的科学排毒指南