基于51单片机的低成本多路程控定时插座设计与制作 - 图文

更新时间:2024-06-07 13:40:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

一、设计任务:

1、利用单片机设计一定时开关,在24小时内的时间里能预先设定定时范围,每天周而复始地控制用电器具的自动开启和关闭。

2、要求最少能独立控制两路220V/10A的交流负载。 3、产品的成本应尽量低,不能超过35元。

4、产品的功能应尽量多,最少应具有时间显示和校正、定时显示和设置等功能。 5、产品的质量应可靠、安全。具体性能指标如下:

供电电源:220V 50Hz 使用环境温度:-10至40度 功率消耗:<2W 负载功率:2500W(250V 10A)

最大负载电流:>10A 定时范围:1分钟至23小时59分任意设定 最小设定单位:1分钟 最小设定间隙:1分钟 定时精度:1分钟 可定时次数:不少于1次 工作方式:连续工作制

6、设计并制作单片机控制电路,要求能够显示时间、通过按键修改时间和设置定时。 7、设计并制作输出控制电路,要求能控制两路以上的220V/10A的插座。 8、编写产品使用说明书。

二、方案选择:

三、主要元件介绍:

1、 AT89C52是美国Atmel公司生产的低电压、高性能CMOS 8位单片机,片内含8KB的可反复檫写的程序存储器和12B的随机存取数据存储器(RAM),器件采用Atmel公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内配置通用8位中央处理器(CPU)和Flash存储单元,功能强大的AT89C52单片机可灵活应用于各种控制领域。其主要工作特

性是:

片内程序存储器内含8KB的Flash程序存储器,可擦写寿命为1000次; 片内数据存储器内含256字节的RAM; 具有32根可编程I/O口线; 具有3个可编程定时器;

中断系统是具有8个中断源、6个中断矢量、2个级优先权的中断结构; 串行口是具有一个全双工的可编程串行通信口; 具有一个数据指针DPTR;

低功耗工作模式有空闲模式和掉电模式; 具有可编程的3级程序锁定位;

AT89C52工作电源电压为5(1+0.2)V,且典型值为5V; AT89C52最高工作频率为24MHz。 功能特性描述

AT89S52是一种低功耗、高性能CMOS8位微控制器,具有8K 在系统可编程Flash 存储器。使用Atmel 公司高密度非易失性存储器技术制造,与工业80C51 产品指令和引脚完全兼容。片上Flash允许程序存储器在系统可编程,亦适于常规编程器。

在单芯片上,拥有灵巧的8 位CPU 和在系统可编程Flash,使得AT89S52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。 AT89S52具有以下标准功能:

8k字节Flash,256字节RAM,32 位I/O 口线,看门狗定时器,2 个数据指针,三个16 位定时器/计数器,一个6向量2级中断结构,全双工串行口,片内晶振及时钟电路。

另外,AT89S52 可降至0Hz 静态逻辑操作,支持2种软件可选择节电模式。空闲模式下,CPU停止工作,允许RAM、定时器/计数器、串口、中断继续工作。掉电保护方式下,RAM内容被保存,振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止。8 位微控制器8K 字节在系统可编程

AT89C52是一个低电压,高性能CMOS 8位单片机,片内含8k bytes的可反复擦写的Flash只读程序存储器和256 bytes的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内置通用8位中央处理器和Flash存储单元,功能强大的AT89C52单片机可为您提供许多较复杂系统控制应用场合。

AT89C52有40个引脚,32个外部双向输入/输出(I/O)端口,同时内含2个外中断口,3个16位可编程定时计数器,2个全双工串行通信口,2个读写口线,AT89C52可以按照常规方法进行编程,也可以在线编程。其将通用的微处理器和Flash存储器结合在一起,特别是可反复擦写的Flash存储器可有效地降低开发成本。

AT89C52有PDIP、PQFP/TQFP及PLCC等三种封装形式,以适应不同产品的需求。 主要功能特性:

· 兼容MCS51指令系统 · 8k可反复擦写(>1000次)Flash ROM · 32个双向I/O口 · 256x8bit内部RAM

· 3个16位可编程定时/计数器中断 · 时钟频率0-24MHz · 2个串行中断 · 可编程UART串行通道 · 2个外部中断源 · 共6个中断源 · 2个读写中断口线 · 3级加密位

