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 support@ccsinfo.com

Using interrupts on the PIC 16F877

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
mccraydw
Guest







Using interrupts on the PIC 16F877
PostPosted: Sun Apr 13, 2003 8:33 pm     Reply with quote

<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
PostPosted: Sun Apr 13, 2003 9:58 pm     Reply with quote

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
PostPosted: Mon Apr 14, 2003 3:09 am     Reply with quote

:=<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
PostPosted: Mon Apr 14, 2003 7:29 pm     Reply with quote

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
PostPosted: Tue Apr 15, 2003 2:19 am     Reply with quote

:=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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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