Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[General] different task performed at every push of one button

Status
Not open for further replies.

hsa.a

Junior Member level 3
Joined
Dec 15, 2016
Messages
30
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
232
hi,
can somebody tell me how to perform two different tasks with one push button i.e, if the push button is pressed once, it performs task A. If the button if pressed the 2nd time, it should perform task B and it should wait till the button is pressed again.
i am using 89c2051 uc and assembly language.
 

I can't help with specifc code but in general, you can do it three ways:

1. if there are only two alternatives, increase a variable at each press of the button, it doesn't matter if it 'overflows' and goes back to zero. Then use the least significant bit of the variable to decide which task is performed. 0 = task A, 1 = task B. It relies on the binary count sequence always alternating the LSB.

2. At the end of task A, wait for the button to be pressed, then execute task B. At the end of task B, wait for it to be pressed and jump to the code for task A. This method runs one tasks after the other with a pause between them until the button has been pressed.

3. Is the more generic method which is easily expanded to more tasks if necessary, increments a variable at each press of the button then use a look-up table of the task servicing addressess to find the address to jump to. At the end of the table you add a routine to reset the variable. Like this:
a. button pressed, increment variable
b. variable is used to pick an entry in the look-up table (task A, task B, task C.... task x)
c. jump to that entry and return to 'a' when finished
d. last entry sets variable back to zero so it selects the first task at the next press.


Brian.
 
  • Like
Reactions: hsa.a

    hsa.a

    Points: 2
    Helpful Answer Positive Rating
OKAY... I tried doing what you suggested. below is the code attached. the problem within this code is that it doesn't print the message on screen. Can you tell me where am i making a mistake?
Code:
ORG 000H
MAIN:

MOV IE,#10001011B;   
MOV TMOD,#00101101B;          ;TR1 M2 / TM0-CT0 M1   
MOV TH1,#0FDH;	              ;9600BAUD RATE, ,8-BIT,1-STOP BIT;;;;;;;;;;;;;;
MOV SCON,#50H                 ;01010000b
SETB TI;                      ; TRANSMIT BIT HIGH, TRANSMITS WHEN LOW
setb TR1;
SJMP loop


ORG 000BH;            interrupt TIIMER routine
		PUSH ACC;
		SETB P1.4;
		SETB P1.5;
		POP ACC;
		RETI;
		
ORG 0003H;
	AJMP INITIAL;
	
ORG 00F0H                          ;MEMORY ADDRESS FOR THE STRING "ON"
	MS:DB 13,10,"ON",10,13,0		
		
ORG 00F9H
	MS1:DB 13,10,"OFF",10,13,0

ORG 0030H
	
loop:        
MOV R0,0                  ; LOADING THE VALUE FOR THE INTERNAL INTERRUPT COUNTER
led4:
		clr p1.4
		setb p1.5;
		mov R3,#4;
		JNB INT0,INITIAL;
		BL:
		MOV R4,#30;              LOOP FOR REPEATING COUNT
		LRPT:                   ;MAX DELAY
		MOV TL1,#0H;
        MOV TH1,#0H;
		SETB TR1;
		LAGAIN: 
		JNB TF1, LAGAIN;
		CLR TR1;
		CLR TF1;
		DJNZ R4,LRPT;
		CPL P1.4;
		DJNZ R3,BL;
		SJMP led4;

INITIAL:
INC R0
CJNE R0,#1,ONloop             ; comparing the value of the register bank
CJNE R0,#2,OFFloop
LJMP MAIN;

ONloop:
ACALL DISPLAY1
		LOP:
		clr p1.5;
		setb p1.4
		mov R3,#4;
		BLINK:
		MOV R4,#150;              LOOP FOR REPEATING COUNT
		RPT:                   ;2 sec DELAY
		MOV TL0,#0H;
        MOV TH0,#0H;
		SETB TR0;
		AGAIN: 
		JNB TF0, AGAIN;
		CLR TR0;
		CLR TF0;
		DJNZ R4,RPT;
		CPL P1.5;
		DJNZ R3,BLINK;
		SJMP led4

ORG 00B0H;