· 低功耗空闲和掉电模式 · 软件设置睡眠和唤醒功能 AT89C52各引脚功能及管脚电压

概述:AT89C52P为40 脚双列直插封装的8 位通用微处理器,采用工业标准的C51内核,在内部功能及管脚排布上与通用的8xc52 相同,其主要用于会聚调整时的功能控制。功能包括对会聚主IC 内部寄存器、数据RAM及外部接口等功能部件的初始化,会聚调整控制,会聚测

2

试图控制,红外遥控信号IR的接收解码及与主板CPU通信等。主要管脚有:XTAL1(19 脚)和XTAL2(18 脚)为振荡器输入输出端口,外接12MHz 晶振。RST/Vpd(9 脚)为复位输入端口,外接电阻电容组成的复位电路。VCC(40 脚)和VSS(20 脚)为供电端口,分别接+5V电源的正负端。P0~P3 为可编程通用I/O 脚,其功能用途由软件定义,在本设计中,P0 端口(32~39 脚)被定义为N1 功能控制端口,分别与N1的相应功能管脚相连接,13 脚定义为IR输入端,10 脚和11脚定义为I2C总线控制端口,分别连接N1的SDAS(18脚)和SCLS(19脚)端口,12 脚、27 脚及28 脚定义为握手信号功能端口,连接主板CPU 的相应功能端,用于当前制式的检测及会聚调整状态进入的控制功能。

·P0 口:P0 口是一组8 位漏极开路型双向I/O 口, 也即地址/数据总线复用口。作为输出口

用时,每位能吸收电流的方式驱动8 个TTL逻辑门电路,对端口P0 写“1”时,可作为高阻抗输入端用。在访问外部数据存储器或程序存储器时,这组口线分时转换地址(低8 位)和数据总线复用,在访问期间激活内部上拉电阻。在Flash 编程时,P0 口接收指令字节,而在程序校验时,输出指令字节,校验时,要求外接上拉电阻。

·P1 口:P1 是一个带内部上拉电阻的8 位双向I/O 口, P1 的输出缓冲级可驱动(吸收或输

出电流)4 个TTL 逻辑门电路。对端口写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作输入口。作输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流(IIL)。与AT89C51 不同之处是,P1.0 和P1.1 还可分别作为定时/计数器2 的外部计数输入(P1.0/T2)和输入(P1.1/T2EX)。Flash 编程和程序校验期间,P1 接收低8 位地址。表.P1.0和P1.1的第二功能

·P2 口:P2 是一个带有内部上拉电阻的8 位双向I/O 口,P2 的输出缓冲级可驱动(吸收或

输出电流)4 个TTL 逻辑门电路。对端口P2 写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作输入口,作输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流(IIL)。在访问外部程序存储器或16 位地址的外部数据存储器(例如执行MOVX @DPTR 指令)时,P2 口送出高8 位地址数据。在访问8 位地址的外部数据存储器(如执行MOVX @RI 指令)时,P2 口输出P2 锁存器的内容。Flash 编程或校验时,P2亦接收高位地址和一些控制信号。

·P3 口:P3 口是一组带有内部上拉电阻的8 位双向I/O 口。P3 口输出缓冲级可驱动(吸收

或输出电流)4 个TTL 逻 辑门电路。对P3 口写入“1”时,它们被内部上拉电阻拉高并可作为输入端口。此时,

被外部拉低的P3 口将用上拉电阻 输出电流(IIL)。

P3 口除了作为一般的I/O 口线外,更重要的用途是它的第二功能 P3 口还接收一些用于Flash 闪速存储器编程和程序校验的控制信号。 ·RST: 复位输入。当振荡器工作时,RST引脚出现两个机器周期以上高电平将使单片机复位。 ·ALE/PROG:当访问外部程序存储器或数据存储器时,ALE(地址锁存允许)输出脉冲用于锁存

地址的低8 位字节。一般情况下,ALE 仍以时钟振荡频率的1/6 输出固定的脉冲信号,因此它可对外输出时钟或用于定时目的。要注意的是:每当访问外部数据存储器时将跳过一个ALE 脉冲。对Flash 存储器编程期间,该引脚还用于输入编程脉冲(PROG)。如有必要,可通过对特殊功能寄存器(SFR)区中的8EH 单元的D0 位置位,可禁止ALE 操作。该位置位后,只有一条

