☰
嵌入式SPI与SCI通信:寄存器配置、时序分析与避坑实战
2026/10/31 4:05:36 网站建设 项目流程

1. 为什么SPI和SCI总是“看起来简单,用起来翻车”

SPI和SCI(很多人习惯叫它UART)大概是每个嵌入式从业者入门后最早接触、也最容易被轻视的两条总线。说它简单,是因为协议本身确实不复杂:SPI四根线、同步移位;SCI两根线、起始位加数据位加停止位。说它容易翻车,是因为真正决定通信能不能跑通的,往往不是协议概念,而是寄存器里那几个位有没有配对、时序参数有没有压在器件手册的边界内、片选和时钟的先后顺序有没有摆对。我见过太多项目,原理图连通、代码编译通过、单步调试也正常,一上整机就间歇性丢包或者花屏,最后查出来是CPHA配反了或者波特率误差累积超了采样窗口。

这篇内容围绕SPI与SCI通信的寄存器配置、时序细节和实战避坑展开,面向已经能写基础驱动、但被偶发故障折腾过的嵌入式开发者,也适合刚接手板级通信调试、想把底层逻辑一次性理顺的朋友。我不会只贴一段初始化代码了事,而是把每个控制位背后的意图、每个时序参数为什么要留余量、每种异常波形对应的硬件或配置原因都拆开讲。读完之后,你至少应该能做到两件事:拿到一款新MCU的参考手册,能独立把SPI和SCI的初始化顺序排对;接上逻辑分析仪,能看懂波形哪里不对、该往哪个寄存器上找原因。

先给一个整体判断:SPI的难点在“同步”二字,SCI的难点在“异步”二字。同步意味着有时钟线兜底,理论上只要时钟和数据沿对齐就能传,但正因为有时钟,极性、相位、片选建立时间这些细节会被放大;异步意味着没有共享时钟,收发双方全靠各自的波特率发生器“对表”,误差、采样点、帧格式任何一项偏了,数据就会错位。把这两条主线抓住,后面所有的寄存器配置和排查动作都有落脚点。

1.1 两种总线的本质差异与选型逻辑

先把两者的定位说清楚,不然后面配置时很容易把思路串掉。SPI是同步、全双工、主从结构的总线,典型四线:SCLK时钟、MOSI主出从入、MISO主入从出、CS片选。它没有地址概念,靠片选选从机,靠时钟同步移位,速率可以做到几十兆赫兹,适合板内短距离、高速率、数据量大的场景,比如外部Flash、LCD屏、高速ADC、传感器阵列。代价是线数多、没有应答机制、没有硬件差错重传,主设备发出去的数据从设备有没有收到,协议层是不管的,得靠上层自己校验。

SCI是异步、全双工、点对点的串行接口,典型两线:TX和RX,加上可选的硬件流控RTS/CTS。它没有时钟线,收发双方约定同一个波特率,靠起始位下降沿对齐,靠停止位收尾。速率通常从几千到几兆波特,适合板间通信、连接上位机、接GPS/蓝牙/工业仪表这类外设。它的优势是线少、距离相对远、几乎每款MCU都带,缺点是速率上不去、点对点为主、多机场景要额外做地址识别或软件协议。

选型时我一般按这几个维度过一遍:距离——板内几厘米到十几厘米优先SPI,超过半米基本考虑SCI或差分总线;速率——需要几兆以上的连续数据流,SPI更稳;线数预算——排线紧张、连接器针脚有限,SCI两线更划算;是否需要多从机——SPI靠片选扩展,SCI要靠地址位或软件轮询;实时性要求——SPI是全双工同步,收发同时进行,SCI全双工但收发独立缓冲,中断响应要及时。

这里有个容易被忽略的点:很多人以为SPI一定比SCI快,其实要看有效吞吐。SPI虽然时钟高,但如果每次只传一个字节、片选频繁拉高拉低,加上软件开销,实际吞吐未必比一个配置良好的SCI高多少。反过来,SCI如果波特率误差控制得好、配合DMA搬运,做几百KB级别的数据回传也很稳。所以选型不是背结论,而是把上面几个维度列出来打分。