TRANS:
MOV SBUF, A;
JNB TI,$
CLR TI
ret

DISPLAY1:                   ;displays ON
setb p1.4
MOV DPTR,#MS;
MOV R2,2
dis:
CLR A
MOVC A,@A+DPTR;
acall TRANS
INC DPTR;
DJNZ R2, dis
RET

OFFloop:
ACALL DISPLAY2
ACALL LOP
LJMP MAIN;

DISPLAY2:
setb p1.4
MOV DPTR,#MS1;
MOV R2,3
dis1:
CLR A
MOVC A,@A+DPTR;
acall TRANS
INC DPTR;
DJNZ R2, dis1
RET

END
 

But generally writing in c is recommended and easy also for portability.
 

I'm no expert in 89C2051 but at first glance there is something wrong with the start of your program. You set ORG to 000H, follow it with 7 instructions (I'm not sure how many bytes they actually use) then later have an ORG 003H and another instruction. I think you are overwriting some of the resulting code, the part that initialises the UART.

Brian.
 

I have to do this in assembly language.
 

actually those addresses are of the Interrupt service routine for timer and interrupt 0.
 

I'm no expert in 89C2051 but at first glance there is something wrong with the start of your program. You set ORG to 000H, follow it with 7 instructions (I'm not sure how many bytes they actually use) then later have an ORG 003H and another instruction. I think you are overwriting some of the resulting code, the part that initialises the UART.

Brian.

this code is running the only problem now is that is doesnt print "on" of "off" when an interrupt is called at org 003h. it skips the display1 loop and goes to LOP loop. after that it returns to the normall routine labelled as 'loop'.
 

actually those addresses are of the Interrupt service routine for timer and interrupt 0.

They may well be vectors for the ISR but when you set ORG to 000H it sets the address where the following instructions are located. They then occupy consecutive addresses. By setting ORG to 003H you again set the location for the following instructions so you overwrite what you just placed there.

You probably want to make the instruction at 000H a jump to MAIN: rather than place the code at 000H.

Brian.
 

They may well be vectors for the ISR but when you set ORG to 000H it sets the address where the following instructions are located. They then occupy consecutive addresses. By setting ORG to 003H you again set the location for the following instructions so you overwrite what you just placed there.

You probably want to make the instruction at 000H a jump to MAIN: rather than place the code at 000H.

Brian.

you are suggesting the following;
Code:
ORG 000H
Sjmp MAIN

ORG 000BH;            interrupt TIIMER routine
		PUSH ACC;
		SETB P1.4;
		SETB P1.5;
		POP ACC;
		RETI;
		
ORG 0003H;
	AJMP INIT;
	
ORG 00F0H                          ;MEMORY ADDRESS FOR THE STRING "ON"
	MS:DB 13,10,"ON",10,13,0		
		
ORG 00F9H
	MS1:DB 13,10,"OFF",10,13,0

ORG 0030H
MAIN:
MOV IE,#10001011B;   
MOV TMOD,#00101101B;          ;TR1 M2 / TM0-CT0 M1   
MOV TH1,#0FDH;	              ;9600BAUD RATE, ,8-BIT,1-STOP BIT;;;;;;;;;;;;;;
MOV SCON,#50H                 ;01010000b
SETB TI;                      ; TRANSMIT BIT HIGH, TRANSMITS WHEN LOW
setb TR1;
SJMP loop

right?

- - - Updated - - -

They may well be vectors for the ISR but when you set ORG to 000H it sets the address where the following instructions are located. They then occupy consecutive addresses. By setting ORG to 003H you again set the location for the following instructions so you overwrite what you just placed there.

You probably want to make the instruction at 000H a jump to MAIN: rather than place the code at 000H.

Brian.

you are suggesting the following;
Code:
ORG 000H
Sjmp MAIN

ORG 000BH;            interrupt TIIMER routine
		PUSH ACC;
		SETB P1.4;
		SETB P1.5;
		POP ACC;
		RETI;
		
ORG 0003H;
	AJMP INIT;
	
ORG 00F0H                          ;MEMORY ADDRESS FOR THE STRING "ON"
	MS:DB 13,10,"ON",10,13,0		
		
