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.

How to reduce LedTimer after interrupt ?

Status
Not open for further replies.

bianchi77

Advanced Member level 4
Advanced Member level 4
Joined
Jun 11, 2009
Messages
1,313
Helped
21
Reputation
44
Reaction score
20
Trophy points
1,318
Location
California
Visit site
Activity points
9,442
Guys,

I want to reduce LedTimer after interrupt but it returned to 20 again after interrupt,
Do you have idea how handle it ?
thanks
Code:
LedTimer EQU .20 ;10 decimal (for content of the counter to get 100ms)

	led_state_1
				bcf     INTCON,T0IF             ;clear the interrupt flag
				bsf  	PORTB, POWERLED 		;Turn on LED
		    movlw LedTimer
				movwf COUNT
	      
		  
		  ;counting 	 
                     
		 check_counter
						btfss INTCON,T0IF
            goto  check_counter
                       
					 
					 sublw .1
					 btfss STATUS, Z		;Is the result 0, clear COUNT
					 

           goto  check_counter	 ;if false check the COUNTER again
					 goto  next_state        ;if true  go to this statement

					 
		
		next_state	
					clrf    COUNT			 ;if false go to this statement
					incf    LedState,1			; if 00 increase the state, for the next state               
				    
					return
 

Hi,

Your sublw.1 does just that, subracts 1 from whatever was in W, hard to tell if that was COUNTs value without seeing all your code.
The thing is, the result of sublw is saved in W , not in COUNT so it is never reduced.

Use this instruction instead.

Code:
 check_counter
			        btfss INTCON,T0IF
            			goto  check_counter
                       					 
			       decfsz	COUNT,F			; decrement Count and save result in File Count
					 				; skip the next insrtuction if the Count become Zero

       			      goto  check_counter	        ;if false check the COUNTER again
					 goto  next_state        ;if true  go to this statement
 

How can it decrement by itself if there's interrupt without using decfsz COUNT,F ?

first file :
Code:
  LIST P=16F628A
  #include p16f628A.inc
  #include globals.inc
 
 extern TimerInt
 
;-------------------------------------------------------------------------------
BANK0 UDATA
;-------------------------------------------------------------------------------
;..... your variables here ....
LedState 	RES	1
COUNT		RES 1   
COUNT1      RES 1
 
;-------------------------------------------------------------------------------
PROG0	CODE
;-------------------------------------------------------------------------------

LEDManager
 GLOBAL LEDManager
 

                 LedTimer set .20
               movf    LedState,w
			   			addwf   PCL,f	
               goto    led_state_1
			   			goto    led_state_2 
		;...... your state machine here ......
		led_state_1
				bcf     INTCON,T0IF             ;clear the interrupt flag
				bsf  	PORTB, POWERLED 		;Turn on LED
          movlw LedTimer
					movf COUNT,W
	      
		  
                     
		 check_counter
					 btfss INTCON,T0IF
           goto  check_counter
                       
					 decfsz	COUNT,F			; decrement Count and save result in File Count		
					 

                     goto  check_counter	 ;if false check the COUNTER again
					 goto  next_state        ;if true  go to this statement

		
		next_state	
					clrf  COUNT			 ;if false go to this statement
                incf    LedState,1			; if 00 increase the state, for the next state               
				    
					return
        ;led_state_1 end

		;led_state_2 begin		
		led_state_2
					bcf     INTCON,T0IF				;clear the interrupt flag
           			bcf		PORTB, POWERLED         ;Turn off LED
			       
					;movf 	COUNT,W ; load value to W , Status register bit Zero is altered according to value
					movlw LedTimer
					;call COUNT	
					movwf COUNT
					;movf COUNT1,W 
		;count for how many interrupts for the next state

       
	       check_counter2 
	 				 ;check if COUNT = 2 ? if COUNT equal to 2 then go to the next state! let's jump 16F648A!
		             ;COUNTER is inside working register now, wait until W = 10 then go to next state	
                      ;subwf COUNT, W		  ;give a test
					  ;sublw .1
					  decf COUNT			  ;	
					  btfss STATUS, Z		  ;Is the result 0

                      goto  check_counter2 	  ;if false go to this statement
					  goto  next_state2        ;if true  go to this statement

		;counting1 	 ;decf	LedTimer,1          ;if T0IF=true reduce the counter
                     ;btfsc 	STATUS, Z 			; Z bit is set to 1 if W was 00 - skip next instruction if not 00
		     	     ;COUNT=0			         
					 ;goto   next_state2      	;from btfsc if it's 1, go to next state
                     ;COUNT!=0
					 ;goto   counting1			;from btfsc if it's 0 keep counting

         next_state2   
						clrf  	COUNT			 ;if false go to this statement
						decf    LedState,1			; if 00 increase the state, for the next state               
                       ;btfss INTCON,T0IF
					   ;goto   led_state_2  
			    	   ;movlw 	.10   				; reload value of content working register			
					   ;movwf   COUNT_TIMER          ;load the working register into file register
						

				;btfsc 	STATUS, Z 					; Z bit is set to 1 if W was 00 - skip next instruction if not 00
     			; if 00 decrease the state, for the next state
 				;decf 	COUNT_TIMER 		; if not 00 carry on here 
				;movlw 	LedTimer   			;reload of content of LedTimer				
				return
		;led_state_2 end
			
   return ;LEDManager