MOVX 和MOVC指令才能将ALE 激活。此外,该引脚会被微弱拉高,单片机执行外

部程序时,应设置ALE 禁止位无效。

·PSEN:程序储存允许(PSEN)输出是外部程序存储器的读选通信号,当AT89C52 由外部程序

存储器取指令(或数据)时,每个机器周期两次PSEN 有效,即输出两个脉冲。在此期间,当访问外部数据存储器,将跳过两次PSEN信号。

3

·EA/VPP:外部访问允许。欲使CPU 仅访问外部程序存储器(地址为0000H—FFFFH),EA 端

必须保持低电平(接地)。需注意的是:如果加密位LB1 被编程,复位时内部会锁存EA端状态。如EA端为高电平(接Vcc端),CPU 则执行内部程序存储器中的指令。Flash 存储器编程时,该引脚加上+12V 的编程允许电源Vpp,当然这必须是该器件是使用12V 编程电压Vpp。

·XTAL1:振荡器反相放大器的及内部时钟发生器的输入端。 ·XTAL2:振荡器反相放大器的输出端。 ·特殊功能寄存器:

在AT89C52 片内存储器中,80H-FFH 共128 个单元为特殊功能寄存器(SFE)。并非所有的地址都被定义,从80H—FFH 共128 个字节只有一部分被定义,还有相当一部分没有定义。对没有定义的单元读写将是无效的,读出的数值将不确定,而写入的数据也将丢失。不应将数据“1”写入未定义的单元,由于这些单元在将来的产品中可能赋予新的功能,在这种情况下,复位后这些单元数值总是“0”。

AT89C52除了与AT89C51所有的定时/计数器0 和定时/计数器1 外,还增加了一个定时/计数器2。定时/计数器2 的控制和状态位位于T2CON、T2MOD,寄存器对(RCAO2H、RCAP2L)是定时器2 在16 位捕获方式或16 位自动重装载方式下的捕获/自动重装载寄存器。 ·数据存储器:

AT89C52 有256 个字节的内部RAM,80H-FFH 高128 个字节与特殊功能寄存器(SFR)地址是重叠的,也就是高128字节的RAM 和特殊功能寄存器的地址是相同的,但物理上它们是分开的。当一条指令访问7FH 以上的内部地址单元时,指令中使用的寻址方式是不同的,也即寻址方式决定是访问高128 字节RAM 还是访问特殊功能寄存器。如果指令是直接寻址方式则为访问特殊功能寄存器。

堆栈操作也是间接寻址方式,所以,高128 位数据RAM 亦可作为堆栈区使用。

·定时器0和定时器1:AT89C52的定时器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。为确保采样的正确性,要求输入的电平在变化前至少保持一个完整周期的时间,以保证输入信号至少被采样一次。

·捕获方式:在捕获方式下,通过T2CON 控制位EXEN2 来选择两种方式。如果EXEN2=0,定时

器2 是一个16 位定时器或计数器,计数溢出时,对T2CON 的溢出标志TF2 置位,同时激活中断。如果EXEN2=1,定时器2 完成相同的操作,而当T2EX 引脚外部输入信号发生1 至0 负跳变时,也出现TH2 和TL2 中的值分别被捕获到RCAP2H 和RCAP2L 中。另外,T2EX 引脚信号的跳变使得T2CON 中的EXF2 置位,与TF2 相仿,EXF2 也会激活中断。

·自动重装载(向上或向下计数器)方式:

当定时器2工作于16位自动重装载方式时,能对其编程为向上或向下计数方式,这个功能可通过特殊功能寄存器T2CON的DCEN 位(允许向下计数)来选择的。复位时,DCEN 位置

4

“0”,定时器2 默认设置为向上计数。当DCEN置位时,定时器2 既可向上计数也可向下计数,这取决于T2EX 引脚的值,当DCEN=0 时,定时器2 自动设置为向上计数,在这种方式下,T2CON 中的EXEN2 控制位有两种选择,若EXEN2=0,定时器2 为向上计数至0FFFFH 溢出,置位TF2 激活中断,同时把16 位计数寄存器RCAP2H 和RCAP2L重装载,RCAP2H 和RCAP2L 的值可由软件预置。若EXEN2=1,定时器2 的16 位重装载由溢出或外部输入端T2EX 从1 至0 的下降沿触发。这个脉冲使EXF2 置位,如果中断允许,同样产生中断。定时器2 的中断入口地址是:002BH ——0032H 。

