最近将多年来收集到的教学视频、国内外图书、源码等整理整合拿出来,涉及计算机基础、单片机(51、AVR、PIC)、STM32、ARM、Linux、Python、制图(protel、AD、cadence)、周边(外设模块)、源文件、上位机(C++、C#、delphi等)、模数电、FPGA、DSP、Arduino、MSP430、仿真、Kali、μcos、信号完整性、C、Java、汇编、算法、射频、Scratch、安卓、出版社图书等。资料目前约 1.5TB+。详情请见:
一 引言
随着人们生活水平的不断提高,大家对住宅和办公室的安全意识也日益增加。因此,研究和开发防盗报警装置引起了科研单位和生产厂家的重视,特别是面对普通居民、价格低、运行可靠的自动报警系统。
长期以来,一些电子杂志介绍的廉价防盗报警均无电话拨号报警功能,而市售的可自动拨号报警的防盗器材又价格高昂。这里介绍的电话拨号防盗报警器可在这两者之间找到平衡,即兼具高性能和低价位。为了以低成本实现高性能,设计时利用了电信局的交换机支持脉冲拨号方式来实现拨号报警,这样可利用单片机直接发出拨号脉冲,精简了电路,降低了成本。
电话拨号防盗报警器作为家庭防盗报警器材的一员,非常经济实用。它进入工作警戒后,主控CPU不断检查触发开关的状态,当盗贼入室触发开关时,立即启动电话拨号报警程序向主人告警(当然也可以通过修改软件使其在现场发出高分贝报警音)。实践证明,该系统报警快速、准确。由于该系统电路简单,而且利用的是公共通信网,因此不存在建立的报警系统网络问题,具有成本低、体积小、能耗极低、体积小、能耗极低且不影响正常打电话等突出优点。平时可以作为时钟计时器来使用,真是一举两得。
二 硬件系统方案设计
2.1电话拨号防盗报警器硬件系统方案
2.1.1 硬件系统方案设计
图2.1为电话拨号报警器的系统构成方框图,由单片机控制器、键盘输入、数码管显示、触发电路、拨号电路及电源等6部分组成。
单片机控制器是整个系统的核心,负责控制检测输入/输出显示、模拟摘机、拨号摘机、拨号报警、挂机等一系列的程序动作。这里使用了小引脚、高性能、低价位的AT89S2052。
键盘输入电路负责输入电片机中一系列工作参数及功能设定。
发光二极管数码管显示器在整个系统工作过程中充当一个简单的人机界面,用以显示工作状况及输入/输出的数据等。
电话拨号防盗报警器的触发电路用磁性开关(门磁开关),简单可靠,也可用红外探测器或无线门磁,以实现全方位远距离监测。报警器应采用隐蔽安装,防止小偷发现。
拨号及报警电路用来完成模拟摘机、拨号、发出报警音、挂机等工作过程,它的工作由单片机控制。
电源部分负责对整个系统供电。平时由电话线上取得工作电流并对后备电池充电,拨号报警时转由后备电池供电。
图2.1 电话拨号防盗报警器方框图
2.1.2 脉冲拨号原理
脉冲拨号是目前电话机两种拨号方式中的一种,另一种为双音多频拨号方式。
脉冲拨号就是指在电话机上拨入的电话号码以脉冲个数的形式发出,也就是说,在已经通以直流电流的回路上,利用拨号盘及发号电路将回路断开、再接通而形成的脉冲信号,来完成输入电话号码的发送。在操作中,若用户拨1,则送出1个脉冲,回路中断一次、接通一次;拨2,则发出2个脉冲,回路断一次、接通一次、再断一次;……;而拨0时,则发出10个脉冲,回路断、接通轮流10次。图2.2为电话号码“32”的脉冲波形。
图2.2 电话号码“32”的脉冲波形
正常拨号时,电路电流中断的时间一般在58~65ms之间,视断续比的不同而不同。快速拨号时,只要取一半时间即可。电路电流接通的时间(即在同一位号码中的2个断脉冲之间的接通电流时间)约在32~42ms之间,视断续比的不同而不同。快速拨号时,只要取一半时间即可。显然脉冲周期等于脉冲中断时间和脉冲接通时间之和,每一个周期的时间为100ms左右。快速拨号时,在50ms左右。2位号码(即2组脉冲串)之间的最小时间间隔,通常为800ms左右;而快速拨号时,其值减半,为400ms左右。
我国目前采用的电话脉冲拨号的速率是10PPS(每秒的脉冲数),即每秒发出10个脉冲,因此上述各参数不存在快速拨号时的值。
为了提高拨号的可靠性及稳定性,这里设计时选定更低的脉冲拨号速率:1个脉冲代表播出1,2个脉冲代表拨出2,……,10个脉冲代表拨出0,每个脉冲的宽度和间隔为100ms。工作时首先进行模拟摘机,然后开始脉冲拨号,拨出1位号码后停顿500ms(保持接通)再拨下一位,直至全部拨完后再发报警音,……,最后挂机。
2.1.3 脉冲拨号实现过程
图2.3为脉冲拨号的实现电路。平时电话线上的电压约为50~60V左右。未拨号时电片机的P3.0、P3.1 均输出低电平。
拨号过程如下:
①单片机的P3.0输出高电平,使TR1导通,由于电话线路上接入了负载R1,这样电话线的电压下降,模拟摘机。
②单片机的P3.0开始输出拨号脉冲,使电话线的电压(电平)也呈高、低变化。1个脉冲代表拨出1,2个脉冲代表拨出2,……,10个脉冲代表拨出0,每个脉冲的宽度和间隔均为100ms。拨出1位号码后停顿500ms(保持P3.0高电平)再拨下一位,直至全部拨完。
③P3.0 保持高电平(保持电话线路接通),P3.1输出1KHz的报警音脉冲驱动TR2,以2Hz进行调制(即接通1kHz信号0.5s、断开1kHz信号0.5s),这样从接听方的电话中就会听到“嘟、嘟……”的报警声。报警音的时间根据设计为60s。
④60后,P3.1输出低电平,TR2 截止,停止报警。随后P3.0也输出低电平,模拟挂机。完成一次报警过程。
图2.3 脉冲拨号实现电路
2.1.4 AT89S2052单片机的功能特点
电话拨号防盗报警器的核心控制器是单片机AT89S2052。AT89S2052 是美国ATMEL半导体公司生产的一种高性能单片机。该单片机以与MCS-51系列单片机高度兼容、低功耗、可以在接近零频率下工作等诸多优点,而广泛应用于各类计算机系统、工业控制、电信设备、消费类产品中。由于ATMEL是全球最大的FLASH和EEPROM生产制造公司之一,加之以其EEPROM技术与INTEL的80C51内核技术交换,使ATMEL拥有了80C51内核的使用权,其生产的AT89系列电片机不仅与80C51有极好的兼容性,而且具有极高的性能价格比。
1.AT89S2051的主要性能特点
指令与MCS-51完全兼容;内带2KB可编程闪速存储器(FLASH MEMORY)可重复擦写1000次;数据保留10年;工作电压范围2.7~6V;工作频率0~24MHZ;两极程序加密锁定;128B内部RAM;15条可编程双向I/O口线;2个16位定时器/计时器;5个中断源;可编程串行UART通道;输出口可直接驱动LED;片内含模拟比较器;低功耗的闲置和掉电模式。
AT89S2052是AT89 系列电片机种的一种精简产品。它是将TA89C52的P0口、P2口、EA/Vpp、ALE/PROG、PSEN口线省去后,形成的一种仅20个引脚的单片机,相当于早期INTEL8031的最小应用系统。这对于一些不太复杂的控制场合,仅用一片AT89S2052就足够了,是真正意义上的“单片机”。
由于将多功能8位CPU和2KB的闪速存储器集成在单个芯片中,使其成为一种高效的微控制器。AT89S2052的出现为很多规模不太大的嵌入式控制系统提供了一种极佳的选择方案,使传统的51系列单片机的体积大、功耗大、可选模式少等诸多困扰设计工程师们的致命弱点不复存在。
2.引脚功能介绍
AT89S2052引脚外形如图所示。
Vcc:电源端。
GND:接地。
P1 口(P1.0~P1.7):是一个8位双向I/O口,其中P1.2至P1.7提供内部上拉电阻,P1.0和P1.1需外接上拉电阻。P1.0和P1.1也可作为片内精确模拟比较器的正向输入(AINO)和反向输入(AINI)。P1口输出缓冲器能提供20mA的灌电流,可直接驱动LED。P1口写入“1”后可用作输入。
P3口:引脚P3.0至P3.7(P3.5除外)是7个带内部上拉电阻的双向I/O口线。原P3.6不能使用,已连接片内比较器输出端。与P1口相同,P3口也能提供20mA的灌电流,并可直接驱动LED显示器。与80C51相同,P3口也有第2功能,P3.0作为串行数据接收RXD;P3.1作为串行数据发送TXD;P3.2为外部中断0申请INT0;P3.3 为外部中断1申请INT1;P3.4 为定时器/计时器0输入;P3.5位定时器/计数器1输入;P3.7无第2功能RD。
RST:复制输入。要使芯片可靠复位,要保持RST引脚2个机器周期的高电平。
XTAL1:反向振荡放大的输入及内部时钟电路的殊荣。
XTAL2:来自反向振荡放大器的输出。
3.特殊功能寄存器(SFR)与80C51完全相同
4.程序存储器锁定
AT89S2052片内有2个锁定位,可以不编程(U),也可以编程(P),以获得一些附加的特性,如表2.1所示。
表2.1 程序存储器锁定
5、闲置模式
在闲置模式下,CPU自身处于休眠状态,而片内所有其他外围设备保持工作状态。该模式是软件生成的。在该模式期间,片内RAM和所有特殊功能寄存器的内容保持不变。闲置模式可以允许由中断或硬件复位终止。如果不采用外部上拉,P1.0和P1.1应置0;如果采用外部上拉,则置1。应注意的是,当闲置模式被硬件复位中止时,器件要从闲置处恢复程序的执行,执行2个机器周期后,内部复位算法才起作用。此时,硬件禁止访问内部RAM,但允许访问端口引脚。为了排除闲置被复位中止时对端口意外写入的可能性,跟在生成闲置模式后的指令不应是对端口引脚的读/写操作。
6.掉电模式
在掉电模式下,振荡器停止工作,生成掉电状态的指令是最后执行的一条指令。片内RAM和特殊功能寄存器保持其值不变直到掉电模式终止。从掉电模式退出的唯一办法是硬件复位。复位将重新定义特殊功能寄存器(SFR),但不会影响片内RAM。在Vcc没有恢复到其正常工作电压之前,不应进行复位,且复位的保持时间应足够长,使振荡器能重新开始工作并稳定下来。同样,如果不采用外部下拉,P1.0和P1.1应置0,如果采用外部上拉,则置1。
2.2 时钟计时器的硬件设计方案论证分析
2.2.1 功能要求
时钟计时器要求用六位LED数码管显示时、分、秒、以二十四小时方式运行,使用按键开关实现时,分调整功能。
2.2.2 方案论证
为实现LED显示器的数字显示,可以采用静态显示法和动态显示法。由于静态显示法需要数据锁存器等硬件,接口复杂一些,考虑到时钟显示只有六位,且系统没有其它复杂的处理任务,所以决定用动态扫描实现LED显示。单片机采用易购的AT89S52系列,这种单片机可具有足够的空余硬件资源,以实现其它的扩充功能。若使用电池供电,可采用低电压的LV系列单片机时钟计时器电路系统的总体设计框架如图3.1所示。
图3.1 硬件系统的总体设计框架
2.2.3 系统硬件电路设计
电话拨号防盗报警器的硬件电路设计描述
为了发挥电片机强大的计算、控制能力,充分发挥软件的优势,这里极大地简化了电路,但可实现以前需要几片甚至十几片小规模数字电路才能完成的任务。
电路原理如图所示,共有4个按键,即rst、ok、up、set。
rst:系统复位键。
ok:输入数据确认键。
up:显示的数字增加键。
set:工作模式设定键,可设定管机、工作、输入时间t1、输入时间t2及输入电话号码5种模式。
磁性开关即为装于门或窗口的防盗感应开关,门关闭时常开,门打开时闭合接通。当然也可改用其他的感应器件,如激光探测、超声波感应、热释电感应、主动红外线探测或无线门磁等,以实现全方位远距离检测。为了防止磁性开关离控制器较远而产生引入干扰,使用了光耦作信号传递,效果良好。LED数码管用于工作状态指示或输入数据指示。L1、L2接电话线,ZND为击穿电压120V的压敏二极管,防止电路受雷电干扰。平时系统处于低功耗待机状态(此时耗电仅2mA左右),由电话线上取电工作,并对3.6V/60mA镍铬电池充电,当输入数据进行设定或进行拨号报警时,耗电会达到10mA,这时主要由镍铬电池供电。由于有镍铬电池后备供电,即使电话线断电也不会使已输入的数据丢失。该机除用于防盗报警外,若对软件进行一些修改,也可通过电话线进行远程数据传递。三极管T1、T2及电阻R1、R2构成拨号及报警电路,其工作原理前面已作详细介绍。
4.1.2时钟计时器的硬件电路设计描述
时钟计时器的硬件电路,采用AT89S52单片机最小化应用设计,显示采用共阳七段LED显示器,P0口输出段数码数据,P2.0~P2.5口作列扫描输出,P1.0,P1.1和P1.2口接三个按钮开关用以实现调时,调分功能.为了提供共阳LED数码管的驱动电压,用三极管8550作电源驱动输出。采用12MHZ晶振有利于提高秒计时的精确性。硬件电路图如图3.2示。
图3.2 具有时钟功能的电话报警器原理图
三 系统的软件设计
3.1电话拨号防盗报警器程序设计
3.1.1主程序设计
主程序的工作过程为:先进行初始化工作,随后根据输入的键值分别散转输入的键值分别散转至对应的子程序(管机、警戒工作、输入时间t1、输入时间t2、输入电话号码)循环工作。T0为100ms定时中断服务子程序,它实现精确的拨号脉冲时序。INT0外中断服务子函数用于实现功能选择;而INT1外中断服务子函数则检测防盗触发开关的状态。
主程序状态流程图如图3.6所示。INT0外中断服务子函数状态流程图及INT1外中断服务子函数的状态流程图分别如图3.7、图3.8所示。
图3.6 主程序状态流程
图3.7 INT0外中断服务子函数状态流程
图3.8 INT1外中断服务子函数结束
3.2 时钟显示程序设计
3.2.1主函数
本设计中计时采用定时器T0中断完成,其余状态循环调用显示子函数及键扫描子函数,当端口开关按下时,转入相应调时功能。其主函数执行流程如图3.3所示。
图3.3 主函数流程图
3.2.2 LED显示子函数
数码管显示的数据存放在内存单元dis[0]~dis[5]中,其中dis[0]~dis[1]存放秒数据,dis[2]~dis[3]存放分数据,dis[4]~dis[5]存放时数据,每一单元内均为十进制BCD码。由于采用软件动态扫描实现数据显示功能,显示用的十进制BCD码数据的对应段码存放在ROM表(dis7[11])中,显示时,先取出dis[0]~dis[5]中的某一数据,然后查得对应得显示段码从P0口输出,P2口将对应得数码管选中供电,就能显示该地址单元的数据值。
3.2.3 定时器T0中断函数
定时器T0用于时间计时。定时溢出中断周期可设为50ms,中断进入后先判断,中断计时累计20次(即1ms)时对妙计数单元进行加1操作。时钟计数单元在 义的6个单元(timedata[6])中。timedata[0]~timedata[1]存放秒数据,timedata[2]~timedata[3]存放分数据,timedata[4]~timedata[5]存放时数据。最大计时值为23小时59分59秒。在计数单元中采用十进制BCD码计数,秒,分、时之间满60进位。T0中断服务程序执行流程如图3.4所示。
图3.4 T0 中断函数
3.2.4 中断函数
T1中断服务程序用于指示调整数字单元的亮闪,在时间调整状态下,每过0.4s,将对应单元的显示数据换成“熄灭符”数据(0x0a)。这样,在调整时间时,对应调整单元的显示数据会间隔闪亮。
3.2.5 功能函数
调时功能函数的设计方法是:按下T0键,进入调分状态,时钟停止走动;按T1或T2键可进行加1或减1操作 ;继续按T0键可分别进行分十位、时个位和时十位调整;最后按T0建将退出调整状态,时钟开始计时运行。
四 系统的调试部分
4.1 时钟系统的调试
4.1.1 时钟系统的硬件调试
硬件调试时可先检查印制板及焊接的质量情况,在检查无误后可通电检查LED显示器的点亮状况。若亮度不理想,可以调整P0口的电阻大小,一般情况下取200欧姆电阻即可获得满意的亮度效果。
4.1.2 时钟系统的软件调试
软件调试Keil C51编译器,源程序编译及仿真调试应分段或以子函数为单位一个个地进行,最后可结合硬件实时运行调试。
4.1.3 性能分析
按照设计程序分析,LED显示器动态扫描频率约为167Hz,实际使用观察时完全没有闪烁,实际计时时精度较高,可满足一般场合的应用需要。
4.2 拨号报警器功能调试
通电前应检查焊接质量,确认无短路、虚焊等故障。将拨码开关J2指向下侧,即断开3.6V镍铬电池与系统的连接。将外部直流可调稳压电源调整为3.6V。接入系统的Vcc与地。如果系统耗电小于15mA为正常,否则应检查是否有短路、元器件不良或错焊现象存在。随后取下外接直流稳压电源,恢复3.6V镍铬电池与系统的连接,进行软、硬件统调测试。
由于AT89S52的I/O引脚有限,故数码管只设一位,因此输入数字时只能分阶段一位一位输入。
假设需输入t1=061,t2=025,电话号码=12345678,在此详述如下:
地1步:接上电话线(也即接上电源)后,数码管显示“E”,意为数据错误,因为此时我们尚未输入任何数据。
第2步:
①点按一下set键,键值加1,即此时set=1.这时数码管最下的一横点亮,显示“_”,意为可输入时间t1,点按ok键确认(小数点被同时点亮)。然后数码管显示数字“0”。
②按下up键后,数字开始从0~9循环递增,调至0后松开up键,点按ok键确认(小数点被同时点亮)。此时百位数字“0”存入内存。
③按下up键后,数字开始循环递增,调至1后松开up键,点按ok键确认(小数点被同时点亮)。此时十位数字“6”存入内存。
④按下up键后,数字开始循环递增,调至1后松开up键,点按ok键确认(小数点被同时点亮)。此时个位数字“6”存入内存。
这样就完成了将061(代表t1=61s)存入内存的过程。同时数码管又恢复显示“_”
。
第3步:
①点按一下set键,键值加1,即此时set=2。这时数码管下面的二横点亮,显示“二”,意为可输入时间t2,点按ok键确认(小数点被同时点亮)。然后数码管显示数字“0”。
②按下up键后,数字开始从从0~9循环递增,调至0后松开up键,点按ok键确认(小数点被同时点亮)。此时百位数字“0”存入内存。
③按下up键后,数字开始循环递增,调至2后松开up键,点按ok键确认(小数点被同时点亮)。此时十位数字“2”存入内存。
④按下up键后,数字开始循环递增,调至5后松开up键,点按ok键确认(小数点被同时点亮)。此时个位数字“5”存入内存。
这样就完成了将025(代表t1=25s)存入内存的过程。同时数码管又恢复显示“二”以后的调试同前面的方法相同。
附录1:程序清单
(1) 电话拨号报警程序
程序设计时需要设立3个数组DATA[20]、X[3]、Y[3]。DATA[20]用于存放电话号码(最长20位),X[3]用于存放时间t1(000~999s),Y[3]用于存放时间t2(000~999s)。
另外还要设立3个软件计数器data_flag、t1_flag、t2_flag。Data_flag用于统计输入的电话号码位长,t1_flag用于统计输入的时间t1位长,t2位长。
uchar DATA[20]; /*存放电话号码的数组*/
uchar X[3]; /*存放时间t1数组*/
uchar Y[3]; /*存放时间t2数组*/
uchar flag; /*RAM区防干扰标志*/
uchar data_flag=0; /*输入电话号码计数器(最长20位)*/
uchar set=0; /*功能键值*/
uchar m=0; //全局变量
uchar n=0;
uint f;
uchar t1_flag=0; /*输入时间t1计数器(最长3位)*/
uchar t2_flag=0; /*输入时间t2计数器(最长3位)*/
uchar cnt_1=0; /*时间t1单元数学运算后暂存单元*/
uchar cnt_2=0; /*时间t2单元数学运算后暂存单元*/
/*定时器T0初始化*/
viod init_timer()
{
TMOD=0x01; //定时器T0方式1
TH0=-(50000/256); //装载100ms定时初值
TL0=-(50000%256);
IE=0x82; //开中断
}
启动报警器子程序模块
/*---启动报警器进入警戒---*/
void work()
{uchar h;
p1=0xdf; /*数码管左上角显示“1”*/
delay(1);
if(set==1) /*进入时间1循环*/
{while(cnt<=x[0]*100+X[1]*10+X[2])
{
delay(1000);
cnt_1++; /*计数器cnt_1累加*/
if(set!=1){EX1=0;cnt_1=0;break;}
} /*如按下Set键,则推出此循环*/
}
else {EX1=1;PCON=0x00;}
if(set==1)
{if(cnt_1>=X[0]*100+X[1]*10+X[2])
{EX1=1;cnt_1=0;} /*时间1到,打开外中断1,计数器归零*/
/*进入待机。若有1s以上开关动作,退出待机*/
while(1)
{PCON=0x01;if(f>=5{PCON=0x00;break;})
}
/*-----------------------------------------------------------*/
EX1=0; /*关闭外中断1*/
if(set==1) /*进入时间2循环*/
{while(cnt_2<=Y[0]*100+Y[1]*10+Y[2])
{
delay(1000);
cnt_2++; /*计时器cnt_2累加*/
if(set!=1){cnt_2=0;break;}
} /*如按下Set键,则退出此循环*/
}
if(set==1)
{
bh(); /*时间2到,调用拨号子程序*/
delay(3000);
p3_7=0; //控制输出端为低,可驱动蜂鸣器等
for(h=0;h<60;h++) /*发出60s警音*/
{ for(f=0;f<500;f++)
{f++;
P3_1=! P3_1;P1=0x5f;
delay(1);
}
P3_1=0;P1=0x7f;delay(500);
}
P3_7=1;//控制输出端恢复高
cnt_1=0;cnt_2=0; /*有关计数器、端口回到初始状态*/
P3_0=0;P3_1=0;P1_7=1;
for(f=0;f<3;f++)delay(60000); /*关闭3min,让接警人进行手机或电话座机报警*/
}
}
拨号脉冲子程序模块
/*---拨号---*/
void bh()
{data_flag=0; /*电话号码计数器(20位)归零*/
P3_0=1; /*接通线路*/
p1_7=0; /*数码管小数点亮*/
delay(1000);
while (DATA[data_flag]<10) /*号码小于10进入循环拨号状态*/
{
if(DATA[data_flag]==0) /*若号码为0*/
{TR0=1; /*启动T0定时器*/
if(n==20){data_flag++; /*进行20次中断,产生10个脉冲*/
n=0;TR0=0;
P3_0=1;P1_7=0;
delay(500);
}
}
if(DATA[data_flag]>0) /*若号码〉0但<10*/
{TR=1; /*启动T0定时器*/
if(n==((DATA[data_flag]*2)) /*进行号码x2次中断,产生号码个脉冲*/
{data_flag++;
n=0;TR0=0;
P3_0=1;P1_7=0;
delay(500);
}
}
}
TR0=0;
}
关机子程序模块
void stop() //*关机子程序
{if(flag==0x55)P1=0xfb; //*若标志为55H,说明内存区未受干扰,数码
//管右下角显示“1”
else P1=0x86; //否则数码管显示“E”
delay(1); //延时1ms再判
if(flag==0x55)PCON=0x01; //进入低耗节电待机状态
delay(1); //延时1ms
}
完整代码
#include //器件配置文件
#define uchar unsigned char //变量类型的宏定义
#define uint unsigned int
uchar code DATA_7SEG[10]={0xC0,0xF9,0xA4,0xB0,0x99
0x92,0x82,0xF8,0x80,0x90,}; /*0~9数码管段码*/
uchar DATA[20]; /*存放电话号码的数组*/
uchar x[3]; /*存放时间t2数组*/
uchar flag; /*RAM区防干扰标志*/
uchar data_flag=0; /*输入电话号码计数器(最长20位)*/
uchar set=0; /* 功能键值*/
uchar m=0; //全局变量
uchar n=0;
uint f;
uchar t1_flag=0; /*输入时间1计数器(最长3位)*/
uchar t2_flag=0; /*输入时间2 计数器(最长3位)*/
uchar cnt_1=0; /*时间t1单元数学运算后暂存单元*/
uchar cnt_2=0; /*时间t2单元数学运算后暂存单元*/
/*************************************************/
void delay(uint k); /*延时子函数声明*/
void stop(); /*关机子函数声明*/
void bh(); /*拨号子函数声明*/
/*************************************************/
/*定时器T0初始化*/
void init_timer()
{
TMOD=0x01;
TH0=-(50000/256);
TL0=-(50000%256);
IE=0x82;
}
/***********************************************************/
/*100ms定时中断服务子函数*/
void zd0()interrupt 1
{
P3_0=! P3_0; //P3.0每100ms取反一次,送出脉冲
P1_7=! P1_7; //数码管小数点同步闪烁
n++;
TH0=-(50000/256);
TL0=-(50000%256);
}
/********************************************************/
/*100ms定时中断服务子函数*/
void zd0()interrupt 1
{
p3_0=!P3_0; //P3.0每100ms取反一次,送出脉冲
P1_7=!P1_7; //数码管小数点同步闪烁
n++;
TH0=-(50000/256);
TL0=-(50000%256);
}
/*********************************************/
/*INT0中断服务子函数*/
viod zd_int0()interrupt 0
{
delay(10);
if(P3_2==0)set++; //功能键值递增
if(set>=5)set=0; //键值的范围0~4
if(set==1)flag=0x55; //向RAM区的标志flag写入55H
PCON=0x00;f=8;
again:if(P3_2==0)goto again; //若按键未释放,则等待
}
/*****************************************/
/*INT1中断服务子函数*/
void zd_int1()interrupt 2
{uchar h;
f=0;
for(h=0;h<10;h++) /*检查磁性开关(P3_3状态)10次,共1s*/
{
delay(100)
if(P3_3==0)f++;
}
}
/********************************************************************/
/*---关机---*/
void stop()
{if(flag==0x55)P1=0xfb;
elsep1=0x86; //数码管右下角显示“1”。
delay(1);
if(flag==0x55)PCON=0x01; /*进入节电待机状态*/
delay(1);
}
/*********************************************************************/
/*延时1ms*K子函数*/
void delay(uint k)
{
uint i,j;
for(i=1;j
for(j=0;j<60;j++)
{;}}
}
/*********************************************************************/
/*----输入时间t1----*/
viod in_time1()
{
P1=0xf7;delay(1); /*数码管显示“—”*/
if(P3_5==0)
{
delay(10); /*按下OK键确认并点亮小数点*/
if(P3_5==0){P1=0x7f;m=0;t1_flag=0;delay(500);}
while(t1_flag<3)
{
if(P3_4==0)
{delay(10);if(P3_4==0) /*按下UP键数码管作0~9递增显示*/
{m++;if(m==10)m=0;P1=DATA_7SEG[m];delay(300);}
}
P1=DATA_7SEG[m];delay(1); /*若不按下UP键数码管也作0~9显示*/
if(P3_5==0)
{delay(10);if(P3_5==0) /*按下OK键显示的数据存入数组X中*/
{X[t1_flag]=m;t1_flag++;P1=0x7f;delay(500);}
}
}
}
if(t1_flag>=3)t1_flag=0; /*时间1计数器>=3时归零*/
}
/**********************************************************************
/
/*-----输入时间t2-----*/
viod in_time2()
{
P1=0xb7;delay(1); /*数码管显示“二”*/
if(P3_5==0)
{
delay(10); /*按下OK键确认并点亮小数点*/
if(P3_5==0){P1=0X7f;m=0;t2_flag=0;delay(500);}
while(t2_flag<3)
{
if(P3_4==0)
{delay(10);if(P3_4==0) /*按下UP键数码管作0~9递增显示*/
{m++;if(m==10)m=0;P1=DATA_7SEG[m];delay(300);}
}
P1=DATA_7SEG[m];delay(1); /*若不按UP键数码管也作0~9显示*/
if(P3_5==0)
{delay(10);if(P3_5==0) /*按下OK键显示的数据存入数组Y中*/
{Y[t2_flag=m;t2_flag++;P1=0x7f;delay(500);}
}
}
}
if(t2_flag>=3)t2_flag=0; /*时间2计数器>=3时归零*/
}
/***********************************************************************
/
/*----输入电话号码----*/
vioa in_data()
{uchar g;
P1=0xb6;delay(1); /*数码管显示三*/
if(P3_5==0)
{delay(10);if(P3_5==0)
{p1=0x7f;m=0;data_flag=0; /*按下OK键确认并点亮小数点*/
for(g=0;g<20;g++){DATA[g]=10;}
delay(500); /*同时DATA数组中全部写入10*/
while(1)
{
if(P3_4==0){delay(10); /*按下UP键数码管作0~9递增显示*/
if(P3_4==0);{m++;if(m==10)m=0;P1=DATA_7SEG[m];delay(300);}
}
P1=DATA_7SEG[m];delay(1); /*若不按UP键数码管也作0~9显示*/
if(P3_5==0)
{delay(10);
if(P3_5==0) /*按下OK键显示的数据(号码)存入数组DATA中*/
{DATA[data_flag]=m;data_flag++;P1=0x7f;delay(500);}
} /按下OK键超过2s则退出向数组DATA送入号码*/
if(P3_5==0){delay(2000);if(P3_5==0)break;}
}
}
}
F1:if(P3_5==0){delay(10);if(P3_5==0){P1=0xb6;delay(1);goto F1;}}
/********************************************************************/
/*--主函数--*/
void main()
{
int_timer(); /*定时器T0初始化*/
EA=1;EX0=1; /*开总中断,开外中断0*/
p3_0=0; /*关闭线路(挂机)*/
p3_1=0;
while(1) /*无限循环*/
{
switch(set) /*根据Set标志散转*/
{
case 0:stop();break; /*关机*/
case 1:work();break; /*警戒工作*/
case 3:in_time2();break; /*输入时间t1*/
case 4:in_data();break;
}
if(flag!=0x55)
{p1=0x86;delay(1);}
}
}
(2) 时钟计时器程序
/**************************************************************/
// 采用6位LED动态扫描时钟演示程序
// 使用Keil C51
// 2004.03.31
/*************************************************************/
/*使用AT89S52单片机,12MHZ晶振,P0口输出段码,P2口作列扫描,用共阳LED数码管*/
//key0为调时位选用,key1为加1键,key2为减1键
#include "reg51.h"
#define char unsigned char
//
char code dis_7[11]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xff};
/*共阳LED段码表"0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "不亮"*/
char code scan_con[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //列扫描控制字
char data timedata[6]={0x00,0x00,0x00,0x00,0x00,0x00}; //计时单元数据初值,共6个
char data dis[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,}; //显示单元数据,共6个数据
char data con1s=0x00,con04s=0x00,con=0x00; //秒定时用
sbit key0=P1^0;
sbit key1=P1^1;
sbit key2=P1^2;
//
/************/
//1ms延时函数//
/***********/
dalaylms(int t)
{
int i,j;
for(i=0;i
for(j=0;j<120;j++)
;
}
/*************/
//键扫描子函数//
keyscan()
{
EA=0;
if(key0==0)
{
delaylms(10);
while(key0==0);
if(dis[con]==10)
{dis[7]=dis[con];dis[con]=dis[6];dis[6]=dis[7];}
con++;TR0=0;ET0=0;TR1=1;ET1=1;
if(con >=6)
{con=0;TR1=0;ET1=0;TR0=1;ET0=1;}
}
//
if(con!=0)
{
if(key1==0)
{
delaylms(10);
while(key1==0);
timedata[con]++
if(timedata[con]>=10)
{timedata[con]=0;}
dis[con]=timedata[con];dis[6]=0x0a;
}
}
//
if(con!=0)
{
if(key2==0)
{
delaylms(10);
while(key2==0);
if(timedata[con]==0)
{timedata[con]=0x90;}
else{timedata[con]--;}
dis[con]=timedata[con];dis[6]=0x0a;
}
}
EA=1;
}
//
/***********/
//显示函数//
/***********/
scan()
{
char k;
for(k=0;k<6;k++)
{
p0=dis_7[dis[k]];p2=scan_con[k];delaylms(1);p2=0xff;
}
}
/*************/
//初始化函数//
/*************/
clearmen()
{
int i;
for(i=0;i<6;i++)
{
dis[i]=timedata[i];}
TH0=0x3C;TL0=0xB0; //50ms定时初值(T0计时用)
TH1=0x3C;TL1=0xB0; //50ms定时初值(T1计时用)
TMOD=0X11;ET0=1;ET1=1;TR1=0;TR0=1;EA=1;
}
/**********/
//主函数//
/*********/
main()
{
clearmen();
while(1)
{
scan();
keyscan();
}
}
/********************/
//1s中断处理函数//
/*******************/
viod time_intt0(viod) interrupt 1
{
ET0=0;TR0=0;TH0=0x3C;TL0=0xB0;TR0=1;
con1s++;
if(con1s==20)
{
con1s=0x00;
timedata[0]++;
if(timedata[0]>=10)
{
timedata[0]=0;timedata[1]++;
if(timedata[1]>=6)
{
timedata[1]=0;timedata[2]++;
if(timedata[2]>=10)
{
timedata[2]=0;timedata[3]++;
if(timedata[3]>=6)
{
timedata[3]=0;timedata[4]++;
if(timedata[4]>=10)
{
timedata[4]=0;timedata[5]++;
}
if(timedata[5]==2)
{
if(timedata[4]==4)
{
timedata[4]=0;timedata[5]=0;
}
}
}
}
}
}
dis[0]=timedata[0];dis[1]=timedata[1];dis[2]=timedata[2];
dis[3]=timedata[3];dis[4]=timedata[4];dis[5]=timedata[5];
}
ET0=1;
}
/********************/
//0.4S闪烁中断函数//
/*******************/
viod time_intt1(viod) interrupt3
{
EA=0;TR1=0;TH1=0x3C;TL1=0xB0;TR1=1;
con04s++;
if(con04s==8)
{
con04s=0x00;
dis[7]=dis[con];dis[con]=dis[6];dis[6]=dis[7];
}
EA=1;
}
附录2:系统使用说明
1.电话防盗报警器的拨号报警功能简介
采用磁性开关进行检测,磁性开关即为装于门或窗口的防盗感应开关,门关闭时常开,门打开时闭合接通。实现全方位远距离监测。为了防止外界对磁性开关的影响,使用光藕传递信号。当有人触动装有磁性开关的门或窗口时,这时磁性开关闭合,实现报警。这时数码管会把信息纪录下来,同时蜂鸣器会发出尖锐的声音。告知房主。
2.电话防盗报警器的时钟功能简介
平时没有报警的情况下,数码管上显示的时间同我们的手表或钟表的时间是一致的。因此平时我们可以将它作为钟表来使用。数码管上显示时间的时,分,秒,以24小时计时方式运行,使用与单片机P1.0、P1.1、P1.2口相连接的按键T0、T1、T2实现对时、分、秒的调整。
3.注意事项
磁性开关在安装时,一定要隐蔽不要让人察觉。内部的硬件硬件电路我们可以将它装在与匹配的钟表壳内或其它容器内。总之要让别人觉得这只是一个普通的钟表。