How to switch between programs using ISR

Status
Not open for further replies.

sohagiut

New Member
I am using PIC18f4620 and MPLAB. instead of doing each 'built' and 'program' and downloading the code in the PIC i want to write a program containing 3 individual program (i may call it as a 'case') inside my main program. after 'programming' i just want to press 3 individual button from the keyboard to switch between them. how this can be written inside the ISR? the pc will be interfaced with PIC using a serial port connection.

Here is the code that contains 3 different TEST, but i can use once at a time. i just want to avoide multiple programming and exploite the benefit of ISR.



Code:
#include "UARTIntC.h"
#include "delays.h"

#include <p18f4620.h>


/*---------------------------------*/
/* Interrupt routine
/*---------------------------------*/

void low_isr(void);

// serial interrupt taken as low priority interrupt
#pragma code uart_int_service = 0x08
void uart_int_service(void)
{
	_asm	goto low_isr	_endasm
	
}
#pragma code

#pragma	interruptlow low_isr save=section(".tmpdata")
void low_isr(void)
{	
	// call of library module function, MUST
	UARTIntISR();
}

void main(void)
{
	// Test data array
	unsigned char cArray[10]
	   = { 'A','B', 'C', 'D', 'E', 'F', 'G','H','I' , 'J'};
	
	// temporary local array	   
	unsigned char writtenArray[10];
	
	// local variables for all test cases and their initialisation
	unsigned char chData;
	unsigned char *pReadArray;
	unsigned char *pWriteArray;
	unsigned char j = 0;
	unsigned char i  = 0;
	unsigned char l = 0;
	unsigned char k = 0;			
	pReadArray = pWriteArray = writtenArray;	


	// call of library module , MUST
	UARTIntInit();	


//	TEST 1
//  Chunk of 30 characters can be sent from PC to micro-controller.
//  Each received character at micro-controller is read and immediately 
//	sent back to PC.
	/*
	
	while(1)
	{
		while(!vUARTIntStatus.UARTIntRxBufferEmpty)
		{
			UARTIntGetChar(&chData);			
			if(!vUARTIntStatus.UARTIntTxBufferFull)
				UARTIntPutChar(chData);
		};
	};

	*/


//	TEST 2
// 	Chunk of data is sent from PC to micro. Data received at micro is
//	read in to temporary buffer. The data is immediately sent back to 
//  PC. Usage of pointers is displayed in below example
	/*
	
	while(1)   
	{		   
		l = 0;
		l = UARTIntGetRxBufferDataSize();	
		while(l > 0)
		{
			if(UARTIntGetChar(pWriteArray))
			{				
				if(!vUARTIntStatus.UARTIntTxBufferFull)
				    UARTIntPutChar(*pWriteArray);
				l--; pWriteArray++;
				if(pWriteArray == (writtenArray + 10))
					pWriteArray = writtenArray;
			}
		}
	}
		
	*/
	

//	TEST 3
// 	Chunk of data is sent from PC to micro. Data received at micro is
//	read in to temporary buffer. The data is sent back to PC. Here 
//  reception and transmission is done independently.
	
	
	
	while(1)   
	{					   
		l = 0;
		l = UARTIntGetRxBufferDataSize();	
		while(l > 0)
		{
			if(UARTIntGetChar(pReadArray))
			{				
				l--; pReadArray++;
				if(pReadArray == (writtenArray + 10))
					pReadArray = writtenArray;
			}
		}		
		if((pWriteArray < pReadArray) || ((pWriteArray - pReadArray) == 9 ))
		{  
			if(!vUARTIntStatus.UARTIntTxBufferFull)
			{
				UARTIntPutChar(*pWriteArray);
	    		i--; pWriteArray++;
 			    if(pWriteArray == (writtenArray + 10))				  			
					pWriteArray = writtenArray;		
			}
		}									
	}
	
	
	
	
}
 
Put your buttons on PORTB 4-7 which have interrupt on change.

Use a global var named curTest to indicate which test should be running.

When you press button X(1-3) have the ISR set curTest to X. All the ISR needs to do is change the value of curTest based on the button pushed.

