CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

I can't get the interrupts to work
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Guest








I can't get the interrupts to work
PostPosted: Fri Mar 21, 2008 7:48 am     Reply with quote

Hi, I've been trying to get a 16F876A PIC to read data from an encoder but can't seem to get any of the interrupts to work. the serial port interrupt was working fine until yesterday but strangely stopped working. Could anyone please explain why the interrupts aren't working? bare in mind that I'm a newbie so please explain everything in detail please.

thanks in advance.

Here's the code I developed

Code:

#include <16F876A.h>
#device ICD=TRUE
#device adc=8
#use delay(clock=20000000)
#fuses NOWDT,HS, NOPUT, NOPROTECT, DEBUG, BROWNOUT, NOLVP, NOCPD, NOWRT
#use rs232(baud=115200, xmit=PIN_C6, rcv=PIN_C7)

   CHAR selection;


#byte PortB = 6
unsigned long  counter_A=0; 
unsigned long  counter_B=0; 
int value, valueanterior;



VOID Le_ADC1()                         
{
   putc(counter_A);
}

VOID Le_ADC2()               
{
putc(counter_B);

}


void le_portb ()                     
{
   value=input_b()&0x0f;               
   printf("%d", value);
               

}


void escreve_portb()                 
{

   value=getc();
   if (value < 0x10 )
      output_b(swap(value)&0xf0);


}

#int_rda
void serial_isr()
{

selection=getc();

WHILE ( (selection < 'A') || (selection > 'H'));
         SWITCH (selection)
         {
         case 'A' : prINTf ("\r\nA");
         le_ADC1 ();
         BREAK;
         case 'B' : prINTf ("\r\nB");
         le_ADC2 ();
         BREAK;
        case 'C' : prINTf ("\r\nC");
         le_portb ();
         BREAK;
        case 'H' : prINTf ("\r\nH");
         escreve_portb();
         counter_A=0;
         counter_B=0;

        BREAK;
        }
}



#int_RB
void RB_isr(void)      //Interrupt handler for line change in port B
{
int8 c;

//clear_interrupt(INT_RB);

disable_interrupts(INT_RB);
if (value != valueanterior)
{
++counter_A;
if (counter_A>200)
{
counter_A=0;
++counter_B;
}
}
 valueanterior=value;

set_tris_B (0x0f);
port_b_pullups(TRUE);
delay_us(10);

clear_interrupt(INT_RB);

enable_interrupts(INT_RB);   
c=PortB;

}


VOID main()
{
char c;
set_tris_B (0x0f);

port_b_pullups(TRUE);
delay_us(10);
c=PortB;


clear_interrupt(INT_RB);
counter_A=0;
counter_B=0;
enable_interrupts(INT_RB);      // turn on port b interrupt on change
enable_interrupts(GLOBAL);
enable_interrupts(int_rda);



 setup_timer_0 (RTCC_INTERNAL|RTCC_DIV_1);


 setup_timer_2 (T2_DIV_BY_4, 255, 1);

SET_TRIS_C (0xF0);


output_bit( PIN_C4, 0);   
output_bit( PIN_C4, 1);     
Delay_ms (10);               
output_bit( PIN_C4, 0);   

WHILE (TRUE)   
      {

   value=input_b()&0x0f;
      }
}
Guest








PostPosted: Fri Mar 21, 2008 8:17 am     Reply with quote

Start with the int_rda. This is terrible...
If you receive any character, above 'H', or below 'A', the routine will hang for ever, locking the processor up.
Rethink this.

Now the interrupt on change. There is a huge amount of c&*p here. First of all, it is pointless clearing, and disabling this interrupt in the routine. You _cannot_ clear this interrupt, _till the port is read_. Second, the compiler automatically clears the interrupt for you, when the routine is exited. There is no point in disabling the interrupt in the routine (since the flag is already set, it can't get set again...)_. Similarly there is no point in re-enabling it at the end. Just leave it unchanged.
Then, setting the tris. Since you don't specify 'use fast_io', the tris value _will_ be overridden as soon as you read the port. Since you are reading the port in the main all the time, the tris value _will_ immediately be set to 0xFF. Either use fast_io, set the tris just once (and the pull-ups, you don't need to set these in the interrupt), or get rid of all the extraneous tris operations.