当DCEN=1 时,允许定时器2 向上或向下计数,如图6 所示。这种方式下,T2EX 引脚控制计数器方向。T2EX 引脚为逻辑“1”时,定时器向上计数,当计数0FFFFH 向上溢出时,置位TF2,同时把16 位计数寄存器RCAP2H 和RCAP2L 重装载到TH2 和TL2 中。 T2EX 引脚为逻辑“0”时,定时器2 向下计数,当TH2 和TL2 中的数值等于RCAP2H 和RCAP2L

中的值时,计数溢出,置位TF2,同时将0FFFFH 数值重新装入定时寄存器中。当定时/计数器2 向上溢出或向下溢出时,置位EXF2 位。 ·波特率发生器:

当T2CON(表3)中的TCLK 和RCLK 置位时,定时/计数器2 作为波特率发生器使用。如果定时/计数器2 作为发送器或接收器,其发送和接收的波特率可以是不同的,定时器1 用于其它功能。若RCLK 和TCLK 置位,则定时器2工作于波特率发生器方式。

波特率发生器的方式与自动重装载方式相仿,在此方式下,TH2 翻转使定时器2 的寄存器用RCAP2H 和RCAP2L 中的16位数值重新装载,该数值由软件设置。在方式1 和方式3 中,波特率由定时器2 的溢出速率根据下式确定:方式1和3的波特率=定时器的溢出率/16定时器既能工作于定时方式也能工作于计数方式,在大多数的应用中,是工作在定时方式(C/T2=0)。定时器2 作为波特率发生器时,与作为定时器的操作是不同的,通常作为定时器时,在每个机器周期(1/12 振荡频率)寄存器的值加1,而作为波特率发生器使用时,在每个状态时间(1/2 振荡频率)寄存器的值加1。波特率的计算公式如下:方式1和3的波特率=振荡频率

/{32*[65536-(RCP2H,RCP2L)]}式中(RCAP2H,RCAP2L)是RCAP2H 和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 可通过编程从P1.0 输出一个占空比为50%的时钟信号。P1.0 引脚除了是一个标准的I/O 口外,还可以通过编程使其作为定时/计数器2 的外部时钟输入和输出占空比50%的时钟脉冲。当时钟振荡频率为16MHz 时,输出时钟频率范围为61Hz—4MHz。

当设置定时/计数器2 为时钟发生器时,C/T2(T2CON .1)=0,T2OE (T2MOD.1) =1,必须由TR2(T2CON.2)启动或停止定时器。时钟输出频率取决于振荡频率和定时器2 捕获寄存器(RCAP2H,RCAP2L)的重新装载值,公式如下:输出时钟频率=振荡器频率

/{4*[65536-(RCP2H,RCP2L)]}在时钟输出方式下,定时器2 的翻转不会产生中断,这个特性与作为波特率发生器使用时相仿。定时器2 作为波特率发生器使用时,还可作为时钟发生器使用,但需要注意的是波特率和时钟输出频率不能分开确定,这是因为它们同使用RCAP2L和RCAP2L。

·UART:AT89C52的UART 工作方式与AT89C51 工作方式相同。

5

·中断:AT89C52 共有6 个中断向量:两个外中断(INT0 和INT1),3 个定时器中断(定时

器0、1、2)和串行口中断。这些中断源可通过分别设置专用寄存器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 状态置位,并在同一个机器周期内查询到该标志。

·时钟振荡器:AT89C52 中有一个用于构成内部振荡器的高增益反相放大器,引脚XTAL1 和

XTAL2 分别是该放大器的输入端和输出端。这个放大器与作为反馈元件的片外石英晶体或陶瓷谐振器一起构成自激振荡器,振荡电路参见图10。外接石英晶(或陶瓷谐振器)及电容C1、C2 接在放大器的反馈回路中构成并联振荡电路。 对外接电容C1、C2 虽然没有十分严格的要求,但电容容量的大小会轻微影响振荡频率的高低、振荡器工作的稳定性、起振的难易程序及温度稳定性,如果石英晶体,我们推荐电容使用30pF±10pF,而如使用陶瓷谐振器建议选择40pF±10F。用户也可以采用外部时钟。采用外部时钟的电路,这种情况下,外部时钟脉冲接到XTAL1 端,即内部时钟发生器的输入端,XTAL2 则悬空。由于外部时钟信号是通过一个2 分频触发器后作为内部时钟信号的,所以对外部时钟信号的占空比没有特殊要求,但最小高电平持续时间和最大的低电平持续时间应符合产品技术条件的要求。

