打印

51新手问题:中断响应后片子里面哪些地方改写了

[复制链接]
4037|35
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
bg6nw|  楼主 | 2007-1-22 16:36 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我是一个单片机初学者,刚刚学了七八天,试着写了一个小程序,翻了一些资料,头都大了,好不容易挤出了一些代码,但是出现了一个莫名其妙的现象,希望哪位弟兄百忙之中抽空看看,这里先谢过。
这是一个电话遥控电器的试验,2051的p1.7接光耦,检测振铃,来振铃将p1.7拉低,p1.1到p1.5接cm8870的std,D,C,B,A,用来检测摘机后拨进来的双音码,如果依次是*,0两个码,就向电话线送【嘀嘀声】然后打开电器,这里我做了两个定时中断都是十秒左右的,在检测振铃时用一个,两次振铃间隔超过十秒就回到开始【start】;另一个是摘机后十秒内不输完密码就回到开始【start】。开机从头到尾执行起来都正常,出现了这样的问题:
如果从开机复位,振铃6次到摘机后,不输密码,等待定时中断超时回到开始挂断电话,再重新送振铃6次摘机,摘机后定时中断不起作用了,多少秒钟以后也不挂断,这时输入密码也可以向下执行。硬件复位后第一次超时挂机正常。
我已经黔驴技穷了,呵呵。弄了两整天,改代码,写片子,2051都写了100多次了,还是不行。我想可能是中断响应之后半路跳到【start】,还有什么东西没有复位造成的,请各位弟兄指点指点。


代码如下,第一次写程序,有点乱-------那位老弟又说了:岂止乱,那是真乱呀

;单片机是89c2051,晶振是4Mhz
org 0000h
ajmp start
org 000bh         ;定时器0的中断向量地址
ajmp time0        ;跳转到真正的定时器程序处
org 0030h
start:
mov p1,#0ffh     ;将p1口全置高,作为输入端
mov p3,#00h     ;将p3口全置低,作为输出端
clr a    ;累加器a清零
mov sp, #5fh           ;堆栈起始设置
mov 30h, #00h          ;软件计数器清零
mov tmod, #00000001b  ;定时/计数器0工作于方式1
mov th0, #3ch       ;装入预置数高位
mov tl0, #0b0h     ;装入预置数低位 总数是15536,即计数到50000
setb ea           ;开总中断
setb et0          ;开定时/计数器0允许
l1:jnb p1.7,d2   ;p1.7为高则向下执行,为低即跳至d2
ljmp l1           ;跳回l1
d2:setb tr0       ;定时/计数器0开始运行
mov 30h, #00h          ;软件计数器清零
lcall delay    ;调用2秒延时
inc a             ;累加器a加1
cjne a, #6, l1    ;判断累加器a里面的数字为6否,是6,向下,不是6,回l1
clr tr0            ; 定时/计数器停止运行
setb p3.7        ;现在摘机, 推动一个继电器,将一个300欧姆电阻并到电话线上
lcall delay    ;调用2秒延时,这时将有一个音乐片说一声【请输入密码】
clr a         ;累加器a清零mov 30h, #00h          ;软件计数器清零
mov th0, #3ch       ;重置定时器,装入预置数高位
mov tl0, #0b0h     ;装入预置数低位
setb tr0           ;定时/计数器0开始运行
mima:jnb p1.1, mima   ;检测8870的15脚,低电平循环,高电平向下执行
jnb p1.2, start       ;d位电平高继续
jb p1.3, start       ;c位电平低继续
jnb p1.4, start      ;b位电平高继续
jnb p1.5, start      ;a位电平高继续,这四个是第一位密码 【*】
mima2:jb p1.1, mima2   ;检测8870的15脚,高电平循环,低电平向下执行
mima3:jnb p1.1, mima3   ;检测8870的15脚,低电平循环,高电平向下执行
jnb p1.2, start       ;d位电平高继续
jb p1.3, start       ;c位电平低继续
jnb p1.4, start      ;b位电平高继续
jb p1.5, start       ;a位电平低继续,这四个是第二位密码 【0】
lcall didixiang       ;以下重复嘀嘀响十次
nop
lcall didixiang
nop
lcall didixiang
nop
lcall didixiang
nop
lcall didixiang
nop
lcall didixiang
nop
lcall didixiang
nop
lcall didixiang
nop
lcall didixiang
nop
lcall didixiang
nop
kaiguan:setb p3.4
ljmp kaiguan  ;p3.4推动一个继电器,打开被控制的电器开关
;未完待续------挂机电路还没想起来,写到这里卡壳了