You code now looks like this.

Code:
while(1)
{
    if(curTest==1)
    {
        // your test one code
        while(curTest==1)
	{
		while(!vUARTIntStatus.UARTIntRxBufferEmpty)
		{
			UARTIntGetChar(&chData);			
			if(!vUARTIntStatus.UARTIntTxBufferFull)
				UARTIntPutChar(chData);
		};
	};
    }
    if(curTest==2)
    {
            // your test two code
            while(curTest==2) 
           {
                ....
           }         
    }
    if(curTest==3)
    {
            // your test three code
            while(curTest==3) 
           {
                ....
           }         
    }
}
 
Last edited:
Please tell me detail how to put buttons on PORTB. It would be batter if you kindly write few lines code.
 
sohagiut said:
Please tell me detail how to put buttons on PORTB. It would be batter if you kindly write few lines code.

You will not learn much if I were to do that. And I am short on time.

Each switch will ground one bit of portb.
Each bit needs a pullup resistor between the switch and the PIC or use the internal weak pull-up by clearing the RBPU bit.

Enable the interupt on change for portb. When portb interrupts you read portb to determine which switch is active. Use that to set curTest. Clear the IF and then return from the interrupt.

You have to read the uC data sheets and the compiler info, including the .h file, for the processor.

Do the best you can and post the code.
 
i tried to make some update. please verify


Code:
#include "UARTIntC.h"
#include "delays.h"

#include <p18f4620.h>


/*---------------------------------*/
/* Interrupt routine
/*---------------------------------*/

void low_isr(void);

// serial interrupt taken as low priority interrupt
#pragma code uart_int_service = 0x08
void uart_int_service(void)
{
	_asm	goto low_isr	_endasm
	
}
#pragma code

#pragma	interruptlow low_isr save=section(".tmpdata")
void low_isr(void)
{	
	// call of library module function, MUST
	UARTIntISR();
}

void main(void)
{
	// Test data array
	unsigned char cArray[10]
	   = { 'A','B', 'C', 'D', 'E', 'F', 'G','H','I' , 'J'};
	
	// temporary local array	   
	unsigned char writtenArray[10];
	
	// local variables for all test cases and their initialisation
	unsigned char chData;
	unsigned char *pReadArray;
	unsigned char *pWriteArray;
	unsigned char j = 0;
	unsigned char i  = 0;
	unsigned char l = 0;
	unsigned char k = 0;			
	unsigned char curTest = 0;
	pReadArray = pWriteArray = writtenArray;	


	// call of library module , MUST
	UARTIntInit();
	
	TRISB = 0;
	PORTB = 0;
 
 k = 0;

	while(k < 3)

{

    if(curTest==1)
    {
        // test code 1
        while(curTest==1)
	{
		while(!vUARTIntStatus.UARTIntRxBufferEmpty)
		{
			UARTIntGetChar(&chData);			
			if(!vUARTIntStatus.UARTIntTxBufferFull)
				UARTIntPutChar(chData);
		};
	};
    }
    
    if(curTest==2)
    {
            // test code 2
            while(curTest==2) 
            
  {		   
		l = 0;
		l = UARTIntGetRxBufferDataSize();	
		while(l > 0)
		{
			if(UARTIntGetChar(pWriteArray))
			{				
				if(!vUARTIntStatus.UARTIntTxBufferFull)
				    UARTIntPutChar(*pWriteArray);
				l--; pWriteArray++;
				if(pWriteArray == (writtenArray + 10))
					pWriteArray = writtenArray;
			}
		}
	}
     }
     
   {    
			if(UARTIntGetChar(&curTest))
			PORTB = curTest;
		}
		   
    k++; 
 }
   	 
   	
}
 
what should i do if i want to see the output activity? i mean how i'll understand that the code really executing.
 
We can make you life easier. There is no good reason to use an interrupt to read the switches on portb. Poll instead. It is not complete and I did not try to compile it. They may be syntax errors and such. I did not look at the test code.