;function decrement led timer with counter ==>begin
;if led timer is not zero, then decrement the timer
;how  can I call it from timer.asm ?

   ;goto led_state_1

			
;function decrement led timer with counter ==>end
		END
second file :
Code:
;
;
;	File: timer.ASM
;

	list	p=16f628A
	#include p16f628A.inc
	#include globals.inc
	
	;external routines that are needed
	;extern LEDManager
	;extern	led_state_1
	;extern  led_state_2
	;extern led_state
   

;------------------------------------------------------------------------------
BANK0	UDATA
;------------------------------------------------------------------------------
COUNT		RES	1	;COUNT OF INTERRUPTS
COUNT1		RES	1	;COUNT FOR  1 SECOND TIMER


;------------------------------------------------------------------------------
PROG0		CODE			; program code section
;------------------------------------------------------------------------------
TimerInt 	; Interrupt routine

		global TimerInt		; Define as global 

;intsOff		bcf INTCON, T0IE	;Disable timer interrupts
            bsf INTCON, T0IE    ;Enable timer interrupts
			bcf INTCON, T0IF    ;clear interrupt flag
            bsf INTCON, GIE     ;Enable global interrupt
	
;-------------- Insert no new code above here ---------------------------------
	 
        	
		;*********************************************************************
		; 1 ms timer function calls
		;*********************************************************************
		bcf  STATUS, RP0		;Select Bank 0
		bcf  STATUS, RP1	

		;....... 1ms  timer counter here.....		

	;	clrf TMR0 ;Clear TMR0 and prescaler
	;	banksel TMR0
	;	;movlw 0xB2 ;Count=B2  ;I  get 2.00ms on stopwatch
    ;   movlw .217            ; 0xD9 for getting 1ms
	;	movwf TMR0
				
     
       	
	    ;test toggle LED here...
        ;bcf  	PORTB, POWERLED 		;Turn off LED 

;         movf COUNT,W ; load value to W , Status register bit Zero is altered according to value
;counting btfsc 	STATUS, Z 			;Z bit is set to 1 if W was 00 - skip next instruction if not 00
;		 ;LedTimer=0
;		 nop 						;from btfsc if it's 1, do nothing for a test
;         ;LedTimer!=0
;		 goto   counting

		;....................................
	
		incf  COUNT, f
		movlw  .10		;Compare count to 10 decimal
		;movlw  .2		;Test with .2 decimal ?
		subwf COUNT, W		;Store the result back in 
		;how can I take this COUNT variable into LedMgr and use it for a loop?
		
		btfss STATUS, C		;Is the result 0, skip if no
        ;goto led_state_1
        ;goto LEDManager ;it can be called and simulation is running
        		

		goto  exittimer

		clrf COUNT		;Clear count register
       
		;**********************************************************************
		; 10ms timer function calls
		;**********************************************************************
		;....... 10ms  timer counter here.....	
		;
        ;test toggle LED off here...
		;bcf  	PORTB, POWERLED 		;Turn off LED 
		
		;....................................

    	incf    COUNT1, f
		;movlw .1 				;Compare count to 1 decimal to give a test!
		movlw   .10			    ;Compare count to 100 decimal
		;movlw  .50				;Probe with 50 decimal will give me 1.007388 second on nop Line 94
		subwf   COUNT1, W		;Store the result back in 
		btfss   STATUS, C		;Is the result 0, skip if no
		;goto state1 ?
       
   		;check how many COUNT of interrupts
      	 