1.2 新手最容易踩的三个认知误区

误区一:SPI只要把时钟分频配好就能通信。实际上CPOL和CPHA决定了时钟空闲电平和采样沿,配错一个位,数据就会整体移一位或者采样到跳变沿上,现象是收到全0、全1或者规律性错位。更隐蔽的是,有些从器件手册写的是“模式0”,但它的时序图里片选拉低到第一个时钟沿之间有最小时间要求,配置对了模式、片选时序没留够,照样偶发失败。

误区二:SCI只要两边波特率数字一样就能通。波特率是“标称值”,真正的误差来自系统时钟分频后的实际频率。两边各自有误差,误差会累积到采样点上。SCI接收端通常做16倍过采样、在中间几位做多数表决,理论上能容忍百分之二点几的偏差,但如果你用的晶振本身精度差、分频系数又取得粗,实际偏差摸到临界值,短帧能通、长帧就丢。我调试时就遇到过一个案例:单字节收发测试全对,连续发两百字节偶尔错一个,最后算下来误差接近百分之二点八,换了分频系数就恢复了。

误区三:寄存器写完就立刻生效。很多外设的使能位、缓冲空标志、错误标志有固定的清除顺序。比如发送数据寄存器写进去之后,要等状态寄存器的发送空标志置位才能写下一个字节;接收标志读完数据寄存器才清除。顺序反了,要么丢字节,要么中断反复进出。还有一种情况是配置寄存器在模块使能状态下修改无效,必须先关使能、改配置、再重新使能。这些细节参考手册里都有,但散落在不同章节,不系统梳理一遍很容易漏。

2. SPI寄存器配置全拆解:从时钟极性到数据位宽

2.1 SPI控制寄存器的位域逐项解析

不同MCU的SPI寄存器命名不一样,但核心位域大同小异。我按功能把它们归成四组:使能与主从组(SPE模块使能、MSTR主从选择)、时钟组(CPOL极性、CPHA相位、波特率分频位)、数据格式组(数据位宽、LSB/MSB先行)、中断与片选组(发送空中断、接收满中断、片选输出使能)。初始化时建议按“先清控制寄存器、再配时钟和数据格式、最后开使能和中断”的顺序走,避免模块在半配置状态下被意外触发。

以常见的8位数据、模式0、主机、分频系数4为例,一段典型的初始化代码长这样:

void spi_master_init(void) { SPI_CR1 = 0x00; /* 先清零,确保模块处于已知状态 */ SPI_CR1 &= ~(1 << 6); /* SPE=0,配置期间关闭模块 */ SPI_CR1 |= (1 << 4); /* MSTR=1,主机模式 */ SPI_CR1 &= ~(1 << 3); /* CPOL=0,空闲低电平 */ SPI_CR1 &= ~(1 << 2); /* CPHA=0,第一个边沿采样 */ SPI_CR1 &= ~(1 << 1); /* 8位数据宽度 */ SPI_CR1 &= ~(1 << 0); /* MSB先行 */ SPI_BR = 0x01; /* 分频系数4,具体编码查手册 */ SPI_CR1 |= (1 << 6); /* SPE=1,使能模块 */ }

这段代码看起来平平无奇,但每一行都有讲究。先清零是为了清掉复位后可能残留的默认位,有些MCU复位值并不是全0。配置期间关闭SPE,是因为部分型号在模块运行时修改分频或模式位会不生效甚至产生异常时钟。MSTR必须在片选有效之前置位,否则主机没进入主模式,时钟根本不会输出,你看到的波形就是一条平线。最后开SPE的时机也有说法:如果从器件对片选和时钟的先后有要求,最好先把片选拉高(无效),开SPE之后再按协议拉低片选启动传输。