Your use of global 1 letter vars like l and k is very bad. For index vars and such it is better give them meaningful names and better yet declare them in the code block where they are used. Even it means doing it twice.


Code:
// POLLED VERSION

// switches on portb 4-7 so you can use weak pullups
#define TEST1 0x10
#define TEST2 0x20
#define TEST3 0x40
#define TEST4 0x80

unsigned char switches = 0;

int readSwitches()
{
  switches = PORTB;
}

// ....    uart init code and such

void main()
{
  while(1)
  {
    //	TEST 1
    //  Chunk of 30 characters can be sent from PC to micro-controller.
    //  Each received character at micro-controller is read and immediately 
    //	sent back to PC.
    while(switches & TEST1)
    {
      readSwitches();
      while(!vUARTIntStatus.UARTIntRxBufferEmpty)
      {
        UARTIntGetChar(&chData);			
        if(!vUARTIntStatus.UARTIntTxBufferFull)
          UARTIntPutChar(chData);
      }
    }

    //	TEST 2
    // 	Chunk of data is sent from PC to micro. Data received at micro is
    //	read in to temporary buffer. The data is immediately sent back to 
    //  PC. Usage of pointers is displayed in below example    
    while(switches & TEST2) 
    {
      readSwitches()
        l = UARTIntGetRxBufferDataSize();	
      while ((l > 0) && (switches & TEST2))
      {
        if(UARTIntGetChar(pWriteArray))
        {				
          if(!vUARTIntStatus.UARTIntTxBufferFull)
            UARTIntPutChar(*pWriteArray);
          l--; pWriteArray++;
          if(pWriteArray == (writtenArray + 10))
            pWriteArray = writtenArray;
        }
      }
    }         

    //	TEST 3
    // 	Chunk of data is sent from PC to micro. Data received at micro is
    //	read in to temporary buffer. The data is sent back to PC. Here 
    //  reception and transmission is done independently.
    while(switches & TEST3) 
    {
      l = UARTIntGetRxBufferDataSize();	
      readSwitches();
      while ((l > 0) & (switches & TEST3))
      {
        if(UARTIntGetChar(pReadArray))
        {				
          l--; pReadArray++;
          if(pReadArray == (writtenArray + 10))
            pReadArray = writtenArray;
        }
      }		
      if((pWriteArray < pReadArray) || ((pWriteArray - pReadArray) == 9 ))
      {  
        if(!vUARTIntStatus.UARTIntTxBufferFull)
        {
          UARTIntPutChar(*pWriteArray);
          i--; pWriteArray++;
          if(pWriteArray == (writtenArray + 10))				  			
            pWriteArray = writtenArray;		
        }
      }									
    }

  }

}
 