Best Wishes
Guest








PostPosted: Fri Mar 21, 2008 8:36 am     Reply with quote

thanks for the fast reply. like I said, I'm very new at this so I make lots of mistakes.

starting with the INT_RB, if I understood you correctly, the clear interrupt, disable interrupt and the enable interrupt inside the routine are useless. so I only need to enable the interrupt once in the main() outside of the while(TRUE) is that correct?
now the TRIS command. I did look at the fast_io command but couldn't get it to work properly. but from what I understould from your post, I can simply delete the tris command from the interrupt too, is that it?


thanks again for all the help.
Matro
Guest







PostPosted: Fri Mar 21, 2008 8:47 am     Reply with quote

Hi,

You well understood. But a lot of things in your program can't be understood. Even what you are trying to do.
If you are a newbie my advice is :
- clear all
- make your program step by step and test it every step
- give logical names to functions, variables and so on
- add comments
- very often refer to datasheet to understand what is happening in the PIC

Maybe try to say to us what your program needs to do, it could be simpler.

Other tips :
"#device icd = true" isn't needed if you don't use ICD as debugger.
if you want to use fast_io all port "tris" registers shall be initialized.

Matro.
Guest








PostPosted: Fri Mar 21, 2008 9:11 am     Reply with quote

Quote:

Hi,

You well understood. But a lot of things in your program can't be understood. Even what you are trying to do.
If you are a newbie my advice is :
- clear all
- make your program step by step and test it every step
- give logical names to functions, variables and so on
- add comments
- very often refer to datasheet to understand what is happening in the PIC

Maybe try to say to us what your program needs to do, it could be simpler.

Other tips :
"#device icd = true" isn't needed if you don't use ICD as debugger.
if you want to use fast_io all port "tris" registers shall be initialized.

Matro.


hi matro, thanks for the advice.

I have been putting comments in the code but since english isn't my first language, the comments aren't in english, so when I posted the code here, I removed the comments so not to confuse anybody.

what I want my program to do (for now), is to count the impulses from an encoder connected to it and send that info through the serial port. In the future, I want it to count time and use that time to calculate angular velocities, Than I want to control the motor to which the encoder is connected to and recieve information from the RS232 port with the angular velocity that I need the motor to turn and use the information from the encoder to increase or decrease the voltage to the motor and make it work at that speed.

I'm going to start to clean the code. your right that the variable and funtion names are a quite complex. Mainly because half of them are in my native language and the other half are in english Embarassed

the other thing that is puzzling me at the moment is that the serial port interrupt only seems to work sometimes. I can send a 'A' ou 'B' and it will work, other times it will only work if I put the selection=getc(); line inside the while(true). is this normal or am I doing something wrong?
rnielsen



Joined: 23 Sep 2003
Posts: 852
Location: Utah

View user's profile Send private message

PostPosted: Fri Mar 21, 2008 9:21 am     Reply with quote

Your #use rs232() is incomplete. You need to specify how many bits you want to use. Plus, add ERRORS in it so any overrun will be automatically cleared. Try:
#use rs232(baud=115200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,errors);

You might want to try 9600 baud at first, just in case the higher baud rate might cause problems.

Since you're new to this, I would suggest you start your code with one section of code and work with it until you get it working. Then, add another section, or fuctionality, and work with it until it's doing what you want. Start simple and add one thing at a time. I would leave out the tris and fast_io stuff for now. Just let the compiler take care of that stuff until you get a better handle on the quirks of how the compiler does things.

Never enable/disable any of the interrupts while you're inside of one. Make your interrupt routines short and sweet. You want to get in, do something quick and then get out. If you need to do something extensive, set a flag in the interrupt routine and then poll that flag in main() and have whatever function called from there.

Good luck!

Ronald
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Mar 21, 2008 9:27 am     Reply with quote

Quote:
You need to specify how many bits you want to use.

It defaults to 8 bits and no parity.
Ttelmah
Guest







PostPosted: Fri Mar 21, 2008 9:41 am     Reply with quote

