ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

51单片机万年历设计:DS1302时钟与DS18B20温度显示完整方案

51单片机万年历设计:DS1302时钟与DS18B20温度显示完整方案 简介本资源是一套完整的基于51单片机的万年历毕业设计开发包面向电子类、自动化及嵌入式方向的本科生课程设计与毕业设计需求解决时间显示、温度采集、闹钟提醒与掉电记忆等典型单片机综合应用问题。压缩包共75个文件涵盖Keil源程序工程含C语言代码与汇编文件、Proteus仿真工程含操作视频.mp4及PDF/JPG仿真图、AD绘制的电路原理图.schdoc/.pdf、元器件清单.xlsx、配套技术手册DS1302/DS18B20等芯片资料ZIP包、答辩参考论文与PPT等总大小9.67MB。已有151人学习下载内容组织清晰按“设计说明→原理图→仿真→源码→论文→工具教程”分模块归档关键文档均标注“必读”并提供焊接指南、常见问题解答及答辩技巧等实用支撑材料显著降低初学者上手门槛与项目复现难度。 万年历这个题目在单片机课程设计和入门练手里属于经久不衰的经典款。很多朋友第一个拿得出手的完整项目就是它——不是因为简单恰恰是因为它够综合显示要用到液晶计时要用到时钟芯片测温要用到单总线传感器人机交互要处理按键报警反馈要驱动蜂鸣器。一套做下来51单片机的大部分外设基本都摸了一遍。这篇博文我就直接把整个基于51单片机、1602液晶、DS1302时钟芯片、DS18B20温度传感器的万年历方案掰开揉碎来讲从电路设计、仿真搭建到代码实现、踩坑实录一次说清楚。不管你是要做课程设计答辩还是想自己焊一块板子玩都能照着复现。先说清楚这个项目到底能干什么。上电后1602液晶第一行显示当前的年月日时分秒第二行显示星期、农历月日或者公历的月日周次以及环境温度。四个按键负责完成全部交互设置时间、切换显示模式、开启关闭闹钟、调整闹钟时间。到点后蜂鸣器响按键可以停止。整个过程全自动运行掉电后时间不乱走因为DS1302有独立的备用电池供电。整套系统用到的核心器件就六个但把它们串起来之后就构成了一个完整的嵌入式应用案例。我特别推荐把下面这部分选型思路看完因为很多人在网上抄电路图、抄代码却不清楚为什么偏偏选这几个芯片换个器件行不行结果稍微改个需求就卡住了。1. 项目整体设计思路与器件选型解析1.1 核心功能需求拆解万年历本质上是一个多功能时钟系统我在设计的时候把它拆成了五个子模块时间基准模块负责产生和维护当前时间、显示模块将时间、日期、温度直观呈现、测温模块感知环境温度、输入模块接收用户设置指令、输出告警模块闹钟响铃提示。时间基准这块是核心中的核心。最原始的做法是用51单片机的定时器自己计时一个定时器中断软件计数也能跑出“秒”来。但问题很明显单片机一断电时间就归零晶振频率的微小偏差还会导致每天快慢几十秒甚至更多。所以这里必须引入独立的实时时钟芯片。DS1302就是干这个的它自带晶振和日历电路功耗极低外接一个纽扣电池就能在系统断电后继续走时。这就是为什么方案里选1302而不是用单片机定时器硬扛。显示模块选择1602液晶是另一个很务实的决定。相比数码管1602能在两行各16个字符的位置上显示完整数字和少量字母做界面友好得多相比12864点阵屏1602接线少、驱动简单、资料铺天盖地非常适合课程设计和入门。别小看这16*2的字符区域合理布局之后完全能放下“年、月、日、星期、时、分、秒、温度”这些关键信息。温度采集选了DS18B20这个芯片最吸引人的地方是一条数据线就能完成双向通信也就是所谓单总线协议。你省下的不仅仅是IO口还有PCB上的走线空间。而且它在-10到85度范围内的精度是±0.5℃测个室内环境温度绰绰有余。1.2 为什么这套组合是课程设计的“黄金搭配”我见过大量课程设计题目要求基本是“实时时钟日历温度显示可调闹钟”。51单片机、1602、DS1302、DS18B20、蜂鸣器、按键这六个模块恰好覆盖了所有这些需求而且没有一项是重复或多余的。这背后其实有个很现实的考量这六个模块对应了六种典型的单片机外设接口方式。51单片机最基本的IO操作按键和蜂鸣器、并行总线接口1602、SPI类三线串行协议DS1302、单总线协议DS18B20。你做这一个项目等于把单片机和外设打交道的几种主流玩法都过了一遍无论是学习价值还是答辩时能讲的东西都足够丰富。另外从复现难度上说这套方案对硬件要求很低。Proteus里能完美的仿真所有器件在仿真库里都是现成的实物的花销也就几十块钱洞洞板就能搭不像STM32方案那样要画PCB或者做四层板。对于手头设备有限的学生党来说这是最稳妥的选择。1.3 整体系统框图与数据流向确认了器件选型再把数据流动捋一遍。DS18B20把温度数据通过单总线送到单片机单片机按照18B20的时序要求读出温度值。DS1302通过三线接口SCLK、I/O、CE和单片机交换数据读出的时间以BCD码形式存在寄存器里单片机拿到之后转成十进制再交给1602显示。用户按动按键时单片机检测到变化进入设置模式把新的时间值写回DS1302或者设置闹钟时间。闹钟时间到后单片机输出方波驱动蜂鸣器发声。整个过程里51单片机就像一个大管家它自己不存时间只是通过轮询和中断的方式去各个外设取数据、发指令。这也是我认为这套设计最值得学习的地方主控和功能模块的职责清晰软件上可以模块化开发哪里出问题就查哪里。配套的电路图、Proteus仿真文件和C语言源码是打包在一起的下面我会按照硬件到软件的顺序把每一部分的实现细节都过一遍。2. 硬件电路设计与关键模块拆解2.1 主控最小系统与液晶接口电路主控芯片用STC89C52或者AT89C51都可以前者在实验板上更常见自带8K Flash程序存储空间绰绰有余。最小系统就是经典的复位电路加晶振电路晶振我用12MHz两个30pF负载电容接地复位脚接10uF电容到VCC、10K电阻到GND。这套配置和后面定时器初值的计算是对应的建议不要随意改晶振频率否则定时器、串口相关的延时逻辑全要重算。1602液晶的数据接口接在P0口上因为P0是开漏输出必须外接10K排阻上拉否则高电平拉不上去显示会花屏。控制引脚分配为RS接P2.6RW接地只写不读E接P2.5。这里有一个我当时踩过的坑很多人图省事会把RW直接接地这样确实能省一个IO但是就没法读忙标志了每次写指令前只能用延时硬等。1602初始化上电需要等15ms以上写指令前等5ms写数据前等几百微秒延时给够也能稳定运行我代码里就是这种延时驱动方式。初始化时要注意1602有8线模式和4线模式两种接法。8线模式一次传8位数据速度更快但占用8个IO4线模式只接高四位省IO但代码要复杂些。因为51单片机IO口本来就多所以我选择了8线模式操作时序是先拉低RS选择指令寄存器或数据寄存器再拉高E在E的下降沿数据被锁存。每次操作结束延时一会儿再执行下一次稳定第一。2.2 DS1302时钟电路三线通信与备用电池DS1302周边电路非常简洁但有两个关键细节必须处理好。第一是32.768kHz的晶振要尽量靠近芯片的第2、3脚负载电容选6pF左右走线别绕太远。这个晶振频率是32768Hz正好是2的15次方内部经过15级分频得到1Hz的秒脉冲所以一旦晶振没起振读出来的时间永远是初始化值这个要注意。第二是备用电池电路。VCC1接3V纽扣电池正极VCC2接系统5V主电源芯片会自动选择电压高的一路供电。当系统断电后DS1302就靠这颗纽扣电池维持计时电流消耗在微安级别一颗CR2032撑一两年没有问题。注意电池正极要串一个1N4148二极管防止倒灌很多厂家给的参考电路里直接画了实物里漏了这个二极管容易漏电。DS1302的数据接口有三根线CE也叫RST、SCLK、I/O。通信协议很接近SPI但是又有区别它是在SCLK上升沿输出数据、下降沿输入数据而且读和写都从最低位开始。后面代码部分我会详细展开这里只说硬件上三个引脚都需要接10K上拉电阻到VCC尤其是I/O线因为它是双向的必须通过上拉保证空闲时处于确定电平。CE在每次通信开始时要拉高通信结束拉低。寄存器操作方面DS1302内部有秒、分、时、日、月、星期、年的存储寄存器地址从0x80开始奇偶地址分别对应对读操作和写操作。所有时间数据都以BCD码存储比如秒寄存器里0x59就代表59秒。还有个写保护寄存器地址0x8E第7位是WP位写任何时间寄存器之前必须先把WP清零否则写入无效。这条规则我一开始不知道导致调了半天代码时间就是写不进去后来查到数据手册才明白。2.3 DS18B20温度采集电路DS18B20有VCC、DQ、GND三个引脚我用的是外部供电方式VCC接5V、GND接地、DQ接P3.7。DQ引脚必须接一个4.7K的上拉电阻到VCC这是单总线通信正常工作的前提。没有这个上拉电阻总线拉不高初始化永远失败。它在工作时有几个细节值得注意。首先上电后芯片默认的分辨率是12位对应温度最小刻度是0.0625℃这个精度显示在1602上完全够用。其次DS18B20返回的温度数据是16位补码形式存放在寄存器的高两个字节里正数直接乘以0.0625就是实际温度负数则需要取反加一后再乘0.0625。虽然室内环境基本遇不到负温度但代码里必须处理这种情况否则冬天室外测试时显示会完全错乱。还有一点DS18B20在转换温度期间会占用750毫秒左右12位分辨率下这个时间内总线被锁定单片机不能下发其他指令。我在设计主循环时就利用这段等待时间去刷新液晶显示或者扫描按键避免出现单片机傻等的情况。如果你是放在Proteus里仿真用默认的模型参数就能跑但实测注意如果仿真中温度显示85℃那是模型初始化问题不是代码问题后面问题排查里细说。2.4 按键与蜂鸣器电路设计四个独立按键我接在P1.0到P1.3上每个按键一端接地另一端接IO口IO内部通过上拉电阻保证空闲时为高电平。按下时IO被拉低单片机检测到低电平就认为按键触发。这种接法最简单不需要额外增加上拉。不过要注意51单片机P1口内部有上拉如果是P0口按键就还得外部上拉我特意选了P1口就是为了省事。消抖处理上硬件工作是在每个按键并联一个0.1uF电容滤除高频抖动软件上在主循环里加10到20毫秒的延时确认。我的做法是两层都做虽然属于“双保险”但实际体验下来能有效避免一次按下被识别成多次触发的问题。具体到软件扫描思路后面第三章单独讲这里先记住一点所有按键必须通过状态判断来识别“按下边沿”而不是“按下电平”否则长按的时候程序会反复执行同一操作。蜂鸣器这里有个常见分歧有源蜂鸣器和无源蜂鸣器。有源蜂鸣器内部自带振荡电路通电就响单片机只要给个高电平就能驱动无源蜂鸣器则需要外部给一定频率的方波才能发声。我用的有源蜂鸣器接在P2.4口上通过一个NPN三极管S8550驱动。为什么不用IO直接驱动因为单片机IO口输出电流只有十几毫安蜂鸣器正常工作需要30毫安以上直接推不动。三极管基极串一个1K电阻发射极接5V集电极接蜂鸣器负极蜂鸣器正极接VCC。这样IO输出高电平时三极管导通蜂鸣器得电发声。实测这个电路非常稳而且电流只在响铃时才流过平时不耗电。顺便说一句很多初学者会把蜂鸣器正极直接接IO口、负极接地去驱动这在电流需求小的模块上勉强能用但在蜂鸣器这种感性负载上就容易出现驱动不足或者反电动势打坏IO口的情况。加个三极管或者直接用ULN2003驱动才是工程上合理的做法。3. 软件架构与核心代码实现3.1 工程文件组织与主循环框架软件部分我用C语言编写Keil工程里按功能划分了文件这样逻辑清晰也方便后期维护。main.c放主循环ds1302.c统一处理时钟芯片ds18b20.c处理温度采集lcd1602.c处理液晶显示key.c处理按键扫描alarm.c处理闹钟逻辑。虽然是小项目但这种模块化习惯在日后做大工程时会让你省很多事。主循环的设计思路不是让单片机每个时刻都在刷新所有外设而是分时复用。系统启动后先做初始化1602初始化、DS18B20初始化、DS1302初始化并把默认时间写进去。然后进入主循环循环里依次执行读取DS1302时间、读取DS18B20温度判断转换是否完成、刷新1602显示、扫描按键、检查闹钟是否触发。每个任务执行速度都很快整体循环一次也就几毫秒人眼看到的就是实时刷新。主循环写成这样的骨架后面每个模块往里面填充即可。void main(void) { unsigned char tempL 0, tempH 0; unsigned int temperature 0; LCD_Init(); DS1302_Init(); DS18B20_Init(); Alarm_Init(); while(1) { DS1302_ReadTime(); Key_Scan(); Alarm_Check(); if (DS18B20_ConvertDone()) { tempL DS18B20_ReadByte(); tempH DS18B20_ReadByte(); temperature DS18B20_ProcessTmp(tempH, tempL); } LCD_Refresh(); } }3.2 DS1302读写时序与BCD码转换DS1302是典型的SPI类似的串行时钟芯片写一个字节的流程是CE拉高启动通信然后循环8次每次先发送一位数据到I/O引脚再产生一个上升沿让芯片采样发送完指令字节后再继续发送或读取数据字节。读数据时单片机在SCLK下降沿之后读取I/O引脚的电平因为芯片是在下降沿把数据送出来的。这个时序方向很多人会搞混写的时候是先给数据再给时钟上升沿读的时候是先给时钟下降沿再读数据。以读秒寄存器为例代码这样写unsigned char DS1302_ReadByte(unsigned char address) { unsigned char i, temp 0; DS1302_CE 0; DS1302_SCLK 0; DS1302_CE 1; // 启动通信 for (i 0; i 8; i) // 发送读地址低位在前 { DS1302_IO address 0x01; address 1; DS1302_SCLK 1; DS1302_SCLK 0; } for (i 0; i 8; i) // 读取数据字节 { temp 1; if (DS1302_IO) temp | 0x80; DS1302_SCLK 1; DS1302_SCLK 0; } DS1302_CE 0; // 结束通信 return temp; }读出的是BCD码比如返回0x59代表59秒。BCD码转十进制有个经典写法十进制值 (BCD值 4) * 10 (BCD值 0x0F)。写入时反过来十进制秒转BCD十位和高位拼一起。注意星期寄存器取值范围是1到7分别对应周日到周六不是我们习惯的0到6我第一次显示星期的时候就是因为这个差一天调了好半天。还有一个特别需要强调的是每次修改时间之前要把写保护寄存器0x8E的WP位清零。写保护开启时任何写入操作都会被拒绝。清零的做法是往0x8E写入0x00写完后如果需要再往0x8E写入0x80开启写保护。很多人在写时间后忘记重新开启写保护结果跑着跑着时间被异常改写排查起来非常隐蔽。3.3 DS18B20单总线时序与温度数据处理DS18B20的单总线通信比DS1302更严格因为它对时序延时要求精确到微秒级别。三个关键时序分别是初始化、读时隙和写时隙。初始化时序是主机先把总线拉低至少480微秒然后释放总线由上拉电阻把总线拉高。DS18B20检测到这个下降沿后会等待15到60微秒然后拉低总线60到240微秒作为存在脉冲。单片机在释放总线后延时60微秒左右去读取总线电平如果读到低电平说明器件存在初始化成功。如果这个过程中时序稍差一点读出的是高电平后续所有操作都会失败读温度永远返回85或者0。在位操作层面写时序是主机拉低总线延时约15微秒然后发送数据位写1就释放总线写0就保持低电平整个时隙持续约60微秒。读时序是主机拉低总线约1微秒后释放然后在大约15微秒的时刻去采样总线电平。DS18B20会在这个窗口内把数据输出到总线上。读温度的流程是初始化发送ROM命令0xCC跳过ROM匹配发送温度转换命令0x44然后等待转换完成。再次初始化发送0xCC发送读暂存器命令0xBE连续读出两个字节低字节是温度低八位高字节是温度高八位。这两个字节组合成16位有符号数前5位是符号扩展位。unsigned int DS18B20_ProcessTmp(unsigned char high, unsigned char low) { unsigned int temp 0; temp (high 8) | low; // 组合成16位 if (temp 0x8000) // 负温度取反加一 { temp ~temp 1; // 此时temp的数值乘以0.0625就是实际温度绝对值 } temp temp * 625; // 乘以0.0625转化成整数显示两位小数 return temp; }实测下来在12位分辨率下每读一次温度需要约750ms所以别在主循环里频繁调用读取否则整个系统会卡顿。我在代码里设置了一个转换完成标志读取转换结果后才发起下一次转换这样就能避免阻塞。3.4 1602液晶驱动与显示布局优化1602驱动是这类项目里相对基础的部分。初始化序列是延时15ms发送功能设置指令0x388位模式、两行、5x7点阵再发送显示开关指令0x0C开显示不显示光标然后是清屏指令0x01最后是输入模式指令0x06写入后地址自动加一光标右移。时序上每个指令之间都留出足够的延时特别是清屏指令需要等待约1.6毫秒才能执行下一条。显示位置控制靠的是DDRAM地址。第一行的地址起始是0x80第二行是0xC0。向某个位置写字符前要先发送“地址0x80”的指令然后连续写入字符数据。比如在第二行第三个字符位置显示温度就先写0xC02然后发送温度字符。我在显示布局上做过几版调整最终选了这个方案在紧凑和可读性之间比较平衡第一行YYYY-MM-DD HH:MM 例如2025-05-18 14:30 第二行WEEK T25.5C 或 设置菜单 例如WED T25.5C星期用英文缩写显示MON、TUE、WED、THU、FRI、SAT、SUN比显示数字1到7更直观。温度保留一位小数显示为T25.5C。这里有个处理细节十进制转字符串时要处理好数字和小数点的拼装我用sprintf格式化到一个临时数组再逐字符写入液晶。51单片机没有足够RAM跑标准库里的sprintf格式化占空间很多所以我手写了一个简单的整数转字符串函数速度快且不占资源。3.5 按键扫描与设置状态机四颗按键分别定义为功能键进入/退出设置、加键数值加、减键数值减、确认键切换设置项并保持设置。按下功能键进入设置模式后被设置的项在1602上闪烁或者用下划线提示方便用户知道当前在调哪一位。按键扫描我用的是状态机思路比简单的if加延时判断更可靠。核心是记录上一次的按键状态只有当“上次是高电平、这次是低电平”的边沿变化出现时才被认为是一次有效按下。这样能避免长按时连续触发。消抖延时放在检测到低电平之后延时10到20毫秒再读一次确认为低电平才算有效。设置模式的流转逻辑是按下功能键进入时间设置状态默认定位到“年”位。每按一次确认键设置项从年切换到月、日、星期、时、分、秒最后退出设置模式。在某个设置项下按下加键或减键对应数值加一或减一范围根据是日、月、时等做上限判断。退出设置模式时把所有寄存器值统一写入DS1302。闹钟逻辑单独一个状态机默认关闭按按键进入闹钟设置后可以设置小时和分钟开启时LCD上显示闹钟图标。主循环里每秒检查一次当前时间和闹钟时间是否相同相同时以方波驱动蜂鸣器响持续30秒或者任意按键停止。这个“按键停止响铃”的处理也要加个标志位防止蜂鸣器状态和按键状态打架。4. 仿真搭建与实物移植要点4.1 Proteus仿真快速搭板在Proteus里新建工程后依次从元件库调出AT89C51、LM016L这是1602的仿真模型、DS1302、DS18B20、BUTTON按键、BUZZER蜂鸣器、RESPACK-8排阻以及晶体振荡器。连接关系按照第二章的电路图来注意仿真里DS1302和DS18B20都要加对应的上拉电阻否则行为异常。仿真中比较重要的一步是给单片机加载hex文件。在Proteus里双击单片机芯片在Program File里选择Keil编译生成的hex文件然后设置晶振频率为12MHz。仿真运行时如果发现1602没有任何显示先别怀疑代码先检查对比度引脚VL是不是通过一个电位器接到了地。仿真里可以直接把VL接地实物则需要调整电位器到合适的对比度电压通常0.5V到1V左右。加载完hex之后仿真时钟芯片默认时间是2000年1月1日你可以通过设置模式把时间改成当前时间再观察走时和闹钟功能。温度部分Proteus的DS18B20模型默认输出温度是25℃左右可以通过修改模型属性调整仿真温度验证显示和温度转换逻辑。4.2 从仿真到实物的关键差异仿真跑通了不代表实物一次能成我在这上面栽过跟头给你说几个最需要注意的差异。第一点Proteus里的液晶模型对时序的宽容度比实物高很多。实物1602如果初始化时序太紧经常出现只亮背光不显示字的情况这时候大概率是初始化延时不够。解决办法是把初始化里的延时增大几倍实测降到10ms后基本没出过问题。第二点DS1302的32.768kHz晶振在实物中必须配负载电容推荐6pF到12.5pF。如果你用Proteus仿真晶振不需要电容也能工作但实物的晶振如果没有负载电容或者匹配不对时间会偏快或者偏慢。我做了一版实板测试没有负载电容的时候每天快约20秒加上12pF电容后误差降到每天1到2秒。第三点实物的DS18B20必须加上拉电阻仿真里如果忘了加上拉可能还能出结果但实物就会表现为温度一直显示85℃。这个85是芯片上电复位后的默认温度寄存器值如果一直停在85℃说明单总线初始化或者通信失败芯片根本没有完成温度转换。排查时先量DQ线电平再确认时序延时。第四点实物的蜂鸣器驱动代码里如果有延时翻转方波的写法Proteus仿真会一样响但实物声音小或者不响多半是三极管引脚搞错或者基极电阻太大。一般情况下S8550的基极电流在1mA左右就足够导通基极电阻选1K到4.7K都没问题。5. 常见问题与排查技巧实录5.1 时钟不走、时间写不进去这是我被问到最多的问题。DS1302读出来的时间永远停在初始值或者写入后没变化。排查顺序建议这样先确认写保护寄存器是否清零。程序在写时间之前必须向0x8E写入0x00否则所有写入操作都会被忽略。这一点是软件层面最容易被忽略的。再确认CE引脚和SCLK引脚是否接对。DS1302对时序极其敏感如果CE和SCLK接反或者接错IO口通信会彻底失败。检查代码里的端口定义和硬件连接是否一致。然后把IO线上拉电阻加上没有上拉时通信大概率不稳定。最后检查晶振是否起振。用示波器测量32.768kHz晶振引脚正常情况能看到正弦波形。没有示波器的话可以在断电重新上电后观察时间是否从电池供电期间继续走。如果时间完全是初始化时写的固定值且不变化基本可以断定晶振没起振或者芯片没工作。5.2 温度一直显示85℃或0℃温度显示85℃基本就是DS18B20通信失败芯片返回了上电默认值。原因有两类一类是初始化时序有问题拉低480微秒的时间不够长或者释放总线后延时没给足芯片没来得及发存在脉冲。另一类是外部上拉电阻缺失或阻值不对总线拉不高通信失败。温度显示0℃时先看是不是负温度处理逻辑没做。如果程序只写了正温度处理显示的是原始补码看起来可能像0。另外如果读取到的两个字节都是0可能是读时序太慢芯片数据已经被时钟覆盖了检查读时序里的延时是否在规范范围内。5.3 1602显示乱码或花屏花屏最常见原因是P0口上拉电阻没接。P0口是开漏输出必须外接上拉才能输出高电平否则1602数据线上的高电平状态不确定显示自然混乱。另一个原因是总线时序太紧初始化时数据没稳定。1602对时序的要求是数据建立时间至少要40纳秒但51单片机跑12MHz时一条指令就要1微秒按理说不会不够。实际操作中大多是初始化顺序错了或者RW没有拉低。如果RW悬空电平随机液晶可能处于读模式写指令自然无效。还有一个容易忽略的就是对比度。VL引脚的电压决定字符显示深浅如果调不对屏幕上可能是一堆黑块。一般来说VL和GND之间接一个10K电位器调到约0.5V到1.0V显示最清晰。如果是插的模块自带电位器直接拧到能清晰显示为止。5.4 按键失灵或者设置时间错乱按键按下了没反应第一反应检查IO口定义。如果按键接在P1口代码里却读的是P3口那自然没反应。其次是消抖延时是否过短如果按键有物理抖动但程序没有消抖状态机可能识别到多次跳变表现为设置值一次跳了好几格。设置时间错乱还有一个隐蔽原因确认键切换设置项时需要先把当前设置项的值保存下来再切换到下一项。如果切换时误触发加键或减键的中断数值就会乱掉。我的建议是按键处理全用查询方式别用外部中断因为按键抖动很容易产生误中断。5.5 闹钟不响或者响不停闹钟不响大概率是时间比较的代码写法问题。DS1302读出来的秒、分、时都是BCD码闹钟比较前必须统一转换成十进制再比较否则0x09和9不相等闹钟永远不触发。如果响了停不下来检查停止标志位应该是按键按下时置标志、主循环判断标志清除蜂鸣器而不是只判断按键电平导致长按一直关不掉。6. 我个人实操中的一些心得整套项目从画电路图到仿真验证再到实板调试我前后花了大概三个晚上。第一晚把电路和代码框架搭完第二晚在Proteus里跑通基本功能第三晚移植到实物上主要时间花在调晶振匹配和按键手感上。整体体验下来这个项目最大的价值不是“做出来一块万年历”而是让你把单片机的几种典型外设通信方式都练了一遍而且每个模块都能单独验证、单独Debug。有些细节是网上教程不会告诉你的。比如DS1302的时间寄存器在仿真里默认是乱值但实物却可能是任意值所以初始化时一定要强制写入一次完整时间不要只初始化部分寄存器。再比如DS18B20的延时函数在不同晶振下要微调12MHz下没问题换成11.0592MHz后如果还用原来的延时次数通信就可能失败。如果后面想在这个基础上做扩展可以考虑加一个AT24C02存储闹钟配置这样掉电后闹钟设置不会丢失或者把DS1302换成DS3231带温度补偿走时精度会高很多再进阶一点接一个ESP8266模块通过串口同步网络时间整个项目就带上了物联网属性。当然这些都是后话先把这版做到稳定运行就已经比大多数只交代码不跑板子的课程设计强太多了。本文还有配套的精品资源点击获取
返回列表