|
|
View previous topic :: View next topic |
Author |
Message |
Andrew83
Joined: 16 Sep 2008 Posts: 51
|
Question about ext_int_edge use ! |
Posted: Tue Feb 03, 2009 7:58 am |
|
|
Hello everybody !
I have a problem with a program.
First of all, as usual, I'm using pic18f452 @ 10 MHz and CCS C compiler version 4.057.
PROBLEM : the output of the next code should be 1110101010 and in reality is 1111111111.
I have two boards : 1 sends a IR code ( only 10 bits using the RC5 protocol) and the other should receive the command.
So .... first the receiver code ( which I'm having trouble with) :
Code: |
#include <18f452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=10000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#define tsop pin_b0
#define min 2000
#define max 3000
int16 timer_value=0;
char buffer[10];
char temp;
int i;
char flag;
#int_ext //IR bits detected by edge triggering
void ext_isr() {
//disable_interrupts(int_ext); // i don't know ... is this right here ?
set_timer1(0); // set timer to zero
while(!(input(tsop))); //measure how long the input is low
timer_value = get_timer1();
if ( (min < timer_value) && (timer_value < max)) // if it's low for 900 uS -> OK
if (input(tsop)) //now, if the pin is high
buffer[i++]='1'; //then it's a "1"
else
buffer[i++]='0'; //else it's a "0"
flag=1;
}
void main() {
setup_timer_1(t1_internal|t1_div_by_1);
flag=0;
while(1) {
ext_int_edge(0,H_to_L); //falling edge
enable_interrupts(int_ext); //enable external interrupt
enable_interrupts(global); //enable interrupts
if (flag==1){
for(i=0; i<10;i++){
flag=0;
printf("%c",buffer[i]); }
}
}
|
The following code is working as it should. Here is the transmitter part :
Code: |
#include <16f877.h>
//#include <18f452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=10000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
char slave_cmd[10]={'1','1','1','0','1','0','1','0','1','0'};
//=============================================================================
void check_for_SLAVE(void) {
char i;
for(i=0;i<9;i++)
{
if (slave_cmd[i]=='0')
{
output_high(pin_e1);
delay_us(900);
output_low(pin_e1);
delay_us(900);
}
else
{
output_low(pin_e1);
delay_us(900);
output_high(pin_e1);
delay_us(900);
}
}
delay_ms(100);
}
//==========================================
void main() {
//--------------------------------------------------
setup_timer_1(t1_internal|t1_div_by_1);
ext_int_edge(0,h_to_l);
enable_interrupts(int_ext);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
while(1)
{
check_for_SLAVE();
}
}
|
Thank you very much !
Andrew. |
|
|
Andrew83
Joined: 16 Sep 2008 Posts: 51
|
|
Posted: Tue Feb 03, 2009 9:33 am |
|
|
Any ideas ? Anyone ? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Feb 03, 2009 2:53 pm |
|
|
There's tons of RC5 code out there. Do a Google search for CCS code
with this search string:
This will get you CCS code that uses INT_EXT interrupts for the decoder. |
|
|
Andrew83
Joined: 16 Sep 2008 Posts: 51
|
|
Posted: Wed Feb 04, 2009 3:35 am |
|
|
Hello PCM Programmer !
Thank you 4 your answer.
The code is inspired by this loginway article : http://loginway.net/the-rc5-decoder-based-on-a-pic16f877a-and-pic-01-developement-board/.
So ...what i'm trying to do is to determine straight forward if the received signal is a "1" or a "0".
The "ext_int_edge" work's like this (please corect me if i'm wrong) :
- when the signal from the TSOP goes low i enter the ISR routine.
- if the output stays low for a period of about 900 uS then it's a valid IR bit.
- so... 900 uS have passed ...i check the state of the pin ...if the pin is high...then the bit is a "1", else it's a "0".
Is this logic bad ? Why do i get 10 bits of "1" ? ... Please take a look at my implementation and point me in the right way.
I must mention that the transmitter part is working properly. I've tested it with a oscilloscope and verified it.
Thank you !! |
|
|
Ttelmah Guest
|
|
Posted: Wed Feb 04, 2009 4:22 am |
|
|
The logic is wrong.
There are a number of problems:
The first is with your transmit. You need to take the line back to 'high', when the transmit finishes. At present, if the last bit sent is a '0', the line will remain low. Then there won't be a falling edge for the first start bit at all....
The second though is with the logic of the receive. If you look at your bit pattern - 1110101010. The pattern of hghs and lows sent (with the above fault fixed), will be (starting with a '1' as the line idles between the characters) -
Code: |
fixed pitch font needed here to see properly
1010101100110011001101
1 1 1 1 1 1 1
|
Your code as it stands, only triggers on the falling edges, The ones in the second line show where it'll trigger. So it will trigger correctly for the first three bits, but then will trigger in the middle of the fourth bit. At this point, your test half a bit time latter, will still see a low, and return a '1'. It won't then trigger at all for the next '1', but will again trigger at the falling edge in the middle of the next bit, and will again see this as a 1....
Best Wishes |
|
|
Andrew83
Joined: 16 Sep 2008 Posts: 51
|
|
Posted: Wed Feb 04, 2009 2:08 pm |
|
|
Hello Ttelmah !
Thak you for your response.
You are right about the transmitter code ... point taken !
Now...about the receiver code :
Let's take an example so i can understand why it is not working:
Code: |
------ ------ -------- ------
| | | | | | | |
|___| | |___ ___| | |___|
| | | | |
idle | "1" | "0" | "1" | "0" | idle
|
Ok...so the interrupt triggers on the falling edge. Then ... after 900 us low , if the pin is high, that means that it's a "one" and i wait for next falling edge .
The next falling edge comes, after 900 us low, if the pin is still low, that means that there must have been a "zero".
You say:
Quote: |
then will trigger in the middle of the fourth bit. At this point, your test half a bit time latter, will still see a low, and return a '1'. |
Why is this happening, when the pin is still low ? If the pin is still low after 900 us the it should be a zero.
Where is the mistake ?.... Please clarify this to me.
I know that somewhere is a mistake but i don't understand where.
Thank you for your patience !! |
|
|
Andrew83
Joined: 16 Sep 2008 Posts: 51
|
|
Posted: Wed Feb 04, 2009 2:24 pm |
|
|
Basically ... I'm retaining the value of the last bit.
Or so it should be !
Hmm...i'm confused ....pls give me a hand in solving this ! |
|
|
Ttelmah Guest
|
|
Posted: Wed Feb 04, 2009 4:38 pm |
|
|
Look at your own picture.
First bit, falling edge at the start of the bit. You wait 900uSec (really ought to be a couple of uSec longer to allow for the transmitter taking _time_ to actually set/clear the bit in the loop. If the signal has gone high, it implies a '1'. Now your next interrupt trigger, is in the middle of the next bit. Your test would then work (with the commment about the timing). However your next interrupt is now, not in the next bit at all (you miss the '1', since there is no falling edge in it at all...). You would then interrupt in the middle of the last '0', and 900uSec latter, see a high!...
With your approach, if you get the timings 'right', you would _only_ detect a '0', as a zero, if it is immediately followed by a '1'. You also will only detect a '1, if if follows another '1'.
What you need to do, is start the clock at the _first_falling edge, and then sample at 1800uSec intervals after this point, if you find a falling edge, you have a 0, if you have a rising edge, you have a 1.
In fact you will only sample seven times in your nine bits, and would return 1110001 for those seven bits.
However your code, doesn't wait for 900uSec, it waits for the next rising edge. The value sampled then will always be '1' (after all the signal _has_ risen). At this point, if the time was longer than 900uSec, it doesn't increment the counter, or write a value into the buffer at all. So the only bits it'll write to the buffer, are 1's, when it happens to find them...
So all it'll do, is write four 1's to the buffer, for the nine bits sent.
Best Wishes |
|
|
Andrew83
Joined: 16 Sep 2008 Posts: 51
|
|
Posted: Thu Feb 05, 2009 12:56 pm |
|
|
Hello Ttelmah !
Based on your last post, the following implementation is my latest shot at sloving this problem, but unfortunately it is still not working.
Code: |
#include <18f452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=10000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#define tsop pin_b0
char buffer[10];
char temp;
char i;
char count;
int1 timer_flag;
int1 done=false;
#int_ext
void ext_isr() {
disable_interrupts(int_ext);
enable_interrupts(INT_TIMER1);
set_timer1(61036); // overflow in 1,8 ms
}
#int_timer1
void timer1_isr() {
for(i=0; i<9; i++) {
if (timer_flag){
set_timer1(61036);
if (input(TSOP))
temp='1';
else
temp='0';
timer_flag=false;
}
else
{
set_timer1(61036);
if (input(TSOP))
temp='1';
else
temp='0';
timer_flag=true;
}
buffer[i]=temp;
done=true;
}
}
void main() {
setup_timer_1(t1_internal|t1_div_by_1);
ext_int_edge(0,H_to_L); //falling edge
enable_interrupts(int_ext); //enable external interrupt
enable_interrupts(global); //enable interrupts
do {
if (done)
done=false;
printf("%s",buffer);
} while (1);
}
|
How can i make this right ?
Thank you for your input !! |
|
|
Andrew83
Joined: 16 Sep 2008 Posts: 51
|
|
Posted: Thu Feb 05, 2009 12:59 pm |
|
|
Where should i put the FOR LOOP ?
Without the FOR loop the program kind'a works, but I need to printf the result to the serial port, and for this I need a string ( BUFFER[10]).
Hmm...I don't know what else to try. |
|
|
Ttelmah Guest
|
|
Posted: Thu Feb 05, 2009 4:17 pm |
|
|
First, shorten the time set in int_ext.
Think about it for a moment, you need to sample in the second half of each bit time. So you want to sample at perhaps 1100uSec in the first bit, and then then 1800uSec latter till the data is finished. Remember also that entering the interrupt takes time, so set the timer value to give a timeout in about 1790uSec from the point where you enter the timer routine.
Then, you don't want a 'for' loop. Have a global counter 'bitnumber'. Set it to 10 in int_ext. Then in the timer routine, after setting the new timer value, save the bit, and decrement it. If it is '0', disable the timer interrupt, and set a flag to say 'val_complete'. Re-enable int_ext as well here.
In your main code, if 'val_complete' is set, clear it, and print the value.
Best Wishes |
|
|
Andrew83
Joined: 16 Sep 2008 Posts: 51
|
|
Posted: Mon Feb 09, 2009 2:04 pm |
|
|
Hello Ttelmah !
Thank you for answering my post and sorry i didn't aswer it.
I didn't get a chance to actualy test the code posted below...so if you can take a look over it and see if it makes sense, i will deeply apreciate it.
As u see i've made some minor modifications because i think that without the extra "IF" statement in the timer isr, the value of the bitnumber variable would have been reinitialized to 10 on each "0".
Is this right ?..What's your opinion ?
So...here is my latest implementation considering your sugestions:
Code: |
#include <18f452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=10000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#define tsop pin_b0
char buffer[10];
char bitnumber=0;
int1 val_complete=false;
#int_ext //IR bits detected by edge triggering
void ext_isr() {
disable_interrupts(int_ext);
enable_interrupts(INT_TIMER1);
//set_timer1(61036); // overflow in 1,8 ms
//set_timer1(63286); // overflow in 900 us
//set_timer1(61061); // overflow in 1,790 ms
bitnumber=10;
set_timer1(62786); // overflow in 1,1 ms
}
#int_timer1
void timer1_isr() {
set_timer1(61061); // overflow in 1,790 ms
if (input(TSOP)){
buffer[bitnumber]='1';
bitnumber--;}
else
{ buffer[bitnumber]='0';
bitnumber--; }
if (bitnumber==0){
disable_interrupts(INT_TIMER1);
enable_interrupts(int_ext);
val_complete=true; }
}
void main() {
setup_timer_1(t1_internal|t1_div_by_1);
ext_int_edge(0,H_to_L); //falling edge
enable_interrupts(int_ext); //enable external interrupt
enable_interrupts(global); //enable interrupts
while(1) {
if (val_complete)
val_complete=false;
printf("%s",buffer); }
}
|
Thank you ! |
|
|
Ttelmah Guest
|
|
Posted: Mon Feb 09, 2009 3:15 pm |
|
|
1) Move the decrement of bit_number outside the if statement. Doesn't really matter, but no point in having two copies, one in each branch...
I have put it into the test (decrementing before testing).
2) The big one. Clear the timer interrupt before enabling it in int_ext. Clear int_ext, before enabling it in the timer. Otherwise both _will_ have already triggered in the past, resulting in the routines being incorrectly called...
So:
Code: |
#int_ext //IR bits detected by edge triggering
void ext_isr() {
disable_interrupts(int_ext);
set_timer1(62786); // overflow in 1,1 ms
clear_interrupts(INT_TIMER1);
enable_interrupts(INT_TIMER1);
bitnumber=10;
}
#int_timer1
void timer1_isr() {
set_timer1(61061); // overflow in 1,790 ms
if (input(TSOP))
buffer[bitnumber]='1';
else
buffer[bitnumber]='0';
if (--bitnumber==0) {
disable_interrupts(INT_TIMER1);
clear_interrupts(INT_EXT);
enable_interrupts(int_ext);
val_complete=true;
}
}
|
You have exactly the testing I described. Can't see any 'extra' if.
Best Wishes |
|
|
Andrew83
Joined: 16 Sep 2008 Posts: 51
|
|
Posted: Tue Feb 10, 2009 7:09 am |
|
|
So...i've tested the program and it still doesn't work !
In the hyperterminal window it outputs an endless row of "P".
It seems to be stuck in the WHILE in the main().
The program executes 1 time when it receives a IR signal but then remains in the main() although the variable val_complete is now false.
Any ideas why is this happening ?
I trully don't understand what's happening ! |
|
|
Ttelmah Guest
|
|
Posted: Tue Feb 10, 2009 7:15 am |
|
|
You have got the brackets missing....
Currently the test for the value being 'complete', only affects the clear operation, not the print.
Best Wishes |
|
|
|
|
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
|