| View previous topic :: View next topic | 
	
	
		| Author | Message | 
	
		| bdivi 
 
 
 Joined: 26 Sep 2005
 Posts: 3
 
 
 
			    
 
 | 
			
				| Jump out of while(1) on interrupt |  
				|  Posted: Mon Sep 26, 2005 2:27 am |   |  
				| 
 |  
				| Hello, 
 I am writing a program for PIC16 to measure a number of counter related things (freq, period, capacitance, etc.) but I am stuck at managing the button events and change system states. Down is the sample code.
 I want to jump to the beginning of the measurement cycle on button press and initiate according to the new state not waiting for measurement to complete (some may take 10 sec). Without the goto_address() it changes the state properly but I have to wait for the counting cycle to finish. With the goto_address() it does not seem to do anything. Any help is appreciated.
 
  	  | Code: |  	  | #int_rb
 void button_interrupt() {
 disable_interrupts(GLOBAL);
 if (input(PIN_B5)==0){
 // debounce
 currentState++;}      // to next state
 
 else if (input(PIN_B6)==0){
 // debounce
 if (currentState==cap || currentState==ind)
 lc_calibrate();}
 
 else if (input(PIN_B7)==0){
 // debounce
 if (currentState==cap)
 cap_null();
 else if (currentState==ind)
 ind_null();}
 
 enable_interrupts(GLOBAL);
 goto_address (label_address(measureCycle));
 }
 
 void main() {
 lcd_init();
 system_test();
 
 currentState = freq1s; // this is the initial state
 
 enable_interrupts(INT_RB);
 enable_interrupts(GLOBAL);
 
 measureCycle:
 
 while(TRUE)
 {
 switch (currentState){
 case freq01s:
 frequency = pulse_count (ms100);
 display_on_LCD (frequency, gate01s);
 break;
 case freq1s:
 frequency = pulse_count (ms1000);
 display_on_LCD (frequency, gate1s);
 break;
 case freq10s:
 frequency = pulse_count (ms10000);
 display_on_LCD (frequency, gate10s);
 break;
 case period:
 period = measure_period()
 display_on_LCD (period);
 break;
 }
 }
 }
 | 
 |  | 
	
		|  | 
	
		| Mark 
 
 
 Joined: 07 Sep 2003
 Posts: 2838
 Location: Atlanta, GA
 
 
			      
 
 | 
			
				|  |  
				|  Posted: Mon Sep 26, 2005 6:27 am |   |  
				| 
 |  
				| The interrupt handler saves working registers when it enters the isr.  These registers are then restored when leaving the isr.  This code 
 will trash those registers.  In addition, the return address from when the isr was called will be left on the hardware stack.  This will also cause you problems. 	  | Code: |  	  | enable_interrupts(GLOBAL); goto_address (label_address(measureCycle));
 
 | 
 |  | 
	
		|  | 
	
		| bdivi 
 
 
 Joined: 26 Sep 2005
 Posts: 3
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Mon Sep 26, 2005 6:46 am |   |  
				| 
 |  
				| Yes, I can understand the issue. 
 The question here is how to work it out - I have no problems loosing the W register and the program counter. I just want to trash them and start over from a specific point. I will take care of reinitializing the registers.
 
 Thanks anyway for the help.
 |  | 
	
		|  | 
	
		| Mark 
 
 
 Joined: 07 Sep 2003
 Posts: 2838
 Location: Atlanta, GA
 
 
			      
 
 | 
			
				|  |  
				|  Posted: Mon Sep 26, 2005 7:03 am |   |  
				| 
 |  
				| You could use the watchdog. 
 Set your state in the ISR
 Timeout the watchdog in the ISR
 On startup, check for the wdt and bypass and intial startup code (initializations) and go to your state machine.
 |  | 
	
		|  | 
	
		| bdivi 
 
 
 Joined: 26 Sep 2005
 Posts: 3
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Mon Sep 26, 2005 8:49 am |   |  
				| 
 |  
				| So it is efectively reseting the PIC. I have two questions here: 
 1. Can I use the reset_cpu() instead?
 2. How I preserve the system state after reset? Is the RAM sufficient or I use the EEPROM?
 |  | 
	
		|  | 
	
		| Mark 
 
 
 Joined: 07 Sep 2003
 Posts: 2838
 Location: Atlanta, GA
 
 
			      
 
 | 
			
				|  |  
				|  Posted: Mon Sep 26, 2005 9:31 am |   |  
				| 
 |  
				| On a wdt the RAM should not be affected.  You would not be able to use the #zero_ram CCS option though.  This would kill any values that have been stored.  Also, any values that need to survive the reset cannot be initialized in their declaration.  You will need to do this in the main().  You will need to test to see if the wdt caused the reset.  If so, then do NOT initialize the variables since this would destory their values.  The reset_cpu() could be used on a PIC18 since you can test to see the cause of the reset.  On the PIC16, you would need to set a flag or save an eeprom value to determine that you reset via code.  You could use the POR (power on reset) flag to do this.  Any reset that is not caused by a power on reset could be used to switch your task.  Read the section in the datasheet about the POR. |  | 
	
		|  | 
	
		|  |