状态寄存器这边重点关注三个标志:发送缓冲空(可以写下一个字节)、接收缓冲满(有数据可读)、模式错误(主机模式下片选被外部拉低,说明多主冲突)。模式错误一旦置位,很多MCU会强制退出主模式,必须软件清标志再重新配置,这个坑在多设备共板、片选走线干扰大的场景里很常见。

数据寄存器是收发共用的,写操作填发送缓冲,读操作取接收缓冲。全双工的本质是:你写一个字节出去的同时,从器件也在往MISO上移一个字节回来。所以主机发数据时不要以为“只发不收”,接收缓冲该读还得读,不读会溢出。

2.2 CPOL/CPHA四种模式与时序对应关系

CPOL决定时钟空闲时是高还是低,CPHA决定在第一个边沿还是第二个边沿采样。两个位组合出四种模式,这是SPI调试里最高频的翻车点。我用一张表把它固定下来:

模式CPOLCPHA空闲电平采样沿数据移位沿
000低上升沿下降沿
101低下降沿上升沿
210高下降沿上升沿
311高上升沿下降沿

记忆方法别死背表,用“CPHA=0看第一个边沿,CPHA=1看第二个边沿”这条规则推。模式0和模式3是最常用的,大部分Flash和传感器用模式0或模式3。模式1和模式2相对少,但不是没有,接之前务必翻从器件手册的时序图,看它在时钟的哪个沿上把数据摆稳、哪个沿上要求主设备采样。

生活化一点类比:SPI通信像两个人按节拍传球。CPOL是约定“不说话的时候手放低还是放高”,CPHA是约定“哨声响第一下就传,还是等第二下再传”。两个人约定不一致,球就掉地上。你配的模式和从器件要求的不一致,示波器上能看到数据和时钟错开半个周期,解码出来就是整体移位的乱码。

这里有一个实操细节:改模式之前先把片选拉高、等时钟稳定几个周期再改。有些从器件在片选有效期间收到异常时钟沿,内部状态机会乱,表现是改完模式第一次通信正常、第二次开始错。保险做法是配置阶段片选一直保持无效,配置完成后再按正常流程拉低启动。

2.3 波特率分频计算与实战取值

SPI的时钟来自系统总线时钟分频,公式通常是SCLK = f_bus / 分频系数,分频系数多为2的幂次(2、4、8、16、32、64、128)或者2、4、6、8这种偶数序列,具体看型号。计算时先确认两件事:从器件支持的最高SCLK,以及主机在这个时钟下PCB走线能不能撑住信号完整性。

举个例子,系统总线时钟48MHz,从器件手册标最高20MHz,分频系数取4得12MHz,留了余量,稳。如果取2得24MHz,超了从器件上限,轻则通信不稳,重则从器件锁死。再比如总线时钟25MHz,想跑10MHz,25/10=2.5,没有这个分频档,只能取4得6.25MHz或者取2得12.5MHz。取12.5MHz虽然没超很多器件上限,但走线长、又没有端接电阻,时钟边沿振铃明显,采样容易出错。我一般会在满足吞吐的前提下把时钟往低取一档,尤其是排线连接、非板内直连的场景。

还有一个容易漏的点:分频寄存器写入后,如果模块已经使能,新分频可能要等到当前传输结束才生效。连续传输中间改分频,会出现前半段一个速率、后半段另一个速率,从器件的时序窗口未必兼容。需要动态调速率时,老老实实拉高片选、关模块、改分频、再开模块。

2.4 片选管理与多从机拓扑

片选看着最简单,一根GPIO或者硬件片选输出,实际上它是SPI稳定性的关键。片选的建立时间和保持时间必须满足从器件要求:片选拉低到第一个时钟沿之间要有最小延时,最后一个时钟沿到片选拉高之间也要有最小延时。这两个参数在从器件手册的时序表里通常叫 tCSS 和 tCSH,值可能只有几十纳秒,但软件模拟片选时如果写完GPIO立刻启动传输,中间没有插入延时,就可能踩线。