ORG 00F9H
	MS1:DB 13,10,"OFF",10,13,0

ORG 0030H
MAIN:
MOV IE,#10001011B;   
MOV TMOD,#00101101B;          ;TR1 M2 / TM0-CT0 M1   
MOV TH1,#0FDH;	              ;9600BAUD RATE, ,8-BIT,1-STOP BIT;;;;;;;;;;;;;;
MOV SCON,#50H                 ;01010000b
SETB TI;                      ; TRANSMIT BIT HIGH, TRANSMITS WHEN LOW
setb TR1;
SJMP loop

right?
 

They may well be vectors for the ISR but when you set ORG to 000H it sets the address where the following instructions are located. They then occupy consecutive addresses. By setting ORG to 003H you again set the location for the following instructions so you overwrite what you just placed there.

You probably want to make the instruction at 000H a jump to MAIN: rather than place the code at 000H.

Brian.


i tried what you suggested. that way the code soesnt even run one instruction of it. the circuit remains dead.
 

Please post the whole code.

Why do you have so many ORGs in your program? The idea of using labels is you can make the assembler decide the addresses to use, you shouldn't normally need to use ORG directives yourself except maybe to locate the start and ISR routines. By setting the addresses yourself you run the risk of 'back tracking' and overwriting previous code.

Brian.
 
  • Like
Reactions: hsa.a

    hsa.a

    Points: 2
    Helpful Answer Positive Rating
Code:
ORG 000H
MAIN:

MOV IE,#10001011B;   
MOV TMOD,#00101101B;          ;TR1 M2 / TM0-CT0 M1   
MOV TH1,#0FDH;	              ;9600BAUD RATE, ,8-BIT,1-STOP BIT;;;;;;;;;;;;;;
MOV SCON,#50H                 ;01010000b
SETB TI;                      ; TRANSMIT BIT HIGH, TRANSMITS WHEN LOW
setb TR1;
SJMP loop


ORG 000BH;                     interrupt TIIMER routine
		PUSH ACC;
		SETB P1.4;
		SETB P1.5;
		POP ACC;
		RETI;
		
ORG 0003H;                     interrupt 0 routine
	AJMP INITIAL;
	
ORG 0030H
	
loop:        
MOV R0,2                     ; LOADING THE VALUE FOR THE INTERNAL INTERRUPT COUNTER
led4:
		clr p1.4
		setb p1.5;
		mov R3,#4;
		JNB INT0,INITIAL;
		BL:
		MOV R4,#30;              LOOP FOR REPEATING COUNT
		LRPT:                   ;MAX DELAY
		MOV TL1,#0H;
        MOV TH1,#0H;
		SETB TR1;
		LAGAIN: 
		JNB TF1, LAGAIN;
		CLR TR1;
		CLR TF1;
		DJNZ R4,LRPT;
		CPL P1.4;
		DJNZ R3,BL;
		SJMP led4;

INITIAL:
DEC R0
CJNE R0,#0,ONloop             ; comparing the value of the register bank
SJMP OFFloop
LJMP MAIN;

ONloop:
ACALL DISPLAY1
		LOP:
		clr p1.5;
		setb p1.4
		mov R3,#4;
		BLINK:
		MOV R4,#150;              LOOP FOR REPEATING COUNT
		RPT:                   ;2 sec DELAY
		MOV TL0,#0H;
        MOV TH0,#0H;
		SETB TR0;
		AGAIN: 
		JNB TF0, AGAIN;
		CLR TR0;
		CLR TF0;
		DJNZ R4,RPT;
		CPL P1.5;
		DJNZ R3,BLINK;
		SJMP led4;

TRANS:
MOV SBUF, A;
JNB TI,$
CLR TI
ret

DISPLAY1:                   ;displays ON
setb p1.4
MOV DPTR,#MS;
MOV R2,2
dis:
CLR A
MOVC A,@A+DPTR;
acall TRANS
INC DPTR;
DJNZ R2, dis
RET

MS:DB 13,10,"ON",10,13,0
	
OFFloop:
ACALL DISPLAY2
ACALL LOP
LJMP MAIN;