·空闲节电模式:在空闲工作模式状态, CPU 自身处于睡眠状态而所有片内的外设仍保持激活

状态,这种方式由软件产生。此时,同时将片内RAM 和所有特殊功能寄存器的内容冻结。空闲模式可由任何允许的中断请求或硬件复位终止。由硬件复位终止空闲状态只需两个机器周期有效复位信号,在此状态下,片内硬件禁止访问内部RAM,但可以访问端口引脚,当用复位终止空闲方式时,为避免可能对端口产生意外写入,激活空闲模式的那条指令后一条指令不应是一条对端口或外部存储器的写入指令。

·掉电模式:在掉电模式下,振荡器停止工作,进入掉电模式的指令是最后一条被执行的指令,

片内RAM 和特殊功能寄存器的内容在终止掉电模式前被冻结。退出掉电模式的唯一方法是硬件复位,复位后将重新定义全部特殊功能寄存器,但不改变RAM中的内容,在Vcc恢复到正常工作电平前,复位应无效,且必须保持一定时间以使振荡器重启动并稳定工作。

·Flash存储器的编程:AT89C52单片机内部有8k字节的Flash PEROM,这个Flash 存储阵列出厂时已处于擦除状态(即所有存储单元的内容均为FFH),用户随时可对其进行编程。编程接口可接收高电压(+12V)或低电压(Vcc)的允许编程信号。低电压编程模式适合于用户在线编程系统,而高电压编程模式可与通用EPROM 编程器兼容。AT89C52 单片机中,有些属于低电压编程方式,而有些则是高电压编程方式,用户可从芯片上的型号和读取芯片内的签名字节获得该信息。AT89C52 的程序存储器阵列是采用字节写入方式编程的,每次写入一个字节,要对整个芯片内的PEROM 程序存储器写入一个非空字节,必须使用片擦除的方式将整个存储器的内容清除。

·编程方法:编程前,设置好地址、数据及控制信号, AT89C52 编程方法如下:

a. 在地址线上加上要编程单元的地址信号。 b. 在数据线上加上要写入的数据字节。 c. 激活相应的控制信号。

6

d. 在高电压编程方式时,将EA/Vpp 端加上+12V 编程电压。

e. 每对Flash 存储阵列写入一个字节或每写入一个程序加密位,加上一个ALE/PRO编程

脉冲。每个字节写入周期是自身定时的,通常约为1.5ms。重复1—5 步骤,改变编程单元的地址和写入的数据,直到全部文件编程结束。

·数据查询:AT89C52 单片机用Data Palling 表示一个写周期结束为特征,在一个写周期中,

如需读取最后写入的一个字节,则读出的数据的最高位(P0.7)是原来写入字节最高位的反码。写周期完成后,所输出的数据是有效的数据,即可进入下一个字节的写周期,写周期开始后,Data Palling 可能随时有效。

·Ready/Busy:字节编程的进度可通过“RDY/BSY 输出信号监测,编程期间,ALE 变为高电平

“H”后,P3.4(RDY/BSY)端电平被拉低,表示正在编程状态(忙状态)。编程完成后,P3.4 变为高电平表示准备就绪状态。

2、LG2841结构图:

3、排阻:所谓排阻就是若干个参数完全相同的电阻,它们的一个引脚都连到一起,

作为公共引脚。其余引脚正常引出。所以如果一个排阻是由n个电阻构成的,那么它就有n+1只引脚,一般来说,最左边的那个是公共引脚。它在排阻上一般用一个色点标出来。排阻一般应用在数字电路上,比如:作为某个并行口的上拉或者下拉电阻用。使用排阻比用若干只固定电阻更方便。 排阻有a型和b型的区别。

a型排阻的引脚总是奇数的。它的左端有一个公共端(用白色的圆点表示),常见的排阻有4、7、8个电阻,所以引脚共有5或8或9个。

B型排阻的引脚总是偶数的。它没有公共端,常见的排阻有4个电阻,所以引脚共有8个。