;-----------------以下为嘀嘀响程序----------------------
didixiang:
mov r7, #100
didi1: mov r6, #200
setb p3.5         ;p3.5推动一个三极管,去调制电话线,送出断续方波
didi2: djnz r6, didi2
clr p3.5
djnz r7, didi1
mov r7, #100
didi3: mov r6, #200
didi4: djnz r6, didi4
djnz r7, didi3
ret
;-----------------;以下为2秒延时-----------------------
delay: mov r7, #250
y1: mov r6, #200
y2: mov r5, #5
y3: djnz r5, y3
djnz r6, y2
djnz r7, y1
ret
;----------------------------------------------------------
time0: ;定时器0的中断处理程序
push acc
inc 30h       ;软件定时器加1
mov a, 30h              ;软件定时器送累加器a
cjne a, #65, tret     ;到65了吗?到了向下执行,未到65转到tret
ljmp start          ;回到开始,挂掉电话,重来。
tret: 
mov th0, #3ch       ;重置定时器,装入预置数高位
mov tl0, #0b0h     ;装入预置数低位
pop acc
reti

end

相关帖子

沙发
hotpower| | 2007-1-22 16:46 | 只看该作者

中断也要保护psw

因为用了cjne a, #65, tret     
破坏了CY

使用特权

评论回复
板凳
bg6nw|  楼主 | 2007-1-22 16:53 | 只看该作者

我曾经加了

曾经这样改过

;----------------------------------------------------------
time0: ;定时器0的中断处理程序
push acc
PUSH PSW
inc 30h       ;软件定时器加1
mov a, 30h              ;软件定时器送累加器a
cjne a, #65, tret     ;到65了吗?到了向下执行,未到65转到tret
ljmp start          ;回到开始,挂掉电话,重来。
tret: 
mov th0, #3ch       ;重置定时器,装入预置数高位
mov tl0, #0b0h     ;装入预置数低位
POP PSW
pop acc
reti

end


是不是在ljmp start之前也要加上一句呀
谢谢。

使用特权

评论回复
地板
bg6nw|  楼主 | 2007-1-22 17:47 | 只看该作者

我刚刚写了片子试了

我刚刚写了片子试了

time0: ;定时器0的中断处理程序
push acc
push psw
inc 30h       ;软件定时器加1
mov a, 30h              ;软件定时器送累加器a
cjne a, #65, tret     ;到65了吗?到了向下执行,未到65转到tret
pop psw
pop acc
ljmp start          ;回到开始,挂掉电话,重来。
tret: 
mov th0, #3ch       ;重置定时器,装入预置数高位
mov tl0, #0b0h     ;装入预置数低位
pop psw
pop acc
reti



即使是这样,还是老问题。差哪儿呢

使用特权

评论回复
5
hotpower| | 2007-1-22 17:51 | 只看该作者

不要这样软复位

time0: ;定时器0的中断处理程序
push acc
push psw
inc 30h       ;软件定时器加1
mov a, 30h              ;软件定时器送累加器a
cjne a, #65, tret     ;到65了吗?到了向下执行,未到65转到tret
;///////////////////////////////////////////////////
;//ljmp start          ;回到开始,挂掉电话,重来。
  acall treti;//空调用一次reti
  clr a
  push acc
  push acc
  reti;//调用第二次reti//;回到开始,挂掉电话,重来。
;////////////////////////////////////////////////////
tret: 
mov th0, #3ch       ;重置定时器,装入预置数高位
mov tl0, #0b0h     ;装入预置数低位
pop psw
pop acc
treti:
reti


再:
start处最好加mov ie,#0;或clr ea


作为"一个单片机初学者,刚刚学了七八天"
能编出这样的程序来,菜农在这里敬礼了~~~

使用特权

评论回复
6
bg6nw|  楼主 | 2007-1-22 19:25 | 只看该作者

向高手敬礼

    不愧是高手呀,经菜农这么一改,写到片子里居然就解决了。但是老哥我还有问题:
    一,我还是没看懂,调用两次reti为什么就能使程序回到start去,又没有用ljmp start语句。reti语句不是回到被打断的PC指针那里吗,怎么跑到start去了?翻书也没有找到相关内容。
    二,acall treti;//空调用一次reti
这一句执行过以后PC指针跑其他地方去了吧,他下面的一句clr a
  push acc..........是怎么被执行到的?我老是绕不过来这个弯。
    三,如果在start后面加上【关总中断】语句,我在后面隔几句又有【开总中断】,会不会这里会有一个小BUG。可不可以在start后面用clr tr0 语句,待第一个振铃脉冲来到之后再setb tr0
      

使用特权

评论回复
7
lpf336| | 2007-1-22 19:34 | 只看该作者

老哥我 今年三十六了

好像没hotpower大

使用特权

评论回复
8
bg6nw|  楼主 | 2007-1-22 19:45 | 只看该作者

不好意思

我一直以为我这样的老【电痴】不太多,我错了,对不住

使用特权

评论回复
9
twz8858877| | 2007-1-22 20:11 | 只看该作者

这是初学者易犯的一个错误