3v0 said:
Your use of global 1 letter vars like l and k is very bad. For index vars and such it is better give them meaningful names and better yet declare them in the code block where they are used. Even it means doing it twice.
I thought it was now convention to use i,j and k as general loop counters?
I.E.
Code:
     for(i=0;i<listCount;i++){
Mike.
 
I, J, K = Fortran

The "single letter" variables like I, J, K are a "programming" holdover from early Fortran (yes from the 60s). They were used because in Fortran 2, etc the variables starting with I, etc were integer variables as opposed to A, B, etc which were floating point variables.
Some folks still use them as index/counter variables. Since they get used over and over, they make names shorter.

MyDataArray = whatever;

as opposed to:

MyDataArray[dataArrayIndex] = whatever;

From this point of view, programming is an "art". So it doesn't matter as long as the code is understandable.

 
Personally, I like the single character loop variables.
Code:
    for(i=0;i<listCount;i++){
Makes more sense than,
Code:
    for(listCountCount=0;listCountCount<listCount;listCountcount++){


If you accept the convention then it is so much easier to follow code.

Mike.
 
Maybe very bad was a bit too strong.

I use single letter vars but only within a confined scope, normaly the code block where it is used. Making them global is in my viewpoint, bad. Too many people use them for things other the loop indexes and get in trouble. At best their code is difficult to read.

Code:
{
   int i;
   for (i=0; i<LIMIT; i++)
   {
   }
}
// or if the compiler supports it
for (int i = 0; i<LIMIT; i++)
{
}

// I teach my students to use idx
{
   unsigned char idx;
   for(idx=0; idx<LIMIT; idx++)
   {
   }
}
 

Thank you for that, it was really interesting to know!
 
3v0 said:
// I teach my students to use idx
Code:
{
   unsigned char idx;
   for(idx=0; idx<LIMIT; idx++)
   {
   }
}
I assume that idx is a short form of index and is only appropriate is you are using it as an index. What do you use if you need a second (inner) index? jdx? Do you also advocate cnt if it is a simple counter? And again, what for an inner counter?

I just think the simple convention of ijk would be fine if everyone used it. It just seems that academics won't accept such a simple system.

Mike.
 
I, J, K = Fortran

Mike,

Maybe the current "accamedians" won't, but their fathers did. It doesn't matter what you do, as long as it is consistent.

Programming over time is a style (as it is an art). It is only when the "science" tries to make it something it isn't.

Think of it like writing. The first paper you wrote in the 3rd or 4th grade wasn't very good and had no style. By the time you made it out of high school, you had developed a bit of style. Those who are Language majors and want to be writers develop more style.

This is pretty close to what happens as you develop programming skills. I have written: fortran, cobol, pl/i, assembler on the IBM big iron mainframe. C, assembler on PC, C, Perl, etc on the Unix boxes. Once you have a "style", you adapt it to the grammar of the language you are using.

My Perl code looks a lot like my C code, etc.

In the Pic world, you have a lot of folks that are having to learn to program. They spend lot's of time fighting the language because programming is a new discipline to them. In my case, I spend time fighting the oddities of the PIC hardware.
 
One of my profs in school told us that naming was by far the hardest problem in computer science. If you get the names right it makes everything else easier.

The use of terse variable names is not a black and white issue. More like shades of gray. Names need to make sense, at the very least, in the context in which they are used..

If I let the students use i, j, and k in loops they start using terse names everywhere. The use of meaningful names help the programmer understand what the code is doing.

August Treubig said:
Maybe the current "accamedians" won't, but their fathers did. It doesn't matter what you do, as long as it is consistent.

That works for the first few hundred lines of code, after that it trouble. It is well know that over the life of a program the cost of maintaining it far outweighs the cost of writing it. You might save time up front with terse meaningless names but down the line someone may be paying for it in spades.

Some programs have become so complex that the people working on the code prior to the first release have a hard time understanding the code. Thus the term project restart.

Mike said:
I assume that idx is a short form of index and is only appropriate is you are using it as an index. What do you use if you need a second (inner) index? jdx? Do you also advocate cnt if it is a simple counter? And again, what for an inner counter?

Doing idx, jdx, kdx is as bad as i, j, k. Better to use meaningful names. Names like employeeIdx. I do agree that there is a point of diminishing returns as names increase in length. Managing the scope of variables allows us to use shorter names.

EDIT: When I first start teaching loops I use idx in place of i to keep students from thinking they can get by with meaningless 1 letter variables. Idx may be meaningless but it is a good fit for the trival examples.
 
Last edited:
what does it mean by "The data is immediately sent back to PC". Does it means the output will be displayed at the pc. how?
 
sohagiut said:
what does it mean by "The data is immediately sent back to PC". Does it means the output will be displayed at the pc. how?
Yes. For test one as each char is recieved by the PIC it is sent back to the PC by the uart.


Read the code.
This code seems to be way over your head. Is it home work?
Have you done the simple stuff link blinking LEDs etc.
 
Actually i tried to program and used the Hyperterminal with proper settings to see the output. but nothing appears.
 
sohagiut said:
Actually i tried to program and used the Hyperterminal with proper settings to see the output. but nothing appears.

If it was that easy everyone would do it.

Debug the code.

Verify that you can select a given test with a switch.

Then choose or write a test that sends data from the PIC to the PC.

Then choose or write a test that sends data from the PC to the PIC.

Then try one that reads data from the PC and sends it back.

Use the debugger.
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…