应用电子技术毕业论文基于AT89S52单片机的定时电源插座设计.doc
江苏信息职业技术学院毕业论文课题 定时电源插座 系 电子信息工程系 专业 应用电子技术 姓名 班级 学号 指导教师 职称 指导教师 职称 设计时间 2010.11.222011.1.8 摘要近年来随着科技的飞速发展,单片机的应用正在不断深入,同时带动传统控制检测技术日益更新。在实时检测和自动控制的单片机应用系统中,单片机往往作为一个核心部件来使用,仅单片机方面知识是不够的,还应根据具体硬件结构软硬件结合,加以完善。本论文是基于单片机技术原理,以单片机芯片AT89S52作为核心控制器,通过硬件电路的制作以及软件程序的编制,设计制作出一个定时电源。关键词:单片机;定时电源;AT89S52目录目录3第一章 前言41.1设计任务41.2 总设计框图5第二章 主要元件介绍52.1 AT89S52的功能特性描述52.2 AT89S52引脚功能62.3 特殊功能寄存器72.4 数据存储器72.5 捕获方式82.6 自动重装载方式82.7波特率发生器82.8可编程始终输出92.9中断92.10时钟振荡器92.11 模式10212 Flash存储器的编程10第三章 系统设计113.1 编程方法113.2 数据查询113.3 Ready/Busy123.4 排阻123.5硬件电路图13第四章软件方案设计164.1 程序设计16总结24致谢25参考文献26附录1 总系统框图27附录2 使用说明书27第一章 前言1.1设计任务1. 利用单片机设计一定时开关,在24小时内的时间里能预先设定定时范围,每天周而复始地控制用电器具的自动开启和关闭。2. 要求最少能独立控制两路220V10A的交流负载。3. 产品的成本应尽量低。4. 产品的功能应尽量多,最少应具有时间显示和校正、定时显示和设置等功能。5. 产品的质量应可靠、安全。具体性能指标如下:供电电源:220V 50Hz 使用环境温度:-10至40度功率消耗:<2W 负载功率:2500W(250V 10A)最大负载电流:>10A 定时范围:1分钟至23小时59分任意设定最小设定单位:1分钟 最小设定间隙:1分钟 定时精度:1分钟 课定时次数:不少于1次工作坊式:连续工作制6. 设计并制作单片机控制电路,要求能够显示时间、通过按键修改时间和设置定时。7. 设计并制作输出控制电路,要求能控制两路以上220V/10A的插座。8. 编写产品使用说明书。1.2 总设计框图第二章 主要元件介绍2.1 AT89S52的功能特性描述AT89S52是一个低功耗,高性能CMOS 8位单片机,片内含8K可反复擦写的程序存储器和12B的随机存储数据存储器(RAM),器件采用Atmel公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内配置通用8位中央处理器(CPU)和Flash存储单元,功能强大的AT89S52单片机课灵活应用于各种控制领域。其主要工作特性如下:片内程序存储器含8K的Flash程序存储器,可擦写寿命为1000次;片内程序存储器256字节的RAM;具有32根可编程I/O口线;具有3个可编程定时器;中断系统是具有8个中断源、6个中断矢量、2个级优先权的中断结构;串行口是具有一个全双工口的可编程串行通信口;具有一个数据指针DPTR;低功耗工作模式有空闲模式和掉电模式;具有可编程的3级程序锁定位;AT89S52工作电源电压为5(1+0.2)V,且典型值为5V;2.2 AT89S52引脚功能AT89S52引脚图(1)P0口:P0口是一组8位漏级开路双向I/O口,也即地址/数据总线复用口。作为输出口用时,每位能吸收电流的方式驱动8个TTL逻辑门电路,对端口P0写“1”时,可作为高阻抗输入端用。在访问外部数据存储器或程序存储器时,这组口线分时转换地址的(低八位)和数据总线复用,在在访问期间激活内部上拉电阻。在FIASH编程时,P0 口接收指令字节, 而在程序校验时,输出指令字节,校验时,要求外接上拉电阻。(2)P1口:P1口是一个带有内部提供上拉电阻的8位双向I/O口,P1口输出缓冲级可驱动(吸收或输出)4个TTL逻辑门电路。对端口写入“1”,通过内部的上拉电阻把端口拉到高电平,此时,可用作输入口。作为输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流(ILL)。与AT89C51不同之处是,P1.0和P1.1还可分别作为定时/计数2的外部计数输入(P1.0/T2)和输入(P1.1/T2EX)。FLASH编程和校验期间,P1接收低八位地址。(3)P2口:P2口为一个带有内部上拉电阻的8位双向I/O口,P2口输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑门电路。当端口P2写“1”, 通过内部的上拉电阻把端口拉到高电平,此时,可用作输入口。作为输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流(ILL)。在访问外部程序存储器或16位地址的外部数据存储器,(例如执行MOVX DPTR指令)时,P2口送出高8位地址数据。在访问8位地址的外部数据存储器(例如执行MOVX R1指令)时,P2口输出P2锁存器的内容。FLASH编程和校验时P2亦接收高位地址和一些控制信号。(4)P3口:P3是一组带有内部上拉电阻的8位双向I/O口,P3口输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑门电路。对P3口写入“1”时,它们被内部上拉为高电平并用作输入端口。此时,被外部拉低的P3口将用上拉电阻输出电流(ILL)。P3口除了作为一般的I/O口线外,更重要的用途是它的第二功能,P3口还接收一些用于Flash闪速存储器编程和程序校验的控制信号。(5)RST:复位输入。当振荡器工作时,RST引脚出现两个机器周期以上高电平使单片机复位。(6)ALE/PROG:当访问外部存储器或数据存储器时,ALE(地址锁存允许)的输出脉冲用于锁存地址的低8位字节。一般情况下,ALE仍以时钟振荡频率的1/6输出固定的脉冲信号。因此它可对外部输出的脉冲或用于定时目的。要注意的是:每当访问外部数据存储器时,将跳过一个ALE脉冲。如有必要,可通过对特殊寄存器(SFR)区中的8EH单元的D0位置位,可禁止ALE操作。该位置后,只有一条MOVX和MOVC指令才能将ALE激活。此外,该引脚会被略微拉高。单片机执行外部程序时,应设置ALE禁止位无效。(7)/PSEN:程序存储允许(PSEN)是外部程序存储器选通信号。当AT89S52由外部程序存储器取指令(或数据)时,每个机器周期两次/PSEN有效即输出两个脉冲。在此期间,当访问外部数据存储器时,将跳过两次/PSEN信号。(8)/EA/VPP:外部访问允许。欲使CPU仅访问外部程序存储器(地址为0000H-FFFFH),EA端必须保持低电平(接地)。需注意的是:如果加密LB1被编程,复位时会锁存EA端状态。如/EA端为高电平(接Vcc端),CPU则执行内部程序存储器中的指令。FLASH编程时,该引脚也加上+12V编程电源(VPP),当然这必须是该器件是使用12V编程电源(VPP)。(9)XTAL1:振荡器反相放大器的及内部时钟发生的输入器。(10)XTAL2:振荡器反相放大器的输出端。 2.3 特殊功能寄存器在AT89S52片内存储器中,80H-FFH共128个单元为特殊功能寄存器(SFR)。并非所有的地址都被定义,从80H-FFH共128个字节只有一部分被定义,还有相当一部分没有定义。对没有定义的单元读写将是无效的,读出的数据将不确定,而写入的数据也将丢失。不应将数据“1”写入未定义的单元,由于这些单元在将来的产品中可能赋予新的功能,在这种情况下,复位后这些单元数值总是“0”。 AT89S52除了与AT89C51所有的定时/计数0和定时/计数1外,还增加了一个定时/计数2。定时/计数2的控制和状态位位于T2CONT2MOD,寄存器对(RCA02HRCAP2L)是定时器2在16位捕捉方式或16为自动重装载方式下的捕捉/自动重装载寄存器。2.4 数据存储器AT89S52有256个字节的内部RAM,80H-FFH高128个字节与特殊功能寄存器(SFR)地址是重叠的,也就是高128个字节的RAM与特殊功能寄存器的地址死机相同的,但物理上它们是分开的。当一条指令访问7FH以上的内部地址单元时,指令中使用的寻址方式是不同的,也即寻址方式决定是访问特殊功能寄存器。如果指令是直接寻址方式则为访问特殊功能寄存器。堆栈操作也是间接寻址方式,所以,高128位数据RAM亦可作为堆栈区使用。定时器0和定时器1:AT89S52的定时器0和定时器1的工作方式与AT89C51相同。定时器2:定时器2是一个16位定时/计数器。它既可以当定时器使用,也可作为外部事件计数器使用,其工作方式由特殊功能寄存器T2CON的C/T2位选择。定时器2有三种工作方式:捕获方式,自动重装载(向上或向下计数)方式和波特率发生器方式,工作方式由T2CON的控制位来选择。定时器2由两个8位寄存器TH2和TL2组成,在定时器工作方式中,每个机器周期TL2寄存器的值加1,由于一个机器周期由12个振荡时钟构成,因此,计数速率为振荡器的1/12。在计数工作方式时,当T2引脚上外部输入信号产生由1至0的下降延时,寄存器的值加1,在这种工作方式下,每个机器周期的5SP2期间,对外部输入进行采样。若在第一个机器周期中采到的值为1,而在下一个机器周期中采到的值为0则在紧跟着的下一个机器周期的S3P1期间寄存器加1.由于识别1至0的跳变需要2个机器周期(24个振荡周期),因此,最高计数速率为振荡频率的1/24。为确保采样的正确性,要求输入的电平在变化前至少保持一个完整周期的时间,以保证输入信号至少被采样过一次。2.5 捕获方式在捕获方式下,通过T2CON控制位EXEN2来选择两种方式。如果EXEN2=0,定时器2是一个16位定时器或计数器,计数溢出时,对T2CON的溢出标志TF2置位,同时激活中断。如果EXEN2=1,定时器2完成相同的操作,而当T2EX引脚外部信号发生1至0负跳变时,也出现TH2和TL2中的值分别被捕获到RCAP2H和RCAP2L中。另外,T2EX引脚信号的跳变使得T2CON中的EXF2置位,与TF2相仿,EXF2也会激活中断。2.6 自动重装载方式当定时器2工作于16位自动重装载方式时,能对其编程为向上或向下计数器方式,这个功能可通过特殊功能寄存器T2CON的DCEN位(允许向下计数)来选择。复位时,DCEN位置“0”,定时器2默认设置为向上计数。当DCEN位置时,定时器2既可向上计数也可向下计数,这取决于T2EX引脚的值,当DCEN=0时,定时器2自动设置为向上计数,在这种方式下,T2CON中的EXEN2控制位有两种选择。若EXEN2=0,定时器2为向上计数至0FFFFH溢出,置位TF2激活中断,同时把16位计数寄存器RCAPL2H和RCAP2L重装载,RCAPL2H和RCAP2L的值可由软件预置。若EXEN2=1,定时器2的16位重装载由溢出或外部输入端T2EX从1至0的下降沿触发。这个脉冲是EXF2置位,如果中断允许,同样产生中断。定时器2的中断入口地址是002BH-0032H。当DCEN=1时,允许定时器2向上或向下计数,如图所示。这种方式下,T2EX引脚控制计数方向。T2EX引脚为逻辑“1”时,定时器向上计数,当计数到0FFFFH向上溢出时,置位TF2,同时把16位计数寄存器RCAP2H和RCAP2L重装载到TH2和TL2中。T2EX引脚为逻辑“0”时,计数溢出,置位TF2,同时将0FFFFH数值重新装入定时寄存器中。当定时/计数器2向上或向下溢出时,置位EXF2。2.7波特率发生器当T2CON中的TCLK和RCLK置位时,定时/计数器2作为波特率发生器使用。如果定时/计数器2作为发送器或接收器,其发送和接收的波特率可以是不同的,定时1用于其他功能。若RCLK和TCLK置位,则定时器2工作于波特率发生器方式。波特率发生器的方式与自动重装载方式相仿,在此方式下,TH2翻转使定时器2的寄存器用RCAP2H和RCAPL中的16为数值重新装载,该数值由软件设置。在方式1和方式3中,波特率由定时器2的溢出速度根据下式确定:方式1和3的波特率=定时器的溢出率/16定时器既能工作于定时方式也能工作于计数方式,在大多数的应用中,是工作在定时方式(C/T2=0)。定时器2作为波特率发生器时,与作为定时器的操作是不同的,通常作为定时器时,在每个机器周期(1/12振荡频率)寄存器的值加1,而作为波特率发生器使用时,在每个状态时间(1/2振荡频率)寄存器的值加1。波特率的计算公式如下:方式1和3的波特率=振荡频率/32*65536-(RCAP2H,RCAP2L)式中(RCAP2H,RCAP2L)是RCAP3H和RCAP2L中的16位无符号数。T2CON中的RCLK或TCLK=1时,波特率工作方式才有效。在波特率发生器工作方式中,TH2翻转不能使TF2置位,故而不产生中断。但若EXEN2置位,且T2EX端产生由1至0的负跳变,则会使EXF2置位,此时并不能将(RCAP2H,RCAP2L)的内容重新装入TH2和TL2中。所以,当定时器2作为波特率发生器使用时,T2EX可作为附加的外部中断源来使用。需注意的是,当定时器2工作于波特率发生器时,作为定时器运行(TR2=1)时,并不能访问TH2和TL2。因此每个状态时间定时器都会加1,对其读写将得到一个不确定的数值。然而,对RCAP2则可读而不可写,因为写入操作将是重新装载,写入操作可能令写和重新装载出错。在访问定时器2或RCAP2寄存器之前,应将定时器关闭(清除TR2)。2.8可编程始终输出定时器2可通过编程从P1.0输出一个占空比为50%的时钟信号。P1.0引脚除了是一个标准的I/O口外,还可以通过编程使其作为定时/计数器2的外部时钟输入和输出占空比50%的时钟脉冲。当时钟振荡频率为16MHz时,输出时钟频率范围为61Hz-4MHz。 当设置定时/计数器2为时钟发生器时,C/T2(Y2CON.1)=0,T2OE(T2MOD.1)=1,必须由TR2(T2CON.2)启动或停止定时器。始终输出频率取决于振荡频率和定时器2捕获寄存器(RCAP2H,RCAP2L)的重新装载值,公式如下:输出时钟频率=振荡器频率/4*65536-(RCAP2H,RCAP2L)在时钟输出方式下,定时器2的翻转不会产生中断,这个特性与作为波特率发生器使用时相仿。定时器2作为波特率发生器使用时,还可以作为时钟发生器使用,但需注意的是波特率和时钟输出频率不能分开确定,这是因为它们同时使用RCAP2H和RCAP2L。2.9中断AT89S52共有6个中断向量:2个外部中断源(INT0和INT1),3个定时器中断(定时器012)和串行口中断。这些中断源可通过分别设置专用寄存器IE的置位或清0来控制每一个中断的允许或禁止。IE也有一个总禁止位EA,它能控制所有中断的允许或禁止。注意表5中的IE.6为保留位,在AT89C51中IE.5也是保留位。程序员不应将“1”写入这些位,它们是将来AT89系列产品作为扩展用的。定时器2的中断是由T2CON中的TF2和EXF2产生的,当转向中断服务程序时,这些标志位不能被硬件清除,事实上,服务程序需确定是TF2或EXF2产生中断,而有软件清除中断标志位。定时器0和定时器1的标志位TF0和TF1在定时器溢出那个周期的S5P2状态位置,而会在下一个机器周期才查询到该中断标志。然而,定时器2的标志位TF2在定时器溢出的那个周期的S2P2状态位置,并在同一个周期内查询到该标志。2.10时钟振荡器AT89S52中是一个用于构成内部振荡器的高增益反向放大器,引脚XTAL1和XTAL2分别是该放大器份的输入端和输出端。这个放大器与作为片外石英晶体或陶瓷谐振器一起构成自激振荡器。外接石英晶体或陶瓷谐振器及电容C1,C2接在放大器的反馈回路中构成并联振荡电路。对外接电容C1,C2虽然没有十分严格的要求,但电容容量的大小会轻微影响振荡频率的高低,振荡器工作的稳定性,起振的难易程度及温度稳定性。如果石英晶体,我们推荐电容使用30pF+10pF,而使用陶瓷谐振器建议使用40pF+10pF。用户也可以采用外部时钟。采用外部时钟的电路,这种情况下,外部时钟脉冲接到XTAL1端,即内部时钟发生器的输入端,XTAL2则悬空。由于外部时钟信号是通过一个2分频触发器后作为内部时钟信号的,所以对外部时钟信号的占空比没有特殊要求,但最小高电平持续时间和最大的低电平持续时间应符合产品技术条件的要求。2.11 模式(1)空闲节电模式:在空闲工作模式状态, CPU 自身处于睡眠状态而所有片内的外设仍保持激活状态,这种方式由软件产生。此时,同时将片内RAM 和所有特殊功能寄存器的内容冻结。空闲模式可由任何允许的中断请求或硬件复位终止。由硬件复位终止空闲状态只需两个机器周期有效复位信号,在此状态下,片内硬件禁止访问内部RAM,但可以访问端口引脚,当用复位终止空闲方式时,为避免可能对端口产生意外写入,激活空闲模式的那条指令后一条指令不应是一条对端口或外部存储器的写入指令。(2)掉电模式:在掉电模式下,振荡器停止工作,进入掉电模式的指令是最后一条被执行的指令,片内RAM 和特殊功能寄存器的内容在终止掉电模式前被冻结。退出掉电模式的唯一方法是硬件复位,复位后将重新定义全部特殊功能寄存器,但不改变RAM中的内容,在Vcc恢复到正常工作电平前,复位应无效,且必须保持一定时间以使振荡器重启动并稳定工作。212 Flash存储器的编程AT89S52单片机内部有8k字节的Flash PEROM,这个Flash 存储阵列出厂时已处于擦除状态(即所有存储单元的内容均为FFH),用户随时可对其进行编程。编程接口可接收高电压(+12V)或低电压(Vcc)的允许编程信号。低电压编程模式适合于用户在线编程系统,而高电压编程模式可与通用EPROM编程器兼容。AT89S52 单片机中,有些属于低电压编程方式,而有些则是高电压编程方式,用户可从芯片上的型号和读取芯片内的签名字节获得该信息。AT89S52 的程序存储器阵列是采用字节写入方式编程的,每次写入一个字节,要对整个芯片内的PEROM 程序存储器写入一个非空字节,必须使用片擦除的方式将整个存储器的内容清除。第三章 系统设计3.1 编程方法编程前,设置好地址、数据及控制信号,AT89S52 编程方法如下:1 在地址线上加上要编程单元的地址信号。2 在数据线上加上要写入的数据字节。3 激活相应的控制信号。4 在高电压编程方式时,将EA/Vpp 端加上+12V 编程电压。5 每对Flash 存储阵列写入一个字节或每写入一个程序加密位,加上一个ALE/PROG 编程脉冲。每个字节写入周期是自身定时的,通常约为1.5ms。重复15 步骤,改变编程单元的地址和写入的数据,直到全部文件编程结束。3.2 数据查询AT89S52 单片机用Data Palling 表示一个写周期结束为特征,在一个写周期中,如需读取最后写入的一个字节,则读出的数据的最高位(P0.7)是原来写入字节最高位的反码。写周期完成后,所输出的数据是有效的数据,即可进入下一个字节的写周期,写周期开始后,Data Palling 可能随时有效。3.3 Ready/Busy字节编程的进度可通过“RDY/BSY 输出信号监测,编程期间,ALE 变为高电平“H”后,P3.4(RDY/BSY)端电平被拉低,表示正在编程状态(忙状态)。编程完成后,P3.4 变为高电平表示准备就绪状3.4 排阻排阻,就是若干个参数完全相同的电阻,它们的一个引脚都连到一起,作为公共引脚,其余引脚正常引出。所以如果一个排阻是由n个电阻构成的,那么它就有n+1只引脚,一般来说,最左边的那个是公共引脚。它在排阻上一般用一个色点标出来。排阻一般应用在数字电路上,比如:作为某个并行口的上拉或者下拉电阻用。使用排阻比用若干只固定电阻更方便。 排阻有a型和b型的区别。a型排阻的引脚总是奇数的。它的左端有一个公共端(用白色的圆点表示),常见的排阻有4、7、8个电阻,所以引脚共有5或8或9个。B型排阻的引脚总是偶数的。它没有公共端,常见的排阻有4个电阻,所以引脚共有8个。排阻的阻值读法如下:“103”表示:10k,“510”表示:51。以此类推。LG2841结构图:3.5硬件电路图(1)电源部分:(2)单片机部分:(3)开关控制部分:第四章 软件方案设计4.1 程序设计/*程控定时开关*/#include<at89s52.h>/*包含库函数*/*七段数码管,高电平有效,顺序为abcdefg*/unsigned char led=0,0,0,0;/*将四个LED定义成一个数组,用来显示时、分和秒*/char code num=0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00;unsigned int counter;/*counter作为定时器中断次数的计数器*/unsigned char n,w=0,flag1=0,flag2=0;/*n为闪烁次数计数器,w为显示计数器,flag为设置按键计数器,flag1和flag2均为延时消抖计数器*/unsigned char K1_on=0,K2_on=0;/*K1_on和K2_on分别为开关1和开关2的开启和关断状态寄存器*/unsigned char h_date=0.m_data=0,s data=0;/*时钟的时、分、秒计数器*/unsigned char hdata1_off=0,mdata1_on=3,hdata2_on=0,mdata_on=7;/*开关1和开关2的开启时间寄存器*/unsigned char hdata1_off=0,mdata1_off=5,hdata2_off=0,mdata_off=9;/*开关1和开关2的关断时间寄存器*/void display(void);/*申明显示子程序*/void delay(unsigned int j)/*定义可变延时子程序*/unsigned int i;for(i=0;i<j;i+);void load_LED(unsigned char H,unsigned char M)/*定义将实际时间代码装LED显示区的子程序,作用是将个位和十位分离开*/ led0=H/10;led0/*装时的十位*/led1=H%10;led1/*装时的个位*/led2=M/10;led2/*装分的十位*/led3=M%10;led3/*装分的个位*/unsigned char H1_set(unsigned char H1) H1=(H1/10+1)*10+H1%10;if(H1>23)H1=H1%10;return H1;/*定义时的十位加1函数*/unsigned char H0_set(unsigned char H0) if(H0%10=3&&H0/10=2) H0=H0/10*1;else H0=H0%10+1+H0/10*10;return H0;/*定义时的个位加1函数*/unsigned char M1_set(unsigned char M1)M1=(M1/10+1)*10+M1%10;if(M1>=60)M1=M1%10;return M1;/*定义分的十位加1函数*/unsigned char M0_set(unsigned char M0) if(M0%10=9) M0=M0/10*10;else M0=M0%10+1+M0/10*10;return M0;/*定义分的个位加1函数*/void display(void)/*定义显示子程序*/char code num=0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00;/*定义0-9的LED显示段码数组.0x00为不显示(消隐)*/char code tv=0xfe,0xfd,0xfb,oxf7;/*定义位码数组,用于控制显示码送到哪个LED*/unsigned char k,I;switch(flag)/*根据设置所处的模式显示时钟*/case 0:load_LED(h_data,m_data);break; /*显示时钟*/case 1:load_LED(h_data,m_data);break; /*显示修改时钟设置*/case 2:load_LED(hdata1_on,mdata1_on);break;/*显示设置开关1开启时间设*/case 3:load_LED(hdata1_off,mdata1_off);break;/*显示设置开关1关断时间设置*/case 4:load_LED(hdata2_on,mdata2_on);break;/*显示设置开关2开启时间设置*/case 5:load_LED(hdata2_off,mdata2_off);break;/*显示设置开关2关断时间设置*/case 6:load_LED(hdata1_on,mdata1_on);break;/*显示设置开关1设置好的开启时间*/case 7:load_LED(hdata1_off,mdata1_off);break;/*显示设置开关1设置好的关断时间*/case 8:load_LED(hdata2_on,mdata2_on);break;/*显示设置开关2设置好的开启时间*/case 9:load_LED(hdata2_off,mdata2_off);break;/*显示设置开关2设置好的关断时间*/default:P1=0xFF;load_LED(h_data,m_data);break; /* 其他情况下,显示时钟*/ n+; /*n用来对显示的次数进行计数,以便控制对需要设置的位进行闪烁*/for(k=0;k<4;k+) /*以下为控制被设置位闪烁的程序语句*/if(flag) /* 如果处在设置模式,则对设置位进行闪烁显示*/If(n>180) /*每送显示180次则进行一次闪烁*/n=0;if(k=w) /*如果送显示的位是正准备调整的位,则需要闪烁显示,以下两句是控制闪烁显示*/If(n<90) /*以下语句是将LED的七段码送P0口,前90次显示*/ i=ledk; /*将该LED位需要显示的数存于i中*/P0=num10; /*该LED位不显示(短时消隐),送消隐段码*/P2=tvk; /*送需要显示的LED位码*/delay(10); /*短时消隐延时,有利于显示位的切换*/P0=numi; /*将要显示的数字i作为七段码表的序号(段码数组下标),取出显示码送显示*/if(k=1) /*如果送显示的LED为分的个位*/P0=numi|0x80; /*则将分的个位显示码附加小数点*/delay(100); /*显示延时,让LED充分点亮*/ else /*后90次消隐*/P0=num10; /*送LED消隐段码*/if(k=1) /*如果消隐的是分的个位*/P0=num10|0x80; /*则将个位后的小数点点亮(小数点不闪烁)*/P2=tvk; /*送消隐的位码(即哪个LED需要闪烁)*/delay(100); /*消隐延时,让其充分消隐*/ else /*如果送显示的位不调整的位,则不需要闪烁显示*/ i=ledk; /*将该LED为需要显示的数字存于i中*/P0=num10; /*该LED位不显示(短时消隐),送消隐段码*/P2=tvk; /*送需要显示的LED位码*/delay(10); /*短时消隐延时,有利于显示位的切换*/P0=numi; /*将要显示的数字i作为七段码表的序号(段码数组下标),取出显示码送显示*/if(k=1) /*如果送显示的LED为分的个位*/ P0=numi|0x80; /*则将分的个位显示码附加小数点*/delay(100); /*显示延时,让LED充分点亮*/ else /*如果不是处在设置模式,则正常显示*/ load_LED(h_data,m_data);/*调用实际时间代码装LED显示区的子程序,分离个位和十位*/i=ledk; /*将该LED为需要显示的数字存于i中*/P0=num10 /*该LED位不显示(短时消隐),送消隐段码*/P2=tvk;/*送需要显示的LED位码*/delay(10);/*短时消隐延时,有利于显示位的切换*/P0=numi;/*将要显示的数字i作为七段码表的序号(段码数组下标),取出显示码送显示*/if(k=1) /*如果送显示的LED为分的个位*/ P0=numi|0x80; /*则将分的个位显示码附加小数点*/delay(100); /*显示延时,让LED充分点亮*/ /*/void adjust(void) /*调整函数定义*/if(P3_0=0)delay(100);while(P3_0=0) flag1+;display(); /*当调整键按下时,延时消抖,flag1控制延时时间*/if(flag1>50)flag1=0; flag+; /*用flag对调整键按下次数计数,目的是通过一个按键实现多种功能*/if(flag>=10) flag=0; /*/if(P3_1=0) /* 移位控制键,在4个LED上来回移动,选择需要设置的LED*/ delay(100); /* 消抖*/while(P3_1=0)display()if(flag)/*当flag不等于0时,说明处于调整状态,此时通过移位键选择调整哪一个LED*/w=w+1; /*移位键控制w加1,用于修改位码,w代表4个LED数码管的某一位*/if(w>=4) w=0; /*/if(P3_2=0) /* 加1操作*/delay(100); /* 消抖*/while(P3_2=0)display();if(flag) /*当处于调整模式时,对所选择的LED进行加1*/switch(flag)case 1: if(w=0) h_data=H1_set(h_data);display(); /*校准时间的时、分*/if(w=1) h_data=H0_set(h_data);display();if(w=2) m_data=M1_set(m_data);display();if(w=3) m_data=M0_set(m_data);display();break; case 2: if(w=0) hdata1_on=H1_set(hdata1_on);display();/* 设置开关1开启时间的时、分*/if(w=1) hdata1_on=H0_set(hdata1_on);display();if(w=2) mdata1_on=M1_set(mdata1_on);display();if(w=3) mdata1_on=M0_set(mdata1_on);display(); /* 设置开关1关断时间的时、分*/break; case 3: if(w=0) hdata1_off=H1_set(hdata1_off);display();if(w=1) hdata1_off=H0_set(hdata1_off);display();if(w=2) mdata1_off=M1_set(mdata1_off);display();if(w=3) mdata1_off=M0_set(mdata1_off);display();break; case 4: if(w=0) hdata2_on=H1_set(hdata2_on);display(); /*设置开关2开启时间的时、分*/if(w=1) hdata2_on=H0_set(hdata2_on);display