排阻的阻值读法如下:“103”表示:10kΩ,“510”表示:51Ω。如所用的排阻是330Ω。

四、单元电路设计: 1、电源部分:

7

2、单片机部分: 3、开关控制部分:

8

五、软件方案设计:

/*程控定时开关*/

/*包含库函数 */

#include

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,flag=0,flag1=0,flag2=0; /*n为闪烁次数计数器,w为显示位计数器,flag为设置按键计数器,flag1和flag2均为延时消抖计数器*/ unsigned char K1_on=0,K2_on=0; 态寄存器*/

unsigned char h_data=0,m_data=0,s_data=0;/*时钟的时、分、秒计数器*/

unsigned char hdata1_on=0,mdata1_on=3, hdata2_on=0,mdata2_on=7; /*开关1和开关2的开启时间寄存器*/

unsigned char hdata1_off=0,mdata1_off=5,hdata2_off=0,mdata2_off=9;/*开关1和开关2的关断时间寄存器*/

void display(void); /*申明显示子程序*/

void delay(unsigned int j) /*定义可变延时子程序*/

{

unsigned int i; }

for(i=0;i

/*K1_on和K2_on分别为开关1和开关2的开启和关断状

/*七段数码,高电平有效 ,顺序为.gfedcba*/

void load_LED(unsigned char H,unsigned char M) /*定义将实际时间代码装LED显示区的子程序,作用是将个位和十位分离开*/ {

led[0]=H/10; /*led[0]装时的十位*/ led[1]=H; /*led[1]装时的个位*/ led[3]=M; /*led[3]装分的个位*/

led[2]=M/10; /*led[2]装分的十位*/ }

unsigned char H1_set(unsigned char H1)

{ H1=(H1/10+1)*10+H1;if(H1>23){H1=H1;};return H1;} /*定义时的十位加1函数*/ unsigned char H0_set(unsigned char H0) { if(H0==3&&H0/10==2) H0=H0/10*10;else H0=H0+1+H0/10*10;return H0;} /*定义时的个位加1函数*/ unsigned char M1_set(unsigned char M1)

{ M1=(M1/10+1)*10+M1;if(M1>=60){M1=M1;};return M1;} /*定义分的十位加1函数*/ unsigned

char

M0_set(unsigned

char

M0)

{

if(M0==9)

M0=M0/10*10;else

M0=M0+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的

9

LED显示段码数组,0x00为不显示(消隐)*/

char code tv[]={0xfe,0xfd,0xfb,0xf7}; /*定义位码数组,用于控制显示码送到哪个LED*/ unsigned char k,i;

switch(flag) /*根据设置所处的模式显示时钟*/

{ case 0: {load_LED(h_data, m_data);break;} /*显示时钟*/ } {

if(flag) /*如果处在设置模式,则对设置位进行闪烁显示*/

{

if(n>180) /*每送显示180次则进行一次闪烁*/

{

i=led[k]; /*将该LED位需要显示的数存于i中*/ P0=num[10]; /*该LED位不显示(短时消隐),P2=tv[k]; /*送需要显示的LED位码*/ delay(10);

/*短时消隐延时,有利于显示位的切

10

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++) /*以下为控制被设置位闪烁的程序语句*/

n=0;

if(k==w) /*如果送显示的位是正准备调整的位,则需要闪烁显示,以

{

if(n<90) /*以下语句是将LED的七段码送P0口,前90次显

下两句是控制闪烁显示*/

示*/

送消隐段码*/

换*/

*/

}

} { }

} { }

P0=num[i]; /*将要显示的数字i作为七段码表

的序号(段码数组下标),取出显示码送显示*/

if(k==1) /*如果送显示的LED为分的个位*/ P0=num[i] | 0x80; /*则将分的个显示码附加小数

delay(100);

点*/

/*显示延时,让LED充分点亮*/

else /*后90次消隐*/

P0=num[10];/*送LED消隐段码*/

if(k==1) /*如果要消隐的是分的个位*/ P0=num[10] | 0x80;

/*则将分的个位后的小数

点点亮(小数点不闪烁)*/

P2=tv[k]; /*送消隐的位码(即哪个LED需要闪delay(100);

/*消隐延时,让其充分消隐*/

烁)*/

else /*如果送显示的位不调整的位,则不需要闪烁显示*/

i=led[k]; /*将该LED位需要显示的数存于i中*/ P0=num[10]; /*该LED位不显示(短时消隐),送消隐P2=tv[k]; /*送需要显示的LED位码*/ delay(10); P0=num[i];

/*短时消隐延时,有利于显示位的切换/*将要显示的数字i作为七段码表的序

段码*/

号(段码数组下标),取出显示码送显示*/

if(k==1) /*如果送显示的LED为分的个位*/ { P0=num[i] | 0x80;}/*则将分的个显示码附加小数点*/

delay(100);

/*显示延时,让LED充分点

亮*/

else /*如果不是处在设置模式,则正常显示*/

{ load_LED(h_data, m_data); /*调用将实际时间代码装LED显示区的子程

i=led[k];

/*将该LED位需要显示的数存于i中*/

/*该LED位不显示(短时消隐),送消隐段

11

序,分离个位和十位*/

P0=num[10];

码*/

/********************************************************************************************************/

void adjust(void)

{

if(P3_0==0)

{

delay(100);

while(P3_0==0) {flag1++; display();} /*当调整键按下时,延时消抖,flag1控制

/*调整函数定义*/

}

delay(100);

/*显示延时,让LED充分点亮*/

}

P2=tv[k]; delay(10); P0=num[i]; if(k==1)

/*送需要显示的LED位码*/

/*短时消隐延时,有利于显示位的切换*/ /*将要显示的数字i作为七段码表的序号(段

}

码数组下标),取出显示码送显示*/

/*如果送显示的LED为分的个位*/ /*则将分的个显示码附加小数点*/

{ P0=num[i] | 0x80;}

延迟时间*/

if(flag1>50)

{

flag1=0;

flag++; /*用flag对调整键按下次数计数,目的是通过一个按键实现

多种功能 */

if(flag>=10) {flag=0;} }

}

/*************************************************************************************/

if(P3_1==0) /*移位控制键,在4个LED上来回移动,选择需要设置的LED

{

delay(100); display();

/*当flag不等于0时,说明处于调整状态,此时通过移位键 /*消抖*/

位*/

while(P3_1==0)

if(flag)

{

选择调整哪一个LED*/

12

**/

}

w=w+1; /*移位键控制w加1,用于修改位码,w代表4个LED

数码管的某一位*/

if(w>=4) w=0; }

