万年历电子钟设计报告含电路图和源程序(共28页).doc
精选优质文档-倾情为你奉上电子时钟 万年历设计报告 学院: 班级: 组员: 专心-专注-专业一、设计要求与方案论证1.1设计要求:1.1.1基本要求(1)准确显示:时、分、秒(24小时制)(2)显示星期(3)显示公历(4)时间、日期、星期可调节(5)断电记忆功能1.1.2发挥部分(1)闹钟功能(2)显示阴历(3)显示24节气(4)其他1.2 系统基本方案选择和论证1.2.1单片机芯片的选择方案和论证:方案一: 采用89C51芯片作为硬件核心,采用Flash ROM,内部具有4KB ROM 存储空间,能于3V的超低压工作,而且与MCS-51系列单片机完全兼容,但是运用于电路设计中时由于不具备ISP在线编程技术, 当在对电路进行调试时,由于程序的错误修改或对程序的新增功能需要烧入程序时,对芯片的多次拔插会对芯片造成一定的损坏。方案二: 采用AT89S52,片内ROM全都采用Flash ROM;能以3V的超底压工作;同时也与MCS-51系列单片机完全该芯片内部存储器为8KB ROM 存储空间,同样具有89C51的功能,且具有在线编程可擦除技术,当在对电路进行调试时,由于程序的错误修改或对程序的新增功能需要烧入程序时,不需要对芯片多次拔插,所以不会对芯片造成损坏。所以选择采用AT89S52作为主控制系统.1.2.2 显示模块选择方案和论证:方案一: 采用点阵式数码管显示,点阵式数码管是由八行八列的发光二极管组成,对于显示文字比较适合,如采用在显示数字显得太浪费,且价格也相对较高,所以不用此种作为显示.方案二:采用LED数码管动态扫描,LED数码管价格适中,对于显示数字最合适,但无法显示图形文字,在显示星期是也只能用数字表示,而且采用动态扫描法与单片机连接时,在编程时比较复杂。所以也不采用了LED数码管作为显示。方案三: 采用LCD液晶显示屏,液晶显示屏的显示功能强大,可显示文字,图形,显示多样,清晰可见,所以在此设计中采用LCD液晶显示屏.1.2.3时钟芯片的选择方案和论证:方案一: 采用DS1302时钟芯片实现时钟,DS1302芯片是一种高性能的时钟芯片,可自动对秒、分、时、日、周、月、年以及闰年补偿的年进行计数,而且精度高,位的RAM做为数据暂存区,工作电压2.5V5.5V范围内,2.5V时耗电小于300nA.但在,题目中明确规定不能选用不可以使用任何专用的时钟芯片和模块,因此不采用此方案。方案二: 直接采用单片机定时计数器提供秒信号,使用程序实现年、月、日、星期、时、分、秒计数。采用此种方案可以减少芯片的使用,也可以节约成本。所以采用此方案。1.3 电路设计最终方案决定综上各方案所述,对此次作品的方案选定: 采用AT89S52作为主控制系统;采用单片机定时器提供时钟; 液晶显示屏作为显示。二、理论分析与计算2.1,秒数的产生由定时器T0产生:T0置10ms定时初值dc00H(216=65536D,dc00H=56320D)定时时间=(65536-56320)*(1/11.0592)*12=10ms (单片机晶振f0=11.0592Mhz)用累加的方法让定时时间累加一百次即可产生一秒时间:100*10ms=1000ms=1s2.2. 总天数的算法:首先用if语句判断定义年到输入年之间每一年是否为闰年,是闰年,该年的总天数为366,否则,为355。然后判断输入的年是否为定义年,若是,令总天数S=1,否则,用累加法计算出定义年到输入年之间的总天数,再把输入年的一月到要输出的月份之间的天数累加起来,若该月是闰年中的月份并且该月还大于二月,再使总天数加1,否则,不加,既算出从定义年一月一日到输出年的该月一日的总天数。2.3 输出月份第一天为星期几的算法:使总天数除以7取余加2得几既为星期几,若是7,则为星期日。2.4. 算出输出月份的完整日历算法:算出输出月份第一天为星期几后,把该日期以前的位置用空格补上,并总该日起一次输出天数直到月底,该月中的天数加上该月一日为星期几的数字再除以7得0换行,即可完整的输出该月的日历。5,计算某一天是星期几的算法:蔡勒(Zeller)公式 历史上的某一天是星期几?未来的某一天是星期几?关于这个问题,有很多计算公式(两个通用计算公式和一些分段计算公式),其中最著名的是蔡勒(Zeller)公式。 即:w=y+y/4+c/4-2c+26(m+1)/10+d-1 公式中的符号含义如下,w:星期;c:世纪-1;y:年(两位数);m:月(m大于等于5,小于等于14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月来计算,比如2003年1月1日要看作2002年的13月1日来计算);d:日; 代表取整,即只要整数部分。(C是世纪数减一,y是年份后两位,M是月份,d是日数。1月和2月要按上一年的13月和 14月来算,这时C和y均按上一年取值。)算出来的W除以7,余数是几就是星期几。如果余数是0,则为星期日。以2049年10月1日(100周年国庆)为例,用蔡勒(Zeller)公式进行计算,过程如下: 蔡勒(Zeller)公式:w=y+y/4+c/4-2c+26(m+1)/10+d-1 =49+49/4+20/4-2×20+26× (10+1)/10+1-1 =49+12.25+5-40+28.6 =49+12+5-40+28 =54 (除以7余5) 即2049年10月1日(100周年国庆)是星期5。三.系统的硬件设计与实现3.1 电路设计框图:AT89S52主控制模 块液晶显示模块键盘模块 闹钟模块3.2 系统硬件概述:本电路是由AT89S52单片机为控制核心,具有在线编程功能,低功耗,能在3V超低压工作;显示部份LCD1602实现,能够同时显示16x02即32个字符;闹钟部分由蜂鸣器构成,蜂鸣器是一种一体化结构的电子讯响器,采用供电,广泛应用于、打印机、复印机、报警器、汽车电子设备、电话机、等电子产品中作发声。3.3 主要单元电路的设计3.3.1单片机主控制模块的设计 AT89S52单片机为40引脚双列直插芯片,有四个I/O口P0,P1,P2,P3, MCS-51单片机共有4个8位的I/O口(P0、P1、P2、P3),每一条I/O线都能独立地作输出或输入。单片机的最小系统如下图所示,18引脚和19引脚接时钟电路,XTAL1接外部晶振和微调电容的一端,在片内它是振荡器倒相放大器的输入,XTAL2接外部晶振和微调电容的另一端,在片内它是振荡器倒相放大器的输出.第9引脚为复位输入端,接上电容,电阻及开关后够上电复位电路,20引脚为接地端,40引脚为电源端. 如图-1 所示 图-1 主控制系统 3.3.2显示模块的设计LCD1602液晶显示屏 工业字符型液晶,能够同时显示16x02即32个字符。(16列2行),有16个引脚,通过D0D7的8位数据端传输数据和指令,引脚图如图6-5。图6-5LCD1602引脚示意图LCD1602液晶显示屏引脚功能如表6-5所示:表6-5 LCD1602引脚功能管脚1Vss一般接地管脚2Vdd接电源(+5V)管脚3V0液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高管脚4RSRS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器管脚5R/WR/W为读写信号线,高电平(1)时进行读操作,低电平(0)时进行写操作。管脚6EE(或EN)端为使能(enable)端,下降沿使能。管脚7DB0底4位三态、 双向数据总线 0位管脚8DB1底4位三态、 双向数据总线 1位管脚9DB2底4位三态、 双向数据总线 2位管脚10DB3底4位三态、 双向数据总线 3位管脚11DB4高4位三态、 双向数据总线 4位管脚12DB5高4位三态、 双向数据总线 5位管脚13DB6高4位三态、 双向数据总线 6位管脚14DB7高4位三态、 双向数据总线 7位管脚15BLA背光电源正极管脚16BLK背光 电源负极1602液晶模块内部的控制器共有11条控制指令,如表10-14所示:序号指令RSR/WD7D6D5D4D3D2D1D01清显示00000000012光标返回000000001*3置输入模式00000001I/DS4显示开/关控制0000001DCB5光标或字符移位000001S/CR/L*6置功能00001DLNF*7置字符发生存贮器地址0001字符发生存贮器地址8置数据存贮器地址001显示数据存贮器地址9读忙标志或地址01BF计数器地址10写数到CGRAM或DDRAM)10要写的数据内容11从CGRAM或DDRAM读数11读出的数据内容表10-14:控制命令表1602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。(说明:1为高电平、0为低电平)指令1:清显示,指令码01H,光标复位到地址00H位置。指令2:光标复位,光标返回到地址00H。指令3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移 S:屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效。指令4:显示开关控制。 D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示 C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。指令5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标。指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线 N:低电平时为单行显示,高电平时双行显示 F: 低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符。指令7:字符发生器RAM地址设置。指令8:DDRAM地址设置。指令9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。指令10:写数据。指令11:读数据。将lcd的引脚与单片机连接,通过单片机实现对显示的输出,电路图实现如下:3.3.3闹钟模块的设计闹钟模块采用蜂鸣器实现,蜂鸣器是一种一体化结构的电子讯响器,采用供电。通过单片机的p3.7引脚输出的电平变化来控制蜂鸣器的导通与否,设计如下:3.3.4电源稳压模块方案一:LM7805稳压方案二:USB接口+5V供电四、系统的软件设计开始初始化LCD、时间日期处理程序允许LCD显示?读取时间LCD显示LCD关闭YESNO扫描按键时间设定闹钟设定4.1程序流程框图开始初始化扫描按键闹钟设定数据保存返回4.2闹钟模块流程图:4.3按键调整模块流程图:五、测试方案与测试结果分析5.1 测试仪器序号名称作用1KELL 51 软件编写调试C程序并生成可烧录hex文件2仿真软件Proteus对电路进行焊接前的仿真与测试3变压器提供5伏输出电源4数字万用表测试工作电源检测电路运行状况5.2软件测试平台 Keil C51Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用。用过汇编语言后再使用C来开发,体会更加深刻。Keil C51软件提供丰富的库函数和功能强大的集成开发调试工具,全Windows界面。另外重要的一点,只要看一下编译后生成的汇编代码,就能体会到Keil C51生成的目标代码效率非常之高,多数语句生成的汇编代码很紧凑,容易理解。在开发大型软件时更能体现高级语言的优势。下面详细介绍Keil C51开发系统各部分功能和使用。Keil C51工具包的整体结构,其中uVision与Ishell分别是C51 for Windows和for Dos的集成开发环境(IDE),可以完成编辑、编译、连接、调试、仿真等整个开发流程。 5.3 模块测试5.3.1显示模块测试出现的问题:LCD1602液晶显示屏背景灯亮但不显示内容。解决问题:初步假设电源已经供电但单片机没有工作。用万用表测试LCD使能端6引脚和写命令选择端4引脚,均有电位变化,推出单片机已经工作。再次假设,LCD1602的显示屏对比度没调好。让电路工作,慢慢旋转变阻器,但仍无内容显示。三次假设,LCD1602某些引脚短路,经检测各引脚电平,发现6脚线路某地方与电源VCC相连,导致数据命令无法写入LCD1602显示器,导致内容无法显示,改正后,显示正常,问题解决。VCC1602MOXx01) /"); 5.4测试结果分析与结论5.4.1测试结果分析在测试过程中遇到lcd1602显示不出来,首先使用万用表对电路进行测试,检查工作电压是否正常并查找出电路没正常工作的部分,再次检查各引脚接线情况。5.4.2 测试结论经过多次的反复测试与分析,可以对电路的原理及功能更加熟悉,同时提高了设计能力与及对电路的分析能力.同时在软件的编程方面得到更到的提高,对编程能力得到加强.同时对所学的知识得到很大的提高与巩固.六、作品总结在整个设计过程中,发挥团队精神,分工合作,我吴余壮健负责电路设计,软件编程,设计报告的编写,李培文负责网上查阅相关有用资料,王文龙负责电路的焊接,充分发挥人的主观能动性,自主学习,学到了许多没学到的知识。较好的完成了作品。达到了预期的目的,在最初的设计中,发挥“三个臭皮匠,顶个诸葛亮”的作用。相互学习、相互讨论、研究。完了最初的设想。在此次设计中,知道了做凡事要有一颗平常的心,不要想着走捷径,一步一脚印。也练就了我们的耐心,做什么事都在有耐心。此次比赛中学到了很多很多东西,这是最重要的。总之,参加电子竞赛我们的能力得到了全方位的提高。 参考文献新概念51单片机C语言教程 郭天祥编 电子工业出版社 2009单片机C语言应用一百例 王东锋 王会良 董冠强编电子工业出版社 2009杨子文 编 单片机原理及应用 西安电子科技大学出版社 2006附录一:系统电路图附录二:仿真效果图附录三:系统C程序#include<reg52.h>#include<intrins.h>unsigned char code dis_week="SUN,MON,TUE,WED,THU,FRI,SAT"unsigned char code para_month13=0,0,3,3,6,1,4,6,2,5,0,3,5; /星期月参变数unsigned char data dis_buf116; /lcd上排显示缓冲区unsigned char data dis_buf216; /lcd下排显示缓冲区 unsigned char data year,month,date,week;/年、月、日、星期unsigned char data armhour,armmin,armsec;/闹钟时、分、秒unsigned char data hour,min,sec,sec100; /时、分、秒、百分之一秒unsigned char data flag,vkey,skey;/设置状态计数标志、按键先前值、按键当前值 bit alarm; /标识是否启用闹钟,1-启用,0-关闭sbit rs = P20; /LCD数据/命令选择端(H/L)sbit rw = P21; /LCD读/写选择端(H/L)sbit ep = P22; /LCD使能控制sbit PRE = P16; /调整键(k3)sbit SET = P17; /调整键(k4)sbit SPK = P37; void delayms(unsigned char ms); /延时程序bit lcd_busy(); /测试LCD忙碌状态程序void lcd_wcmd(char cmd); /写入指令到LCD程序void lcd_wdat(char dat); /写入数据到LCD程序void lcd_pos(char pos); /LCD数据指针位置程序void lcd_init(); /LCD初始化设定程序void pro_timedate(); /时间日期处理程序void pro_display(); /显示处理程序void pro_key(); /按键处理程序void time_alarm(); /定时报警功能(闹钟)unsigned char scan_key(); /按键扫描程序unsigned char week_proc(); /星期自动计算与显示函数bit leap_year(); /判断是否为闰年void lcd_sef_chr(); /LCD自定义字符程序void update_disbuf(unsigned char t1,unsigned char t2,unsigned char dis_h,unsigned char dis_m,unsigned char dis_s); /更新显示缓冲区函数 / 延时程序void delay(unsigned char ms) while(ms-) unsigned char i; for(i = 0; i< 250; i+) _nop_(); /执行一条_nop_()指令为一个机器周期 _nop_(); _nop_(); _nop_(); /测试LCD忙碌状态bit lcd_busy() bit result; rs = 0; rw = 1; ep = 1; _nop_(); _nop_(); _nop_(); _nop_(); result =(bit)(P0&0x80); /LCD的D0-D7中,D7=1为忙碌,D7=0为空闲 ep = 0; return result; /写入指令到LCDvoid lcd_wcmd(char cmd) while(lcd_busy(); /当lcd_busy为1时,再次检测LCD忙碌状态,lcd-busy为0时,开始写指令 rs = 0; rw = 0; ep = 0; _nop_(); _nop_(); P0 = cmd; _nop_(); _nop_(); _nop_(); _nop_(); ep = 1; _nop_(); _nop_(); _nop_(); _nop_(); ep = 0; /写入数据到LCDvoid lcd_wdat(char dat) while(lcd_busy(); /当lcd_busy为1时,再次检测LCD忙碌状态,lcd-busy为0时,开始写数据 rs = 1; rw = 0; ep = 0; P0 = dat; _nop_(); _nop_(); _nop_(); _nop_(); ep = 1; _nop_(); _nop_(); _nop_(); _nop_(); ep = 0; /LCD数据指针位置程序void lcd_pos(char pos) lcd_wcmd(pos|0x80); /数据指针=80+地址码(00H27H,40H67H)/设定二个自定义字符,(注意:LCD1602中自定义字符的地址为0x00-0x07,即可定义8个字符)/这里我们设定把一个自定义字符放在0x00位置(000),另一个放在0x01位子(001)void lcd_sef_chr() /第一个自定义字符 lcd_wcmd(0x40); /"01 000 000" 第1行地址 (D7D6为地址设定命令形式D5D4D3为字符存放位置(0-7),D2D1D0为字符行地址(0-7)) lcd_wdat(0x1f); /"XXX 11111" 第1行数据(D7D6D5为XXX,表示为任意数(一般用000),D4D3D2D1D0为字符行数据(1-点亮,0-熄灭) lcd_wcmd(0x41); /"01 000 001" 第2行地址 lcd_wdat(0x11); /"XXX 10001" 第2行数据 lcd_wcmd(0x42); /"01 000 010" 第3行地址 lcd_wdat(0x15); /"XXX 10101" 第3行数据 lcd_wcmd(0x43); /"01 000 011" 第4行地址 lcd_wdat(0x11); /"XXX 10001" 第4行数据 lcd_wcmd(0x44); /"01 000 100" 第5行地址 lcd_wdat(0x1f); /"XXX 11111" 第5行数据 lcd_wcmd(0x45); /"01 000 101" 第6行地址 lcd_wdat(0x0a); /"XXX 01010" 第6行数据 lcd_wcmd(0x46); /"01 000 110" 第7行地址 lcd_wdat(0x1f); /"XXX 11111" 第7行数据 lcd_wcmd(0x47); /"01 000 111" 第8行地址 lcd_wdat(0x00); /"XXX 00000" 第8行数据 /第二个自定义字符 lcd_wcmd(0x48); /"01 001 000" 第1行地址 lcd_wdat(0x01); /"XXX 00001" 第1行数据 lcd_wcmd(0x49); /"01 001 001" 第2行地址 lcd_wdat(0x1b); /"XXX 11011" 第2行数据 lcd_wcmd(0x4a); /"01 001 010" 第3行地址 lcd_wdat(0x1d); /"XXX 11101" 第3行数据 lcd_wcmd(0x4b); /"01 001 011" 第4行地址 lcd_wdat(0x19); /"XXX 11001" 第4行数据 lcd_wcmd(0x4c); /"01 001 100" 第5行地址 lcd_wdat(0x1d); /"XXX 11101" 第5行数据 lcd_wcmd(0x4d); /"01 001 101" 第6行地址 lcd_wdat(0x1b); /"XXX 11011" 第6行数据 lcd_wcmd(0x4e); /"01 001 110" 第7行地址 lcd_wdat(0x01); /"XXX 00001" 第7行数据 lcd_wcmd(0x4f); /"01 001 111" 第8行地址 lcd_wdat(0x00); /"XXX 00000" 第8行数据/LCD初始化设定void lcd_init() lcd_wcmd(0x38); /设置LCD为16X2显示,5X7点阵,八位数据借口 delay(1); lcd_wcmd(0x0c); /LCD开显示及光标设置(光标不闪烁,不显示"-") delay(1); lcd_wcmd(0x06); /LCD显示光标移动设置(光标地址指针加1,整屏显示不移动) delay(1); lcd_wcmd(0x01); /清除LCD的显示内容 delay(1);/闰年的计算bit leap_year() bit leap; if(year%4=0&&year%100!=0)|year%400=0)/闰年的条件 leap=1; else leap=0; return leap;/星期的自动运算和处理unsigned char week_proc() unsigned char num_leap; unsigned char c; num_leap=year/4-year/100+year/400;/自00年起到year所经历的闰年数 if( leap_year()&& month<=2 ) /既是闰年且是1月和2月 c=5; else c=6; week=(year+para_monthmonth+date+num_leap+c)%7;/计算对应的星期 return week;/更新显示缓冲区void update_disbuf(unsigned char t1,unsigned char t2,unsigned char dis_h,unsigned char dis_m,unsigned char dis_s) dis_buf10=t1; / dis_buf11=0x20; /空格 dis_buf12=50; /'2' dis_buf13=48; /'0' dis_buf14=year/10+48; dis_buf15=year%10+48; dis_buf16=0x2d; dis_buf17=month/10+48; dis_buf18=month%10+48; dis_buf19=0x2d; /'-' dis_buf110=date/10+48; dis_buf111=date%10+48; dis_buf112=0x20; dis_buf113=dis_week4*week; dis_buf114=dis_week4*week+1; dis_buf115=dis_week4*week+2; dis_buf20=t20; dis_buf21=t21; dis_buf22=t22; dis_buf23=t23; dis_buf24=t24; dis_buf25=t25; dis_buf26=0x20; /空格 if (alarm) dis_buf27=0x01; /alarm=1,显示闹钟启用标致(第二个自定义字符) else dis_buf27=0x20; /alarm=0,不显示闹钟启用标致 dis_buf28=dis_h/10+48; dis_buf29=dis_h%10+48; dis_buf210=0x3a; /':' dis_buf211=dis_m/10+48; dis_buf212=dis_m%10+48; dis_buf213=0x3a; dis_buf214=dis_s/10+48; dis_buf215=dis_s%10+48;/时间和日期处理程序void pro_timedate() sec+; if(sec > 59) sec = 0; min+; if(min>59) min=0; hour+; if(hour>23) hour=0; date+; if (month=1|month=3|month=5|month=7|month=8|month=10|month=12) if (date>31) date=1;month+; /大月31天 if (month=4|month=6|month=9|month=11) if (date>30) date=1;month+; /小月30天 if (month=2) if( leap_year() /闰年的条件 if (date>29) date=1;month+; /闰年2月为29天 else if (date>28) date=1;month+; /平年2月为28天 if (month>12) month=1;year+; if (year>99) year=0; week_proc(); if (sec=armsec && min=armmin && hour=armhour) if (alarm) TR1=1; /闹钟启用时,报警时间到,启动Timer1 /显示处理程序void pro_display() unsigned char i; lcd_pos(0x00); for (i=0;i<=15;i+) lcd_wdat(dis_buf1i); lcd_pos(0x40); for (i=0;i<=15;i+) lcd_wdat(dis_buf2i);/Timer0中断处理程序,秒的产生void timer0() interrupt 1 TH0=0xdc; /Timer0置10ms定时初值dc00H(216=65536D,dc00H=56320D) TL0=0x00; /定时时间=(65536-56320)*(1/11.0592)*12=10ms (f0=11.0592Mhz) sec100+; if(sec100 >= 100) /1秒时间 (100*10ms=1000ms=1s) sec100 = 0; pro_timedate();/调用时间和日期处理程序 if (sec&0x01) / 一秒显示“hello”,一秒显示“kitty” update_disbuf(0x00,"KITTY",hour,min,sec); /0x00表示显示00位置的自定义字符 else update_disbuf(0x00,"HELLO",hour,min,sec); pro_display(); /调用显示处理函数 /按键扫描程序unsigned char scan_key() skey=0x00; /给变量vkey置初值 skey|=PRE; /读取PRE键的状态 skey=skey<<1; /将PRE键的状态存于skey的B1位 skey|=SET; /读取SET键的状态,并存于skey的B0位 return skey; /返回skey的键值(即PRE,SET的状态)/外部中断INT0中断处理程序void int0() interrupt 0 TR0=0; /禁止Timer0 IE=0; /禁止中断 lcd_wcmd(0x0e); /显示光标"_",整个光标不闪烁 alarm=1; update_disbuf(0x50,"alarm:",armhour,armmin,armsec); /更新显示数据,0x50表示要显示"P" pro_display(); /调用显示处理程序 lcd_pos(0x47); /使光标位于第一个调整项下 flag=0; vkey=0x03; while(flag0x0a) skey = scan_key(); /扫描按键状态 if (skeyvkey) /若skey与vkey相同,跳出循环,相异执行循环体 delay(10); /去按键抖动 skey = scan_key(); /转回扫描按键状态 if (skeyvkey) /