|
|
View previous topic :: View next topic |
Author |
Message |
mccraydw Guest
|
Using interrupts on the PIC 16F877 |
Posted: Sun Apr 13, 2003 8:33 pm |
|
|
<font face="Courier New" size=-1>I am having problems passing variables from my ISR back to main. The two variable I am trying to pass are current_state and echo_delay. The program moves current_state = WAIT_FOR_B4_HIGH into the ISR fine, but will not move variable out. Here is the code I am using.
Thanks for helping
dwayne
#include <16F877.h>
#fuses HS,NOPROTECT,NOWDT,BROWNOUT,PUT,NOLVP
#use delay(clock=20000000)
#define DELAY_BETWEEN_ECHO_PULSE 12500 // 10ms
#define MAX_DELAY_ECHO_PULSE 45000 // 36ms delay between pulse
#define START_TX 0 // State definitions
#define WAIT_FOR_B4_HIGH 1
#define WAIT_FOR_B4_LOW 2
#define DISTANCE 3
#define END_DELAY 4
// Type definitions
typedef int uint8_t;
typedef long uint16_t;
// Variable definitions
uint16_t echo_delay;
uint8_t current_state;
uint16_t distance;
#int_rb
void rb_isr()
{
if ((current_state == WAIT_FOR_B4_HIGH) && input(PIN_B4))
{
current_state = WAIT_FOR_B4_LOW;
set_timer1(0);
}
if ((current_state == WAIT_FOR_B4_LOW) && !input(PIN_B4))
{
echo_delay = get_timer1(); //Here is the problem. These
current_state = DISTANCE; //2 variable are not be send
} //back to main.
}
main()
{
set_tris_b(0b00010000);
output_low(PIN_B3);
current_state = START_TX;
setup_timer_1(T1_INTERNAL | T1_DIV_BY_4);
enable_interrupts(INT_RB);
enable_interrupts(GLOBAL);
if (current_state == START_TX)
{
output_high(PIN_B3);
delay_us(10);
output_low(PIN_B3);
set_timer1(0);
current_state = WAIT_FOR_B4_HIGH;
}
if (current_state == DISTANCE)
{
if (echo_delay >= 1200)
{
output_high(PIN_D2);
}
else
{
output_high(PIN_D4);
}
current_state = END_DELAY;
set_timer1(0);
}
if (current_state == END_DELAY)
{
if (get_timer1() >= DELAY_BETWEEN_ECHO_PULSE)
{
current_state = START_TX;
}
}
delay_us(20);
}
}
</font>
___________________________
This message was ported from CCS's old forum
Original Post ID: 13643 |
|
|
Rollo Guest
|
Re: Using interrupts on the PIC 16F877 |
Posted: Sun Apr 13, 2003 9:58 pm |
|
|
I'm no expert or anything, but I think there's a good chance that your interrupt routine is too long. You need fairly short interrupt routines, usually. I will post the code I used to measure the period of a pulse ( from one upwards to the next upwards ). Notice especially how short I kept my interrupt routine. Hope this helps a bit.
Rol
#include <16F877.h>
#FUSES XT,NOWDT,NOPROTECT,NOLVP,PUT,NOBROWNOUT
#use delay(clock=4000000)
#include <lcd.c>
set_tris_B(1);
int overflows =0;
long tiks;
float value, calc;
#int_timer1 // This interrupt routine runs each time timer1 overflows
void timer1_isr() // Timer1 is 16-bit timer therefore every 65536 clicks
{
overflows++; // Count the overflows
}
void initHardware()
{
lcd_init();
delay_ms(1000);
setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_1 ); // setup time scale
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
}
void doTSLReading()
{
while( input(PIN_B7)); // if now already up, wait...
while(!input(PIN_B7)); // if now already down, wait...
while( input(PIN_B7)); // if going from down to up.
overflows = 0; // in case this needs doing ( more than 256 o/flows?)
set_timer1(0); // set timer to zero
enable_interrupts(GLOBAL);
while(!input(PIN_B7)); // if low now.. wait
while( input(PIN_B7)); // if high a second time, get time elapsed from timer.
disable_interrupts(INT_TIMER1);
}
float pulseToHz( )
{
tiks = get_timer1();;
calc = (float)(overflows * 65536);
calc = calc + tiks;
calc = calc * 0.000001;
calc = 1 / calc;
return calc;
}
void displayValue(float value)
{
lcd_gotoxy(1,1);
printf(lcd_putc, "\%f\n Hertz ", value );
delay_ms(5000);
}
main() {
float hertz;
initHardware();
do {
doTSLReading();
hertz = pulseToHz();
displayValue( hertz );
} while(true); // just to keep the clock running!
}
:=<font face="Courier New" size=-1>I am having problems passing variables from my ISR back to main. The two variable I am trying to pass are current_state and echo_delay. The program moves current_state = WAIT_FOR_B4_HIGH into the ISR fine, but will not move variable out. Here is the code I am using.
:=
:=Thanks for helping
:=dwayne
:=
:=#include <16F877.h>
:=#fuses HS,NOPROTECT,NOWDT,BROWNOUT,PUT,NOLVP
:=#use delay(clock=20000000)
:=#define DELAY_BETWEEN_ECHO_PULSE 12500 // 10ms
:=#define MAX_DELAY_ECHO_PULSE 45000 // 36ms delay between pulse
:=
:=#define START_TX 0 // State definitions
:=#define WAIT_FOR_B4_HIGH 1
:=#define WAIT_FOR_B4_LOW 2
:=#define DISTANCE 3
:=#define END_DELAY 4
:=
:=// Type definitions
:=typedef int uint8_t;
:=typedef long uint16_t;
:=
:=// Variable definitions
:=uint16_t echo_delay;
:=uint8_t current_state;
:=uint16_t distance;
:=
:=#int_rb
:=void rb_isr()
:= {
:= if ((current_state == WAIT_FOR_B4_HIGH) && input(PIN_B4))
:= {
:= current_state = WAIT_FOR_B4_LOW;
:= set_timer1(0);
:= }
:= if ((current_state == WAIT_FOR_B4_LOW) && !input(PIN_B4))
:= {
:= echo_delay = get_timer1(); //Here is the problem. These
:= current_state = DISTANCE; //2 variable are not be send
:= } //back to main.
:= }
:=
:=main()
:= {
:= set_tris_b(0b00010000);
:= output_low(PIN_B3);
:= current_state = START_TX;
:= setup_timer_1(T1_INTERNAL | T1_DIV_BY_4);
:= enable_interrupts(INT_RB);
:= enable_interrupts(GLOBAL);
:=
:= if (current_state == START_TX)
:= {
:= output_high(PIN_B3);
:= delay_us(10);
:= output_low(PIN_B3);
:= set_timer1(0);
:= current_state = WAIT_FOR_B4_HIGH;
:= }
:= if (current_state == DISTANCE)
:= {
:= if (echo_delay >= 1200)
:= {
:= output_high(PIN_D2);
:= }
:= else
:= {
:= output_high(PIN_D4);
:= }
:= current_state = END_DELAY;
:= set_timer1(0);
:= }
:= if (current_state == END_DELAY)
:= {
:= if (get_timer1() >= DELAY_BETWEEN_ECHO_PULSE)
:= {
:= current_state = START_TX;
:= }
:= }
:= delay_us(20);
:= }
:=}
:=</font>
___________________________
This message was ported from CCS's old forum
Original Post ID: 13646 |
|
|
R.J.Hamlett Guest
|
Re: Using interrupts on the PIC 16F877 |
Posted: Mon Apr 14, 2003 3:09 am |
|
|
:=<font face="Courier New" size=-1>I am having problems passing variables from my ISR back to main. The two variable I am trying to pass are current_state and echo_delay. The program moves current_state = WAIT_FOR_B4_HIGH into the ISR fine, but will not move variable out. Here is the code I am using.
:=
:=Thanks for helping
:=dwayne
:=
:=#include <16F877.h>
:=#fuses HS,NOPROTECT,NOWDT,BROWNOUT,PUT,NOLVP
:=#use delay(clock=20000000)
:=#define DELAY_BETWEEN_ECHO_PULSE 12500 // 10ms
:=#define MAX_DELAY_ECHO_PULSE 45000 // 36ms delay between pulse
:=
:=#define START_TX 0 // State definitions
:=#define WAIT_FOR_B4_HIGH 1
:=#define WAIT_FOR_B4_LOW 2
:=#define DISTANCE 3
:=#define END_DELAY 4
:=
:=// Type definitions
:=typedef int uint8_t;
:=typedef long uint16_t;
:=
:=// Variable definitions
:=uint16_t echo_delay;
:=uint8_t current_state;
:=uint16_t distance;
:=
:=#int_rb
:=void rb_isr()
:= {
:= if ((current_state == WAIT_FOR_B4_HIGH) && input(PIN_B4))
You will only get here, if the 'current state' is 'WAIT_FOR_B4_HIGH', and pin B4 is high. Seems right.
:= {
:= current_state = WAIT_FOR_B4_LOW;
:= set_timer1(0);
:= }
:= if ((current_state == WAIT_FOR_B4_LOW) && !input(PIN_B4))
Now you should only get here, on the next change, when current_state is not saying 'WAIT_FOR_B4_LOW', and the pin has dropped.
However I can see a problem.
Remember that in C, a logical test is exited, as soon as it becomes non-true. Now the RB interrupt, only resets if the port is read. So you will get an RB interrupt, when the main code has not got the state set to 'WAIT_FOR_RB_HIGH', or the 'Low' equivalent, and in these, the port will not be read. Since the port has not been read, there will not be a further 'change' interrupt.
I'd re-code as:
void rb_isr()
{
static int8 portval;
portval=input_b();
if ((current_state == WAIT_FOR_B4_HIGH) && (portval & 0x10))
{
current_state = WAIT_FOR_B4_LOW;
set_timer1(0);
}
if ((current_state == WAIT_FOR_B4_LOW) && !(portval & 0x10))
{
echo_delay = get_timer1(); //Here is the problem. These
current_state = DISTANCE; //2 variable are not be send
} //back to main.
}
:=
:=main()
:= {
:= set_tris_b(0b00010000);
:= output_low(PIN_B3);
:= current_state = START_TX;
:= setup_timer_1(T1_INTERNAL | T1_DIV_BY_4);
:= enable_interrupts(INT_RB);
:= enable_interrupts(GLOBAL);
:=
:= if (current_state == START_TX)
:= {
:= output_high(PIN_B3);
:= delay_us(10);
:= output_low(PIN_B3);
:= set_timer1(0);
:= current_state = WAIT_FOR_B4_HIGH;
:= }
:= if (current_state == DISTANCE)
:= {
:= if (echo_delay >= 1200)
:= {
:= output_high(PIN_D2);
:= }
:= else
:= {
:= output_high(PIN_D4);
:= }
:= current_state = END_DELAY;
:= set_timer1(0);
:= }
:= if (current_state == END_DELAY)
:= {
:= if (get_timer1() >= DELAY_BETWEEN_ECHO_PULSE)
:= {
:= current_state = START_TX;
:= }
:= }
:= delay_us(20);
:= }
:=}
:=</font>
So I think your problem is that you do not read the port, in the event of a 'change' interrupt, when the state variable is not in one of the two defined states, resulting in a failure to continue.
Best Wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 13649 |
|
|
mccraydw Guest
|
Re: Using interrupts on the PIC 16F877 |
Posted: Mon Apr 14, 2003 7:29 pm |
|
|
Thank you for the help so far. I have two more questions about rb_isr. The compiler(PCW Compiler Ver. 2.679) that I am using does not reconize int8 or input_b(). Is there a way to get around this? MY TA wants to know what header file are you using and could this be why the compiler does not reconize it?
thanks again
:=:=<font face="Courier New" size=-1>I am having problems passing variables from my ISR back to main. The two variable I am trying to pass are current_state and echo_delay. The program moves current_state = WAIT_FOR_B4_HIGH into the ISR fine, but will not move variable out. Here is the code I am using.
:=:=
:=:=Thanks for helping
:=:=dwayne
:=:=
:=:=#include <16F877.h>
:=:=#fuses HS,NOPROTECT,NOWDT,BROWNOUT,PUT,NOLVP
:=:=#use delay(clock=20000000)
:=:=#define DELAY_BETWEEN_ECHO_PULSE 12500 // 10ms
:=:=#define MAX_DELAY_ECHO_PULSE 45000 // 36ms delay between pulse
:=:=
:=:=#define START_TX 0 // State definitions
:=:=#define WAIT_FOR_B4_HIGH 1
:=:=#define WAIT_FOR_B4_LOW 2
:=:=#define DISTANCE 3
:=:=#define END_DELAY 4
:=:=
:=:=// Type definitions
:=:=typedef int uint8_t;
:=:=typedef long uint16_t;
:=:=
:=:=// Variable definitions
:=:=uint16_t echo_delay;
:=:=uint8_t current_state;
:=:=uint16_t distance;
:=:=
:=:=#int_rb
:=:=void rb_isr()
:=:= {
:=:= if ((current_state == WAIT_FOR_B4_HIGH) && input(PIN_B4))
:=You will only get here, if the 'current state' is 'WAIT_FOR_B4_HIGH', and pin B4 is high. Seems right.
:=
:=:= {
:=:= current_state = WAIT_FOR_B4_LOW;
:=:= set_timer1(0);
:=:= }
:=:= if ((current_state == WAIT_FOR_B4_LOW) && !input(PIN_B4))
:=Now you should only get here, on the next change, when current_state is not saying 'WAIT_FOR_B4_LOW', and the pin has dropped.
:=However I can see a problem.
:=Remember that in C, a logical test is exited, as soon as it becomes non-true. Now the RB interrupt, only resets if the port is read. So you will get an RB interrupt, when the main code has not got the state set to 'WAIT_FOR_RB_HIGH', or the 'Low' equivalent, and in these, the port will not be read. Since the port has not been read, there will not be a further 'change' interrupt.
:=I'd re-code as:
:=
:=void rb_isr()
:= {
:= static int8 portval;
:= portval=input_b();
:= if ((current_state == WAIT_FOR_B4_HIGH) && (portval & 0x10))
:= {
:= current_state = WAIT_FOR_B4_LOW;
:= set_timer1(0);
:= }
:= if ((current_state == WAIT_FOR_B4_LOW) && !(portval & 0x10))
:= {
:= echo_delay = get_timer1(); //Here is the problem. These
:= current_state = DISTANCE; //2 variable are not be send
:= } //back to main.
:= }
:=
:=:=
:=:=main()
:=:= {
:=:= set_tris_b(0b00010000);
:=:= output_low(PIN_B3);
:=:= current_state = START_TX;
:=:= setup_timer_1(T1_INTERNAL | T1_DIV_BY_4);
:=:= enable_interrupts(INT_RB);
:=:= enable_interrupts(GLOBAL);
:=:=
:=:= if (current_state == START_TX)
:=:= {
:=:= output_high(PIN_B3);
:=:= delay_us(10);
:=:= output_low(PIN_B3);
:=:= set_timer1(0);
:=:= current_state = WAIT_FOR_B4_HIGH;
:=:= }
:=:= if (current_state == DISTANCE)
:=:= {
:=:= if (echo_delay >= 1200)
:=:= {
:=:= output_high(PIN_D2);
:=:= }
:=:= else
:=:= {
:=:= output_high(PIN_D4);
:=:= }
:=:= current_state = END_DELAY;
:=:= set_timer1(0);
:=:= }
:=:= if (current_state == END_DELAY)
:=:= {
:=:= if (get_timer1() >= DELAY_BETWEEN_ECHO_PULSE)
:=:= {
:=:= current_state = START_TX;
:=:= }
:=:= }
:=:= delay_us(20);
:=:= }
:=:=}
:=:=</font>
:=
:=So I think your problem is that you do not read the port, in the event of a 'change' interrupt, when the state variable is not in one of the two defined states, resulting in a failure to continue.
:=
:=Best Wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 13668 |
|
|
R.J.Hamlett Guest
|
Re: Using interrupts on the PIC 16F877 |
Posted: Tue Apr 15, 2003 2:19 am |
|
|
:=Thank you for the help so far. I have two more questions about rb_isr. The compiler(PCW Compiler Ver. 2.679) that I am using does not reconize int8 or input_b(). Is there a way to get around this? MY TA wants to know what header file are you using and could this be why the compiler does not reconize it?
:=
:=thanks again
input_b, appeared in the latter compilers. You can code instead, by using a #byte statement, like this:
#byte PORTB = 0xnnn
#define input_b() (PORTB)
Then if you replace 'nnn', with the address of port b on your chip (data sheet), you can use the 'input_b' function, just like the latter compilers.
The same applies to 'int8'. This is defined in the latter header files, using:
#define int8 int
It is purely done, to make it clearer that the default integer is 8bits long. With the latter compilers, you then have 'int8', 'int16', and 'int32' all available, making the actual lengths obvious.
Best Wishes
:=:=:=<font face="Courier New" size=-1>I am having problems passing variables from my ISR back to main. The two variable I am trying to pass are current_state and echo_delay. The program moves current_state = WAIT_FOR_B4_HIGH into the ISR fine, but will not move variable out. Here is the code I am using.
:=:=:=
:=:=:=Thanks for helping
:=:=:=dwayne
:=:=:=
:=:=:=#include <16F877.h>
:=:=:=#fuses HS,NOPROTECT,NOWDT,BROWNOUT,PUT,NOLVP
:=:=:=#use delay(clock=20000000)
:=:=:=#define DELAY_BETWEEN_ECHO_PULSE 12500 // 10ms
:=:=:=#define MAX_DELAY_ECHO_PULSE 45000 // 36ms delay between pulse
:=:=:=
:=:=:=#define START_TX 0 // State definitions
:=:=:=#define WAIT_FOR_B4_HIGH 1
:=:=:=#define WAIT_FOR_B4_LOW 2
:=:=:=#define DISTANCE 3
:=:=:=#define END_DELAY 4
:=:=:=
:=:=:=// Type definitions
:=:=:=typedef int uint8_t;
:=:=:=typedef long uint16_t;
:=:=:=
:=:=:=// Variable definitions
:=:=:=uint16_t echo_delay;
:=:=:=uint8_t current_state;
:=:=:=uint16_t distance;
:=:=:=
:=:=:=#int_rb
:=:=:=void rb_isr()
:=:=:= {
:=:=:= if ((current_state == WAIT_FOR_B4_HIGH) && input(PIN_B4))
:=:=You will only get here, if the 'current state' is 'WAIT_FOR_B4_HIGH', and pin B4 is high. Seems right.
:=:=
:=:=:= {
:=:=:= current_state = WAIT_FOR_B4_LOW;
:=:=:= set_timer1(0);
:=:=:= }
:=:=:= if ((current_state == WAIT_FOR_B4_LOW) && !input(PIN_B4))
:=:=Now you should only get here, on the next change, when current_state is not saying 'WAIT_FOR_B4_LOW', and the pin has dropped.
:=:=However I can see a problem.
:=:=Remember that in C, a logical test is exited, as soon as it becomes non-true. Now the RB interrupt, only resets if the port is read. So you will get an RB interrupt, when the main code has not got the state set to 'WAIT_FOR_RB_HIGH', or the 'Low' equivalent, and in these, the port will not be read. Since the port has not been read, there will not be a further 'change' interrupt.
:=:=I'd re-code as:
:=:=
:=:=void rb_isr()
:=:= {
:=:= static int8 portval;
:=:= portval=input_b();
:=:= if ((current_state == WAIT_FOR_B4_HIGH) && (portval & 0x10))
:=:= {
:=:= current_state = WAIT_FOR_B4_LOW;
:=:= set_timer1(0);
:=:= }
:=:= if ((current_state == WAIT_FOR_B4_LOW) && !(portval & 0x10))
:=:= {
:=:= echo_delay = get_timer1(); //Here is the problem. These
:=:= current_state = DISTANCE; //2 variable are not be send
:=:= } //back to main.
:=:= }
:=:=
:=:=:=
:=:=:=main()
:=:=:= {
:=:=:= set_tris_b(0b00010000);
:=:=:= output_low(PIN_B3);
:=:=:= current_state = START_TX;
:=:=:= setup_timer_1(T1_INTERNAL | T1_DIV_BY_4);
:=:=:= enable_interrupts(INT_RB);
:=:=:= enable_interrupts(GLOBAL);
:=:=:=
:=:=:= if (current_state == START_TX)
:=:=:= {
:=:=:= output_high(PIN_B3);
:=:=:= delay_us(10);
:=:=:= output_low(PIN_B3);
:=:=:= set_timer1(0);
:=:=:= current_state = WAIT_FOR_B4_HIGH;
:=:=:= }
:=:=:= if (current_state == DISTANCE)
:=:=:= {
:=:=:= if (echo_delay >= 1200)
:=:=:= {
:=:=:= output_high(PIN_D2);
:=:=:= }
:=:=:= else
:=:=:= {
:=:=:= output_high(PIN_D4);
:=:=:= }
:=:=:= current_state = END_DELAY;
:=:=:= set_timer1(0);
:=:=:= }
:=:=:= if (current_state == END_DELAY)
:=:=:= {
:=:=:= if (get_timer1() >= DELAY_BETWEEN_ECHO_PULSE)
:=:=:= {
:=:=:= current_state = START_TX;
:=:=:= }
:=:=:= }
:=:=:= delay_us(20);
:=:=:= }
:=:=:=}
:=:=:=</font>
:=:=
:=:=So I think your problem is that you do not read the port, in the event of a 'change' interrupt, when the state variable is not in one of the two defined states, resulting in a failure to continue.
:=:=
:=:=Best Wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 13672 |
|
|
|
|
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
|