;		movlw  0x64       	    ;load 100 interrupt for a test
;        movwf  CNT_T0            ;load the LedTimer into file register  
;over	btfss  INTCON,T0IF      ;is it true ?
;        bcf    INTCON,T0IF		;if false clear interrupt flag
;		decfsz CNT_T0           ;true
;        goto   over

		goto exittimer
		clrf 	COUNT1
		;**********************************************************************
		; 100ms timer function calls
		;**********************************************************************
		;....... 100ms  timer counter here.....		
		;
		
		
		;call that function in led manager
        
		;test toggle LED on here...
        ;bsf  	PORTB, POWERLED 		;Turn on LED 
		
        ;call count100	 
        ;goto led_state_2 
		;nop ;test with stopwatch here, how long do I get ? it's 204.728800ms
		;what different does it make ? there'll be a loop on counter ?
		;how can I see it, it seems, it's never being called or used when I ran it       
        ;how can I call my state from here ? come on.....
		;call led_state
		;goto LEDManager ;it can be called and simulation is running but not on the board
		;goto led_state_1
		;
		;
		;....................................
        
exittimer       
		movlw 	.217		;count 14
		;goto led_state 
	    ;reload the timer value
		clrf TMR0 ;Clear TMR0 and prescaler
		banksel TMR0
		movwf TMR0
		
        
        
;-------------- Insert no new code below here ---------------------------------
		bcf INTCON, T0IF	;Clear timer overflow flag
		bsf INTCON, T0IE	;Enable interrupts again
		return
;----------------------------------------------------------------------------------
;**********************************************************************************
initTimer
 Global	initTimer
	GLOBAL 	COUNT
	GLOBAL  COUNT1
	clrf	COUNT
	clrf	COUNT1
	return

   


	end
Third file :
Code:
 LIST P=16F628A
 #include p16f628A.inc
 #include globals.inc


 extern Start,TimerInt
;---------------------------------------------------------------------
shareA 	UDATA_SHR
;---------------------------------------------------------------------
W_TEMP 	RES 	1
;---------------------------------------------------------------------
BANK0 	UDATA
;---------------------------------------------------------------------
PCLATH_TEMP	RES	1
STATUS_TEMP RES	1
FSR_TEMP 	RES	1
;---------------------------------------------------------------------
STARTUP CODE
;---------------------------------------------------------------------

       	goto	Start			; Reset Vector
		nop
		nop
		nop
		movwf 	W_TEMP			; Save State
		SWAPF 	STATUS,W
		BANKSEL	STATUS_TEMP
		movwf 	STATUS_TEMP		; save STATUS
		movf	FSR,w
		movwf	FSR_TEMP		; save FSR 
		movf	PCLATH,w
		movwf	PCLATH_TEMP
;******************************************************************************
		call	TimerInt
;******************************************************************************
		BANKSEL	PCLATH_TEMP
		movf	PCLATH_TEMP,w
		movwf	PCLATH
		movf  	FSR_TEMP,w
		movwf	FSR
		swapf 	STATUS_TEMP,W		; Restore State
		movwf 	STATUS
		swapf 	W_TEMP,F
		swapf 	W_TEMP,W
		retfie
;---------------------------------------------------------------------
	END
 

Hi,

Your code is not easy to follow and looking back at your previous posts you have been doing bits of the problem for some time.

However I'm still not clear exactly what you are trying to do as a complete program - can you expand a little more ?

Also you seem to be using relocatable code which makes things more complicated than it needs to be, I would think it could all be done in a much simpler way, but cannot suggest what to do until I understand your objectives.
 

