1. 项目概述与核心价值
在嵌入式系统开发领域,尤其是面对像Motorola MC68341这类经典的32位微控制器时,串行通信(UART)和定时器模块的底层驱动开发是工程师必须跨越的一道坎。这两个模块看似基础,却是连接微控制器与外部世界、实现精确时序控制的核心桥梁。很多新手甚至是有一定经验的开发者,在面对数据手册中密密麻麻的寄存器描述和时序图时,常常感到无从下手,要么是配置后通信不稳定,要么是定时精度达不到要求。
本文将以MC68341的串行模块和定时器模块为例,抛开那些泛泛而谈的理论,直接切入实战。我会结合手册中的关键描述,比如串行模块的FIFO状态机(FFULL、RxRDY)和定时器复杂的模式切换逻辑,为你拆解其背后的工作原理,并给出可直接“抄作业”的初始化代码、配置流程以及我踩过无数坑才总结出的调试心得。无论你是正在维护一个基于68341的老旧工业设备,还是单纯想深入理解微控制器外设的编程精髓,这篇文章都将提供从寄存器位操作到中断服务程序设计的完整视角,让你不仅知道怎么配,更明白为什么要这样配。
2. 串行通信模块深度解析与编程实战
MC68341的串行模块是一个全双工、带缓冲的通用异步收发器(UART)。它的核心价值在于,在有限的CPU干预下,可靠地处理串行数据流。理解其内部数据流和控制机制,是编写稳定驱动的前提。
2.1 核心机制:发送与接收的数据通路
模块的每个通道(A和B)都拥有独立且对称的发送与接收通路。手册中提到的“发送器缓冲区(TB)”和接收FIFO,是数据流的关键节点。
发送通路:数据写入路径是“CPU -> 发送保持寄存器 -> 发送移位寄存器 -> TX引脚”。当程序向TB寄存器写入一个字节时,数据首先进入“发送保持寄存器”。此时,如果“发送移位寄存器”为空,数据会立刻被搬运进去,并开始按设定的波特率逐位发出。如果“发送移位寄存器”正忙于发送上一个字节,则新数据会暂存在“保持寄存器”中等待。状态寄存器(SR)中的TxRDY位就是用来指示“发送保持寄存器”是否为空(即是否可以接收新数据)的关键标志。TxRDY=1表示空闲,可以写入;写入操作后硬件会自动清除该位,直到数据被转移到移位寄存器后,硬件会再次将其置1。
接收通路:数据读取路径是“RX引脚 -> 接收移位寄存器 -> 接收FIFO -> CPU”。从引脚采样恢复的字节先存入“接收移位寄存器”,完成一个字符的接收后,硬件会尝试将其移入一个3字节深的接收FIFO。状态寄存器(SR)中的RxRDY位指示FIFO中是否有至少一个字符待读取。而FFULL位则是一个更高级的“预警”标志,它表示FIFO的三个位置全部占满。此时如果接收移位寄存器又收完了一个新字符,它将无法进入FIFO,必须等待CPU读取FIFO释放出空间后,这个“滞留”的字符才能进入,并且FFULL状态会持续保持,直到CPU读取后FIFO不再满员。
注意:
FFULL和RxRDY的逻辑是新手容易混淆的地方。RxRDY是“有数据”标志,只要FIFO非空就为1。FFULL是“缓冲区将满/已满”标志,它意味着系统正面临数据溢出风险。在编写接收中断服务程序时,除了读取数据,检查FFULL位并采取相应措施(如提升处理优先级、增加缓冲区)是提高通信鲁棒性的关键。
2.2 寄存器配置详解与初始化序列
手册7.5.1节给出了一个推荐的初始化序列。这个序列不是随意的,它遵循了硬件上电后的稳定性和模块内部状态机的需求。下面我将逐条解释其必要性,并给出一个比手册示例更健壮的初始化函数。
1. 模块级全局配置(Module-Level Configuration)这部分配置影响整个串行模块,必须在通道配置前完成。
- 模块配置寄存器(MCR):这里需要设置停止位状态(
STP)、冻结响应(FRZx)、输入捕捉时钟源(ICCS)、访问权限(SUPV)和中断仲裁级别(IARBx)。对于大多数应用,STP清零(正常操作),SUPV清零(用户模式可访问)是常规设置。IARBx需要为模块分配一个唯一的中断仲裁码,以防止与其他模块冲突。 - 中断向量/级别/使能寄存器(IVR, ILR, IER):这是中断系统的三层配置。
IVR设定中断服务程序的入口向量号。ILR设定该模块中断的优先级(0-7)。IER则精细地控制哪些具体事件(如接收就绪、发送就绪、线路状态变化)能触发中断。一个常见的坑是:只使能了IER,却忘了配置ILR或IVR,导致中断根本无法触发。
2. 通道特定配置(Channel-Specific Configuration)这部分针对每个通信通道(A或B)独立进行。
- 时钟选择寄存器(CSR):选择接收和发送的波特率时钟源。MC68341的波特率由主时钟分频而来,
CSR的值决定了分频系数,从而决定波特率。计算波特率的公式必须参考数据手册的时钟树章节。 - 模式寄存器1(MR1)和模式寄存器2(MR2):这是配置通信格式的核心。
MR1:配置每字符位数(B/Cx,通常5-8位)、奇偶校验类型(PM,PT)、错误模式(ERR)以及RxRTS硬件流控。MR2:配置操作模式(CMx,如正常模式、自动回环)、TxRTS和TxCTS硬件流控,以及停止位长度(SBx,通常1或2位)。
- 命令寄存器(CR):这是一个“动作”寄存器。写入特定命令位可以复位接收器/发送器、使能接收器/发送器、错误复位等。关键点:使能操作(
RxE/TxE)必须在所有参数配置完成后进行。
2.3 实战代码:一个增强型的初始化例程
手册7.5.2节的代码是一个基础示例。在实际项目中,我们需要考虑更多,比如等待硬件稳定、配置硬件流控引脚、增加超时判断等。下面是一个更完善的Channel A初始化函数(假设与9600波特率终端通信,8N1格式,无硬件流控):
;*************************************************************************** ;* 增强型串行模块初始化例程 (通道A) ;* 目标:配置为 9600 波特,8位数据,1位停止位,无校验 ;* 增加:晶体振荡稳定等待、发送器空检测、超时保护 ;*************************************************************************** SERIAL_INIT: LEA MODBASE+SERIAL, A0 ; A0指向串行模块基址 ; --- 步骤1: 等待晶体振荡稳定 --- ; 手册强调,必须等待ISR寄存器的XTAL_RDY位清零 MOVE.W #5000, D0 ; 设置超时计数器 XTAL_WAIT: BTST #7, ISR(A0) ; 测试XTAL_RDY位 (假设ISR偏移量为$13) BEQ.S XTAL_OK ; 为0则稳定,跳出 DBRA D0, XTAL_WAIT ; 递减循环 ; 超时处理(可跳转到错误处理) BRA INIT_FAIL XTAL_OK: ; --- 步骤2: 配置模块控制寄存器(MCR) --- ; 正常操作,忽略FREEZE,选择晶体时钟,用户模式可访问,中断仲裁级别2 MOVE.B #$00, MCRH(A0) ; 高字节配置 MOVE.B #$02, MCRL(A0) ; 低字节配置 (IARB=2) ; --- 步骤3: 配置中断 --- MOVE.B #SERIAL_VEC, IVR(A0) ; 设置中断向量号 MOVE.B #$02, ILR(A0) ; 设置中断优先级为2 MOVE.B #$00, IER(A0) ; 初始化时先关闭所有中断源 ; --- 步骤4: 配置辅助控制寄存器(ACR)和输出端口 --- MOVE.B #$80, ACR(A0) ; 选择波特率发生器组2 MOVE.B #$00, OPCR(A0) ; 配置OP0-OP7为通用输出(如果用作RTS/CTS) MOVE.B #$01, OP_BR(A0) ; 拉低RTSA信号(假设OP0为RTSA) ; --- 步骤5: 复位收发器并配置模式 --- MOVE.B #$20, CRA(A0) ; 复位接收器命令 MOVE.B #$30, CRA(A0) ; 复位发送器命令 ; 注意:复位后需要短暂延时,确保内部状态机稳定 MOVE.L #100, D0 DELAY_LOOP: NOP DBRA D0, DELAY_LOOP MOVE.B #$93, MR1A(A0) ; MR1: 8位,无校验,RTS自动控制禁止 MOVE.B #$07, MR2A(A0) ; MR2: 正常模式,1位停止位 ; --- 步骤6: 配置波特率 --- ; 计算公式:波特率 = (主时钟频率) / (分频因子 * 16) ; 假设主时钟3.6864MHz,目标9600波特,分频因子应为24 (0x18) ; CSRA[7:4]为发送分频,[3:0]为接收分频,均设为0xBB? 此处需查表确认。 ; 手册示例为#$BB,我们假设其对应9600。 MOVE.B #$BB, CSRA(A0) ; --- 步骤7: 等待发送器完全空闲(可选但推荐) --- MOVE.W #$FFFF, D0 ; 超时计数 TX_EMPTY_WAIT: BTST #3, SRA(A0) ; 检查TXEMT位(发送器空) BNE.S TX_READY ; 不为0则就绪 DBRA D0, TX_EMPTY_WAIT BRA INIT_FAIL ; 超时,初始化失败 TX_READY: ; --- 步骤8: 使能收发器并可选开启中断 --- MOVE.B #$05, CRA(A0) ; 命令:错误状态复位,使能接收器 ; 先使能接收,稍后再使能发送,避免上电瞬间发送乱码 MOVE.B #$25, CRA(A0) ; 命令:使能接收器和发送器 ; 如果需要中断驱动,在此处使能IER中的相应位 ; MOVE.B #$01, IER(A0) ; 例如,使能接收数据就绪中断 MOVE.B #$01, OP_BS(A0) ; 置位RTSA信号,告知对方本机准备就绪 RTS ; 初始化成功返回 INIT_FAIL: ; 初始化失败处理(如点亮错误LED) ; ... RTS实操心得:
- 顺序是关键:一定要先配置参数(MR1, MR2, CSR),最后再使能收发器(CR命令)。顺序错乱可能导致不可预知的通信故障。
- 复位后等待:发送复位命令后,硬件需要几个时钟周期来清理内部状态。插入一个简短的空循环(如几十个NOP)是廉价且有效的稳定措施。
- 中断的精细控制:不建议在初始化时就打开所有中断。最好先以查询方式测试通信链路,稳定后再切换到中断模式,并仔细规划中断服务程序(ISR)的流程,确保能快速响应并清除中断源。
2.4 数据收发驱动与中断处理
手册7.4.2节给出了INCH(查询接收)、OUTCH(查询发送A)和POUTCH(查询发送B)的流程。在实际应用中,中断驱动效率更高。
中断服务程序(ISR)设计要点:
- 入口保存现场:首先保存所有可能用到的寄存器。
- 判断中断源:读取中断状态寄存器,确定是接收就绪、发送就绪、还是线路断点(Break)等事件。
- 处理数据:
- 接收中断:从接收缓冲寄存器读取数据,存入软件环形缓冲区。务必检查
FFULL和错误位(如奇偶错误PE、帧错误FE)。如果FFULL置位,说明你的处理速度可能跟不上接收速度,需要考虑优化ISR或使用更大的缓冲区。 - 发送中断:从软件发送缓冲区取出下一个字节,写入发送缓冲寄存器。如果缓冲区已空,则必须禁用发送空中断,否则会引发持续的中断风暴。
- 接收中断:从接收缓冲寄存器读取数据,存入软件环形缓冲区。务必检查
- 清除中断标志:通过读取状态寄存器或写入特定命令寄存器来清除已处理的中断标志位。这是防止同一中断重复触发的最关键一步。
- 恢复现场并返回。
一个常见的错误是,在发送中断中,当缓冲区空时,只是简单地返回而没有禁用中断,导致CPU不断进入无数据可发的发送中断,系统负载激增。
3. 定时器模块工作原理与模式应用
MC68341的定时器模块是一个功能强大的可编程间隔定时器/事件计数器。它不仅仅是一个简单的倒计时器,通过其丰富的模式,可以实现输入捕捉、输出比较、PWM生成、脉冲测量等多种功能。
3.1 核心架构:预分频器、计数器与比较器
理解定时器,首先要抓住其三个核心部件,如图8-2所示:
- 8位预分频器:这是一个独立的递减计数器,可以对输入时钟进行1到256的分频。它的存在极大地扩展了定时器的定时范围。例如,系统时钟频率很高,直接计数周期很短,通过预分频器后,可以获得更长的定时周期。
- 16位主计数器:这是定时器的核心,是一个递减计数器。它可以被配置为直接使用时钟源,或者使用预分频器的输出作为时钟。计数器从预装载值(PREL1或PREL2)开始递减,减到0时产生“超时”事件。
- 16位比较器:它持续将主计数器的当前值与比较寄存器(COM)的值进行比较。当两者相等时,产生“比较匹配”事件。这个功能是实现输出比较(在精确时刻翻转引脚)和输入捕捉(在事件发生时锁存计数器值)的基础。
时钟选择逻辑提供了灵活性:计数器时钟可以是外部引脚TIN的信号、系统时钟的一半,或者是经过预分频器分频后的时钟。TGATE引脚可以作为门控信号,控制计数器是否实际计数。
3.2 六大操作模式精讲与选型指南
手册8.3节描述了多种模式,我将它们归纳为三大类,并解释其典型应用场景。
3.2.1 输入捕获/输出比较模式(模式000)这是最通用的模式,兼具输入和输出功能。
- 输出比较:程序设置一个比较值(COM)。当计数器递减到与该值相等时,
TOUT引脚可以根据控制寄存器(CR)中OCx位的设置,产生跳变(置高、置低、翻转)。这常用于生成精确的单个脉冲或PWM信号。例如,设置OCx为“翻转”模式,并让计数器在超时后自动重载,COM设为重载值的一半,即可生成固定占空比(50%)的方波。 - 输入捕获:当
TGATE引脚(在此模式下用作捕获触发)上有指定边沿事件发生时,计数器当前的值会被锁存到计数器寄存器(CNTR)中供CPU读取。这用于测量外部脉冲的宽度或周期。例如,测量一个高电平脉冲的宽度,可以配置为上升沿开始计数,下降沿捕获,两次捕获值之差即对应脉冲宽度。 - “影子”功能:此模式下,
TGATE信号可以禁用“影子寄存器”功能。通常,CPU读取的计数器寄存器(CNTR)是计数器真实值的一个“影子”(延迟拷贝)。当TGATE有效时,可以禁用影子功能,让CNTR直接反映计数器实时值,这对于需要极高精度的时间戳应用很重要。
3.2.2 波形生成模式(模式001、010、011)这类模式专注于在TOUT引脚生成波形。
- 方波发生器(模式001):计数器从PREL1递减到0(超时),
TOUT翻转,然后计数器自动重载PREL1,循环往复。生成方波的周期为(PREL1 + 1) * 计数器时钟周期。这是生成固定频率时钟信号的理想选择。 - 可变占空比方波发生器(模式010):这是模式001的增强版。第一次超时后重载PREL2,第二次超时后重载PREL1,如此交替。
TOUT在每次超时都翻转。这样,高电平和低电平的持续时间分别由PREL1和PREL2控制,非常适合生成任意占空比的PWM信号,用于电机控制、LED调光等。 - 可变宽度单稳态脉冲发生器(模式011):在
TGATE的触发边沿,TOUT输出一个脉冲,脉冲宽度由PREL1的值决定。适用于需要产生精确宽度的单次脉冲的场景,如触发其他设备。
3.2.3 测量与计数模式(模式100、101)这类模式利用TGATE引脚控制计数器的启停,用于测量。
- 脉冲宽度测量(模式100):
TGATE有效(如高电平)期间,计数器对内部时钟计数。通过读取TGATE有效前后计数器的值,可以计算出脉冲宽度。用于测量未知脉冲的宽度。 - 周期测量(模式101):在两个连续的
TGATE有效边沿之间,计数器对内部时钟计数。用于测量周期性信号的频率。 - 事件计数(模式110):计数器对
TGATE引脚上的边沿进行计数。可以将TGATE连接到一个外部传感器,如光电编码器,进行转速测量。
3.3 定时器初始化与模式配置代码示例
下面以生成一个1kHz、占空比30%的PWM信号为例(假设使用模式010,系统时钟为2MHz,预分频器设为不分频)。
;*************************************************************************** ;* 定时器初始化:配置为可变占空比方波模式 (模式010),生成1kHz PWM,占空比30% ;* 系统时钟 = 2MHz, 计数器时钟 = 系统时钟/2 = 1MHz (周期1us) ;* 目标波形周期 T = 1/1kHz = 1000us ;* 计数器总计数次数 N_total = T / 1us = 1000 ;* 高电平时间 T_high = 30% * 1000us = 300us -> N_high = 300 ;* 低电平时间 T_low = 700us -> N_low = 700 ;* 注意:计数器从N递减到0,产生超时,所以装载值应为 N-1。 ;* PREL1 = N_high - 1 = 299 (0x012B) ;* PREL2 = N_low - 1 = 699 (0x02BB) ;*************************************************************************** TIMER_PWM_INIT: LEA MODBASE+TIMER_BASE, A0 ; A0指向定时器模块基址 ; --- 步骤1: 停止并复位定时器 --- ; 在修改配置前,必须确保定时器停止 (SWR=0) MOVE.B #$00, CR(A0) ; 确保SWR位为0,停止定时器 ; 可以写入0到计数器寄存器(CNTR)和比较寄存器(COM)进行软复位 MOVE.W #$0000, CNTR(A0) MOVE.W #$0000, COM(A0) ; --- 步骤2: 配置预分频器与时钟源 --- ; 控制寄存器(CR)配置: ; MODEx=010 (可变占空比方波), OCx=01 (超时时翻转TOUT) ; CPE=1 (使能计数器/预分频器), PCLKx=00 (计数器时钟=系统时钟/2) ; PS[2:0]=000 (预分频器除1), TGE=0 (禁用TGATE门控) ; 先计算CR值: 假设其他位为0 ; 位: 7(SWR) 6(CPE) 5:3(PS) 2:0(PCLK) | 15:14(OC) 13:11(MODE) 10(TGE) ... ; 值: 0 1 000 00 | 01 010 0 ; 需要分两次写入16位CR寄存器 MOVE.B #%00100000, CR(A0) ; 高字节: CPE=1, PS=000 (高5位) MOVE.B #%00010010, CR+1(A0) ; 低字节: OC=01, MODE=010, TGE=0 (低8位) ; --- 步骤3: 设置预装载值和比较值 --- MOVE.W #299, PREL1(A0) ; 高电平计数周期 (300-1) MOVE.W #699, PREL2(A0) ; 低电平计数周期 (700-1) ; 在模式010下,COM寄存器也参与比较,但PWM主要靠PREL1/PREL2。 ; 可将COM设为一个不影响超时的值,或用于产生中间中断。 MOVE.W #$FFFF, COM(A0) ; 设为最大值,避免产生比较匹配中断干扰 ; --- 步骤4: 配置中断(可选)--- ; 如果需要在每次PWM周期结束时产生中断 MOVE.B #TIMER_VEC, IVR(A0) ; 中断向量 MOVE.B #$03, ILR(A0) ; 中断优先级 ; 使能超时中断(TO)和比较中断(TC)(如果需要) MOVE.B #(1<<TO_BIT), IER(A0) ; 假设TO_BIT是超时中断使能位的位置 ; --- 步骤5: 启动定时器 --- ; 设置CR的SWR位为1,启动定时器。注意不能影响已设置的其他位。 ; 通常通过“读-修改-写”或直接写入完整的CR值来启动。 ; 这里我们重新写入完整的启动命令: MOVE.B #%10100000, CR(A0) ; 高字节: SWR=1, CPE=1, PS=000 MOVE.B #%00010010, CR+1(A0) ; 低字节保持不变 RTS注意事项:
- 启动顺序:必须最后设置
SWR位来启动定时器。在SWR=0时配置所有参数。- 周期计算:定时器是递减到0超时,所以装载值 = 所需计数次数 - 1。这是最常犯的计算错误。
- 双字节访问:像CR这样的16位寄存器,在8位数据总线上需要分高低字节访问。务必确认数据手册中寄存器的字节顺序(大端/小端)。
- TGATE引脚:如果未使用门控功能,确保
TGE位为0,并且TGATE引脚被上拉或下拉到一个确定的电平,防止误触发。
3.4 定时器高级应用与调试技巧
动态调整PWM:在电机控制等应用中,需要动态改变PWM占空比。在模式010下,你可以在任何时候写入新的PREL1或PREL2值。但必须注意同步问题:最好在计数器重载的瞬间(即超时事件发生时)更新另一个非活跃的预装载寄存器。例如,当前周期使用PREL1,你可以在超时中断服务程序中更新PREL2,用于下一个周期,这样可以避免PWM波形出现毛刺或断裂。
输入捕捉的精度:当使用输入捕捉功能测量窄脉冲时,TGATE信号的同步和滤波需要考虑。MC68341会对TGATE进行同步,这会产生2-3个系统时钟周期的延迟。对于非常高频的信号,这个延迟可能引入误差。此时,需要校准或选择更高频率的系统时钟。
调试技巧:
- 使用
TOUT引脚:在任何输出模式下,都可以将TOUT引脚连接到示波器,直观地观察波形频率、占空比是否正确,这是最直接的调试手段。 - 监控状态寄存器(SR):在中断服务程序或查询循环中,读取SR的值,检查
TO(超时)、TC(比较匹配)、TG(门控事件)等标志位,可以确认定时器是否按预期工作。 - 软件仿真:在缺乏硬件的情况下,可以编写一个简单的仿真程序,模拟时钟节拍,逐步跟踪计数器、预装载寄存器和状态位的变化,加深对模式逻辑的理解。
4. 常见问题排查与实战经验汇总
即使按照手册和示例代码配置,在实际硬件调试中仍会遇到各种问题。下面是我在多个项目中总结出的典型问题及其排查思路。
4.1 串行通信模块问题排查
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 完全无法收发数据 | 1. 时钟/波特率配置错误。 2. 收发器未使能( RxE/TxE位)。3. 硬件线路连接错误(TX/RX交叉)。 4. 电平不匹配(如TTL与RS232)。 | 1.核对时钟树:确认主频、CSR分频值计算出的波特率与终端设备严格一致。用示波器测量TX引脚波形,计算实际波特率。2.检查命令寄存器:确认最后执行了使能接收和发送的命令( CRA写入$25或$05后再$25)。3.检查硬件:确认TX连接到对方的RX,RX连接到对方的TX。使用逻辑分析仪或USB转串口工具监听数据。 4.检查电平转换:如果连接PC,可能需要MAX232等电平转换芯片。 |
| 能发送但不能接收,或接收乱码 | 1. 双方数据格式不一致(数据位、停止位、校验位)。 2. 接收中断未正确配置或使能。 3. 接收FIFO溢出导致数据丢失。 | 1.比对配置:仔细检查双方设备的MR1和MR2设置,确保完全一致。2.检查中断系统:确认 IER已使能接收中断,ILR优先���非零,IVR设置正确,且CPU全局中断已开启。3.检查状态寄存器:在接收函数中,不仅检查 RxRDY,更要检查FE(帧错误)、PE(奇偶错误)、OE(溢出错误)位。如果OE置位,说明CPU读取速度太慢,需优化代码或使用更大的接收缓冲区。 |
| 通信间歇性失败,偶发错误 | 1. 中断服务程序处理太慢,未及时清除中断标志或读取数据。 2. 硬件噪声干扰。 3. 地线回路问题。 | 1.优化ISR:ISR中只做最必要的操作(读/写数据、清除标志)。将数据处理等耗时任务放到主循环。确保读取数据后,错误状态被正确清除(有时需要写命令寄存器来清除)。 2.硬件检查:检查电源是否干净,在RX/TX线上串联小电阻(如22-100欧姆)或增加RC滤波,有助于抑制振铃和噪声。 3.共地:确保通信双方有良好的共地连接。 |
4.2 定时器模块问题排查
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
定时器完全不工作,TOUT无输出 | 1. 定时器未启动(SWR位为0)。2. 时钟源选择错误或未使能预分频器( CPE)。3. TGATE引脚门控使能但电平不对。 | 1.确认启动位:读取控制寄存器(CR),确认SWR和CPE位都已置1。2.检查时钟配置:确认 PCLKx和PS位设置正确。可以用示波器测量TIN引脚(如果使用外部时钟)或检查系统时钟是否正常。3.检查 TGATE:如果TGE=1,测量TGATE引脚电平,确保其为有效(低)电平以允许计数。 |
| 定时周期不准确 | 1. 预装载值计算错误(未减1)。 2. 时钟源频率误差(如晶体精度)。 3. 中断响应延迟影响周期测量。 | 1.复核计算公式:周期 =(预装载值 + 1) * (计数器时钟周期)。用示波器测量实际周期反推。2.检查晶振:使用高精度频率计测量系统时钟频率。对于精度要求高的应用,选择温漂小的晶振。 3.区分硬件与软件误差:定时器硬件产生的信号周期是精确的。如果你是在中断中基于定时器计数做软件延时,那么中断延迟和指令执行时间会引入误差。 |
| PWM占空比不稳定或跳动 | 1. 动态更新PREL1/PREL2的时机不对,与计数器重载不同步。2. 写入寄存器时发生了数值撕裂(Tearing)。 | 1.同步更新:在超时中断(TO)的服务程序中更新下一个周期将要使用的预装载寄存器。例如,当前周期用PREL1,则在中断中更新PREL2。2.原子操作:预装载寄存器是16位的,在8位总线上需要两次写入。确保在两次写入之间计数器没有读取该寄存器。最安全的方法是在定时器停止( SWR=0)时更新,但会打断输出。更好的方法是在计数器使用另一个寄存器时(如模式010中,计数器正在递减PREL1时)更新PREL2,反之亦然。 |
| 输入捕捉值不准 | 1.TGATE同步延迟。2. 中断响应延迟。 3. 信号边沿存在抖动。 | 1.理解并校准延迟:数据手册会给出同步延迟时间(如2个系统时钟)。在软件计算中减去这个固定延迟。 2.使用高优先级中断:为输入捕捉中断分配高优先级,减少响应时间抖动。 3.硬件滤波:在 TGATE输入引脚增加RC低通滤波电路,消除毛刺。软件上可以进行多次采样取平均。 |
4.3 嵌入式调试的通用心法
- 从简到繁:任何外设驱动,先尝试最简单的功能。对于串口,先配置为查询模式、固定波特率、无中断、无流控,发送一个字符。对于定时器,先配置为简单的方波输出模式,用示波器看波形。基础通了,再叠加复杂功能(中断、DMA、可变参数)。
- 善用示波器和逻辑分析仪:它们是嵌入式开发者的眼睛。测量引脚上的实际波形,是验证配置正确性的唯一金标准。逻辑分析仪可以同时捕获多条数据线和控制线的时序,对于分析通信协议和中断触发条件无比高效。
- 阅读数据手册的“电气特性”和“时序图”章节:很多问题源于不满足建立时间、保持时间或电压电平要求。比如串口通信距离长了之后波形畸变,可能就是驱动能力不足或未端接匹配电阻。
- 编写可测试的代码:在关键函数入口、出口和错误处理分支放置调试输出(如果串口可用)或设置不同的GPIO电平。用LED闪烁不同的模式来指示程序运行到了哪个阶段,这是一种廉价而有效的“printf调试法”。
最后,面对MC68341这类经典芯片,其手册虽然庞杂,但结构清晰。抓住“寄存器配置”和“时序状态机”这两个核心,结合实际的示波器波形,大部分问题都能迎刃而解。每一次解决问题的过程,都是对硬件理解更深一层的积累。