|
|
View previous topic :: View next topic |
Author |
Message |
someone Guest
|
problems with interrupts |
Posted: Wed Dec 13, 2006 12:50 am |
|
|
Hi everyone
I hope every one is doing ok
I am try to use both 'INT_RDA' (serial interrupt) and 'INT_EXT' (external interrupt) in the same code and i seem to be having some problems. I have tried 'INT_RDA' and 'INT_EXT' separately(i.e in separate codes) and they both work fine. This rules out any hardware problem. In the code posted below, a stepper motor should move until an interrupt comes but when i include the line 'enable_interrupts(INT_RDA);' even the motor does not move. I was wondering if there is a bug in the compiler or something. The
compiler version is 3.249. here is the code (i have not included all the defined variable):
Code: |
#include <16F877A.h>
#device *=16
#include <stdlib.h>
#include <string.h>
#include <24512.c> //for the atmel eeprom
#include <math.h>
#USE DELAY (CLOCK=20000000)
#fuses HS,NOWDT,NOLVP
#use rs232(baud=19200,xmit=pin_c4,rcv=pin_c5,parity=N,stream=pc)
#use rs232(baud=19200,xmit=pin_c2,rcv=pin_c3,parity=N,stream=con2)
#use rs232(baud=19200,xmit=pin_d6,rcv=pin_d7,parity=N,stream=sensor)// i have changed this
#use rs232(baud=19200,xmit=PIN_C6,rcv=PIN_C7,ERRORS,stream=special) //this will be used for serial interrupt
//----------------------------------------
int cpos = 30; //this is the initialized value
int apos = 20; //this is the initialized value
void decidecw();
void decideacw();
void movecw();
void moveacw();
#INT_RDA
void serial_isr()
{
command[0] = fgetc(special);
command[1] = fgetc(special);
command[2] = fgetc(special);
command[3] = fgetc(special);
command[4] = '\0';
if(command[0] == 'S' && command[3] == 'P') //means that 'STOP' received
{
decideacw();
factor = 2;
}
}
#INT_EXT // External interrupt
void ext_isr()
{
factor = 3; //so that after one step of CW the no other step is taken
decidecw();
movecw(); //after this is done means that the lrf is at 0 degrees
fprintf(con2,"RESET\r"); //instruction to UC2 to reset
reset_cpu();
disable_interrupts(global);
}
void decidecw()
{
if(apos != 20) //means that acw has already been entered
{
if(apos == 0)
{
cpos = 1;
}
else if(apos == 1)
{
cpos = 0;
}
else if(apos == 2)
{
cpos = 3;
}
else if(apos == 3)
{
cpos = 2;
}
}
else //so apos == 20
{
cpos = 0;
}
}
void decideacw()
{
if(cpos != 30) //means that acw has already been entered
{
if(cpos == 0)
{
apos = 1;
}
else if(cpos == 1)
{
apos = 0;
}
else if(cpos == 2)
{
apos = 3;
}
else if(cpos == 3)
{
apos = 2;
}
}
else //so cpos == 30
{
apos = 0;
}
}
void moveacw()
{
if(apos == 0)
{
output_high(PIN_A3);
delay_ms(150);
output_low(PIN_A3);
apos++;
}
else if(apos == 1)
{
output_high(PIN_A2);
delay_ms(150);
output_low(PIN_A2);
apos++;
}
else if(apos == 2)
{
output_high(PIN_A1);
delay_ms(150);
output_low(PIN_A1);
apos++;
}
else if(apos == 3)
{
output_high(PIN_A0);
delay_ms(150);
output_low(PIN_A0);
apos = 0;
}
}
void movecw()
{
if(cpos == 0)
{
output_high(PIN_A0);
delay_ms(150);
output_low(PIN_A0);
cpos++;
}
else if(cpos == 1)
{
output_high(PIN_A1);
delay_ms(150);
output_low(PIN_A1);
cpos++;
}
else if(cpos == 2)
{
output_high(PIN_A2);
delay_ms(150);
output_low(PIN_A2);
cpos++;
}
else if(cpos == 3)
{
output_high(PIN_A3);
delay_ms(150);
output_low(PIN_A3);
cpos = 0;
}
}
void main()
{
setup_adc( ADC_OFF );
SET_TRIS_A( 0x00 );
OUTPUT_A(0x00);
delay_ms(1000); //this is to cater for the initial jitters in the motor.
decidecw(); //as initially it will be moving in the CW direction
enable_interrupts(INT_RDA);
enable_interrupts(INT_EXT);
ext_int_edge( L_TO_H ); // Sets up EXT
enable_interrupts(global);
while(1)
{
if(factor == 2)
{
moveacw();
}
else if(factor == 1)
{
movecw();
}
}
}
|
Best Regards |
|
|
Martin Berriman
Joined: 08 Dec 2005 Posts: 66 Location: UK
|
|
Posted: Wed Dec 13, 2006 1:43 am |
|
|
Just a very quick look so not sure if this will help but are you definitely sending 4 characters to it. If not you may have problems - if your code receives less than 4 chars then it will get stuck on one of the fgetc waiting for more characters to arrive. If you are sending more than 4 chars then the 5th char will still be in the receive buffer since you are not removing it. You might want to use kbhit to check for available chars. |
|
|
Ttelmah Guest
|
|
Posted: Wed Dec 13, 2006 3:56 am |
|
|
There are a number of problems.
The key rule is 'keep interrupt handlers short'.
Now 'short' here, means _time_. You can have a 100 line interrupt handler, which is only using one instruction per line, and is fine, but have a one line interrupt handler, that delays for something internally, and will cause problems.
Now your 'RDA' interrupt, takes potentially a long time. It will arrive with one character waiting in the hardware buffer, but then have to sit and wait for three more to arrive. At 19200bps, this is about 1.5mSec, which is an 'age' in computer terms. Use this style instead:
Code: |
#INT_RDA
void serial_isr() {
static int8 state=0;
command[state++] = fgetc(special);
if (state==4) {
command[state]='\0';
if(command[0] == 'S' && command[3] == 'P') {
//means that 'STOP' received
decideacw();
factor = 2;
state=0;
}
}
}
|
This receives just a single character on the interrupt, and when four have arrived, then performs the test, rather than waiting n the interrupt. You may well need to tidy things to get the behaviour as you want, but it shows how to approach this type of problem.
As a comment at this point, you do not show the declaration of 'command'. Is it large enough?.
Now the external interrupt is 'messy'. The 'disable_interrupt' line, will never be reached. Global interrupts are already disabled in the handler, and you reset the CPU the line before. You reset the CPU, which forces a jump to address 0, but at this point, the interrupt flag is still set, so the code will loop forever, from the point where the interrupt is enabled in the main. This is probably what is killing the code.
Don't use 'reset_cpu'. This should be treated as _only_ to be used, in some major error recovery code, and using it routinely, should be considered a 'no-no'. Instead set a flag, and then have an outer loop in the main, if this flag is set, send the message, and then restart the main loop.
As a separate comment, don't change the interrupt edge, after enabling the interrupt. Read the data sheet on this. It can result in the interrupt being triggered, which given the 'fatal' nature of this interrupt is another source of problems.
Best Wishes |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Dec 13, 2006 5:31 am |
|
|
Besides all the above:
I don't see the declaration line for 'factor'. Make sure it is initialized to 1 or your code will do very little.
Ttelmah's interrupt handler is a good starting point. One important missing feature is a way of synchronizing the input, i.e. you need a mechanism to handle situations where the user enters a command of more or less than 4 characters. Most common solution is to have the user terminate the command with the enter key.
Code: | #include <string.h>
#define MAX_CMD_LEN 10
char command[MAX_CMD_LEN + 1];
void execute_command()
{
char tmp[MAX_CMD_LEN + 1];
strcpy(tmp, "STOP");
if (strcmp(command, tmp) == 0)
{
decideacw();
factor = 2;
}
}
#int_rda
void serial_isr()
{
static int8 len=0;
char c;
c = fgetc(special);
if ((c >= ' ') && (c <= '~')) // Check for valid input
{
if (len < MAX_CMD_LEN)
{
command[len++] = c;
}
}
else if (c == '\n') // Received newline character?
{
command[len] = '\0'; // Terminate command string
execute_command();
len = 0;
}
} |
|
|
|
someone Guest
|
|
Posted: Wed Dec 13, 2006 6:45 am |
|
|
Thankyou all for your replies.
But i think that there is some other problem. let me explain what i am acutally trying to do.
my second microcontroller '18f452' will serially interrupt my first microcontroller '16f877a' through 'INT_RDA'. Now '18f452' will transmit on pin 17 (pin C2) and this pin will directly be connected with pin c7 (pin 26)(hardware Uart) of '16f877a' and hence will trigger the serial interrupt. but the problem is that pin 17 on '18f452' goes high initially(even when i am not sending any serial data through the pin) and due to this reason the serial interrupt is generated constantly on '16f877a'. Due to this the 16f877a always remains in the interrupt handling routine and hence does nothing else. Now to cater this problem i thought perhaps i should use a max232 ic in between. so what i did was that connected pin17 of 18f452 to max232 pin 11. I shorted pin 14 and 13 of max232 (sort of a loop back) and then took the TTL output through pin 12. Now this pin12 of max232 was connected to pin 26 (c7) of first controller '16f877a'. but with this new configuration the same problem exists, the pin 26 of 16f877a is still constantly high and the pic is still in the interrupt subroutine constantly.
Please tell me if this is a proper way to generate interrupt and capture data from other PIC or should i try some other scheme. Please do reply
Many thanks |
|
|
someone Guest
|
|
Posted: Wed Dec 13, 2006 9:27 am |
|
|
Also i would like to say that i am using a bootloader for both the PIC's (i.e 18f452 and 16f877a). could this be causing the problem.
Can any one suggest a better way of interrupt based communication between the two controllers named above
Many thanks
Best Regards |
|
|
someone Guest
|
|
Posted: Wed Dec 13, 2006 9:36 am |
|
|
I was wondering, is there any need for a pull up or a pull down on the hardware uart for using the 'int_rda' properly
Best REgards |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Dec 13, 2006 10:25 am |
|
|
Quote: | but the problem is that pin 17 on '18f452' goes high initially(even when i am not sending any serial data through the pin) and due to this reason the serial interrupt is generated constantly on '16f877a'. | For RS232 it is normal behaviour for the Rx pin on the PIC to be high. Idle situation is high level, the start and data bits are low level.
As pointed out by two different people your serial interrupt handler routine is flawed. Fix this first, then come back and report the results. |
|
|
|
|
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
|