my purpose is creating state machine base on timer0 interrupt, for a test state1 = turn on LED state2 = turn off LED, but I'm using interrupt between state...
I can give you the complete project if you want to understand...

- - - Updated - - -

That's the complete files
 

Attachments

  • LED.rar
    3.8 KB · Views: 96

That code formatting is very difficult to read!

I would suggest you remove ALL the code from the ISR except for the check for TMR0 being the source and decrementing COUNT, personally I would also add ORG 0x004 to absolutely locate the ISR and move all the ISR code into one block to save an extra stack level being used.

Then in the main code I would do the 'state' checking and reset COUNT as necessary. As a general rule - keep ISRs as short as possible and do all your processing in the main part of the program.

Brian.
 

Hi,

Sorry for delay, have been out all day.

attached are two examples in Absolute Mode.

One uses the TM0 IF only , the other uses the full ISR which may seem a more complex way, but as your Main code become more complex you will see its advantages.


When you Build this code, it should work or ask you if its to be run as Absolute or Relocatable code - say Absolute.
If neither work properly, then in manually change the setting -PROJECT, BUILD OPTIONS, MPASM SUITE -SELECT ABSOLUTE

The code also sets the chip to use its 4mhz internal oscillator, which is the base for the timer 0
That gives 65ms through Timer0 and 16 seconds when run though COUNT if its set to .255 - You can see the pictures from MPLABs SIMulator where I have timed them.

As you can see the code is so much simpler this way, relocatable is realistically only for very complex code.

Shout if it does not work ..
 

Attachments

  • timer0.7z
    98.9 KB · Views: 93

Hi,

Were you able to open those files ok ? - could you see how they work and how you can use them ?
 

I can open it but it's not working....

- - - Updated - - -

I'll send my file so you can have a look, how can I check my counter already zero and jump to the next state,
is it like this ?
Code:
led_state_1	
				;call 	counter
	            movf    COUNT
				 ; Now you can check the Z flag:
				btfsc  STATUS,Z
				goto   next  ; Counter is zero...
				nop          ; Counter is non-zero...
				bsf  	PORTB, POWERLED ;Turn on LED
			    	
				
	next		incf     LedState,1		 ;increase the state, for the next state

- - - Updated - - -

Please have a look on the file I have, I can't change it, since I can only add to the frame there...
 

Attachments

  • timer.zip
    2.1 KB · Views: 81

I spent about 30 minutes trying to work out what your code is supposed to do - and failed miserably. It looks to be the worlds most complicated LED flasher but it has so many strange constructs i gave up trying to work it out.

I can tell you that you used the wrong linker script and you have labels in the wrong columns and a strange mix of 'banksel' and bank setting instructions. I can't see any trace of a valid interrupt routine although you do seem to expect one and it certainly isn't present in the hex file. I'm also confused why you use binary numbers to set register bits when you can use the bit names.

Before going further:
1. please explain exactly what it is supposed to do?
2. what clock speed and configuration are you using?
3. what version of MPLAB are you using? (latest and sadly final version is 8.91)
4. does it have to be relocatable code?
5. what 'tab' setting are you using in the editor, the columns are all over the place.
6. confirm you are actually using a 16F628A (the linker is set to 16F628 - the non 'A' version)

Brian.
 

Hi,

The two files I sent did work but the ISR one seems to be missing a line of code so does not work ?? - have just re run it on two simulators and it does work ok.

It also answers you question on how to check if a file is Zero.


As I said earlier and Betwixt has just re-iterated in greater detail neither of us can understand your current code and is relocatable style.

Given that you are using a reasonabley recent version of MPlab , think we are both saying you should really restart your code using the Absolute method with the simpler code show below.

Unless you are doing this for work or college and have been told you must use object modules and linker ?

Code:
;**********************************************************************

	list      p=16f628A           ; list directive to define processor
	#include <p16F628A.inc>       ; processor specific variable definitions

	errorlevel  -302              ; suppress message 302 from list file

	__CONFIG   _CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_ON & _WDT_OFF & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT 