"Since you're new to this, I would suggest you start your code with one section of code and work with it until you get it working. Then, add another section, or fuctionality, and work with it until it's doing what you want. Start simple and add one thing at a time. I would leave out the tris and fast_io stuff for now. Just let the compiler take care of that stuff until you get a better handle on the quirks of how the compiler does things. "

This is the best bit of general advice, both when learning, and when trying to debug things latter. Old comments about 'walk before trying to run', definately apply. Smile

Best Wishes
Matro
Guest







PostPosted: Fri Mar 21, 2008 9:43 am     Reply with quote

Try it instead of your ISR :

Code:

#BYTE RCREG = 0x1A;   //RX buffer

#INT_RDA      //A byte has been received
void RX_byte_isr(void)
{
unsigned int8 received_byte;
  received_byte = RCREG;
  switch(received_byte)
  {
    case 'A':
      __your instruction set
      break;
    case 'B':
      __your instruction set
      break;
    case 'H':
      __your instruction set
      break;
  }
}


Notice that english isn't my native language too. ;-)

Matro
Guest








PostPosted: Fri Mar 21, 2008 10:55 am     Reply with quote

thanks everybody for the replies. I'm quite surprised by the number of people that respond in this forum and the speed of the replies Very Happy . I didn't expect so many programers of this kind of hardware.

I can now ount the number of impulses of the encoder and read time too, but only if I keep the set_tris_B (0x0f); comand in the INT_RB. if I delete that code line, I can only read the first impulse and the counter never goes beyond 1. should that happen?

from what I read in the datasheet, the PIC is a 8 bit processor so I shouldn't be able to count beyond 255, but one rotation of the encoder is over 1500 impulses. what I've been doing is when the counter passes 200 it restartes at zero and adds 1 to a second counter. since it's convenient for me to work with numbers higher than 255, is there another way to overcome this limitation?
Ttelmah
Guest







PostPosted: Fri Mar 21, 2008 11:00 am     Reply with quote

int16.....
Though the processor works natively in 8bit values (which is why the default 'int' is 8bit), the compiler is qute capable of working with 16bit values, if you declare them as such.
On the having to keep the tris in the int, switch to fast_io. What is happening is that every time you read the port, the tris is being changed. For something like an encoder, it is better to use fast_io, and set the tris up once.

Best Wishes
Matro
Guest







PostPosted: Fri Mar 21, 2008 11:33 am     Reply with quote

As said by Ttlemah, just use "int16" variables.
If you use fast_io, don't forget to initialize "tris" of ALL ports.
Finally if you really enjoy programming, be aware that built in functions and default options are maybe good for quick and simple programming but that you will obtain better code by programming everything yourself at a lower level (use directly registers, rewrite built in functions to match exactly your needs...).

Matro.
Ttelmah
Guest







PostPosted: Fri Mar 21, 2008 11:35 am     Reply with quote

No, you can set 'fast_io', on just one port. You don't have to change the others.
Generally, something like an optical encoder, is the only circumstance where it is worth usng this ability. Most of the time, the 'standard' handling is fine.

Best Wishes
Matro
Guest







PostPosted: Fri Mar 21, 2008 11:49 am     Reply with quote

You're right.
The correct sentence is "Don't forget to initialize tris of ALL ports concerned by the fast_io." ;-)
When I spoke about doing everything manually, I just think like a guy that program real-time, checking the ASM generated code and trying to optimize anything.
But maybe for most people the default generated code is sufficient. ;-)
Guest








PostPosted: Fri Mar 21, 2008 1:15 pm     Reply with quote

Ttelmah and Matro, I've been trying the fast_io(b) but it doesn't seem to count. I wrote the #use fast_io(b) command
and in the main I put:
set_tris_b (0x0f);
but the counter only counts the first impulse from the encoder. any sugestions on how to correct this?
besides that problem, everything is working fine Smile .
I'm going to start to look at the motors to see if I can figure out a way to get the current voltage and create a proportional derivative controller to adjust the voltage so to get the motor to spin at the desired velocity. If I have any problem I'll let you know ;)
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2, 3  Next
Page 1 of 3

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group