多从机有两种常见接法。独立片选是每个从机一根CS,主机同一时刻只拉低一根,其余保持高。这种方式逻辑简单,但GPIO占用随从机数量线性增长。菊花链是所有从机串起来,数据从一个进去、经过每个器件移位、从最后一个出来,片选共用。菊花链省引脚,但要求从器件支持,而且传输长度等于所有器件位宽之和,软件上要按整条链组织数据。两种方式都别混着用,我见过有人片选独立、数据线却又并联后没处理好MISO冲突,两个从机同时驱动MISO,读回来全是中间电平。

软件片选还有一个实践建议:片选拉低和拉高尽量用位带操作或者寄存器直接写,不要在中间夹打印、夹延时函数调用。调试阶段加了串口打印,片选保持时间被拉得老长,从器件本来能接受,换到正式环境去掉打印反而时序变了。反过来,如果调试时用软件延时凑时序,量产换主频之后延时不准,也会出问题。片选时序要么靠硬件保证,要么用定时器精确控制,别靠“大概等一会儿”。

3. SCI(UART)配置要点:波特率、帧格式与中断

3.1 SCI寄存器组与初始化顺序

SCI的寄存器组通常分三块:波特率寄存器(高位和低位)、控制寄存器(收发使能、中断使能、帧格式)、状态寄存器(发送空、发送完成、接收满、溢出、帧错误、校验错误)。初始化顺序我习惯按这个走:先关收发和中断,再配波特率,再配帧格式(数据位、停止位、校验),最后开接收、开发送、按需开中断。顺序反了,比如先开接收再配波特率,模块会用一个默认或者残留的波特率去采样,起始位都识别不对,直接进帧错误。

void sci_init(uint32_t baud) { SCI_CR1 = 0x00; /* 关闭收发和中断 */ SCI_BDH = (uint8_t)(div >> 8); /* 波特率高位 */ SCI_BDL = (uint8_t)(div & 0xFF);/* 波特率低位 */ SCI_CR1 |= (1 << 4); /* 8位数据 */ SCI_CR1 &= ~(1 << 3); /* 无校验 */ SCI_CR1 &= ~(1 << 2); /* 1位停止位 */ SCI_CR1 |= (1 << 1); /* 接收使能 */ SCI_CR1 |= (1 << 0); /* 发送使能 */ SCI_CR2 |= (1 << 5); /* 接收中断使能,按需 */ }

这里有个细节:波特率寄存器写入通常要等当前传输结束才生效,初始化阶段模块还没开始传,直接写没问题;运行中改波特率必须先关收发。另外发送使能和接收使能是独立的,只做发送的场合没必要开接收中断,省得进中断读空数据。

状态寄存器的标志清除方式也要记牢:接收满标志读数据寄存器自动清,发送空标志写数据寄存器自动清,溢出和帧错误标志一般是“先读状态寄存器、再读数据寄存器”两步清除。顺序错了,标志清不掉,中断会一直进,程序看起来像死循环。这个细节我在早期项目里栽过,接收中断里先读数据没读状态,溢出标志一直挂着,主循环被中断拖死。

3.2 波特率误差计算与晶振选型

SCI没有时钟线,误差直接决定采样点会不会飘出数据位窗口。分频公式一般长这样:分频值 = f_bus / (16 × 波特率),有的型号是8倍或13倍过采样,以手册为准。算出来的分频值取整,再反算实际波特率,误差 =(实际 - 目标)/ 目标 × 100%。

接收端通常16倍过采样,在起始位下降沿之后数到第8、9、10个采样点做多数表决确定起始位中心,之后每个数据位按16个采样点取中间三个表决。理论上单边能容忍的误差大约是半个位宽再打点折扣,工程上我按**总误差不超过2%**来控制,接近2.5%就要警惕,超过3%基本不能指望长帧稳定。

