家用防盗报警器源程序
家用防盗报警器源程序清单 ;采用89C2051无P3.6引脚!正常时P3口输入低电平,报警时P3.0~P3.5输入高电平,从P3.7引脚输出高低电平间隔1秒的报警脉冲信号。
ORG 0000H ;开机复位PC指向0000H地址
AJMP MAIN ;转入主程序
ORG 001BH ;定时器T1入口
LJMP WT0 ;转入定时器T1中断程序
ORG 30H ;这条语句有何作用?指定下一条程序的地址为30H
MAIN: MOV SP,#50H ;堆栈从50H开始
MOV 20H,#0 ;20H清零
MOV 24H,#0 ;24H清零
MOV P3,#0 ;P3口输出低电平
MOV P1,#0 ;P1口输出低电平(红外线发射二极管工作)
MOV TH0,#6 ;此处不懂,预置数为多少?如何计算?答×初值为6,那么256-6=250,当T0计数250个脉冲后发生中断,如果时钟频率为6M那么机器周期为2us,T0的定时时间为500us。
MOV TL0,#6 ;不懂!!
MOV TMOD,#02H ;TO工作方式为2
SETB EA ;打开总中断
SETB ET0 ;开T0中断
SETB TR0 ;T0开始计数
M: MOV P1,#00H ;P1口输出低电平(以上程序所做的是开机初始化,程序进行基本设置)
MOV A,P3 ;将P3口的值赋予A
ANL A,#7FH ;将A的值和01111111作与运算,并且结果保留在A中
CJNE A,#7FH,W37 ;如果A不等于01111111那么跳转到W37(也就是说当P3口输入高电平时报警
AJMP M ;返回到M处(处于监控等待状态)
WT0: PUSH ACC ;将累加器A中的数值压入堆栈
PUSH PSW ;将程序状态字PSW压入堆栈(保护现场)
INC 22H ;将22H中的值加1
MOV A,22H ;将22H中的值赋予A
CJNE A,#200,TORETI ;如果A中的值不等于200那么跳转到TORETI(退出中断)(也就是说中断200次后往下执行)
MOV 22H,#0 ;将22H中的数值清零
INC 23H ;将23H中的值加1
MOV A,23H ;将23H中的值赋予A
CJNE A,#10,TORETI ;1s 如果A中的值不等于10那么跳转到TORETI(退出中断)(在中断10次,那么只有中断200x10=2000次以后程序才能往下执行)
MOV 23H,#0 ;将23H中的数值清零
JNB 00H,WBJ;00H应该是位地址20H.0 如果20H.0的值为0那么跳转到WBJ
TORETI: POP PSW ;恢复PSW中的数值
POP ACC ;恢复A中的数值(恢复现场)
RETI;退出中断
WBJ: CPL P3.7 ;对引脚P3.7状态取反
AJMP TORETI ;跳转到TORETI (退出中断)
W37: INC 24H ;将24H中的值加1
MOV A,24H ;将24H中的值赋予A
CJNE A,#10,M ;如果A中的值不等于10那么跳转到M(增加检测时间,如果重复10次检测到P3口输入高电平时程序往下执行)
SETB 00H ;对位地址20H.0置1
AJMP M ;跳转到M
END ;结束
网上的高手解答
一.功能描述 简易光电报警器,六个光电对管构成六路检测,如发生遮挡事件则输出脉冲报警.
1.硬件 电路比较简单也很典型,其中CD4069可换成40106施密特六路非门,效果会更好;P3.7也可利用起来;P1口要串入限流电阻或接三极管放大.
2.软件 由主程序和中断服务程序组成,主程序负责检测外部触发,由中断程序输出报警脉冲.
二.问题回答
1. "ORG 30H" ORG,END等都为伪指令,在此指出MAIN段程序的程存地址从30H开始,在本程序中也可省略,这只是一般写程序的风格习惯而已.因为串口中断服务入口地址是23H,从30H开始主程序就避免了对五个中断服务程序的干扰,并为以后其他中断的使用留下程存空间.在此程序中由于只用了T0中断,所以紧接"LJMP
WT0" 后面写MAIN段也是可以的.
2. "MOV TH0, #6" 设TH0初值为6,计算很简单,方式2时为8位计数器,256-6=250,故6M时500微秒溢出.你的说明是正确的.
3. "MOV TL0, #6" 因为方式2为8位自动装填,每个机器周期只是对TL0加一,加满后再将TH0的值赋给TL0重新计数,TH0值一直保持不变.设TL0初值为6意味着只要一打开TR0,则从6开始计数.实际上此句也可省略,因为不管TL0初值为何,最长256周期后TH0值6必然要赋给TL0.
三.错误及更正
1. "JNB 00H, WBJ"应为"JB 00H,WBJ"!! 程序开始时,"MOV 20H, #0"已将位00H清零,所以一开始运行不需触发进中断就产生报警信号(P3.7输出方波);相反,外部报警触发后它反而不回报警了(因为00H被置成1了).
2. "MOV P3, #0" 应去掉!! P3口作为光电检测输入口,由P3口的上拉结构可知,要输出数据P3口必须先置为高态,原程序中初始化就将P3口置零,不仅不能输入任何信号而且很容易烧毁芯片(4069输出高时),是很严重的错误!
3. "ANL A, #7FH.CJNE A, #7FH,W37" 其中7F改为3F. P3.6口在2051芯片中作为P1.0和P1.1的比较输出(片内),其值取决于P1.0和P1.1.在此应用中不能保证P3.6一定为高,很容易导致误报或根本不能工作.实际上只用了6路输入检测,干吗是7F呢?
4. 22H,23H是用来作为分频计数控制P3.7输出周期,最好在初始化MAIN将两者清零,避免不必要的麻烦.如22H为200,23H为10时需好长时间才能进入处理P3.7.
5.中断入口地址.....
四.其它
1.时间问题 22H,23H两者作为P3.7输出方波周期的延时计数,故P3.7周期T=2*200*10*500微秒=2秒,占空比为1.
2.24H用来计数检测10次其目的是为了提高抗干扰能力.
五.我的评价(一家之言,仅供参考)
总体看来功能清晰,但程序实在是冗长,有许多地方可简化和改进.严格来说有很多漏洞.
1. 中断中PSW无须压栈保护,程序中没有牵扯到PSW.不是什么都要保护,压栈使用多了都可靠性不利.
2. "INC 22H.MOV A,22H. CJNE A, #20, TORETI"换为"DJNZ
R2,TORETI. MOV R2, #200 ",初始化中加入" MOV R2, #200"岂不更好(参见我以前给你程序),甚至不用什么"PUSH ACC.
POP ACC"了,尽量避免用"CJNE..."之类的指令.程序中其它类同(共有三处).
3. 猜猜WBJ段中" RETI"干什么用?
4. 原程序在主程序中采用循环检测,而用中断来输出报警信号,从资源利用角度来说很不科学.例如:没有报警时程序进中断根本不干事,报警后输出不会停止但还是要中断返回执行主程序的检测过程.实际上定时中断是很宝贵的资源,在原程序中没有涉及到睡眠等问题,中断输出方波功能完全可直接写入主程序,这里用中断可谓"杀鸡用牛刀",利用率太底了。。.
编程学习还差不多.
5. 电路中直接用光电管检测,光电管却一直处于恒开状态.这对安全要求比较高的场合是根本不行的.红外主动报警器安全要求较高时要用到数据加密处理的.例如在原电路软件中各对光电管分别进行动态的可变数据通信(即用数据光通信进行封锁,注意时间问题),一旦发现数据出错即处理报警,这样安全性就可提高一个档次!原电路不需动.写出这样的程序才能算有意思,不是很难,以后有能力你可尝试.
好了,就说怎么多,请你细细分析一下,完全理解后请给我详细谈谈你的感觉.我想如果原程序能顺利工作,我马上就去跳楼(通知我一声).实际上根据电路功能程序有好多写法,都比这个要强.由于时间关系在此省略,见谅,请自行练习.
备注:如果不需要AT89C51实验开发板中的12伏电源变压器,价格可以降低10元
邮局汇款地址:邮编226200 江苏省启东市江海中路511号水晶苑 A-1 谢刚 收
电话/传真:0513-83342087 小灵通:0513-83082087 联系人:谢刚
电子信箱: