8051 timer and external interrupt problem???

Aug 11, 2003 11 Replies

Hi all,



I'm a newbie to 8051 programming. I program in assembly language on a ATMEL 80c51 with a crystal frequency of 18.432 MHz.



I use timer1 for generating baud rate. Timer1 interrupt is not used. I use external interrupt 0 for communicating with 2 other peripherals.



Timer 0 interrupt is used to check if port pin 1.4 is low or high. and a corresponding message is displayed .



Interrupt 0 has high priority than the timer. the moment I enter into Interrupt Service routine, I stop the timer, clr the timer0 overflow flag and the timer 0 interrupt. After completing the job intended, just before exiting the routine I switch on the TImer0 and set the overflow and timer interrup flags.



The program works only when one of the interrupts are enabled in the code. When both Timer0 and Interrupt0 are set, the program hangs......



Especially after external interrupt0 is activated. what happens is , that timer interrupt doesn't detect the status of pin1.4 and displays the message...but interrupt0 gets activated every time interrupt0 occurs.



I have attached the code below. I think its some kind of a clash between the two interrupts. I would like to have pointers in this regard.



TIA. Regards Gayathri


The code :



;--------------When the program resets it jumps to main label-----------------



org 2000h ; start of main program after reset ljmp main ; goto label "main"



;---------------definition of interrupts--------------------------------------



org 0003h ; int0 vector address ljmp mainint reti



org 000bh ; timer0 interrupt ljmp on_off reti



org 0013h ; int1 vector address reti



org 001bh ; timer1 interrupt reti



org 0023h ; ri & ti reti


;------------------------------Byte Storage



---------------------------------- rub_all: db '{C0816 |{C1916 |{C3216 |' rg: db '$BM',0DH


low: db '{C2800 LOW|' high: db '{C2800 HIGH|'


;-----------------------------code segmenting-----------------------------------



cseg at 0100h ; Code starts from location 0100h



;---------------------------------Main------------------------------------------


main: mov SP,#18h ; Stack pointer initialised to 18h clr A ; Clear accumulator setb IT0 ; Interrupt 0 edge sensitive mov IP,#01h clr RS0 ; Select Register Bank 2 setb RS1 CLR TR0 CLR TF0 setb EA ; Enable all Interrupt CLR EX1 setb EX0 ; Set External interrupt 0(main) clr ET1 ; Clear external timer interrupt setb ES ; Enable serial interrupt



mov r1,#2Eh ; Number of characters in rub_all (46D= 2Eh) mov r0,#40h ; Starting location mov dptr, #rub_all ; Ruball is the label for 'db' lcall receiver ; Fill the db into RAM



lcall sio_init ; serial and timer1 initialization LCALL SIO_TIME ; timer0 initialization



infinite: sjmp infinite



;---------------------------TIMER 0 INTERRUPT SERVICE ROUTINE



------------------on_off: CLR EA clr ri clr ti LCALL SIO_INIT jb p1.4,ok ; if pin is high then go to ok mov r1,#0Bh mov dptr, #low ; displaying'{C2800 LOW|' lcall sender_b ; send to the serial port and display message through device2 sjmp done



ok: mov r1,#0Ch ; character counter mov dptr, #high ; '{C2800 HIGH|' lcall sender_b ; send to the serial port



done: LCALL SIO_TIME SETB EA reti



;------------- end of timer 0 interrupt------------------------------------------



mainint: mainloop: CLR EA push acc push psw push dpl push dph push 10h push 11h push 12h push 13h push 14h push 15h push 16h push 17h push b


lcall sio_init



;;;;; code for communicating with DEVICE1 --- get response from device one( through serial communication)



;;;;code for communication with device2 - for displaying the response.



pop b pop 17h pop 16h pop 15h pop 14h pop 13h pop 12h pop 11h pop 10h pop dph pop dpl pop psw pop acc POP 0A8H



LCALL SIO_TIME SETB EA reti ;--------------------subroutine for "ch_s"



-----------------------------------



ch_s: ; subrutine for transmitting data clr ti ; clear transmit interrupt clr a movc a,@a+dptr ; move the first character mov sbuf,a gon: jnb ti,gon ; wait until transmit interrupt is set inc dptr ; to get next data ret ; ret from subroutine


;--------------------Subroutine for "ch_r"



----------------------------------



ch_r: ; subroutine for receiving data from serial port gch: jnb ri,gch ; wait until receive interrupt is set mov @r1,sbuf ; mov sbuf data to address pointed by r1 mov r3,sbuf cjne r3,#2Eh,ter mov a,#06h ter: inc r1 ; to store next data inc a ; decrement character counter clr ri ; clear receive interrupt ret ; ret from subroutine



;______________________________________________________________________________


;--------------------subroutine for "ch_send"



--------------------------------



ch_send: ; subrutine for transmitting data on serial port clr ti ; clear transmit interrupt mov sbuf,@r0 ; move the first character gone: jnb ti,gone ; wait until transmit interrupt is set ret ; ret from subroutine



;--------------------subroutine for "sender"



--------------------------------


sender_b: setb p1.2 ; select Device2 for communication using a DEMUX clr p1.3 lcall sio_init



send_see: lcall ch_s ; call sub for character transmission djnz r1, send_see ; repeat if counter is not = 0 ret