晶振选型是误差的源头。经典的11.0592MHz之所以在串口时代流行,就是因为11.0592M除以16再除以常见波特率(9600、19200、115200)能得到接近整数的分频值。换成8MHz晶振,算115200的分频值是 8M/(16×115200)≈4.34,取4反算实际波特率125000,误差约8.5%,根本不能用;取5反算100000,误差13%,更离谱。这种时候要么换晶振,要么用支持小数分频的型号,要么把系统时钟倍频到一个对波特率友好的频率。我整理过一张常见组合的误差对照,配置前先查表能省很多事:

系统时钟目标波特率分频值(取整)实际波特率误差
11.0592MHz11520061152000%
11.0592MHz96007296000%
8MHz11520041250008.5%
8MHz96005296150.16%
16MHz11520091111113.5%
16MHz960010496150.16%

表格看下来结论很清楚:低速波特率对时钟不挑剔,高速波特率必须挑时钟。115200在8MHz和16MHz下都不能直接用整数分频,要么倍频到能整除的频率,要么换晶振。实际项目里如果板子已经定了8MHz晶振又必须跑115200,优先考虑把总线时钟倍频到48MHz,48M/(16×115200)≈26.04,取26反算115384,误差0.16%,完全可用。

3.3 收发中断与DMA配合

中断方式适合低速、数据量小的场景。接收中断里第一时间把数据寄存器读出来存进环形缓冲,别在中断里做解析。发送中断里从缓冲取一个字节写数据寄存器,缓冲空了就关发送中断,避免空中断反复触发。这里的关键是中断服务程序要短,读、写、清标志,三步走完就退出,解析和业务逻辑放主循环。

数据量大或者波特率高的时候,中断开销会吃掉不少CPU。115200波特率下每个字节间隔约87微秒,如果中断里还做别的事,很容易跟不上。这种场景上DMA更稳:接收DMA配成循环模式或者配合空闲中断,发送DMA搬完一帧再触发完成中断。空闲中断的思路是——总线上连续一段时间没有新数据,判定一帧结束,这时候去DMA缓冲里取整包。这个方案做不定长协议特别好用,比逐字节中断+超时判断干净得多。

不管用中断还是DMA,缓冲区的读写指针要防并发。中断里写指针、主循环里读指针,简单场景用“读指针追写指针”的环形结构,复杂场景加临界区保护。我见过因为指针没保护、主循环读到半写状态的数据,解析出一堆乱码,查了半天以为是波特率问题,其实是并发。

3.4 帧格式、校验与流控

帧格式三要素:数据位(常见7或8)、停止位(1或2)、校验位(无、奇、偶)。两边必须完全一致,少配一位都收不对。8N1是默认选项,绝大多数场景够用。需要校验的场合,硬件奇偶校验能挡掉一部分单比特错误,但挡不住成片干扰,重要数据还是要在应用层加CRC或校验和。

硬件流控RTS/CTS解决的是“接收方缓冲快满时通知发送方暂停”。CTS是输入,低有效表示可以发;RTS是输出,低有效表示自己准备好了。线序交叉接:本方RTS接对方CTS,本方CTS接对方RTS。不接流控又高速连续传输,接收方处理不过来就会溢出。软件流控用XON/XOFF字符,实现简单但会占用数据字符空间,二进制数据里出现这两个字符就麻烦了,一般不推荐。

还有个实际经验:TX和RX的引脚复用和上下拉。TX配成推挽输出,RX配成输入并开上拉,防止悬空时收到随机噪声。板间连接如果线缆较长,TX串一个小电阻(22到100欧姆)能压一压过冲,RX端加对地小电容滤高频毛刺,具体取值看速率和线长,速率越高电阻越小、电容越小。

4. 时序详解:示波器下的真实波形与理论差异

4.1 SPI时序关键参数与建立保持时间

