1. 项目概述深入MC68F375的SCI模块在嵌入式系统开发尤其是涉及工业控制、汽车电子或复杂仪器仪表时串行通信接口SCI或称UART是连接微控制器与外部世界的“咽喉要道”。它负责将CPU内部的并行数据流转换成能在单根线上顺序传输的串行比特流反之亦然。今天我们不谈那些泛泛而论的串口基础而是聚焦于一颗经典的微控制器——摩托罗拉后为飞思卡尔现属NXP的MC68F375来深度剖析其内置的SCI模块特别是它那颇具特色的“队列操作”模式。MC68F375是一款基于68K内核的16位微控制器其内置的“队列串行多通道模块”QSMC集成了强大的串行通信功能。对于许多开发者而言使用SCI无非就是配置波特率、数据位、停止位然后轮询或中断收发数据。但MC68F375的SCI提供了更高级的“队列”模式这就像给你的串口外设配备了一个智能的“收发助理”能极大减轻CPU的负担提升系统在高速或高负载通信下的实时性和可靠性。理解这个机制不仅能让你用好这颗老而弥坚的芯片其设计思想对理解现代MCU的DMA或FIFO机制也大有裨益。2. SCI核心原理与寄存器精讲在切入队列操作之前我们必须夯实基础透彻理解MC68F375 SCI模块的标准工作原理。这不仅仅是配置几个寄存器那么简单而是理解数据如何从CPU的“脑海”走到物理引脚上的电信号。2.1 通信帧数据的“信封”串行异步通信的核心是“帧”。你可以把它想象成一封信必须有开头起始位、正文数据位、可选的身份验证校验位和结尾停止位。起始位Start Bit恒为逻辑0。它标志着一帧数据的开始其关键作用在于提供一个从空闲状态逻辑1或称Mark到有效数据的明确下降沿接收方利用这个边沿来同步其内部采样时钟。手册强调一个有效的起始位之前必须至少有连续三个采样周期的逻辑1这有助于滤除线路上的噪声毛刺。数据位Data Bits紧接起始位之后是要传输的实际信息长度可以是8位或9位由控制寄存器SCCxR1中的M位决定。数据总是从最低有效位LSB开始发送。校验位Parity Bit可选用于简单的错误检测。通过计算数据位中“1”的个数选择奇校验Parity Odd或偶校验Parity Even使得连同校验位在内“1”的总数为奇数或偶数。由SCCxR1中的PE校验使能和PT校验类型位控制。停止位Stop Bit恒为逻辑1标志一帧的结束。它提供至少一个比特时间的“空闲”状态为下一帧的起始位下降沿做好准备。停止位可以是1位、1.5位或2位MC68F375的SCI支持至少1位。MC68F375的SCI支持两种标准帧格式10位帧1起始8数据1停止和11位帧1起始8数据1校验/控制1停止。当启用9位数据模式M1时第9个数据位T8/R8可以用于多机通信中的地址/数据标识。2.2 波特率通信的“心跳”波特率Baud Rate决定了每秒传输的符号数对于二进制NRZ编码就等于比特率。双方波特率必须匹配否则必然产生帧错误。MC68F375的波特率由系统时钟fSYS通过一个13位的可编程分频器SCxBR产生。计算公式非常直接SCI Baud Rate fSYS / (32 * SCxBR)反之要得到特定的波特率需计算SCxBR fSYS / (32 * Desired Baud Rate)这里有个关键细节SCxBR的值范围是1到8191写入0会禁用波特率发生器。例如对于一个33MHz的系统时钟MC68F375最高支持33MHz想要得到115200的波特率计算出的SCxBR约为8.96显然无法精确实现。此时必须取整为9实际波特率变为114583误差约为-0.54%。在长距离或高噪声环境中过大的波特率误差累积可能导致采样点偏移引发帧错误。因此在项目初期就需要根据可用系统时钟仔细计算并选择误差最小的波特率分频值。手册中的表6-29给出了40MHz时钟下的理论值实际使用时应以自己的系统时钟为准重新计算。注意接收端使用了一个16倍于波特率的内部采样时钟来同步和采样输入数据。这意味着在每个比特时间内接收器会进行16次采样并通过多数判决和边沿检测来精确定位比特中心这大大增强了抗噪声能力。这也是为什么双方波特率允许存在小范围误差通常3%仍能正常通信的原因。2.3 核心寄存器与双缓冲机制SCI的操作围绕几个关键寄存器展开理解它们的状态变迁是编程的基础。SCI数据寄存器SCxDR这是一个“窗口”寄存器。读取时它返回接收数据寄存器RDRx的内容写入时数据被送入发送数据寄存器TDRx。它本身并非一个直接的存储单元。SCI状态寄存器SCxSR反映收发状态的核心。关键标志位包括TDRE发送数据寄存器空当TDRx中的数据已转移到发送移位寄存器可以写入新数据时该位置1。这是发送数据前的“安全检查”标志。TC发送完成当发送移位寄存器中的最后一位包括停止位已移出且TDRx也为空时该位置1。表示一次完整的发送序列结束。RDRF接收数据寄存器满当一帧完整数据从接收移位寄存器转移到RDRx后该位置1。表示有数据可读。IDLE空闲线检测检测到接收线空闲连续逻辑1时置位。错误标志NF噪声、FE帧错误、PF校验错误、OR溢出错误。SCI控制寄存器1SCCxR1功能配置寄存器包括收发使能TE RE、中断使能TIE TCIE RIE ILIE、数据格式M、校验控制PE PT、循环回环LOOPS、唤醒控制RWU WAKE等。双缓冲机制是SCI高效运行的关键。无论是发送还是接收都有两个阶段CPU交互阶段CPU与数据寄存器TDRx/RDRx交互。发送时CPU写数据到TDRx接收时CPU从RDRx读数据。串行移位阶段移位寄存器与外部引脚交互。发送时移位寄存器从TDRx取数据并逐位送到TXD引脚接收时移位寄存器从RXD引脚采样并组装数据然后存入RDRx。这两个阶段是并行工作的。例如在发送时当移位寄存器正在向外发送当前帧时CPU可以提前将下一帧数据写入TDRx前提是TDRE1。一旦当前帧发送完毕硬件会自动将TDRx中的数据加载到移位寄存器中并置位TDRE通知CPU可以准备下一帧。这避免了CPU等待每个字节发送完毕的“忙等”时间是实现中断驱动或DMA传输的基础。3. 标准模式下的收发操作与中断策略理解了核心寄存器我们来看在标准非队列模式下如何组织代码实现可靠收发。3.1 发送器操作流程与状态机发送器的状态由TE发送使能、TDRE和TC共同决定。一个稳健的发送流程如下初始化配置波特率SCCxR0、数据格式、校验等。最后置位TE使能发送器。此时若TC1发送器空闲TXD引脚会立即输出一个空闲帧全1作为前导码。检查TDRE在写入SCxDR之前必须检查TDRE是否为1。如果TDRE0说明TDRx中还有未加载到移位寄存器的数据此时写入会覆盖旧数据导致数据丢失。这是新手最常见的错误之一。写入数据确认TDRE1后向SCxDR写入数据。写入操作会自动清除TDRE标志。数据转移当发送移位寄存器空闲即上一帧已发完且TDRx中有新数据TDRE0时硬件自动将TDRx的数据加载到移位寄存器并置位TDRE。此时如果TIE发送中断使能为1会产生中断提示CPU可以准备下一个发送数据。移位发送移位寄存器在波特率时钟驱动下将数据帧起始位、数据位、校验位、停止位逐位移出到TXD引脚。发送完成当移位寄存器中的停止位移出后如果TDRx中已无新数据TDRE1则置位TC标志。如果TCIE发送完成中断使能为1会产生中断。TC标志需要软件手动清除方法是先读SCxSR此时TC1再写SCxDR。关于TE位的技巧手册提到快速地对TE位进行“清零-置位”操作可以在两段消息之间插入一个至少10或11个比特时间的空闲帧前导码。这在多机通信中用于分隔消息包或唤醒处于休眠模式的接收器非常有用。3.2 接收器操作流程与错误处理接收器是异步通信中更复杂的一方因为它需要从连续的比特流中准确识别和提取帧。初始化与使能配置波特率、数据格式置位RE使能接收器。接收器开始监视RXD引脚。起始位检测与同步接收器以16倍波特率的频率采样RXD线。当检测到从1到0的下降沿且之前有至少3个采样点为1时确认为起始位开始。随后接收器调整其内部采样点使其位于每个比特时间的中心位置第7、8、9个采样点以提高采样可靠性。数据采样与移位在预定的采样点对RXD线进行采样将结果移入接收移位寄存器。帧接收完成当收到预定的停止位时一帧接收完成。硬件将移位寄存器中的数据和可能的第9位并行加载到RDRx中并置位RDRF标志。同时如果检测到错误噪声、校验、帧错误相应的NF、PF、FE标志也会被置位。CPU读取软件检测到RDRF1通常通过轮询或中断应立即读取SCxSR以获取状态包括错误标志然后读取SCxDR以获取数据。这个“先读状态再读数据”的顺序至关重要因为它会自动清除RDRF、NF、PF、FE等标志为接收下一帧做好准备。溢出错误OR这是另一个常见陷阱。如果RDRF1即CPU还未读取上一帧数据而接收移位寄存器又收到了一帧完整的新数据此时硬件无法将新数据加载到RDRx就会发生溢出。OR标志被置位RDRx中的旧数据被保留但移位寄存器中的新数据丢失。OR标志不会自动清除需要软件在读取SCxSR和SCxDR后手动处理。3.3 中断与轮询模式选择轮询模式CPU定期如在主循环中检查SCxSR的状态位TDRE RDRF。优点是程序结构简单无需中断上下文切换。缺点是需要CPU持续关注在等待事件时会浪费CPU周期不适合低功耗或高实时性要求场景。中断模式通过设置SCCxR1中的TIE、TCIE、RIE、ILIE等中断使能位让硬件在特定事件如数据寄存器空、接收数据满、空闲线检测发生时主动通知CPU。这极大提高了CPU效率允许CPU在通信间隙处理其他任务。中断服务程序ISR必须高效通常只做最低限度的数据搬运和标志清除避免长时间占用中断。个人经验在简单的单向或低速通信中轮询足够用。但在双向、高速或复杂的多任务系统中中断模式几乎是必须的。使用中断时务必注意中断嵌套和共享资源保护的问题。例如如果发送和接收共享一个缓冲区那么在ISR中访问这个缓冲区时可能需要暂时关闭全局中断或使用信号量。4. 队列操作模式硬件加速的通信引擎现在进入MC68F375 SCI模块的精华部分——队列操作。此功能仅SCI1通道支持。它本质上是在标准的双缓冲之上又增加了两级深度更大的硬件FIFO先入先出队列显著提升了数据吞吐能力和CPU效率。4.1 队列模式概述与使能标准模式下CPU需要为每一个待发送或已接收的字节/字进行干预写SCxDR或读SCxDR。队列模式则将这个交互单位从“一帧”提升到了“多帧”。发送队列一个包含16个条目SCTQ[0:15]的FIFO。CPU可以一次性将多达16帧数据写入这个队列。SCI硬件会自动按顺序将队列中的数据加载到发送数据寄存器SC1DR进而送入发送移位器发出。CPU只需在队列半空或全空时进行批量填充。接收队列同样是一个16条目SCRQ[0:15]的FIFO。接收到的数据帧在填满RDRx后会被自动搬运到接收队列中。CPU可以定期如队列半满或全满时从队列中批量读取多个数据帧而不是每收到一帧就处理一次。使能队列通过设置QSCI1控制寄存器QSCI1CR中的QTE队列发送使能和/或QRE队列接收使能位来分别启用发送和接收队列。一旦队列被启用标准模式下的TDRE和RDRF标志就应被软件忽略TC标志的功能也被重新定义。4.2 队列控制与状态寄存器详解队列的操作完全由两个新增寄存器控制1. QSCI1控制寄存器QSCI1CR这个寄存器负责配置队列的行为和中断。位域名称功能描述与编程要点15:12QTPNT发送队列指针。只读测试模式可写指示下一个将被加载到SC1DR的数据帧在发送队列SCTQ[0:15]中的位置。用于调试和监控队列状态。11QTHFI接收队列上半部满中断使能。当接收队列上半部SCRQ[0:7]被新数据完全填满时若此位置1则产生SCI1中断。10QBHFI接收队列下半部满中断使能。当接收队列下半部SCRQ[8:15]被新数据完全填满时若此位置1则产生SCI1中断。9QTHEI发送队列上半部空中断使能。当发送队列上半部SCTQ[0:7]所有数据都已发送完毕时若此位置1则产生SCI1中断。8QBHEI发送队列下半部空中断使能。当发送队列下半部SCTQ[8:15]所有数据都已发送完毕时若此位置1则产生SCI1中断。6QTE发送队列使能。1启用发送队列此时TDRE应被忽略TC功能被重定义。0禁用使用标准单缓冲模式。5QRE接收队列使能。1启用接收队列此时RDRF应被忽略。0禁用。4QTWE发送队列回绕使能。这是一个强大功能。当设置为1时允许发送队列在到达底部SCTQ[15]后自动回到顶部SCTQ[0]继续发送从而实现超过16帧的连续、无间断发送。每次回绕完成后此位由硬件自动清零。3:0QTSZ队列传输大小。4位可编程定义一次传输序列中要发送的帧数1到16。例如QTSZ4则发送完SCTQ[0], [1], [2], [3]后即使QTWE1也会停止并等待。此值在传输开始时或发生回绕时被加载到QPEND计数器。2. QSCI1状态寄存器QSCI1SR这个寄存器反映了队列的实时状态。位域名称功能描述与编程要点12QOR接收队列溢出错误。当SC1DR中有新数据准备转移到接收队列但接收队列已满QTHF或QBHF仍为1时此位置1。数据转移被禁止直到软件清除QOR。注意此处的“溢出”指队列到数据寄存器的溢出与标准模式的OR数据寄存器溢出不同。11QTHF接收队列上半部满。当SCRQ[0:7]全部被新数据填满时置1。清除方法先读QSCI1SR此时QTHF1再向QTHF位写0。10QBHF接收队列下半部满。当SCRQ[8:15]全部被新数据填满时置1。清除方法同QTHF。9QTHE发送队列上半部空。当SCTQ[0:7]中所有数据都已传输到发送移位器时置1。清除方法先读QSCI1SR此时QTHE1再向QTHE位写0。8QBHE发送队列下半部空。当SCTQ[8:15]中所有数据都已传输到发送移位器时置1。清除方法同QTHE。3:0QPEND队列未决计数器。一个4位递减计数器指示队列中还有多少帧数据等待传输到SC1DR。当计数到0时再减1会翻转为150b1111这个“15”状态表示队列传输已完成或为空闲状态。只读测试模式可写。4.3 发送队列工作流程与编程模型启用发送队列QTE1后发送操作流程发生根本变化初始化配置SCI1基本参数波特率、格式等置位TE。设置QSCI1CRQTE1 根据需要设置QTHEI/QBHEI中断使能、QTWE是否回绕、QTSZ本次发送帧数。将待发送的数据帧写入发送队列寄存器SCTQ[0]到SCTQ[QTSZ-1]。启动发送写入SCTQ后硬件自动开始处理。QPEND初始值为QTSZ并随着每一帧数据从队列加载到SC1DR而递减。队列管理当上半部队列SCTQ[0:7]数据全部发完QTHE置位若QTHEI1则产生中断。同理下半部队列发完QBHE置位并可产生中断。这是实现“乒乓缓冲”的关键CPU可以在上半部队列发送时填充下半部队列当收到下半部空中断时上半部已发送完毕可以安全填充而下半部正在发送如此循环。回绕传输如果使能了QTWE并且QTSZ设置为160b1111当发送完SCTQ[15]后QPEND减到0再变为15硬件会自动将发送指针QTPNT重置为0并从SCTQ[0]开始新一轮发送从而实现超过16帧的连续发送。每次回绕发生后QTWE位会被硬件自动清零因此如果需要无限循环必须在中断服务程序中重新置位QTWE。发送完成在队列模式下TC标志的含义被重定义。当QPEND计数器为150b1111并且发送移位器也已空闲即最后一帧的停止位也已发出时TC标志置位。这表示整个队列包括所有回绕的发送任务彻底完成。清除TC的方法也变为先读SC1SRTC1然后向任意SCTQ寄存器执行一次写操作。关键技巧要启动队列发送必须满足四个条件QTE1TE1QTHE0或QBHE0取决于你从哪半部分开始填充以及标准模式下的TDRE1。在初始化队列时通常需要先向SCTQ[0]写入一个虚拟数据并等待TDRE1以确保发送器处于就绪状态。4.4 接收队列工作流程接收队列的工作相对直接初始化配置SCI1置位RE。设置QSCI1CRQRE1 根据需要设置QTHFI/QBHFI。数据自动入队当接收器收到一帧完整数据后硬件会将其从SC1DR自动搬运到接收队列SCRQ[QRPNT]指向的位置然后QRPNT接收队列指针递增。队列状态当QRPNT移动到8即SCRQ[0:7]满QTHF置位当QRPNT移动到0即SCRQ[8:15]满指针回绕QBHF置位。相应的中断会触发。CPU读取在中断服务程序或主循环中软件根据QRPNT的值从SCRQ[0]开始顺序读取数据。读取后软件需要维护自己的“软件读指针”因为硬件指针QRPNT只指示下一个写入位置。溢出处理如果CPU读取速度跟不上接收速度导致队列满QTHF或QBHF为1时又有新数据到达QOR标志置位。此时必须由软件及时读取队列数据清除满标志然后手动清除QOR位才能恢复接收。5. 队列模式下的中断策略与编程实战队列模式的核心优势在于其智能的中断机制将CPU从频繁的字节级中断中解放出来转变为块级中断。5.1 中断配置策略发送端通常使能QTHEI和QBHEI。采用“半空中断”策略。初始化时将16帧数据分成两批每批8帧填入队列。当上半部SCTQ[0:7]发送完成产生中断时CPU知道下半部SCTQ[8:15]正在发送此时可以安全地重新填充上半部。当填充完成下半部也发送完毕产生中断时CPU再去填充下半部。如此形成“乒乓操作”理论上可以实现无间断的连续发送CPU只需在每8帧数据的时间窗口内完成填充即可中断频率降低为原来的1/8。接收端通常使能QTHFI和QBHFI。采用“半满中断”策略。当接收队列上半部SCRQ[0:7]填满时产生中断CPU批量读取这8帧数据并进行处理。在此期间下半部队列可以继续接收数据。同理下半部满中断触发时CPU处理下半部数据。这避免了每收到一帧就产生一次中断极大减少了中断上下文切换的开销。5.2 示例代码框架伪代码风格以下是一个使用发送队列连续发送数据的简化编程框架// 假设 SCTQ 是一个映射到内存地址的数组 volatile uint16_t* const SCTQ (uint16_t*)0xYFFC00; // 示例基地址需查手册确认 volatile QSCI1CR_t* const QSCI1CR (QSCI1CR_t*)0xYFFC28; volatile QSCI1SR_t* const QSCI1SR (QSCI1SR_t*)0xYFFC2A; volatile SC1SR_t* const SC1SR (SC1SR_t*)0xYFFC20; // SCI1状态寄存器 // 发送缓冲区 uint16_t tx_buffer[16]; uint8_t tx_buffer_index 0; uint8_t tx_half 0; // 0: 上半部 1: 下半部 void SCI1_TxQueue_Init(void) { // 1. 标准SCI初始化波特率、8N1格式、使能TE等 // ... // 2. 确保发送器就绪 (TDRE1) while(!(SC1SR-TDRE)) { /* wait */ } // 3. 配置队列控制寄存器 QSCI1CR-QTE 1; // 使能发送队列 QSCI1CR-QTHEI 1; // 使能上半部空中断 QSCI1CR-QBHEI 1; // 使能下半部空中断 QSCI1CR-QTWE 0; // 初始不使能回绕单次发送16帧 QSCI1CR-QTSZ 15; // 设置传输大小为16 (0b1111 151) // 4. 预填充整个发送队列 (16帧) for(int i0; i16; i) { SCTQ[i] tx_buffer[i]; // 填充数据 } // 数据填充后发送自动开始 } // SCI1 发送队列中断服务程序 void __attribute__((interrupt)) SCI1_Tx_IRQHandler(void) { // 检查中断源 if (QSCI1SR-QTHE) { // 上半部空 QSCI1SR-QTHE 0; // 清除标志 (先读后写0) tx_half 0; refill_tx_queue_half(tx_half); // 用户函数填充SCTQ[0:7] } if (QSCI1SR-QBHE) { // 下半部空 QSCI1SR-QBHE 0; // 清除标志 tx_half 1; refill_tx_queue_half(tx_half); // 用户函数填充SCTQ[8:15] } // 检查发送完成 (TC在队列模式下意义不同) if (SC1SR-TC (QSCI1SR-QPEND 0x0F)) { // 整个队列发送完成 SC1SR-TC 0; // 清除TC: 读SC1SR后写SCTQ SCTQ[0] 0xFFFF; // 虚拟写操作实际可忽略值 // 可以在这里设置完成标志通知主程序 } }5.3 常见问题与避坑指南队列不启动检查四个必要条件是否满足QTE1TE1QTHE/QBHE0取决于你初始填充了哪一半以及标准模式的TDRE1。最常见的是忘记等待TDRE1。中断不触发首先确认QTHEI/QBHEI或QTHFI/QBHFI已使能并且CPU的全局中断和SCI1通道中断已开启。其次队列状态标志QTHE QBHE等的清除有特定顺序必须先读取QSCI1SR寄存器此时标志位为1然后向该标志位写0。直接写0是无效的。回绕功能异常QTWE位在每次回绕发生后会被硬件自动清零。如果你需要连续不断的回绕发送例如发送一个环形缓冲区中的数据必须在每次QTHE或QBHE中断服务程序中在填充完数据后重新置位QTWE位。数据覆盖在发送队列中硬件指针QTPNT由硬件管理。软件在填充队列时必须确保不会覆盖尚未发送的数据。通过利用QTHE/QBHE中断并配合自己的软件写指针可以安全地管理队列。接收队列数据读取硬件只提供写指针QRPNT。软件需要维护一个独立的读指针。判断队列是否有数据可读可以通过比较软件读指针和QRPNT来实现。注意QRPNT是4位循环指针。混合模式下的冲突当QTE1时写入SC1DR是无效的所有发送数据必须通过SCTQ队列写入。同样当QRE1时应从SCRQ队列读取数据而不是SC1DR。务必不要在使能队列后还去操作标准模式的数据寄存器。队列操作是MC68F375 SCI模块提供给开发者的强大武器。它将CPU从繁琐的字节级通信管理中解脱出来通过硬件管理的FIFO和智能中断实现了数据块的流畅搬运。这种设计思想在现代MCU中演变为更通用的DMA控制器。掌握队列操作不仅能最大化发挥MC68F375的通信性能也为理解更先进的嵌入式通信架构打下了坚实的基础。在实际项目中尤其是在需要高速、连续、可靠传输的场合如通过串口升级固件、传输大量传感器数据、与上位机进行文件通信等队列模式的价值会体现得淋漓尽致。