尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

C8051F310单片机SPI通信驱动开发全解析:从寄存器配置到实战代码

C8051F310单片机SPI通信驱动开发全解析:从寄存器配置到实战代码 简介本资源是面向嵌入式开发初学者与C8051F系列单片机实践者的SPI通信专项学习包聚焦Silicon Labs C8051F310芯片的SPI外设驱动开发与主从协同调试。资源提供完整可编译工程涵盖主设备SPI_TEST_Master与从设备SPI_TEST_Save双模式实现包含初始化配置、时钟极性/相位设置、片选控制及数据收发逻辑适用于EEPROM读写、传感器通信等典型应用场景。压缩包共23个文件含2个核心ASM源码、1个C文件、2个WSP工程文件、2个M51链接映射、2个LST列表文件及OBJ/OUT等编译中间产物全面覆盖汇编级开发、构建流程与调试信息整体体积仅42KB轻量易导入。已有147人下载学习配套代码结构清晰、注释完整特别适合理解C8051F310 SPI寄存器配置细节、波形时序关系及主从交互机制是掌握8051架构下同步串行通信落地实践的实用参考。1. 项目概述C8051F310的SPI通信实现最近在整理老项目的代码库翻出了一个名为“SPI.rar”的压缩包里面是关于Silicon Labs C8051F310这款8位MCU的SPI通信实现代码。这个项目标题看起来像是一串搜索关键词的堆砌但对于真正用过C8051F系列尤其是早期型号的工程师来说这背后是一段非常具体的开发记忆。C8051F310以其高速的8051内核、丰富的模拟和数字外设在十多年前的嵌入式领域尤其是工业控制、传感器采集等场景中应用广泛。而SPISerial Peripheral Interface作为当时乃至现在最主流的板级同步串行通信协议其稳定可靠的实现是项目成败的关键之一。这个代码包的核心就是解决如何在C8051F310上高效、稳定地驱动SPI外设与各类SPI从设备如Flash存储器、ADC、DAC、显示屏驱动、传感器等进行数据交换。对于刚接触这款MCU或者从其他平台如STM32、ESP32转过来的开发者可能会觉得配置一个SPI外设很简单但在资源相对有限的8位MCU上尤其是在没有成熟HAL库、需要直接操作SFR特殊功能寄存器的年代每一个配置位的理解、时序的把握、中断与DMA如果支持的运用都直接关系到系统的性能和稳定性。本文将基于这个“SPI.rar”项目深入拆解C8051F310的SPI外设从寄存器配置到实战代码从模式选择到常见坑点手把手带你复现一个稳定可靠的SPI驱动层。2. C8051F310 SPI外设深度解析与设计思路C8051F310内部集成的SPI模块是一个全双工、同步的串行接口它既可以配置为主机Master也可以配置为从机Slave。在设计驱动时我们的首要任务是理解其硬件能力和限制从而做出合理的软件架构设计。2.1 硬件特性与核心寄存器映射C8051F310的SPI模块挂载在它的标准外设交叉开关Crossbar上这意味着SPI的引脚SCK、MOSI、MISO、NSS需要映射到具体的物理I/O口如P0.0-P0.3这通过配置交叉开关优先级寄存器XBR0, XBR1, XBR2来实现。这是与许多ARM Cortex-M芯片固定引脚功能不同的地方也是第一个需要注意的配置点。SPI的核心控制寄存器是SPI0CFG和SPI0CN。SPI0CFG配置寄存器决定了SPI的基本工作模式CKPHA (Clock Phase) 和 CKPOL (Clock Polidity)这两位共同定义了SPI的四种标准工作模式Mode 0, 1, 2, 3。这是与从设备通信的基石必须严格匹配从设备的数据手册要求。例如很多SPI Flash工作在Mode 0或Mode 3。MSTEN (Master Mode Enable)置1为主机模式清0为从机模式。我们的项目通常作为主机。SPIBSY (SPI Busy)这是一个只读状态位当SPI正在发送或接收数据时该位为1。在查询方式下我们需要轮询此位来判断一次传输是否完成。SPI0CN控制寄存器则包含了更多的控制和状态位SPIF (SPI Interrupt Flag)当一次数据传输完成即移位寄存器中的数据已全部移出/移入时硬件将此位置1。如果中断被使能ESPI01则会触发SPI中断。这是实现中断驱动SPI的关键。WCOL (Write Collision Flag)如果在SPI忙SPIBSY1时向数据寄存器SPI0DAT写入数据此位会被置1表明发生了写冲突之前的写入操作无效。良好的驱动代码必须检查并处理此标志。RXOVRN (Receive Overrun Flag)当接收缓冲器一个双缓冲结构中的数据尚未被读取而新的数据已经接收完成时此位置1表明发生了数据覆盖。在高速或中断服务不及时的情况下需要注意。数据交换通过SPI0DAT寄存器进行。写入SPI0DAT的数据会启动发送在主机模式下同时也会产生SCK时钟而接收到的数据也会被读取自SPI0DAT。这里有一个关键点C8051F310的SPI是全双工的每一次有效的写操作启动传输都会同时完成一次发送和一次接收。即使你只想发送数据也会收到一个“无关”的字节反之如果只想接收也必须先写入一个哑元Dummy数据如0xFF来启动时钟。2.2 主机模式驱动设计思路基于以上硬件特性一个健壮的SPI主机驱动设计通常包含以下几个层次初始化层SPI_Init负责配置交叉开关映射SPI引脚、设置端口为推挽输出SCK MOSI NSS或开漏输入MISO、配置SPI时钟分频决定SCK频率、设置SPI工作模式、使能SPI模块。这里时钟频率的计算需要根据系统时钟SYSCLK和从设备支持的最高SCK频率来谨慎选择。数据传输层阻塞式查询传输SPI_TransferByte最简单的方式。写入数据到SPI0DAT然后循环查询SPIF标志位直到传输完成再读取SPI0DAT得到接收数据。优点是代码简单缺点是期间CPU被完全占用无法处理其他任务。中断式传输使能SPI中断ESPI01在中断服务程序ISR中处理SPIF标志读取数据并填充到缓冲区或设置完成标志。适合需要连续传输大量数据且不希望阻塞主循环的场景。需要妥善管理缓冲区通常是环形队列和状态机。DMA传输如果MCU支持C8051F310的某些型号或系列后续产品可能支持DMA可以进一步解放CPU。但在这个基础项目中我们主要聚焦于查询和中断方式。片选NSS控制层SPI协议本身不规定片选的管理方式。硬件上当SPI配置为从机时NSS引脚是输入为主机时它可以被配置为忽略由软件控制这是最常见的方式。我们将NSS引脚配置为一个普通的GPIO输出口。在传输开始前拉低传输结束后拉高。这种方式最为灵活可以轻松控制多个从设备。主模式复用Master Mode Multi-Device硬件自动管理NSS为输出但通常不如软件控制灵活。 我们的驱动需要提供SPI_CS_Low()和SPI_CS_High()这样的宏或函数。应用层接口提供诸如SPI_ReadRegister()SPI_WriteRegister()SPI_ReadBuffer()SPI_WriteBuffer()等函数封装底层传输细节使上层应用无需关心SPI0DAT的读写顺序和片选控制。设计思路的核心是在资源有限的8位平台上在代码复杂度和系统效率之间取得平衡。对于简单的传感器单字节读写阻塞查询足矣对于需要连续读取大量数据的TFT屏或Flash中断加缓冲区是更优解。3. 核心代码实现与实操要点接下来我们深入到代码层面看看如何将上述设计思路转化为具体的C语言代码。这里会包含大量直接可用的代码片段和关键注释。3.1 硬件初始化与配置首先我们需要进行系统时钟和端口的基本配置。假设我们使用内部振荡器22.1184MHz作为系统时钟SYSCLK。/** * brief 初始化系统时钟使用内部22.1184MHz振荡器 */ void SystemClock_Init(void) { OSCICN | 0x03; // 使能内部高频振荡器并等待其稳定 // ... 其他时钟树配置如果有时钟分频器 // C8051F310的时钟配置相对简单主要就是选择振荡源 } /** * brief 初始化SPI为主机引脚映射到P0.0~P0.3 * param clockRate: 期望的SPI时钟频率SCK * note SCK SYSCLK / (2 * (SPI0CKR 1)) */ void SPI_Master_Init(uint32_t clockRate) { // 1. 使能端口交叉开关和弱上拉 XBR0 0x02; // 将SPI (SCK, MISO, MOSI) 映射到P0.0, P0.1, P0.2 XBR1 0x00; XBR2 0x40; // 使能交叉开关和弱上拉 // 2. 配置SPI引脚方向 // P0.0 (SCK) 推挽输出 // P0.1 (MISO) 开漏输入或数字输入 // P0.2 (MOSI) 推挽输出 // P0.3 (NSS/CS) 作为普通GPIO推挽输出初始为高不选中 P0MDOUT | 0x0D; // P0.0, P0.2, P0.3 推挽输出 (0x01 | 0x04 | 0x08) P0MDIN | 0x02; // P0.1 数字输入MISO // 3. 配置SPI时钟分频寄存器 SPI0CKR // 公式 SPI0CKR (SYSCLK / (2 * SCK)) - 1 // 例如SYSCLK22.1184MHz, 期望SCK1.1MHz, 则 SPI0CKR (22.1184/(2*1.1)) -1 ≈ 9 uint8_t spiCkrValue; spiCkrValue (uint8_t)((SYSCLK / (2 * clockRate)) - 1); // 需要确保计算值在0-255之间且不为负 if(spiCkrValue 0xFF) spiCkrValue 0xFF; SPI0CKR spiCkrValue; // 4. 配置SPI为模式0 (CKPHA0, CKPOL0)主机模式 SPI0CFG 0x40; // 0b0100_0000, MSTEN1 (主机), CKPHA0, CKPOL0 // 5. 使能SPI模块 SPI0CN 0x01; // 0b0000_0001, SPIEN1 (使能SPI) // 6. 初始化片选引脚为高电平不选中任何从设备 SPI_CS_HIGH(); } // 片选控制宏假设CS连接在P0.3 #define SPI_CS_LOW() (P0 ~0x08) // P0.3 0 #define SPI_CS_HIGH() (P0 | 0x08) // P0.3 1注意SYSCLK需要根据你实际的系统时钟频率定义为具体的数值如#define SYSCLK 22118400UL。时钟分频的计算是整数运算最终得到的实际SCK频率可能与期望值有细微偏差只要在从设备允许的范围内即可。3.2 阻塞式单字节传输函数这是最基础、最常用的函数。它发送一个字节并接收一个字节。/** * brief 通过SPI阻塞式交换一个字节 * param txData: 要发送的字节 * retval 接收到的字节 */ uint8_t SPI_TransferByte(uint8_t txData) { uint8_t rxData; SPI0CN ~0x03; // 清除SPIF和WCOL标志位写1清零这里是写0具体看手册有些是读后清 SPI0DAT txData; // 写入数据启动传输 while (!(SPI0CN 0x80)); // 等待SPIF标志置位 (SPI0CN.7) rxData SPI0DAT; // 读取接收到的数据 // 读取SPI0DAT会自动清除SPIF标志在某些型号上但为了保险可以显式清除 // SPI0CN ~0x80; // 清除SPIF return rxData; }这个函数的逻辑非常清晰启动传输然后等待完成。但它有一个潜在风险如果在传输过程中发生中断且中断服务程序执行时间过长可能会导致从设备超时。对于时序要求极其严格的设备需要确保此函数执行期间中断响应时间可控或者使用更精确的定时方式。3.3 带片选控制的读写函数实际应用中几乎所有的SPI操作都需要配合片选信号。/** * brief 向SPI设备写入一个字节到指定寄存器 * param regAddr: 寄存器地址 * param data: 要写入的数据 */ void SPI_WriteReg(uint8_t regAddr, uint8_t data) { SPI_CS_LOW(); // 选中设备 SPI_TransferByte(regAddr 0x7F); // 通常最高位为0表示写操作 SPI_TransferByte(data); SPI_CS_HIGH(); // 释放设备 } /** * brief 从SPI设备指定寄存器读取一个字节 * param regAddr: 寄存器地址 * retval 读取到的数据 */ uint8_t SPI_ReadReg(uint8_t regAddr) { uint8_t data; SPI_CS_LOW(); SPI_TransferByte(regAddr | 0x80); // 通常最高位为1表示读操作 data SPI_TransferByte(0xFF); // 发送哑元数据以产生时钟来读取 SPI_CS_HIGH(); return data; } /** * brief 连续读取多个字节常用于读取传感器数据块或Flash * param regAddr: 起始寄存器/命令地址 * param pBuffer: 指向接收缓冲区的指针 * param size: 要读取的字节数 */ void SPI_ReadBuffer(uint8_t regAddr, uint8_t *pBuffer, uint16_t size) { SPI_CS_LOW(); SPI_TransferByte(regAddr | 0x80); // 发送读命令/地址 for (uint16_t i 0; i size; i) { pBuffer[i] SPI_TransferByte(0xFF); // 连续发送哑元连续接收 } SPI_CS_HIGH(); }实操心得很多SPI设备如Flash、ADC在连续读操作时发送起始地址后后续只需要提供时钟从设备会自动递增内部地址并输出数据。这就是为什么SPI_ReadBuffer中循环发送0xFF的原因。这个“哑元”字节的值有时很重要有些设备在特定模式下如快速读可能需要发送特定的命令码而非0xFF务必查阅具体器件的数据手册。3.4 中断驱动SPI实现要点当需要高速、不间断传输如刷新SPI TFT屏时阻塞式传输会严重拖累系统。此时中断驱动是更好的选择。其核心是维护一个发送/接收缓冲区和一个状态机。#define SPI_TX_BUFFER_SIZE 128 #define SPI_RX_BUFFER_SIZE 128 volatile uint8_t spiTxBuffer[SPI_TX_BUFFER_SIZE]; volatile uint8_t spiRxBuffer[SPI_RX_BUFFER_SIZE]; volatile uint16_t spiTxIndex 0; volatile uint16_t spiTxLength 0; volatile uint16_t spiRxIndex 0; volatile uint8_t spiBusyFlag 0; /** * brief 启动一次中断驱动的SPI数据传输 * param pTxData: 发送数据指针 * param pRxData: 接收数据缓冲区指针可为NULL如果只发送 * param length: 数据长度 * retval 0: 成功启动1: SPI忙拒绝请求 */ uint8_t SPI_TransferIT(uint8_t *pTxData, uint8_t *pRxData, uint16_t length) { if (spiBusyFlag) { return 1; // 忙拒绝新请求 } if (length 0 || length SPI_TX_BUFFER_SIZE) { return 1; // 长度无效 } // 复制数据到内部发送缓冲区如果是发送 if (pTxData) { for (uint16_t i 0; i length; i) { spiTxBuffer[i] pTxData[i]; } } else { // 如果只接收也需要填充发送缓冲区哑元数据 for (uint16_t i 0; i length; i) { spiTxBuffer[i] 0xFF; } } // 初始化索引和长度 spiTxIndex 0; spiRxIndex 0; spiTxLength length; spiBusyFlag 1; // 使能SPI中断 ESPI0 1; // 使能SPI中断 IE | 0x02; // 使能全局中断如果尚未使能 // 手动启动第一次传输写入第一个数据触发中断链 SPI0CN ~0x03; // 清除标志 SPI0DAT spiTxBuffer[spiTxIndex]; return 0; // 成功启动 } // SPI中断服务程序 void SPI_ISR(void) interrupt 6 { // C8051F310的SPI中断向量号通常是6需查手册确认 if (SPI0CN 0x80) { // 检查SPIF标志 // 读取接收到的数据 spiRxBuffer[spiRxIndex] SPI0DAT; // 检查是否还有数据要发送 if (spiTxIndex spiTxLength) { // 发送下一个字节 SPI0DAT spiTxBuffer[spiTxIndex]; } else { // 传输完成 spiBusyFlag 0; // 清除忙标志 ESPI0 0; // 可选关闭SPI中断 // 可以在这里设置一个用户回调函数标志通知主程序传输完成 } SPI0CN ~0x80; // 清除SPIF标志如果硬件未自动清除 } // 通常也需要检查WCOL这里省略了错误处理 }中断驱动的核心思想是传输过程被拆解成一个个单字节的中断事件。启动函数SPI_TransferIT填充缓冲区并发送第一个字节后立即返回主循环可以继续做其他事情。每个字节发送完成后触发中断在中断服务程序ISR中读取刚收到的数据并发送下一个字节直到所有数据完成。这种方式极大地提高了CPU利用率。重要注意事项缓冲区管理中断服务程序ISR和主程序共享spiTxBuffer、spiRxBuffer和索引变量。这些变量必须声明为volatile防止编译器优化导致数据不一致。更严谨的做法是在访问这些共享变量的关键段如启动传输前暂时关闭中断。中断优先级SPI中断的优先级需要根据系统整体中断负载来设置。如果SPI中断被其他高优先级中断长时间阻塞可能导致SPI数据流中断或WCOL错误。错误处理示例中省略了WCOL写冲突和RXOVRN接收溢出的错误处理。在生产代码中必须在ISR中检查这些标志并进行相应处理如重置SPI、报告错误等。4. 关键参数配置与计算实例在C8051F310上配置SPI有几个关键参数需要精确计算和选择否则通信根本无法建立。4.1 SPI时钟频率SCK计算与选择SCK频率由系统时钟SYSCLK和SPI时钟分频寄存器SPI0CKR共同决定。公式为SCK SYSCLK / (2 * (SPI0CKR 1))其中SPI0CKR是一个8位寄存器取值范围0-255。实例计算 假设SYSCLK 22.1184 MHz目标SCK 1 MHz。代入公式SPI0CKR SYSCLK / (2 * SCK) - 1 22.1184 / (2 * 1) - 1 11.0592 - 1 10.0592取整SPI0CKR 10向下取整确保不超过从设备最大频率。实际SCK频率SCK_actual 22.1184 / (2 * (10 1)) 22.1184 / 22 ≈ 1.00538 MHz。这个误差在绝大多数设备容忍范围内。选择策略从设备极限首要原则是SCK不能超过从设备数据手册规定的最大SCK频率f_SCK(max)并留有一定余量如80%。通信距离与噪声对于长导线连接或噪声环境应降低SCK频率以提高抗干扰能力。系统需求在满足从设备要求的前提下尽可能提高SCK以加快数据吞吐。对于C8051F310SYSCLK通常为25MHz以内SPI时钟最高可达SYSCLK/2当SPI0CKR0时即12.5MHz但实际中很少用到这么高。4.2 SPI工作模式Clock Phase Polarity这是最容易出错的地方。SPI模式由CPHA时钟相位和CPOL时钟极性两位定义共四种组合模式CPOLCPHA时钟空闲状态数据采样时刻数据变化时刻000低电平第一个时钟边沿上升沿第二个时钟边沿下降沿101低电平第二个时钟边沿下降沿第一个时钟边沿上升沿210高电平第一个时钟边沿下降沿第二个时钟边沿上升沿311高电平第二个时钟边沿上升沿第一个时钟边沿下降沿如何选择完全取决于你的从设备你必须查阅从设备的数据手册。例如AT25DF系列SPI Flash通常支持Mode 0和Mode 3。ADXL345加速度计支持Mode 0和Mode 3。某些特定ADC可能只支持Mode 1。在C8051F310中通过SPI0CFG寄存器的CKPHA和CKPOL位配置。例如Mode 0对应CKPOL0, CKPHA0即SPI0CFG 0x40假设只设置主机位。4.3 数据位顺序MSB/LSB First大多数SPI设备默认是MSB最高位先发送。C8051F310的SPI模块固定为MSB First无法通过寄存器配置为LSB First。如果你的从设备要求LSB First这种情况较少见则需要在软件层对每个发送/接收的字节进行位反转操作。// 软件实现字节位反转LSB First uint8_t ReverseBits(uint8_t b) { b (b 0xF0) 4 | (b 0x0F) 4; // 交换半字节 b (b 0xCC) 2 | (b 0x33) 2; // 交换每对位 b (b 0xAA) 1 | (b 0x55) 1; // 交换相邻位 return b; } // 发送时反转 SPI_TransferByte(ReverseBits(dataToSend)); // 接收时反转 receivedData ReverseBits(SPI_TransferByte(0xFF));这种方法会引入额外的CPU开销在高速通信时需谨慎评估性能。5. 常见问题排查与实战调试技巧即使代码看起来正确在实际硬件调试中SPI通信也常常会遇到问题。以下是一些经典的排查步骤和技巧很多都是我在调试C8051F310 SPI时踩过的坑。5.1 通信完全无响应这是最令人头疼的情况。请按照以下清单逐一排查电源和物理连接用万用表检查从设备供电是否正常VCC和GND是否接好。检查SCK、MOSI、MISO、CS四根线如果是3线模式则没有MISO或MOSI是否与MCU正确连接有无虚焊、短路、断路。这是最常见的问题根源。片选信号CS/NSS确认你的代码在通信前正确拉低了片选引脚。用示波器或逻辑分析仪观察CS引脚确保它在数据传输窗口内为低电平且没有意外的毛刺。很多新手会忘记控制CS脚。SPI模式与时钟极性/相位这是第二大常见问题。用逻辑分析仪同时抓取SCK、MOSI、MISO和CS信号。对照从设备数据手册的时序图检查时钟空闲电平CPOL是否正确数据是在哪个时钟边沿采样CPHA你的MCU配置是否与之匹配 一个快速的验证方法是尝试四种模式0,1,2,3逐一测试。很多设备支持多种模式。时钟频率SCKSCK频率是否超过了从设备的最大允许值尝试将SPI0CKR设置到最大值即最低频率看是否能通信。如果能再逐步提高频率。MCU SPI外设是否使能检查SPI0CN寄存器的SPIEN位是否已置1。检查交叉开关XBR配置是否正确SPI功能是否已映射到正确的引脚。引脚配置冲突检查你使用的SPI引脚是否被其他功能如UART、定时器、ADC输入占用。C8051F310的交叉开关优先级需要妥善安排。5.2 能发送但接收数据错误或全为0/0xFFMISO引脚配置错误确保MISO引脚在C8051F310上通常是P0.1被配置为输入或开漏模式而不是输出模式。P0MDOUT对应位应为0。全双工理解偏差记住SPI是全双工的。即使你只想接收也必须写入一个字节通常是0xFF来产生SCK时钟。检查你的读函数是否包含了发送哑元数据的步骤。从设备输出使能有些从设备需要特定的命令序列来使能其数据输出。例如某些Flash芯片需要先发送“读使能”命令0x03。逻辑分析仪抓包分析这是最强大的调试工具。将逻辑分析仪的通道连接到SCK、MOSI、MISO、CS。触发条件设为CS下降沿。然后执行一次读/写操作。在分析软件中解码SPI协议。你可以清晰地看到MCU发送了什么MOSI线。从设备回复了什么MISO线。时钟和数据的对齐关系是否正确。 通过对比实际抓取的数据和你期望的数据可以迅速定位问题是在命令阶段、地址阶段还是数据阶段。5.3 高速传输时数据出错时序裕量不足当SCK频率接近从设备的极限时由于PCB走线延迟、信号完整性等问题可能导致建立时间Setup Time或保持时间Hold Time不满足。解决方法降低SCK频率在SCK线上串联一个小电阻如22-100欧姆以减小振铃优化PCB布局缩短走线。中断干扰如果使用查询方式while(!SPIF)确保在传输关键字节时没有高优先级的中断长时间关闭全局中断否则可能导致SCK时钟间隔异常变长从设备超时。如果使用中断方式检查ISR执行时间是否过长导致下一个字节发送不及时。电源噪声高速数字开关会在电源上产生噪声可能影响模拟部分或导致逻辑错误。确保MCU和从设备的电源引脚有足够的去耦电容通常每个芯片的VCC附近放置一个0.1uF的陶瓷电容。5.4 C8051F310特定问题交叉开关Crossbar配置遗漏这是C8051F系列特有的问题。除了配置SPI0CFG和SPI0CN必须配置XBR2寄存器的XBARE位为1来使能交叉开关否则数字外设包括SPI根本无法连接到引脚上。我见过不止一个工程师调了一整天最后发现是忘了这一位。端口输出模式SCK和MOSI作为输出推荐设置为推挽输出PxMDOUT.y 1以提供较强的驱动能力和清晰的边沿。MISO作为输入可以设置为开漏PxMDOUT.y 0并上拉或者数字输入。SPI中断向量号C8051F310的中断向量表是固定的。SPI中断的中断号需要查阅数据手册。在Keil C51中通常使用interrupt 6这个数字因型号而异务必核对来声明中断服务函数。如果中断号写错中断永远不会被响应。建立一个系统的调试流程先确保硬件连接和电源无误然后用最简单的阻塞单字节读写测试配合逻辑分析仪观察波形。从最低速开始逐步提高频率并增加数据量。将问题隔离在硬件、配置、时序或软件逻辑的某一个环节能极大提高调试效率。本文还有配套的精品资源点击获取
返回列表