SPI的时序表里,主设备要保证的参数主要有:片选有效到第一个时钟沿的建立时间 tCSS、最后一个时钟沿到片选无效的保持时间 tCSH、时钟周期 tSCLK、时钟高低电平宽度、数据输出相对采样沿的建立时间 tSU 和保持时间 tH。从器件手册给的是它“需要”的最小值,主设备配出来的实际值要大于这些最小值,并且留余量。

最容易忽略的是数据建立和保持时间。主机在移位沿把数据摆到MOSI上,从器件在采样沿读取,中间隔半个时钟周期。时钟频率越高,这半个周期越短。比如12.5MHz时钟,半周期40纳秒,减去PCB走线延迟、引脚输出延迟、从器件输入建立时间,余量可能只剩十几纳秒。走线一长、负载电容一大,边沿变缓,实际到达从器件的有效窗口更窄,就开始偶发错位。示波器上能明显看到时钟和数据边沿不再陡峭,甚至数据在采样沿附近还在爬坡。

我一般的做法是先用较低时钟把功能跑通,再逐步提频,同时用逻辑分析仪看解码误码率。提到某个频率开始出错,就退回上一档,这就是这块板子在当前走线下的实际上限。手册标的最高频率是器件能力,不是你的板子能力。

4.2 SCI异步时序与采样点

SCI接收的时序核心是“对齐”。空闲时线路高电平,起始位是一个下降沿,接收端检测到这个下降沿后启动内部采样计数,在起始位中间确认电平仍为低,然后每隔一个位时间采一次,直到停止位。16倍过采样的意义是把每个位分成16份,取中间几份表决,抗噪能力强。

误差的影响可以这样理解:发送方和接收方的位时间有微小差异,传的位数越多,采样点偏离位中心越远。传10位(1起始+8数据+1停止)时误差累积到接近半个位宽,就开始采错。这就是为什么长帧对波特率误差更敏感。示波器上如果看到接收方的采样点逐渐往数据位边缘漂,基本就是误差偏大。

帧错误(FE)标志就是接收端在停止位位置采到低电平,说明帧没对齐或者线路被干扰。溢出(OR)标志是上一帧还没读走、下一帧已经收完,软件处理太慢。这两个标志在调试时非常有用,连续出现帧错误先查波特率,连续出现溢出先查软件读取频率。

4.3 用逻辑分析仪验证配置

逻辑分析仪的协议解码功能是排查SPI和SCI的利器。SPI解码要设对模式(CPOL/CPHA)、位宽、位序,设错了解出来是乱码,别急着怀疑硬件。SCI解码设对波特率、数据位、校验、停止位,解码窗口里能直接看到每一帧的字节值、帧错误标记。

抓波形时重点看三样:时钟质量(有没有振铃、过冲、边沿变缓)、数据与时钟的相对位置(数据跳变是不是发生在采样沿附近)、片选时序(片选拉低到第一个时钟沿够不够、最后一个时钟沿到片选拉高够不够)。振铃严重时可以在源端串电阻或者降低时钟;数据贴采样沿太近,检查模式配置和走线延迟;片选时序不够,软件里插入几个空操作或者用硬件片选。

5. 实战避坑指南:典型故障与排查路径

5.1 通信无响应的排查清单

通信完全没反应,按这个顺序过一遍,能覆盖九成情况:供电和地——从器件有没有电、地有没有共、电平是否匹配(3.3V器件接5V主机要电平转换);引脚复用——GPIO有没有切到外设功能,很多MCU默认是普通IO,不配复用功能,时钟根本出不来;模块时钟——外设时钟使能位有没有开,这个漏了寄存器写进去也不生效;片选——软件片选有没有拉低、硬件片选极性对不对;模式——SPI的CPOL/CPHA、SCI的波特率和帧格式;使能位——SPE、TE、RE这些总开关有没有置位。