;--------------------subroutine for "receiver"



-------------------------------- receiver: ; for sending program memory to RAM



send_re: clr a movc a,@a+dptr ; move the first character pointed by DPTR mov @r0,a inc dptr inc r0 djnz r1, send_re ; repeat if counter is not = 0 ret ;------------------------------------------sub routine -SIO init---------------- sio_init: CLR TR0 CLR TF0 CLR ET0 mov tmod,#20h ; select timer1 mov TH1,#0f6h ; reload value for 9600 baud rate =f6 mov scon,#50h ; init.serial control reg. & select mode 1 mov 87h,#80h ; pcon register-to multiply baud rate by 2 setb tr1 ; start timer1 clr ti clr ri ret



SIO_TIME: CLR TR0 CLR TF0 CLR ET0 mov tmod,#21h ; select timer1 AND TIMER 0 mov th0,#00h mov tl0,#00h SETB ET0 setb TR0 RET


;-----------------End of program



--------------------------------------------



;end program end


Instead of doing the serial comms inside an interrupt just set a flag which can be actioned in the main loop.

Try putting the code for timer 1 int in the main loop to see if serial comms works ok.

Also there is an extra pop in int0 isr - Im not sure why this is in there ?

Thanx Paul and Gary..

I set two flags in the interrupt service routines and actioned them in the main loop. Now I do not use the timer interrupt at all. Instead I'm trying to do call the on_off routine in the main loop by default.

the program sequence: main:

1.initialise: Ex0,Ex1,SP,EARegister bank etc. 2.in an infinite loop ( check for the flags that my be set by the ISRs and service the routines. then also perform on_off routine then jmp back to inifinite loop).

The program works well only if this on_off routine is excluded from the main program.

On the other hand, if the flags --- ( set by interrupt Service routines) are not actioned..( if that code is removed) then this on_off routine works fine when included in the main program..

I mean... the on_off routine and the flag servicing routines seem to be mutually exclusive...

Please let me know why the program hangs... What am I missing?? Thanks in advance

Gayathri

Have you tried turning interrups off before checking the flags, then on again after you have checked them?

You may be >Thanx Paul and Gary..

Hi,...

why do i have to turn the interrupts off..???

This is what I'm doing: flag1 bit 01h flag2 bit 02h

org 2000h ; start of main program after reset ljmp main ; goto label "main"

org 0003h ; int0 vector address setb flag1 reti

org 0013h ; int1 vector address setb flag2 reti ;------------------------------Byte Storage---------------------------------- rub_all: db '{C0816 |{C1916 |{C3216 |' rg: db '$BM',0DH low: db '{C2800 LOW|' high: db '{C2800 HIGH|'

cseg at 0100h ; Code starts from location 0100h

;---------------------------------Main------------------------------------------ main: mov SP,#55h ; clr A ; Clear accumulator setb IT0 ; Interrupt 0 edge sensitive setb IT1 clr RS0 ; Select Register Bank 2 setb RS1 setb EA ; Enable all Interrupt CLR EX1 setb EX0 ; Set External interrupt 0(main) clr ET1 ; Clear external timer interrupt clr ES ; Enable serial interrupt clr flag1 clr flag2 clr ri clr ti

mov r1,#2Eh ; Number of characters in rub_all (46D= 2Eh) mov r0,#25h ; Starting location mov dptr, #rub_all ; Ruball is the label for 'db' lcall receiver ; Fill the db into RAM

lcall sio_init ; serial and timer1 initialization

infinite:

lcall on_off

jnb flag1,n1 lcall mainint n1: jnb flag2,n2 lcall continue

n2: sjmp infinite

****************************************************************

within mainint I communicate with a device say DEVICE1 within continue I communicate with yet another device say device2

on_off routine displays a message everytime program enters into "infinite:" loop.

I face the following problem. on_off and maintint,continue seem to be mutually exclusive. If "lcall on_off " is removed the program works fine. lcall on_off works fine when the flags 1 and 2 are not checked.

Please let me know what might be the cause???? What am i missing ???

TIA Gayathri

As you say, there must be something you are doing in on_off and (mainint, continue) that are interfering with each other. You'll have to look at the code from those to see why this is. Your interrupt routines are nice and short and shouldn't be a problem.

Hi Gary,...

When I simulate the code on a keil simulator, it works very fine... but when on the actual 89C51, the progtam hangs..... The program misbehaves on my development kit also....

please let me know what might cause these kinds of problems?????

Regards Gayathri

A simulator is just that. It can help you develop your code, but it's not perfect. You can only simulate what the I/O pins see. I don't know if the Keil simulator can simulate things like noise on the I/O lines or not.

In article , Gary Kato writes

No. You can't. AFAIK nothing does that sort of thing.

/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ \/\/\/\/\ Chris Hills Staffs England /\/\/\/\/\ /\/\/ snipped-for-privacy@phaedsys.org

formatting link
\/\/ \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/

I seem to remember a setting in some simulator that could inject random noise into I/O stream. Can't remember what simulator that was though.

One of our products included a welder controlled by the embedded computer - we had to have the computer position the welder, then shut down, let the welder fire, then reboot the computer! It is very hard to isolate power supply from spikes on the ground! - RM

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required