;     This Config  line selects the chips Internal 4mhz oscillator



	cblock	0x020				; user variables
	LEDSTATE
	COUNT	
	COUNT1
	endc

	cblock	0x70				; variables in Access area for ISR
	w_temp            	 	    ; variable used for context saving 
	status_temp     		    ; variable used for context saving
	endc



;**********************************************************************
	ORG     0x000             ; processor reset vector
	goto    main              ; go to beginning of program
	

	ORG     0x004             ; interrupt vector location
	movwf   w_temp            ; save off current W register contents
	movf	STATUS,w          ; move status register into W register
	movwf	status_temp       ; save off contents of STATUS register

	btfss  INTCON,T0IF	 	  ; Make sure it is Timer0 that has Flagged up
	goto	isrend		      ; not tmr0 overflow - error - go back
		 
	bcf		INTCON,T0IF	      ; Clear it Interrupt Flag 
	decf	COUNT,F		  ; decrement COUNT


isrend
	movf    status_temp,w     ; retrieve copy of STATUS register
	movwf	STATUS            ; restore pre-isr STATUS register contents
	swapf   w_temp,f
	swapf   w_temp,w          ; restore pre-isr W register contents
	retfie                    ; return from interrupt


main
	clrf	PORTA		      ; Set up all I/O ports as outputs
	clrf	PORTB
	movlw 	0x07	
	movwf	CMCON			  ; turns off Comparator
	banksel TRISA	
	clrf	TRISA
	clrf	TRISB


	movlw	B'10000111'  		; set up timer0 , bits 0-2 prescaler 1:256,  bit3 prescaler to Timer 0,  PortB Pull ups disabled 
	movwf	OPTION_REG		 	; Timer 0 is now running !
	banksel 0					; return to bank 0	
								 
								; the timing formula for TMR0
								; oscillator 4meg/ 4 = 1meg processor cycle.
								; timer0 prescaler 1,000,000 / 256
								;  
								


		movlw	d'255'			; load count with the delay multiplier
		movwf	COUNT


tm0start
		clrf	TMR0			; clear Timer0 register so it starts counting from 0
		bcf		INTCON,T0IF		; Clear the TMR0 Flag, When its Full it SETS its Flag to let the system know the count is up.
		bsf     INTCON,T0IE               ; ENABLE TIMER0 INTERRUPT
		BSF 	INTCON,GIE	   		; ENABLE GLOBAL INTERRUPTS



		

again	movfw	COUNT		; run you maion code here, testing for when COUNT is Zero
		btfss	STATUS,Z
 		goto	again			; not Zero

set_output						;YES is Zero so set you outputs etc. then repaet the countdown routine.

		bsf		PORTB,0			; TURN ON LED	

LOOP	GOTO	LOOP





	END                       ; directive 'end of program'
 

I spent about 30 minutes trying to work out what your code is supposed to do - and failed miserably. It looks to be the worlds most complicated LED flasher but it has so many strange constructs i gave up trying to work it out.

I can tell you that you used the wrong linker script and you have labels in the wrong columns and a strange mix of 'banksel' and bank setting instructions. I can't see any trace of a valid interrupt routine although you do seem to expect one and it certainly isn't present in the hex file. I'm also confused why you use binary numbers to set register bits when you can use the bit names.

Before going further:
1. please explain exactly what it is supposed to do?
2. what clock speed and configuration are you using?
3. what version of MPLAB are you using? (latest and sadly final version is 8.91)
4. does it have to be relocatable code?
5. what 'tab' setting are you using in the editor, the columns are all over the place.
6. confirm you are actually using a 16F628A (the linker is set to 16F628 - the non 'A' version)

Brian.
Dear Brian,

Thank you very very much for helping and spending your time for it,
Yes it is the most difficult LED flasher I have ever had in my life, so twisty and gave me headache already.

Let me answer your question...
===============
1. please explain exactly what it is supposed to do?
It's supposed to be turning on and of the LED in the state, and the delay is the timer0 and counter, I set timer0 to have overflow in every 1ms, and the counter will do 100 times for having 100ms.

2. what clock speed and configuration are you using?
20Mhz clock and HS configuration, other stuffs in configuration are disabled.