排查时我习惯先量电平再抓波形:万用表量片选、时钟、数据线的静态电平,和预期对比;再用逻辑分析仪抓一次传输,看有没有时钟、有没有数据跳变。有时钟没数据,查MOSI配置和发送缓冲;有数据没时钟,查主从模式和使能;全都没有,回到供电和复用。

5.2 数据错位与位翻转

数据整体移一位,十有八九是CPHA配反了,采样沿和移位沿对调,收到的数据等于发送数据左移或右移一位。规律性错位(比如每隔几位错一次)看位宽配置,8位器件按16位传,高低字节顺序就乱了。随机位翻转优先查信号完整性:时钟太快、走线太长、没有地回流、旁边有开关电源干扰。降频能改善就是信号完整性问题,降频不改善再查配置。

SCI这边,数据位错位常见于波特率误差偏大或者停止位配错。收到的字节值稳定地偏某个固定模式,算一下误差;偶尔错一个字节且伴随帧错误标志,查线路干扰和共地。

5.3 多从机场景的片选时序

多从机最容易出的是片选竞争:一根片选还没拉高,另一根已经拉低,两个从机同时驱动MISO,读回来是中间电平或者互相拉扯的波形。软件上保证“先拉高当前片选、插入短延时、再拉低目标片选”。硬件上片选走线尽量等长,避免到达时间差太多。

菊花链场景还要注意数据长度对齐,整条链的位宽是各器件之和,少发一位后面全错位。配置时把链上每个器件的位宽列清楚,发送缓冲按总长度组织。

5.4 常见问题速查表

现象优先怀疑排查动作
SPI完全无时钟输出模块未使能、非主模式、引脚未复用查SPE、MSTR、复用寄存器
SPI收到全0或全1片选未拉低、MISO未接、模式错误量片选电平、查CPOL/CPHA
SPI数据整体移位CPHA配反、位序配反对照从器件时序图改模式
SPI偶发错位时钟过快、走线过长、无地回流降频验证、查信号完整性
SCI收不到数据波特率误差大、TX/RX接反、未开接收算误差、交叉线序、查RE位
SCI偶发帧错误波特率临界、干扰、停止位不符查误差表、加滤波、核对帧格式
SCI接收溢出软件读取太慢、中断被阻塞提高读取频率、上DMA、查中断优先级
多从机读回异常片选竞争、MISO冲突查片选切换时序、加延时

6. 我在实际项目里沉淀的几条经验

第一条,先把时序图打印出来贴在工位上。寄存器配置可以查、代码可以抄,但时序图里的 tCSS、tCSH、tSU、tH 这些参数是这块板子能不能稳的根。配置前对着图把每个参数的实际值算一遍,比出问题后再回头翻手册省太多时间。

第二条,任何通信驱动都先做回环测试。SPI把MOSI和MISO短接,发什么收什么,验证移位逻辑和中断流程;SCI把TX和RX短接,验证波特率和帧格式。回环能过,再接真实器件,能把“驱动问题”和“器件问题”分开,排查范围直接砍一半。

第三条,示波器和逻辑分析仪别等出问题才用。功能刚跑通的时候就抓一版正常波形存下来,后面出异常拿来对比,一眼就能看出是时钟变了、数据位置偏了还是片选时序短了。没有基准波形,异常波形看起来都差不多。

第四条,配置参数留余量,别贴着手册上限跑。时钟取低一档、波特率误差控制在百分之二以内、片选延时多给几十纳秒,这些余量在实验室看不出来,到了温度变化、电源波动、线缆变长的现场就是稳定和不稳定的分界线。嵌入式通信的很多“玄学问题”,本质都是余量不够。

第五条,错误标志要真的去看。SPI的模式错误、SCI的帧错误和溢出错误,这些标志平时不声不响,出问题时就是最直接的线索。中断里顺手读一下状态寄存器,把异常计数存起来,比事后猜要靠谱得多。这套习惯我保持了很多年,后来接手别人代码时,第一件事也是看它的错误处理有没有把标志读全。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询