51系列中断系统的硬件中还包含了两个不可寻址的“优先级激活”触发器,该触发器在响应中断时由CPU置位,以阻断同级或低优先级的中断,该触发器的置位只能由reti语句释放,所以在你原程序中ljmp start语句后由于没有reti语句,此时CPU仍然认为处于定时器0的中断服务程序中,此时将不再响应同级中断,也就是说将不再响应t0的中断了。至于其他的几个问题:
1、acall treti;//空调用一次reti,这一句执行过以后PC指针跑其他地方去了吧,他下面的一句clr a
 push acc..........是怎么被执行到的?我老是绕不过来这个弯。
acall treti指令执行时首先cpu会自动将当前pc值压栈,然后执行reti时cpu做了两件事 1、释放“优先级激活”触发器;2、将堆栈内容弹回pc;所以程序还是会返回原处继续执行的。至于后面的push acc.......等到是可以由一条语句ljmp start代替了。
如果在start后面加上【关总中断】语句,我在后面隔几句又有【开总中断】,会不会这里会有一个小BUG。可不可以在start后面用clr tr0 语句,待第一个振铃脉冲来到之后再setb tr0
由于你只开了一个t0中断,所以你这样做也可以的,clr ea也不存在有什么BUG,如果开了多个中断,最好还是clr ea

使用特权

评论回复
10
hotpower| | 2007-1-22 20:24 | 只看该作者

哈哈~~~至少小我一轮~~~倒塌了~~~网上没大小,随便就好~~~

很是佩服~~~

记得80多岁的老父50岁学日语(第3外语)的时候...前几年还在写书...**被母亲撕了英文词典...

确实是我一生难忘!!!菜农我自愧不如~~~

奔五的人能在此倒塌,心里就知足了...所以我要向您敬礼!!!

要看电视"卧薪尝胆"了~~~回头我会讲解的...

使用特权

评论回复
11
hq_y| | 2007-1-22 20:26 | 只看该作者

佩服楼主,向楼主学习!

告诉楼主一个秘密:

有什么不懂的,抓住hotpower就行了~~~~~~~~~~~

使用特权

评论回复
12
conwh| | 2007-1-22 20:54 | 只看该作者

前面的CLR A,再加上2个PUSH A,就是设置了返回指针00了

使用特权

评论回复
13
bg6nw|  楼主 | 2007-1-22 20:55 | 只看该作者

都是热心的高手

后面还有密码挂机,忙音检测部分。想想头都大了,下一步我还打算把这个小程序弄完,要不我会天天睡不着的:)
接下来还会遇到这样那样的问题,还不少麻烦诸位。

使用特权

评论回复
14
hotpower| | 2007-1-22 21:05 | 只看该作者

这个程序就先别搞了,先突击学习C51三天再编程序

这样的程序结构本来就没骨架,再搭一点东西就会倒塌了~~~

真的,不骗您~~~

回此帖就是觉得这个程序很有创意~~~但不能做产品~~~

使用特权

评论回复
15
conwh| | 2007-1-22 21:31 | 只看该作者

LS的你最好不要再发4眼的图片了,看得都成4眼了,晕!

同意HOTPOWER的意见,结构式的程序是你进步的梯子。再就是这样复位方式不好,能不这样使用就尽量不这么使用。该挂机就挂机,应该不是个麻烦的事情。尽量使用模块结构,对于变量要使用变量名,总比30H、31H等好的多。

使用特权

评论回复
16
bg6nw|  楼主 | 2007-1-22 22:28 | 只看该作者

理解了两个小时,想通一点了

经过conwh 一点拨,我的明白了,菜农前辈的这几句


acall treti;//空调用一次reti
  clr a
  push acc
  push acc
  reti;//调用第二次reti

是把四个0压入堆栈,等reti的时候,送给PC指针的是四个0呀,那不就回到开始了。

使用特权

评论回复
17
hotpower| | 2007-1-22 22:32 | 只看该作者

理解估计有些偏差,twz8858877解释的很好~~~

先到菜地里玩玩~~~等会给你几个链接.

主要是如何搭汇编的骨架...
相关链接:http://www.**/blog/hotpower/14489/message.aspx

使用特权

评论回复
18
xwj| | 2007-1-22 22:39 | 只看该作者

先把程序结构学好再说,过分追求技巧旧落了下乘了(雕虫小

等你到了一定程度再去讲究精益求精、化腐朽为神奇吧

使用特权

评论回复
19
hotpower| | 2007-1-22 22:45 | 只看该作者

LS放小鸟捣蛋,不怕尿童射小鸟???

使用特权

评论回复
20
xwj| | 2007-1-22 23:00 | 只看该作者

软复位不是那么简单的,还有很多事要做的

IO
SP
PSW
中断标志和配置
IE
中断占用
清内存
部分特殊寄存器
外围器件的释放
正常初始化
等等等等。。。


系统可靠性要考虑的东西很多的,LZ想的还是过于简单了哦
虽然现在能用,但不保证以后或现场不出错误哦

对你的领悟和应用能力表示赞赏,再接再厉,把结构化编程和可靠性考虑成为习惯,把51彻底研究透彻,把思路和知识面无限扩展,那你就是高手了

加油吧!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

34

主题

511

帖子

0

粉丝