MC68HC05键盘接口温度计:PS/2协议与单总线传感器驱动实战

发布时间:2026/6/21 20:19:20
MC68HC05键盘接口温度计:PS/2协议与单总线传感器驱动实战 1. 项目概述与核心价值在嵌入式系统开发的早期资源受限是常态。微控制器MCU的I/O口、电源、通信接口都极为宝贵。今天要分享的这个项目就是一个在资源极度受限条件下“螺蛳壳里做道场”的经典案例基于MC68HC05的键盘接口温度计。它的核心思路非常巧妙——利用PC的PS/2键盘接口同时解决嵌入式设备的供电和通信两大难题。想象一下你有一个MC68HC05微控制器和一个DS1820温度传感器想做一个能向PC报告温度的小设备。常规思路可能需要额外的USB转串口芯片、电平转换电路还得找个5V电源适配器。但这个项目告诉你完全不需要。一根标准的PS/2键盘延长线一头插电脑另一头接上你的设备再把自己的键盘插在设备上电有了数据通道也有了。电脑上跑个简单的DOS程序THERMO.EXE就能像接收键盘输入一样收到设备发来的温度数据。这种设计对于需要与PC进行简单、低成本数据交互的嵌入式应用如环境监测探头、简易数据采集器具有很高的参考价值。整个固件的核心就是让MC68HC05这颗简单的8位MCU同时扮演好三个角色一个PS/2协议分析器一个单总线主机以及一个键盘模拟器。下面我们就来深入拆解这套固件的设计思路、实现细节以及我在复现和调试过程中积累的一些实战经验。2. 系统架构与核心模块设计思路这个键盘温度计固件从功能上清晰地划分为三个模块但它们在逻辑和时序上紧密耦合。理解这个架构是读懂后续所有代码和操作细节的基础。2.1 模块交互与总体工作流系统上电后MCU完成初始化然后便进入一个主循环等待状态。此时键盘与PC之间的通信是直通的设备处于“监听”模式。整个工作流由PC主机主动触发等待激活PC端的THERMO.EXE程序启动后会通过键盘接口向键盘发送两次ECHO命令命令码0xEE。固件的激活信号采集模块持续监听PS/2数据线专门捕捉这个特定的“两次ECHO”序列。只有正确识别到这个“暗号”设备才认为主机发出了数据请求从而启动温度测量流程。采集温度一旦激活温度采集与转换模块开始工作。它通过严格的单总线时序向DS1820传感器发送复位、跳过ROM、启动温度转换、读取暂存器等命令获取原始的9位温度数据。格式化与发送获取的原始温度数据例如代表25.5°C的二进制值需要转换成人类可读的ASCII字符并进一步转换成PC键盘能理解的扫描码Scan Code。键盘接口模块负责将格式化后的扫描码数组按照PS/2设备到主机的通信协议一位一位地“敲”给PC。PC接收到这些扫描码后会如同用户真的在键盘上输入了“25.5”一样将其传递给THERMO.EXE程序显示出来。这个流程的精妙之处在于非侵入性。在设备不活动时键盘与PC通信无阻在设备活动时它通过电子开关原理图中的4066模拟开关暂时接管数据线发送完数据后立即释放键盘功能不受影响。2.2 硬件接口与资源分配解析看原理图Appendix A是理解硬件约束的关键。MC68HC705J1A是核心它的I/O口分配如下PS/2接口侧CLOCK_IN,DATA_IN配置为输入用于监听主机到键盘的通信READ_COMMAND以及键盘到主机的响应READ_RESPONSE。CLOCK_OUT,DATA_OUT配置为输出用于在设备发送数据时模拟键盘产生时钟和数据信号SEND函数。BUSY,CONTROL用于控制模拟开关4066在设备需要发送数据时断开键盘与主机的连接将设备自己的CLOCK_OUT和DATA_OUT接入总线。DS1820传感器侧DQ双向数据线用于单总线通信。需要软件严格模拟复位、读写时序。其他系统使用4MHz外部振荡器。7407是开集电极缓冲器用于增强PS/2接口的驱动能力并实现电平的兼容。注意PS/2协议是双向、开集电极Open-Collector的。这意味着任何设备主机或键盘只能将线拉低逻辑0释放时由上拉电阻拉高逻辑1。因此在代码中无论是监听还是驱动都需要注意“线与”逻辑。驱动时输出0是主动拉低输出1实际上是释放总线高阻态由上拉电阻拉高。3. 核心模块一激活信号采集模块深度解析这个模块是设备与主机建立联系的“握手协议”实现者。它不能干扰键盘正常通信又要能精准捕捉到主机发来的特定指令序列。3.1 协议基础与激活序列设计标准PS/2通信中主机向键盘发送一个命令如0xEEECHO键盘必须回复一个应答对于ECHO命令回复也是0xEE。THERMO.EXE程序连续发送两个ECHO命令并期待收到两个ECHO响应。固件中的CONTACT函数就是为此而生。它循环调用READ_COMMAND和READ_RESPONSE寻找连续的“命令0xEE- 响应0xEE- 命令0xEE- 响应0xEE”序列。为什么是两次主要是为了抗干扰。键盘在正常使用中也可能产生数据单次匹配到0xEE有可能是巧合。连续两次完美匹配的概率极低这大大提高了激活的可靠性。3.2 READ_COMMAND函数主机到设备通信的监听器READ_COMMAND函数的任务是解析一次完整的主机到键盘的数据帧。PS/2协议的一帧数据包含起始位总是08个数据位LSB first奇校验位停止位总是1键盘的应答位ACK低电平函数实现采用了典型的状态机和超时保护思想这是嵌入式裸机编程的精华。关键步骤与代码剖析等待起始条件主机发送数据前会先把时钟线拉低至少100µs然后把数据线拉低。READ_COMMAND首先等待DATA_IN变低并检查此时CLOCK_IN是否为高主机控制时钟线为低是发送起始信号如果时钟线已经是低可能是异常。WAIT4COMMAND BRSET DATA_IN,PORTA,WAIT4COMMAND ; 等待数据线变低 BRSET CLOCK_IN,PORTA,READ_CMD_ERROR ; 如果此时时钟线是高错误位采样与超时之后函数等待时钟线变高上升沿在上升沿后延迟约10µs代码中的GET_BIT_DELAY循环再读取数据线的状态。这里的关键是每一个等待时钟沿的循环都必须加入超时判断。例如等待时钟变高的循环LDA #$48 ; 超时计数器 WAIT4CLOCKHI BRSET CLOCK_IN,PORTA,STARTBITCLOCK ; 时钟变高则跳走 DECA BEQ READ_CMD_ERROR ; 计数到0则超时错误 BRA WAIT4CLOCKHI超时值如#$48需要根据MCU时钟周期精确计算确保覆盖协议允许的最大间隔又不会让MCU死等。这是保证系统鲁棒性的生命线。校验与帧校验8位数据接收完毕后代码会计算收到的奇校验位是否正确并检查停止位是否为1以及键盘是否回送了ACK低电平。任何一步出错都会设置错误标志INC FLAG并退出。3.3 READ_RESPONSE函数设备到主机通信的监听器READ_RESPONSE与READ_COMMAND类似但监听的是键盘到主机的通信。区别在于帧结构键盘到主机的数据帧没有ACK位。函数流程变为等待起始位-读取8位数据奇校验位-检查停止位。实操心得在调试这个模块时最头疼的就是时序问题。逻辑分析仪是必备工具。你需要同时抓取主机时钟、主机数据、键盘数据如果可能以及MCU的某个GPIO用于打点标记代码执行到何处。通过对比抓到的波形和代码中预期的时序比如10µs的采样点才能定位是超时设置太短还是中断干扰了延时循环。在没有逻辑分析仪的情况下可以尝试用GPIO翻转来“模拟”一个简单的波形用示波器观察辅助判断代码执行到哪个阶段卡住了。4. 核心模块二温度采集与转换模块实战要点这个模块负责与DS1820单总线温度传感器通信。单总线协议以其节省IO口著称但代价是极其严格的时序要求所有时序都由MCU软件模拟。4.1 单总线协议与DS1820操作序列DS1820的典型操作序列是初始化复位-存在脉冲-发送ROM命令如SKIP ROM [0xCC]-发送功能命令如CONVERT T [0x44]或READ SCRATCHPAD [0xBE]-读写数据。固件中的ACQUIRE_TEMP函数清晰地体现了这个流程RESET_1820: 发送480-960µs的低电平复位脉冲然后释放总线并等待60-240µs检测DS1820回应的60-240µs低电平存在脉冲。发送SKIP ROM [0xCC]命令因为总线上只有一个传感器可以跳过寻址。发送CONVERT T [0x44]命令启动温度转换。对于DS1820转换时间最多可达750ms。代码采用轮询方式不断发送读时隙直到读到非0xFF值表示转换完成。这是一种简单有效的等待方式。再次复位发送SKIP ROM和READ SCRATCHPAD [0xBE]命令。连续读取两个字节READ_1820得到9位的温度值低字节LSB高字节MSB的bit0是小数部分。4.2 底层读写时序的软件模拟WRITE_1820和READ_1820函数是时序模拟的核心。写时隙MCU将总线拉低至少1µs然后根据要写的是“1”还是“0”在15µs内释放总线写1或继续保持低电平60µs写0。整个时隙持续60-120µs。WRITE_ZERO BCLR DQ,PORTA ; 拉低总线开始写时隙 JSR DELAY_80µS ; 保持低电平约80µs写0 BSET DQ,PORTA ; 释放总线 BRA DEC_WRITE WRITE_ONE BCLR DQ,PORTA ; 拉低总线至少1µs NOP ; 几个NOP指令实现短暂延时 NOP NOP BSET DQ,PORTA ; 很快释放总线写1 JSR DELAY_80µS ; 等待时隙结束这里的DELAY_80µS延时子程序需要根据4MHz主频精确计算指令周期来编写。读时隙MCU发起读时隙拉低总线至少1µs后释放然后在15µs内采样总线状态。DS1820会在MCU拉低总线后在15-60µs的时间窗口内将总线拉低表示0或保持高表示1。READ_BIT BSET DQ,PORTA BSET DQ_CTRL,DDRA ; 确保DQ为输出模式 BCLR DQ,PORTA ; MCU拉低总线至少1µs NOP ; 短暂延时 NOP NOP NOP NOP BCLR DQ_CTRL,DDRA ; 切换DQ为输入模式释放总线 BRSET DQ,PORTA,READ_ONE ; 延时后采样总线 CLC ; 读到0 BRA READ_SHIFT READ_ONE SEC ; 读到1避坑指南延时精度单总线对时序宽容度很小。所有DELAY_xxx函数必须用汇编语言精确实现考虑所有指令周期。使用C语言循环通常难以满足要求。总线恢复每次读写操作后必须保证MCU将总线控制权释放设置为输入或输出高电平并由上拉电阻拉高为下一次操作做好准备。中断干扰如果系统开启了中断在操作单总线的关键时序段如READ_1820,WRITE_1820必须禁用中断否则一个中断服务程序的执行可能彻底破坏时序导致通信失败。本固件作为简单示例可能未考虑但在复杂系统中是必须处理的。5. 核心模块三键盘接口模块与数据发送这是设备“说话”的模块负责将温度值“敲”进电脑。核心是将温度数值转换为PS/2扫描码并模拟键盘发送。5.1 温度数据到扫描码的转换FORMAT_TEMP函数完成了从原始9位温度数据到扫描码数组的转换。DS1820的温度数据格式是低字节的bit0为0.5°C高字节为符号位和整数部分。例如0x0191二进制 0000 0001 1001 0001表示 25.0625°C这里需要仔细核对DS1820数据手册。实际上DS1820的默认分辨率是9位格式为符号位S高字节bit7高字节低7位和低字节bit7组成8位整数部分低字节bit0是0.5°Cbit1-3是0.125, 0.0625等。但本固件似乎只处理了0.5°C精度检查ODD_MULTIPLE标志位将温度转换为带一位小数的字符串。转换步骤判断正负负数则在发送缓冲区存入减号“-”的扫描码MINUS$4E并对数据取补码。分离整数部分和小数部分0或0.5。将整数部分除以10分离十位和个位。通过查表SCAN_TABLE将十位、个位数字转换为对应的通码Make Code。例如数字‘2’的通码是$1E。根据小数部分存入小数点“.”的扫描码POINT$49和“5”FIVE$2E或“0”ZERO$45的扫描码。在缓冲区末尾存入结束符END$5A即回车键的扫描码这里$5A是数字小键盘回车通常主回车是$5A但需要确认和停止符$FF。5.2 模拟键盘发送SEND与SEND_BYTE函数SEND_BYTE是高层发送函数它处理了PS/2协议中的错误重传机制。流程如下通过控制BUSY和CONTROL信号断开键盘连接设备到总线。调用底层SEND函数发送一个字节。如果发送成功PC未拉低时钟线表示错误则结束。如果发送失败设备会等待并调用RECEIVE函数尝试接收主机发来的RESEND命令0xFE。如果收到RESEND则重新发送原数据否则报错。SEND函数是真正的“比特爆破Bit Banging”实现者它严格按照PS/2设备到主机的时序用软件控制CLOCK_OUT和DATA_OUT引脚设备在发送前需要检查时钟线是否为高主机允许发送。设备先将数据线拉低然后产生一个时钟脉冲低-高-低作为起始位。接着从LSB开始依次发送8个数据位和1个奇校验位。每个位都是在时钟线为低时准备好数据然后产生一个时钟脉冲。发送停止位高。释放总线等待主机拉低时钟线作为应答ACK然后主机再释放时钟线。代码中通过PC_BUSY和STILL_BUSY循环等待主机处理。关键时序参数来自PS/2协议时钟频率10-16.7 kHz每个时钟周期60-100 µs数据在时钟下降沿变化在时钟上升沿被采样。设备在发送前必须检查时钟线在高电平状态至少50µs。代码中的HALF_CLOCK和FULL_CLOCK延时循环就是用来产生符合标准的时钟脉冲宽度。5.3 主机端程序THERMO.EXE的角色固件设计是与主机程序THERMO.EXE紧密配合的。该程序大概做了以下几件事向键盘接口发送特定的激活序列两次ECHO。持续监听键盘输入将接收到的扫描码转换为ASCII字符。将转换后的字符串如“25.5”在DOS界面显示出来。提供简单的用户交互如等待用户按Q退出。它的流程图Appendix B清晰地展示了这个交互过程发送激活序列-等待/接收温度字符串-显示-等待用户输入-循环。6. 固件源代码的关键例程与调试技巧翻阅附录D的完整源码除了上述主要函数还有一些支撑性的例程和全局设计值得关注。6.1 全局变量与内存规划在RAM的起始部分定义了一系列变量DATA,FLAG: 通用数据寄存器和状态标志寄存器。TX_BUFFER: 发送缓冲区存放格式化后的扫描码序列。TEMP_HI,TEMP_LO: 存放从DS1820读取的原始温度数据。各种临时变量和掩码常量。在资源紧张的MC68HC705J1A上RAM可能只有64或128字节这种清晰的内存规划至关重要。FLAG变量的各个位被复用为不同函数的错误标志节省了空间。6.2 延时子程序的艺术所有时序都依赖于精确的软件延时。源码最后一部分是延时子程序集如DELAY_80µS,DELAY_500µS,FULL_CLOCK,HALF_CLOCK等。它们都是用汇编指令NOP,DECA,BNE构成的紧密循环。计算延时以4MHz时钟为例一个机器周期是0.25µs假设内部2分频。一个NOP是2个机器周期0.5µs。DELAY_80µS的循环体是NOP; NOP; NOP; DECA; BNE需要计算循环次数A的初始值使得总时间约为80µs。这需要根据指令集手册精确计算是嵌入式汇编编程的基本功。6.3 调试方法与问题排查实录开发此类底层驱动调试是最大的挑战。以下是我总结的排查思路问题设备完全无反应PC程序收不到数据。排查电源首先用万用表测量PS/2接口的5V和GND是否正确接入MCU和传感器。PS/2接口的供电能力有限约100-200mA确保整个电路功耗在其范围内。排查激活在CONTACT函数入口设置一个LED闪烁或GPIO翻转。观察设备是否成功进入了激活序列检测。如果没有问题可能在READ_COMMAND对主机信号的监听上。用逻辑分析仪抓取主机发送的两个ECHO命令序列与代码逻辑对比。排查硬件连接检查原理图中的模拟开关4066和控制信号BUSY,CONTROL逻辑是否正确。设备在监听时开关应连接键盘到主机在发送时应切换为设备到主机。问题能激活但温度读数全是0或错误。排查DS1820通信在ACQUIRE_TEMP函数的RESET_1820、WRITE_1820、READ_1820等关键点设置调试信号。用示波器观察DQ线上的波形与DS1820数据手册的时序图对比。最常见的问题是延时不准或中断干扰。检查传感器连接DS1820的数据线需要接一个4.7kΩ的上拉电阻到VCC。确保连接可靠。问题能激活温度读取似乎正确但PC端收到乱码或部分字符。排查扫描码转换在FORMAT_TEMP函数结束后检查TX_BUFFER数组里的内容。对照PS/2扫描码集看转换是否正确。例如数字‘1’的扫描码是否是$16。排查发送时序用逻辑分析仪同时抓取设备发送时的CLOCK_OUT和DATA_OUT信号。测量时钟周期、数据建立和保持时间是否符合PS/2规范。特别注意设备发送前是否等待了足够长的时间50µs确保时钟线为高。排查PC端程序确认THERMO.EXE程序是否与固件预期的扫描码集匹配通常是XT/AT扫描码集。也可以用一个简单的键盘监听程序看看设备发出的原始扫描码是什么。问题发送数据导致键盘锁死或PC异常。检查总线竞争确保在设备发送数据前BUSY和CONTROL信号已有效断开了键盘。发送完成后必须及时恢复键盘连接。逻辑分析仪可以清晰显示切换过程。检查错误处理SEND_BYTE函数中的错误重发逻辑是否健全如果PC一直不发RESEND命令设备是否能在超时后安全退出恢复键盘连接一个实用的调试技巧利用未使用的I/O口。例如可以在每个主要函数入口、出口或关键判断分支处给某个I/O口一个不同的脉冲如短脉冲、长脉冲、双脉冲。用示波器观察这个“调试通道”就能像单步执行一样了解代码的执行流卡在了哪里。这比点灯更高效。7. 项目总结与扩展思考回顾这个基于MC68HC05的键盘温度计项目其核心价值在于展示了一种极简主义的系统集成思想。它不增加任何额外的接口芯片仅凭MCU的GPIO和软件智慧就巧妙地“寄生”在成熟的PS/2生态系统上实现了数据与电源的获取。从今天的视角看MC68HC05早已不是主流PS/2接口也日渐稀少。但这个项目所蕴含的协议分析、时序模拟、资源管理、软硬件协同调试等技能依然是嵌入式开发的基石。你可以将这套思路迁移到其他场景协议替换将PS/2接口换成USB。虽然USB协议复杂得多但可以使用像V-USB这样的软件USB实现或者更简单的用一个USB转串口芯片如CH340MCU通过UART发送数据主机端用虚拟串口接收。这更符合现代硬件环境。传感器扩展DS1820可以替换为DHT11温湿度、DS18B20更高精度温度或其他I2C、SPI传感器。只需修改对应的驱动函数。功能扩展设备可以不止上报温度。可以做成一个多功能键盘侧边小工具上报传感器数据、自定义宏按键状态等。低功耗优化原设计MCU可能一直处于运行状态。可以修改为平时MCU进入低功耗休眠模式通过PS/2时钟线或数据线的边沿变化需配置为外部中断来唤醒然后执行一轮测量和发送再继续休眠大大降低整体功耗。最后想强调一点阅读和理解这类“古老”的应用笔记和源码最大的收获不是学会如何操作一个特定的过时芯片而是学习前辈工程师在严苛限制下解决问题的架构思维和实现技巧。这些思维和技巧在你面对任何资源受限的嵌入式场景时都会成为你工具箱里最宝贵的资产。动手复现它哪怕是在模拟器上你会对“位操作”、“状态机”、“时序”这些概念有刻骨铭心的理解。