/*****************************************************************************

if(P3_2==0) /*加1操作*/

if(flag) /*当处于调整模式时,对所选择的LED进行加1*/

{

switch(flag)

{

case 1:{ if(w==0) {h_data=H1_set(h_data);display();} /*校准时间的

}

if(w==0) {hdata1_on=H1_set(hdata1_on);display();} /*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();} break;

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;

13

{

/*消抖*/

delay(100); display();

while(P3_2==0)

时、分*/

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: {

}

设置开关1开启时间的时、分*/

case 3: {

设置开关1关断时间的时、分*/

}

}

if(w==0) {hdata2_on=H1_set(hdata2_on);display();} if(w==1) {hdata2_on=H0_set(hdata2_on);display();} if(w==2) {mdata2_on=M1_set(mdata2_on);display();} if(w==3) {mdata2_on=M0_set(mdata2_on);display();} break;

case 4: {

}

/*设置开关2开启时间的时、分*/

case 5: {

}

if(w==0) {hdata2_off=H1_set(hdata2_off);display();} /*if(w==1) {hdata2_off=H0_set(hdata2_off);display();} if(w==2) {mdata2_off=M1_set(mdata2_off);display();} if(w==3) {mdata2_off=M0_set(mdata2_off);display();} break;

设置开关2关断时间的时、分*/

default:{TR0=1;break;} }

}

}

void timer0() interrupt 1 /*定时器中断1服务子程序*/