3. what version of MPLAB are you using? (latest and sadly final version is 8.91)
I'm using 8.84

4. does it have to be relocatable code?
It doesn't matter, I have no idea about it.

5. what 'tab' setting are you using in the editor, the columns are all over the place.
I'm not using tab setting, how can I use it ? it's another experience that I can get.

6. confirm you are actually using a 16F628A (the linker is set to 16F628 - the non 'A' version)
I'm using 16F648A.
 

Hi,

OK, now we know what you are trying to achieve the example I posted is virtually all you need.

I have changed it to use the 48A chip with a HS 20 meg crystal and it turns PORTB,0 on and off every 100 ms.

Thats all the code you need - as simple as that.

A few things to note, why use an external crystal when the chip has a good internal oscillator ?
Timer0 cannot create an exact 1ms delay with 20 or 4 mhz so Count is used to help produce 100ms.

A led flashing at 100ms may not be clearly visible, it might just glow, perhaps better to slow things down to 250ms which can be seen by the eye.



Code:
;**********************************************************************

	list      p=16f648A           ; list directive to define processor
	#include <p16F648A.inc>       ; processor specific variable definitions

	errorlevel  -302              ; suppress message 302 from list file

	__CONFIG   _CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC




	cblock	0x020				; user variables
	LEDSTATE
	COUNT	
	COUNT1
	endc

	cblock	0x70				; variables in Access area for ISR
	w_temp            	 	    ; variable used for context saving 
	status_temp     		    ; variable used for context saving
	endc



;**********************************************************************
	ORG     0x000            	 ; processor reset vector
	goto    main                 ; go to beginning of program
	

	ORG     0x004            	 ; interrupt vector location
	movwf   w_temp           	 ; save off current W register contents
	movf	STATUS,w         	 ; move status register into W register
	movwf	status_temp     	 ; save off contents of STATUS register

	btfss  INTCON,T0IF	 	 	 ; Make sure it is Timer0 that has Flagged up
	goto	isrend		     	 ; not tmr0 overflow - error - go back
		 
	bcf		INTCON,T0IF	     	 ; Clear it Interrupt Flag 
	decf	COUNT,F		  	  	 ; decrement COUNT


isrend
	movf    status_temp,w   	; retrieve copy of STATUS register
	movwf	STATUS          	; restore pre-isr STATUS register contents
	swapf   w_temp,f
	swapf   w_temp,w         	; restore pre-isr W register contents
	retfie                   	; return from interrupt


main
	clrf	PORTA		     	; Set up all I/O ports as outputs
	clrf	PORTB
	movlw 	0x07	
	movwf	CMCON			 	; turns off Comparator
	banksel TRISA	
	clrf	TRISA
	clrf	TRISB


	movlw	B'10000011'  		; set up timer0 , bits 0-2 prescaler 1:16,  bit3 prescaler to Timer 0,  PortB Pull ups disabled 
	movwf	OPTION_REG		 	; Timer 0 is now running !
	banksel 0					; return to bank 0	
								 
								; the timing formula for TMR0
								; oscillator 20meg/ 4 = 5meg processor cycle.
								; timer0 prescaler 1;16  = 0.0008ms
								; x count of .122  = 1ms (almost)
								


		movlw	d'122'			; load count with the delay multiplier
		movwf	COUNT


tm0start
		clrf	TMR0			; clear Timer0 register so it starts counting from 0
		bcf		INTCON,T0IF		; Clear the TMR0 Flag, When its Full it SETS its Flag to let the system know the count is up.
		bsf     INTCON,T0IE
		BSF 	INTCON,GIE	   	; ENABLE GLOBAL INTERRUPTS



		

again	movfw	COUNT			; run you maion code here, testing for when COUNT is Zero
		btfss	STATUS,Z
 		goto	again			; not Zero

set_output						;YES is Zero so set you outputs etc. then repaet the countdown routine.

		movlw    B'00000001'    ;toggle PORTB,bit0
		xorwf    PORTB,F

		movlw	d'122'			; Re load count with the delay multiplier
		movwf	COUNT

		goto	again			;restart countdown loop
		




		END                       ; directive 'end of program'
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top