1. 项目概述如果你在玩MC68000或者类似的经典老系统想搞个串口通信大概率会碰到MC68HC681这颗芯片。它不是什么新玩意儿但绝对是那个时代嵌入式系统里串口扩展的“瑞士军刀”。简单说它就是一颗双通道的通用异步收发器也就是DUART。在那个CPU资源宝贵、外设集成度不高的年代能在一颗芯片里搞定两个独立的全双工串口外加一堆可编程的输入输出引脚和一个16位定时器简直是工程师的福音。我最早接触它是在一些老旧的工控板卡和通信设备上后来在一些复古计算和自制MC68000系统中也经常用到。它的核心价值在于你不需要为每个串口都配一堆逻辑芯片和电平转换电路一颗681就能提供两个完全独立、可高度定制的串行通道还能省出CPU的I/O口去做别的事情。无论是连接终端、调制解调器还是与其他微控制器进行数据交换它都能胜任。这篇文章我就结合手册和实际调板子的经验把这颗芯片从引脚信号、内部架构到每一个寄存器的编程细节掰开揉碎了讲清楚。无论你是刚入门嵌入式的新手还是想重温经典架构的老鸟都能从这里找到直接能用的代码和避坑指南。2. 芯片架构与核心模块解析MC68HC681的架构设计体现了早期Motorola微控制器外设的典型思路模块化、总线兼容、高度可配置。理解它的整体框图是进行有效编程的基础。2.1 内部总线与处理器接口681通过一个8位双向数据总线D0-D7与MC68000系列处理器通信。这不是一个简单的并行口而是一个异步总线接口这意味着读写时序需要由DTACK数据传送应答信号来握手。当CPU选中芯片CS拉低并进行读/写操作时681在准备好数据或接收完数据后会拉低DTACK通知CPU本次操作完成。这种异步方式使得它能适应不同速度的处理器但编程时需要确保你的CPU驱动代码能正确处理DTACK的等待。四根寄存器选择线RS1-RS4决定了CPU访问的是内部26个寄存器/命令中的哪一个。这16个地址编码结合R/W信号构成了对芯片的完全控制。RESET引脚是硬复位它会将芯片恢复到已知的初始状态而软件则可以通过命令寄存器实现部分模块的复位。2.2 双通道UART核心这是芯片的心脏。通道A和B在结构上完全独立每个都包含发送器一个发送保持寄存器THR和一个发送移位寄存器TSR。THR是双缓冲的这意味着你可以在当前字符正在移位发送时预先写入下一个字符从而提高效率。接收器一个四级的FIFO先入先出缓冲区。这是681的一个亮点。接收到的字符会依次存入三个接收保持寄存器RHR和一个接收移位寄存器RSR组成的FIFO中。这意味着CPU可以稍晚一点来读取数据降低了因处理不及时而丢失数据的风险特别适合在中断服务程序中一次处理多个连续到达的字符。独立的波特率发生器与时钟选择器每个通道的接收器和发送器都可以独立选择时钟源。时钟可以来自片内波特率发生器BRG产生的18种标准速率50到38400波特也可以来自可编程的16位计数器/定时器C/T的输出或者直接来自外部输入引脚IP2-IP5提供的1X或16X时钟。这种灵活性允许两个通道以完全不同的速率工作甚至一个通道使用内部时钟而另一个使用外部时钟。2.3 可编程并行I/O端口681提供了14个额外的通用I/O引脚但它们的功能远不止简单的输入输出。6位输入端口IP0-IP5除了作为普通数字输入每个引脚都有第二功能。例如IP0和IP1可分别配置为通道A和B的CTS清除发送输入用于硬件流控。IP2-IP5则可作为外部时钟输入。更实用的是IP0-IP3内置了边沿检测电路。任何引脚上的电平变化高到低或低到高只要稳定超过25-50µs就会在输入端口变化寄存器IPCR中置位相应的标志位并可选择产生中断。这个功能非常适合用来检测按键、开关状态变化或外部事件无需CPU不断轮询。8位输出端口OP0-OP7同样每个输出引脚都可被赋予特定功能。OP0和OP1可分别作为通道A/B的RTS请求发送或RTR准备接收输出。OP2-OP7则可以输出各个通道的“就绪”中断信号如发送器空TxRDY、接收器就绪RxRDY或FIFO满FFULL或者时钟信号。这些中断输出是开漏的可以“线或”在一起方便构建多中断源系统。一个关键细节输出寄存器OPR的逻辑是反相的。向OPR的某位写‘1’对应的OPx引脚输出低电平写‘0’则输出高电平。编程设置输出状态时务必记住这一点。2.4 中断控制系统681的中断设计非常精巧。它提供了一个总的中断请求输出IRQ开漏低有效可以响应8种内部事件通道A发送器就绪通道A接收器就绪或FIFO满通道A断线状态变化计数器/定时器就绪通道B发送器就绪通道B接收器就绪或FIFO满通道B断线状态变化输入端口IP0-IP3状态变化通过中断屏蔽寄存器IMR你可以单独允许或禁止任何一个事件触发IRQ。当IRQ有效且CPU发出中断响应IACK时681会将其内部的中断向量寄存器IVR内容放到数据总线上。这个向量值是可编程的方便你构建中断向量表。更强大的地方在于除了这个集中的IRQ你还可以通过配置输出端口OP3-OP7让它们直接输出上述某些中断条件如TxRDYA、RxRDYA等。这样你可以为高优先级的中断源分配独立的硬件中断线实现更灵活的中断管理。2.5 16位可编程计数器/定时器C/T这个16位的C/T模块是个多面手。它可以从四个时钟源中选择其一X1时钟、X1/16、外部IP2引脚输入、或者来自通道A的发送器时钟。它有两种工作模式定时器模式对选定的时钟进行分频产生一个周期性的方波输出可输出到OP3并可产生中断。常用于产生精确的时间基准或波特率。计数器模式对外部事件IP2的上升沿进行计数当计数值达到预设值时产生中断。常用于测量脉冲宽度或统计事件次数。C/T的当前计数值可以随时被CPU读取这在实现超时检测、软件看门狗或复杂协议定时时非常有用。3. 关键寄存器详解与编程模型理解了架构我们深入到编程的核心——寄存器。681的寄存器访问由RS1-RS4这4根地址线决定共16个地址。其中一些地址对应的是同一物理寄存器的不同“视图”如读状态、写命令还有一些地址触发的是特定操作如复位接收器。3.1 模式寄存器MR1x, MR2x每个通道有两个模式寄存器MR1和MR2它们决定了串口通信的基本格式和行为。重要规则MR1的访问有特殊性。在软件复位接收器或发送器后或者首次访问该通道时下一个对该通道“写”操作的目标地址通常是MR1A/MR1B的地址会被解释为写入MR1。此后对该地址的写操作会被解释为写入MR2直到下一次发生上述复位事件。读操作则总是返回MR1。模式寄存器1MR1主要配置接收器位[1:0]: 字符长度。005位016位107位118位。位[2]: 校验类型。0偶校验1奇校验当启用校验时。位[4:3]: 校验模式。00带校验位01强制校验位为1常用来模拟9位数据中的第9位为110强制校验位为0第9位为011无校验。位[5]: 错误模式。0字符错误模式每个错误字符都会在状态寄存器中标记1块错误模式只在第一个出错的字符处标记后续错误字符只标记FE或PE不标记OE。位[6]: 接收器中断选择。0RxRDY接收器就绪即FIFO中有数据产生中断1FFULLFIFO满产生中断。这个选择也决定了OP4/OP5输出哪个信号。位[7]: 接收器准备接收控制RTR。当OP0/OP1被配置为RTR输出时此位控制其行为。模式寄存器2MR2主要配置发送器和停止位位[1:0]: 与MR1的位[1:0]共同决定字符长度实际上MR2的低两位在5-8位字符模式下被忽略但手册建议写入与MR1相同的值。位[3:2]: 停止位长度。001位011.5位仅用于5位字符102位。位[4]:CTS使能控制。1使能CTS引脚IP0/IP1控制发送器只有CTS有效低电平时才能发送0忽略CTS。位[5]:RTS控制。当OP0/OP1配置为RTS输出时此位控制其行为。位[7:6]: 通道模式选择。00正常全双工模式01自动回波模式接收到的数据自动从发送端发出10本地环回模式发送端输出在内部连接到接收端输入用于自检11远程环回模式发送端输出直接驱动接收端输入同样用于测试。3.2 时钟选择寄存器CSRxCSRA和CSRB分别控制通道A和B的接收与发送时钟源。每个寄存器高4位位[7:4]选择接收时钟低4位位[3:0]选择发送时钟。时钟源编码如下0000: 禁止时钟关闭接收器或发送器。0001-0010: 保留。0011-1100: 选择波特率发生器BRG的18个固定速率之一。具体对应关系需要查表例如对于3.6864MHz的晶振0011对应50波特1100对应38400波特。1101: 选择外部IPx引脚提供的1X时钟RxC或TxC。1110: 选择外部IPx引脚提供的16X时钟。1111: 选择可编程计数器/定时器C/T的输出作为时钟。编程心得通常如果两个通道使用相同的标准波特率可以让它们都使用BRG。如果需要非标准波特率或者一个通道需要非常精确的时钟可以配置C/T产生所需频率然后让通道选择1111。如果需要与外部时钟同步则使用1101或1110。3.3 命令寄存器CRx命令寄存器用于动态控制通道状态写入操作会立即触发相应动作。它是一个只写寄存器。位[1:0]: 接收器命令。00无操作01使能接收器10禁止接收器11软件复位接收器复位后下一次写该通道地址会指向MR1。位[3:2]: 发送器命令。00无操作01使能发送器10禁止发送器11软件复位发送器。位[6:4]: 杂项命令。包括复位错误状态清除FE,PE,OE标志、复位断线状态变化中断、发送断线信号强制TxD输出低电平、使能RTS输出等。位[7]: 必须写0。3.4 状态寄存器SRx状态寄存器是只读的反映了通道的实时状态。轮询或中断服务程序首先要读的就是它。位[0]:RxRDY。1接收保持寄存器FIFO中有数据可读。位[1]:FFULL。1接收FIFO已满3个字符。位[2]:TxRDY。1发送保持寄存器空可以写入下一个字符。位[3]:TxEMT。1发送移位寄存器也为空发送线完全空闲。位[4]:OEOverrun Error。1发生超限错误即CPU未及时读取数据新字符覆盖了未读的旧字符。位[5]:PEParity Error。1奇偶校验错误。位[6]:FEFraming Error。1帧错误未检测到有效的停止位。位[7]: 断线检测。1检测到接收数据线RxD持续为低电平空间状态超过一个完整的字符传输时间。避坑指南读取接收数据寄存器RHR会自动清除RxRDY和FFULL标志。而错误标志OE,PE,FE和断线标志必须通过向命令寄存器写入“复位错误状态”或“复位断线变化中断”命令来清除。如果不清除这些标志会一直存在影响后续的状态判断。3.5 中断相关寄存器中断状态寄存器ISR: 只读。其8位分别对应8个可能的中断源。某位为1表示该中断条件已发生。即使该中断被IMR屏蔽ISR中的标志位依然会被置位。这允许你通过轮询ISR来了解所有事件。中断屏蔽寄存器IMR: 可读写。某位写1则允许对应中断源触发IRQ输出写0则屏蔽。IMR只控制IRQ引脚不影响ISR置位也不影响OP3-OP7输出的独立中断信号。中断向量寄存器IVR: 可读写。存放中断向量号。当CPU响应中断并发出IACK时681将此寄存器的值放到数据总线上。硬件复位后此寄存器初始化为0x0F。辅助控制寄存器ACR: 用于配置一些全局功能。高4位位[7:4]用于选择C/T的时钟源和工作模式。低4位位[3:0]分别用于使能IP0-IP3四个输入引脚的状态变化中断。3.6 计数器/定时器寄存器C/T由两个8位预装寄存器CTUR和CTLR和两个8位当前计数寄存器CUR和CLR组成。CTUR/CTLR: 写入这两个寄存器设置C/T的初始值。CTUR是高8位CTLR是低8位。它们共同组成一个16位值N。CUR/CLR: 只读。反映C/T当前的16位计数值。在计数器模式下停止计数后读取这两个寄存器可以知道计数的结果。工作流程在定时器模式C/T从预装值N开始向下计数减到0时产生中断并置位ISR相应位然后自动重装N继续循环从而在OP3如果配置产生频率为f f_clock / (2 * (N1))的方波。在计数器模式C/T对IP2引脚的外部脉冲下降沿计数计满N后停止并产生中断此时可读取CUR/CLR获知计数值。4. 典型应用配置与驱动编写实战理论讲完了我们来看怎么用。假设我们要用MC68HC681在MC68000系统上实现一个简单的双串口通信通道A连接终端9600波特8N1通道B连接一个传感器2400波特7E1并使用C/T产生一个1Hz的定时中断。4.1 硬件连接与初始化首先硬件上需要连接3.6864MHz的晶振到X1和X2引脚各接一个15pF电容到地。将CS、RS1-RS4、R/W、D0-D7、DTACK、IRQ、IACK正确连接到MC68000的系统总线上。RESET连接到系统的复位信号。TxDA/RxDA和TxDB/RxDB通过电平转换芯片如MAX232连接到DB9接头。初始化代码通常放在系统启动时步骤如下硬件复位后芯片处于基本状态。所有输出为高中断屏蔽通道禁用。配置中断向量向IVR写入我们定义的中断向量号例如0x40。配置C/T假设我们使用X1/163.6864MHz/16230.4kHz作为时钟源要产生1Hz中断则分频系数N (230400 / (2*1)) - 1 115199。换算成十六进制是0x1C1FF。向CTUR写入0x1C向CTLR写入0xFF。在ACR中设置C/T为定时器模式时钟源选择X1/16。配置通道A9600 8N1写MR1A地址设置字符长度8位MR1A[1:0]11无校验MR1A[4:3]11接收中断选择RxRDYMR1A[6]0。假设RTR不使能MR1A[7]0。此时指针自动指向MR2A写MR2A停止位1位MR2A[3:2]00禁用CTS控制MR2A[4]0正常模式MR2A[7:6]00。写CSRA查表可知对于3.6864MHz晶振9600波特对应的BRG编码可能是0110具体需查手册中的波特率表。因此设置CSRA[7:4]0110接收时钟CSRA[3:0]0110发送时钟。配置通道B2400 7E1写MR1B地址字符长度7位MR1B[1:0]10偶校验MR1B[4:3]00,MR1B[2]0接收中断选择RxRDY。写MR2B停止位1位禁用CTS正常模式。写CSRB查表2400波特对应BRG编码可能是1001。设置CSRB[7:4]1001,CSRB[3:0]1001。配置输出端口假设我们想用OP4和OP5分别输出通道A和B的接收中断信号。需要配置OPCR寄存器将OP4和OP5设置为对应的RxRDY输出模式。同时通过向OPR的SET和RESET地址写入特定值可以初始设置这些输出引脚的电平。配置中断在IMR中允许我们关心的中断源例如通道A接收就绪ISR[1]、通道B接收就绪ISR[5]和C/T就绪ISR[3]。同时在ACR的低4位可以设置是否允许输入端口变化中断。使能通道向CRA写入命令使能接收器和发送器CRA[1:0]01,CRA[3:2]01。对CRB做同样操作。启动C/T向C/T命令地址写入启动命令具体操作因访问CTUR/CTLR的地址而异通常写入CTLR的地址会启动C/T。4.2 数据收发与中断服务例程初始化完成后就可以进行数据收发了。发送数据查询方式读取SRA。检查TxRDY位2是否为1。如果为1表示发送保持寄存器空可以写入新数据。向发送保持寄存器THRA地址写入要发送的字符。接收数据中断方式 当接收FIFO中有数据时IRQ引脚会被拉低如果中断被允许。CPU进入中断服务程序后读取ISR判断中断源。可能是通道A接收就绪ISR[1]1、通道B接收就绪ISR[5]1或C/T中断ISR[3]1。如果是通道A中断则循环读取SRA的RxRDY位0只要为1就从RHRA读取数据并检查SRA中的错误标志FE,PE,OE, 断线。处理完数据后如果需要清除错误标志需向CRA写入“复位错误状态”命令。如果是C/T中断则执行1Hz的定时任务然后通过读取ISR或向C/T发送特定命令来清除中断标志。中断服务程序结束。注意事项FIFO操作由于接收端有3级FIFO在中断服务程序中应持续读取数据直到RxRDY变为0以清空FIFO避免残留数据触发不必要的中断。错误处理OE错误通常意味着你的程序处理速度跟不上数据接收速度需要优化。FE和PE错误可能意味着线路噪声或波特率不匹配。DTACK处理在MC68000的异步总线访问中你的总线控制器代码必须等待DTACK有效后才能结束总线周期。许多初学者的问题就出在忽略了DTACK导致读写时序错误。4.3 高级功能应用自动回波与环回测试681的自动回波和环回模式是调试和测试的利器。自动回波模式将MR2x[7:6]设置为01。在此模式下接收器收到的数据会自动从发送器发送出去同时也会送入接收FIFO供CPU读取。这可以用来简单测试串口链路是否通畅。注意在此模式下发送器是被接收器驱动的你通过CPU写入发送保持寄存器的数据会被忽略。本地环回模式将MR2x[7:6]设置为10。发送器的输出在芯片内部直接连接到接收器的输入。TxD引脚被强制为高电平Mark。这个模式用于在不连接外部线路的情况下测试UART自身的发送和接收功能是否正常。你可以写一个数据到发送寄存器然后从接收寄存器读回来验证。远程环回模式将MR2x[7:6]设置为11。发送器的输出直接驱动接收器的输入但信号会经过TxD引脚输出。这主要用于测试线缆和连接器。你需要用一根短线将TxD和RxD引脚短接。在进行环回测试时建议先使用查询方式发送一个已知的数据模式如0x55或0xAA然后读取接收数据进行比较。同时检查状态寄存器确保没有错误发生。5. 常见问题排查与调试技巧调通MC68HC681的关键在于细致的排查。以下是一些常见问题及解决方法完全无通信读取状态寄存器值始终为0或固定值检查总线连接确认CS、RS1-RS4、R/W的地址解码逻辑正确。用逻辑分析仪或示波器观察这些信号在访问681时是否有有效跳变。检查DTACK这是最容易出错的地方。确保你的CPU驱动代码能正确采样DTACK信号。如果DTACK永远为高CPU会插入等待状态直到超时导致读写失败。检查DTACK引脚的上拉电阻是否接好。检查复位确保RESET引脚在上电后有足够长的低电平脉冲通常需要几个时钟周期。测量该引脚电压确认复位后为高电平。能写入配置但发送不出数据或接收不到数据检查时钟配置确认CSRx寄存器写入的值正确波特率计算无误。用示波器测量TxD引脚如果配置正确即使不发送数据它也应该持续为高电平Mark。如果一直是低或高阻态可能发送器未被正确使能。检查使能命令确认在配置完模式、时钟寄存器后向命令寄存器CRx写入了正确的使能命令01for Receiver,01for Transmitter。检查环回模式先将通道配置为本地环回模式发送一个字节然后读取接收寄存器。如果能在环回模式下自发自收说明芯片核心功能是好的问题可能出在线路驱动如MAX232或外部连接上。接收数据错误乱码、帧错误确认波特率发送方和接收方的波特率必须精确一致。使用标准晶振如3.6864MHz并确保CSRx寄存器设置的是同一个标准速率值。检查数据格式数据位、停止位、校验位的设置必须两端匹配。8N1是最常见的格式。检查信号质量用示波器观察RxD引脚上的波形。看起始位下降沿是否清晰数据位宽度是否均匀停止位是否为高电平。过多的毛刺或振铃可能导致采样错误。注意FIFO如果启用的是FFULL中断但你的程序处理速度慢可能导致FIFO溢出OE错误。可以考虑改用RxRDY中断并确保中断服务程序效率足够高。中断不触发检查IMR确认你允许了期望的中断源。检查ISR即使中断被屏蔽事件发生时ISR的标志位也会置1。先轮询ISR看对应的位是否变1。如果ISR有标志而IRQ没触发检查IMR如果ISR都没标志说明事件根本没发生需要检查前面的配置和使能步骤。检查IRQ引脚IRQ是开漏输出必须接上拉电阻通常10kΩ到Vcc否则无法拉高。检查中断向量确认IVR中设置的值与你的中断向量表地址匹配。在MC68000中中断向量号乘以4就是向量地址。计数器/定时器不工作检查时钟源确认ACR中为C/T选择了正确的时钟源如X1/16。检查模式ACR中配置为定时器模式还是计数器模式。检查启动写入预装值CTUR/CTLR后需要向C/T的特定地址通常是CTLR的地址执行一次写操作数据任意来启动它。仅仅配置寄存器不会启动计数。读取当前值在计数器模式下停止计数后读取CUR/CLR可以验证计数值是否符合预期。调试这类老芯片一份完整的数据手册、一个可靠的逻辑分析仪和耐心是必不可少的。从最基本的电源、时钟、复位查起然后验证总线读写再逐步测试各个功能模块。把复杂的功能分解成一个个小测试如先让一个通道在环回模式下工作能大大降低调试难度。