{

counter++; {

s_data++; /*个位秒向十位秒进位*/ counter=0; }

/*如果秒计满60则向分进位,并将秒清0*/

s_data=0; /*秒清0*/ m_data++;

/*分进位 */

{ }

/*如果分计满60则向时进位,并将分清0*/

14

/*counter对定时中断进行计数,10000次中断为1秒*/

if(counter==10000

if(s_data==60)

if(m_data==60)

{

} {

}

m_data=0; h_data++;

/*分清0*/ /*时进位 */

if(h_data==24)

{ }

/*如果时计满24则将时清0*/

/*时清0*/

h_data=0;

main(void)

IE=0x8a; /*EA|-|-|ES|ET1|EX1|ET0|EX0=10001010中断允许控制*/

TMOD=0x02; /*GATE1|C/T|M1|M0|GATE0|C/T|M1|M0=00000010只由TR0来启动T0,TH0=176/*计数常数寄存器设置,中断定时时间为(256+200)x12/f0 */ TL0=-176/*定时计数器装初值*/

TR0=1; /*启动定时器T0,TCON为TF1|TR1|TF0|TR0|IE1|IT1|IE0|IT0*/ P3_6=1; /*关断定时开关1*/ P3_7=1; /*关断定时开关2*/ {

adjust(); /*调用调整函数*/

/*以下程序语句作用是:将设定的开启时间和关断时间分别跟当前时间进行比较, 当大于开启时间小于关断时间则在P3.6或P3.7输出低电平使开关接通,否则输出

K1_on=h_data>hdata1_on&&h_data

T0工作于方式2,(自动再装入的8位计数器)*/

while(1) /*以下为死循环*/

高电平使开关断开*/

m_data>=mdata1_on&&m_data=mdata1_on&&m_data

K2_on=h_data>hdata2_on&&h_data

m_data>=mdata2_on&&m_data=mdata2_on&&m_data

}

}

if(K1_on) P3_6=0; else P3_6=1; if(K2_on) P3_7=0; else P3_7=1;

15

display();

六、绘制PCB电路板:

七、元器件装配与调试记录:

1.按照上面的PCB焊接电路注意问题

电容的正负极不要焊接错误,否则会引起电容爆炸。芯片的正确插拔。 2.电路板调试

首先,检查线路是否存在断路、短路情况,可以用数字万用表的短路检测功能来检查线路。如果听到蜂鸣声,线路就是通的。

然后,检查芯片插槽引脚是否有连接错误的情况。

最后,在确定电路连接无误的前提下,插上芯片,接通电源,查看数码管上是否存在乱码的情况。时间显示是否是真实的时间。 3.调试记录

对于PCB电路板,焊接元器件比较简单,一般不容易出错。万一出现错误,绝大多数情况下是由于焊接不牢,出现虚焊现象。对于数码管出现乱码的现象一般是由于制PCB板时,腐蚀不完全,该断开的地方没有断开。本次实验调试一次性成功。

八、使用说明书:

1、面板上有5个按键,从左到右次编号为1、2、3、4、5。

有5个数码管,4个连在一起记为数码管1用来显示时间的时和分,另一个数码管记为数码管2用来显示工作状态。2个发光二极管,用来判断功能是否达到设计。 1键复位,2键定时功能开关,3键累加1,4键移位,5键选择工作的状态。 2、显示正常时间,数码管2显示0

需要校正时间时,按一下5键,此时数码管2显示1,时的高位在闪烁,按3 键,时的高位累加一。按4键,时的低位闪烁,按3 键,时的低位累加一。按4键,分的高位闪烁,按3 键,分的高位累加一。按4键,分的低位闪烁,按3 键,分的低位累加一。

需要设置开关1的开启时间,连续按5键2次,此时数码管2显示2,时间设定方法同上述

16

的相同。

需要设置开关1的关断时间,连续按5键3次,此时数码管2显示3,时间设定方法同上述的相同。

需要设置开关2的开启时间,连续按5键4次,此时数码管2显示4,时间设定方法同上述的相同。

需要设置开关1的关断时间,连续按5键5次,此时数码管2显示5,时间设定方法同上述的相同。

需要查看开关1的开启时间,连续按5 键6次,此时数码管2显示6,数码管1显示的时间就是开关1的开启时间。

需要查看开关1的关断时间,连续按5 键7次,此时数码管2显示7,数码管1显示的时间就是开关1的关断时间。

需要查看开关2的开启时间,连续按5 键8次,此时数码管2显示8,数码管1显示的时间就是开关2的开启时间。

需要查看开关2的关断时间,连续按5 键9次,此时数码管2显示9,数码管1显示的时间就是开关2的关断时间。

定时插座的功能生效与否用键2来控制。按1 次关,然后按1次开,再按1一又关。

17

本文来源:https://www.bwwdw.com/article/tev6.html

Top