DISPLAY2:
setb p1.4
MOV DPTR,#MS1;
MOV R2,3
dis1:
CLR A
MOVC A,@A+DPTR;
acall TRANS
INC DPTR;
DJNZ R2, dis1
RET;
	
MS1:DB 13,10,"OFF",10,13,0

END

- - - Updated - - -

Please post the whole code.

Why do you have so many ORGs in your program? T

Brian.

I am following mazidi's 8051 microcontrollers. the sample programs were written in the same fashion that is why I used addresses.Even without addresses it gives me the same response as before
 

There is no reti in org 3h interrupt. But i am not sure if that is the issue.
 

There is no reti in org 3h interrupt. But i am not sure if that is the issue.

it doesnt make a difference in the program. the only way it reads the interrupt again is by resetting the whole program after the last command of the interrupt loop.

- - - Updated - - -

i will restate the problem:

1) this program skips the display1 loop and executes LOP.
2) it doesnt compare the value of interrupt press button i.e, INITIAL (loop)
 

You still have the same problem with addresses - I will try to explain:

'ORG' is an assembler directive, when the instructions are converted to binary, it sets the location in memory the binary numbers will be saved to.

Your code assembles like this, the first digits are the address:
000 - (MAIN:) MOV IE,#10001011B; this is a two byte instruction using addresses 000 and 001
002 - MOV TMOD,#00101101B; this is a two byte instruction using addresses 002 and 003
004 - MOV TH1,#0FDH; this is a two byte instruction using addresses 004 and 005
006 - MOV SCON,#50H this is a two byte instruction using addresses 006 and 007
008 - SETB TI; this is a one byte instruction using address 008
009 - setb TR1; this is a one byte instruction using address 009
00A - SJMP loop this is a two byte instruction using addresses 00A and 00B

You then overwrite address 00B, trashing the SJMP instruction by the following code:

ORG 000BH; interrupt TIIMER routine
00B - PUSH ACC; this is a two byte instruction using addresses 00B and 00C
00D - SETB P1.4; this is a two byte instruction using addresses 00D and 00E
00F - SETB P1.5; this is a two byte instruction using addresses 00F and 010
011 - POP ACC; this is a two byte instruction using addresses 011 and 012
013 - RETI; this is a one byte instruction using address 013

then you overwrite address 003 with this code:

ORG 0003H; interrupt 0 routine
003 - AJMP INITIAL; this is a two byte instruction using addresses 003 and 004

so your actual code looks like this:

Code:
000 - ORG 000H
MAIN:

000 - MOV IE,#10001011B;   
002 - MOV (the bytes for the AJMP instruction at 003 and 004)
005 - (the second half of the MOV TH1,#0FDH instruction)
006 - MOV SCON,#50H                 ;01010000b
008 - SETB TI;                      ; TRANSMIT BIT HIGH, TRANSMITS WHEN LOW
009 - setb TR1;
00A - SJMP C0 (then the accumulator address)

which (if I got the instruction lengths right) is not what you thought you were coding!

Brian.
 
  • Like
Reactions: hsa.a

    hsa.a

    Points: 2
    Helpful Answer Positive Rating
You still have the same problem with addresses - I will try to explain:...

which (if I got the instruction lengths right) is not what you thought you were coding!

I corrected that part. however, removing the memory directives for timer and int0, the routines don't work at all. Therefore, I have kept the code under 0003h and 000BH.
Code:
ORG 000H
SJMP CHECK;

org 003H;
	AJMP INITIAL
	RETI
ORG 000BH;                     interrupt TIIMER routine
		PUSH ACC;
		SETB P1.4;
		SETB P1.5;
		POP ACC;
		RETI;
ORG 0030H
	CHECK:
MOV TMOD,#29H;          ;TR1 M2 / TM0-CT0 M1   
MOV IE,#10000011B; 
MOV TH1,#0FDH;	              ;9600BAUD RATE, ,8-BIT,1-STOP BIT;;;;;;;;;;;;;;
MOV SCON,#50H                 ;01010000b
SETB TI;                      ; TRANSMIT BIT HIGH, TRANSMITS WHEN LOW
setb TR1;

loop:        
MOV R0,2                     ; LOADING THE VALUE FOR THE INTERNAL INTERRUPT COUNTER
led4:
		clr p1.4
		setb p1.5;
		mov R3,#4;
		JNB INT0,INITIAL;
		
		BL:
		MOV R4,#15;              LOOP FOR REPEATING COUNT
		LRPT:                   ;MAX DELAY
		MOV TL0,#0H;
        MOV TH0,#0H;
		SETB TR0;
		LAGAIN: 
		JNB TF0, LAGAIN;
		CLR TR0;
		CLR TF0;
		DJNZ R4,LRPT;
		CPL P1.4;
		DJNZ R3,BL;
		SJMP led4;

INITIAL:
DEC R0
CJNE R0,#0,ONloop             ; comparing the value of the register bank
reti;

ONloop:
ACALL DISPLAY1
		LOP:
		clr p1.5;
		setb p1.4
		mov R3,#4;
		BLINK:
		MOV R4,#30;              LOOP FOR REPEATING COUNT
		RPT:                   ;2 sec DELAY
		MOV TL0,#0H;
        MOV TH0,#0H;
		SETB TR0;
		AGAIN: 
		JNB TF0, AGAIN;
		CLR TR0;
		CLR TF0;
		DJNZ R4,RPT;
		CPL P1.5;
		DJNZ R3,BLINK;
		SJMP led4;

TRANS:
MOV SBUF, A;
JNB TI,$
CLR TI
ret

DISPLAY1:                   ;displays ON
MS:DB 13,10,"ON",10,13,0
setb p1.4
MOV DPTR,#MS;
MOV R2,2
dis:
CLR A
MOVC A,@A+DPTR;
acall TRANS
INC DPTR;
DJNZ R2, dis
SJMP LOP
	
OFFloop:
ACALL DISPLAY2
ACALL LOP
LJMP CHECK;

DISPLAY2:
CLR A
setb p1.4
MOV DPTR,#MS1;
MOV R2,3
dis1:
CLR A
MOVC A,@A+DPTR;
acall TRANS
INC DPTR;
DJNZ R2, dis1
ljmp CHECK
		
	MS1:DB 13,10,"OFF",10,13,0

END

further more, it runs the routine once and takes the interrupt, prints "on" followed by random symbols and then goes back to the routine but fails to read the interrupt for the second time
 

Getting closer... but the program structure still doesn't look right.

Consider structure like this:
Code:
ORG 000H
sjmp  Main         ;jump to start of main code
ORG 003H
ajmp Int0ISR      ;jump to the INT0 ISR routine
ORG 00BH
ajmp TimerISR   ;jump to the timer ISR routine

Main:
< code to initialize registers goes here >
Loop:
< code to be repeated goes here >
sjmp Loop           ;go back to the start of Loop again

Int0ISR:
< code to process INTO goes here >
reti                     ;return back to code before the ISR was triggered

TimerISR:
< code to process timer interrupt goes here >
reti                     ;return back to code before the ISR was triggered

So the ORGs are only used to locate the jumps to the ISR routines.
All ISR code MUST end with 'reti' and all subroutines MUST end with 'ret'. If you jump out of a subroutine it leaves the return address on the stack and subsequent POP instructions will return the wrong value. In your present code you 'ACALL' DISPLAY1 which flows into DISPLAY2 then jumps back to MAIN so each time it executes a new value is written to the stack and it will eventually crash. If you ACALL a routine it has to finish with 'reti' not a jump.

Brian.
 
  • Like
Reactions: hsa.a

    hsa.a

    Points: 2
    Helpful Answer Positive Rating
so i did ret and reti the sub routines and the interrupts but this way it never returns from the "LOP" loop. for this very reason i hadi applied sjmp instead of ret or reti command.
Code:
ORG 000H
SJMP CHECK;

org 003H;
	AJMP INITIAL
	
ORG 000BH;                     interrupt TIIMER routine
		ajmp timer
		
ORG 0030H
	CHECK:
MOV TMOD,#29H;                ;TR1 M2 / TM0-CT0 M1   
MOV IE,#10000011B; 
MOV TH1,#0FDH;	              ;9600BAUD RATE, ,8-BIT,1-STOP BIT;;;;;;;;;;;;;;
MOV SCON,#50H                 ;01010000b
SETB TI;                      ; TRANSMIT BIT HIGH, TRANSMITS WHEN LOW
setb TR1;

MS:DB 13,10,"ON",10,13,0
MS1:DB 13,10,"OFF",10,13,0
	
loop:        
MOV R0,2                      ;LOADING THE VALUE FOR THE INTERNAL INTERRUPT COUNTER
led4:
		clr p1.4
		setb p1.5;
		mov R3,#4;
		JNB INT0,INITIAL;
		BL:
		MOV R4,#15;             ;LOOP FOR REPEATING COUNT
		LRPT:                   ;MAX DELAY
		MOV TL0,#0H;
        MOV TH0,#0H;
		SETB TR0;
		JNB INT0,INITIAL;
		LAGAIN: 
		JNB TF0, LAGAIN;
		CLR TR0;
		CLR TF0;
		DJNZ R4,LRPT;
		CPL P1.4;
		DJNZ R3,BL;
		JNB INT0,INITIAL;
		SJMP check;

INITIAL:
dec r0
cjne R0,#1,OFFloop     
acall ONloop;
reti

ONloop:
ACALL DISPLAY1
		LOP:
		clr p1.5;
		setb p1.4
		mov R3,#4;
		BLINK:
		MOV R4,#30;              LOOP FOR REPEATING COUNT
		RPT:                   ;2 sec DELAY
		MOV TL0,#0H;
        MOV TH0,#0H;
		SETB TR0;
		AGAIN: 
		JNB TF0, AGAIN;
		CLR TR0;
		CLR TF0;
		DJNZ R4,RPT;
		CPL P1.5;
		DJNZ R3,BLINK;
		ret

TRANS:
MOV SBUF, A;
JNB TI,$
CLR TI
ret

OFFloop:
ACALL DISPLAY2
ACALL LOP
reti

DISPLAY2:
CLR A
setb p1.4
MOV DPTR,#MS1;
MOV R2,3
dis1:
CLR A
MOVC A,@A+DPTR;
acall TRANS
INC DPTR;
DJNZ R2, dis1
ret
		
DISPLAY1:                   ;displays ON
setb p1.4
MOV DPTR,#MS;
MOV R2,2
dis:
CLR A
MOVC A,@A+DPTR;
acall TRANS
INC DPTR;
DJNZ R2, dis
ret

timer:
        PUSH ACC;
		SETB P1.4;
		SETB P1.5;
		POP ACC;
		RETI;

END


Also on pressing the interrupt button first time, it doesnt print "ON" and runs the LOP loop and hangs. subsequently when i press the button for the second time it prints "OFF" with alot of garbage values and then again hangs in LOP loop.
 
Last edited:

You still haven't understood how interrupts and subroutines work. They are similar but a subroutine is called by an instruction in your program and an interrupt is called by a hardware condition. The assembler works out a subroutine address because it keeps track of where the instructions are placed, interrupts have fixed addresses so they need the ORG to put them in the correct place.

When an a subroutine is called, the address it was called from is saved so that when it has finished (ret instruction) the program flow can resume from where it was before. An interrupt is exactly the same but when it finishes (reti instruction) it not only resumes from the place it was triggered, it also resets the interrupt so it can be used again. In both situations, the address to go back to is saved by the MCU.

Look at your code flow:
1. you arrive at 'loop:', presumably by executing the instructions before it as no instructions jump to it.
2. a few lines later, you 'JNB INT0,INITIAL;' which, if the INT0 bit is set, jumps to 'INITIAL'. So the program continues running from the place labelled 'INITIAL' in your code.
3. at the end of 'INITIAL' you 'reti' to end the interrupt.

So think where the code goes back to after the 'reti'. It tries to resume form the address it saved when the interrupt occurred - but no address was saved so it jumps to a random address.

Brian.
 
  • Like
Reactions: hsa.a

    hsa.a

    Points: 2
    Helpful Answer Positive Rating
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top