|
|
View previous topic :: View next topic |
Author |
Message |
Sebastian
Joined: 01 Dec 2003 Posts: 21 Location: Milan Italy
|
Interrupt problem |
Posted: Thu Jan 12, 2006 4:42 am |
|
|
Hi all .
I need help for understanding interrupt .
I want to insert this code (see also the complete program)
for to put command on rs232.
I don't be able to turn on one led every time the interrupt occur.
the interrupt occour when i recive the string after every command.
static int8 stringa[10]= {STX,0,0,0,1,1,SEMICOLON,AD,ETX};
I put six command on 232 and after every one the led will turn on
for indicate the correct reception, the loop continue always.
Somebody can help me thanks.
Code: |
for(x=0; x<=5; x++)
{
do{
output_high(LED6);
delay_ms(200);
output_low(LED6);
delay_ms(200);
}while(input(PUSH_BUTTON));
delay_ms(1000);
output_b(0x00);
output_low(RXLED);
// STREAM 1,2,3,4,5,6
y= TABLE1[x];
w= TABLE2[x];
printf("\x2");
printf("0001wdloa;");
printf("%c",w);
printf(";");
printf("%c",y);
printf("\x3");
//RX STX,0,0,0,1,1,SEMICOLON,AD,ETX RXLED ON
output_high(LED1);
delay_ms(2000);
}//for |
Code: | #if defined(__PCH__)
#include <18F452.h>
#include <string.H>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7,ERRORS)
#endif
#include <input.c>
#define STX 0x02 // Start of Transmition
#define ETX 0x03 // End of Transmition
#define AD 0xAD
#define SEMICOLON 0x3B
#define LED1 PIN_B0
#define LED6 PIN_B5
#define RXLED PIN_A2
#define PUSH_BUTTON PIN_D0
//------------------------------------------------------------------------------
#define BUFFER_SIZE 9
//------------------------------------------------------------------------------
#DEFINE BUFFER_COMPARE
//------------------------------------------------------------------------------
// GLOBALS
static int8 char_rcved, data_valid, next_in;
static int8 buffer_overflow, stream_complete;
static int8 sermssg[BUFFER_SIZE];
int x;
char y,w;
BYTE CONST TABLE1[7] ={' ','\x80','\x81','\x82','\x83','\x84'};
BYTE CONST TABLE2 [7] ={'1','2','3','4','5','6'};
//--------------------------------------------------------------------------------
static int8 stringa[10]= {STX,0,0,0,1,1,SEMICOLON,AD,ETX};
//--------------------------------------------------------------------------------
// SETTINGS
set_tris_b(0x00);
set_tris_d(0b11111111);
set_tris_a(0b00000000);
//------------------------------------------------------------------------------
#INT_RDA
void isr_serial_rcv()
{
char_rcved = getc(); // Get the incoming char
if ( char_rcved == STX )
{ next_in = 0; // Init the index
data_valid = TRUE; // Enable buffering
buffer_overflow = FALSE;
}
if ( data_valid )
{ sermssg[next_in] = char_rcved;
next_in++;
if ( next_in > BUFFER_SIZE ) // String longer than expected
{ data_valid = FALSE; // Stop buffering
buffer_overflow = TRUE;
}
if ( char_rcved == ETX )
{ data_valid = FALSE; // Stop buffering
stream_complete = TRUE;
}
}
}
//--------------------------------------------------------------------------------
void main()
{
delay_ms(400);
stream_complete = FALSE;
enable_interrupts(GLOBAL);
while(1)
{
enable_interrupts( INT_RDA );
do{
//nothing
}while ( !stream_complete );
//--------------------------------------------------------------------------------
if ( stream_complete )
{
stream_complete = FALSE; // IMPORTANT: If not the program re-enter
if ( !buffer_overflow )
{
disable_interrupts( INT_RDA );
#IFDEF BUFFER_COMPARE //////////////////////////////////////////////////////////
if (strcmp(stringa,sermssg))
{
output_high(RXLED);
}
#ENDIF //////////////////////////////////////////////////////////////////////////
} // if ( !buffer_overflow )
if ( buffer_overflow )
{// something wrong related to incoming string
output_b(0xff);
delay_ms(3000); // Just to see a change in output_b
buffer_overflow = FALSE; // clear the fault !!!!
}
} // if ( stream_complete )
} // while(1)
} // void main() |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jan 12, 2006 3:12 pm |
|
|
Your main problem is that you are doing string operations, but you
never terminate the strings with a byte of 0x00.
In your first string here, you don't terminate it. It actually is terminated
but it's just by luck. The 'static' keyword will set all un-initialized ram
values to 0x00. So you do, by luck, get this string to be terminated.
Quote: | static int8 stringa[10]= {STX,0,0,0,1,1,SEMICOLON,AD,ETX}; |
In your next string here, which is built from incoming RS232 chars,
you notice when the end of a string is received, but you never put a
final 0x00 byte at the end of the string.
Quote: | #INT_RDA
void isr_serial_rcv()
{
.
.
.
if ( char_rcved == ETX )
{ data_valid = FALSE; // Stop buffering
stream_complete = TRUE;
}
}
|
So later, you are doing string operations here, but neither of the
arguments for strcmp() are actually strings. That's because they
are missing the final 0x00 at the end of each one. So your program
operation is unpredictable at this point. It may crash.
Quote: | if (strcmp(stringa,sermssg))
{
output_high(RXLED);
} |
|
|
|
Sebastian
Joined: 01 Dec 2003 Posts: 21 Location: Milan Italy
|
|
Posted: Fri Jan 13, 2006 8:12 am |
|
|
Excuse me I don't understand so much what you want tell me .
Quote: |
Your main problem is that you are doing string operations, but you
never terminate the strings with a byte of 0x00.
|
Why i must terminate the string with 0x00 ?
Quote: |
The 'static' keyword will set all un-initialized ram
values to 0x00. |
I must assign space in ram for my string?
How I can terminate the string with 0x00? |
|
|
mcafzap
Joined: 07 Sep 2003 Posts: 46 Location: Manchester, UK
|
|
Posted: Fri Jan 13, 2006 9:51 am |
|
|
In 'C'strings are ended with '\0' otherwise the various functions would need to know the length of the strings.
To add this to your code you could add this line (untested) :
Code: |
existing interrupt code...
if ( char_rcved == ETX )
{ data_valid = FALSE; // Stop buffering
sermssg[next_in] = '\0';
stream_complete = TRUE;
}
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jan 13, 2006 1:40 pm |
|
|
In my eagerness to find a string problem, I made a mistake.
The array below is actually a string of length = 1, because the
2nd character in the array is 0x00. The only char in it is STX.
static int8 stringa[10]= {STX,0,0,0,1,1,SEMICOLON,AD,ETX};
Is that your intention ?
Or, are they supposed to be ASCII characters ? In that case,
you should initialize them like this, with the 0 and one in single
quotes. Doing that will create ASCII values for 0 and 1 in the array.
Also add a zero on the end to terminate the string.
static int8 stringa[10]= {STX,'0','0','0','1','1',SEMICOLON,AD,ETX, 0};
If you want to use your original array values, then you should use the
memcmp() function to compare the arrays. You have to specify
the number of bytes to be compared, if you use memcmp(). |
|
|
Sebastian
Joined: 01 Dec 2003 Posts: 21 Location: Milan Italy
|
|
Posted: Mon Jan 16, 2006 3:56 am |
|
|
I suppose to be ascii characters in the string.
static int8 stringa[10]= {STX,'0','0','0','1','1',SEMICOLON,AD,ETX,0};
I have insert the function memcmp( s1, s2, n )
Code: |
#IFDEF BUFFER_COMPARE //////////////////////////////////////////////////////////
if (memcmp(stringa,sermssg,9))
{
output_high(RXLED);
|
It return 0 if stringa = sermssg .
How I can use the return 0 of function memcmp ?
I have insert also the string
Code: |
if ( char_rcved == ETX )
{ data_valid = FALSE; // Stop buffering
sermssg[next_in] = '\0';
stream_complete = TRUE; |
is necessary to add this ?? |
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Mon Jan 16, 2006 9:16 am |
|
|
Quote: |
is necessary to add this ??
|
If you define your string as:
static int8 stringa[10]= {STX,'0','0','0','1','1',SEMICOLON,AD,ETX, 0};
as PCM Programmer suggest, it is not necesary.
But if you define your string as:
static int8 stringa[10]= {STX,'0','0','0','1','1',SEMICOLON,AD,ETX};
mcafzap suggest that while receiving the string and detect the ETX char,
the statement
sermssg[next_in] = '\0';
'add' the null ('\0' or 0x00) character at the end of the string.
In C an array of any finite sequence of charaters ending with '\0' is formally a string,
so a null char is needed at the end for further comparations or actions with the string.
In other words, memcmp and others functions that handle strings expect a '\0' as string delimiter.
Quote: |
How I can use the return 0 of function memcmp ?
|
In your statement:
if(memcmp(stringa,sermssg,9))
memcmp compare the first 9 characters of the arrays and return:
Code: |
<0: if stringa < sermssg
0: if stringa == sermssg
>0: if stringa > sermssg
|
Humberto |
|
|
Sebastian
Joined: 01 Dec 2003 Posts: 21 Location: Milan Italy
|
|
Posted: Wed Jan 18, 2006 10:02 am |
|
|
Humberto says
Quote: |
sermssg[next_in] = '\0';
'add' the null ('\0' or 0x00) character at the end of the string.
|
I decide to insert ,in the code, not in the answer of machine,(The machine respond only with 9 characters ETX is the last)the following code.
static int8 stringa[10]= {STX,'0','0','0','1','1',SEMICOLON,AD,ETX,'\0'};
and
Code: | if ( char_rcved == ETX )
{ data_valid = FALSE; // Stop buffering
sermssg[next_in] = '\0';
stream_complete = TRUE; |
is correct ?
Quote: | memcmp compare the first 9 characters of the arrays and return:
|
What is the correct sintax for compare ?
if (memcmp(stringa,sermssg,9)) ==0;
{
output_high(RXLED);
}
Quote: |
In other words, memcmp and others functions that handle strings expect a '\0' as string delimiter.
|
But if the function expect '/0'
if (memcmp(stringa,sermssg,9)) ==0;
is not just correct . |
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Wed Jan 18, 2006 1:21 pm |
|
|
I think you have missunderstood the difference between '0' and '\0'
'\0' is equal to 0x00
'0' is equal to 0x30 wich is the ASCII representation of the decimal number '0'
A string must end with '\0' (null)
The result of a comparation could be '0' (zero)
Quote: |
But if the function expect '/0'
if (memcmp(stringa,sermssg,9)) ==0;
is not just correct .
|
Now I hope you understand that this comment is out of focus.
Quote: |
I decide to insert ,in the code, not in the answer of machine,(The machine respond only with 9 characters ETX is the last)
|
The received packet is:
STX,'0','0','0','1','1',SEMICOLON,AD,ETX
But to be a string, it should end with '\0'.
Using the following code at receiving time, inside the #INT_RDA handler: Code: |
if ( char_rcved == ETX )
{ data_valid = FALSE; // Stop buffering
sermssg[next_in] = '\0';
stream_complete = TRUE;
}
|
would add the (needed) '\0' at the end of the received packet. Now it would look like this:
STX,'0','0','0','1','1',SEMICOLON,AD,ETX,'\0'
which is technically a string (in C)
Quote: |
What is the correct sintax for compare ?
|
Take a look at the function prototype that you are using:
Code: |
signed int memcmp(void * s1,char *s2,size_t n)
{
char *su1, *su2;
for(su1=s1, su2=s2; 0<n; ++su1, ++su2, --n)
{
if(*su1!=*su2)
return ((*su1<*su2)?-1:+1);
}
return 0;
}
|
and you will see that it return an signed integer
so you can compare strings in this way:
Code: |
void CompareStrings()
{
signed int8 compare_result;
compare_result = memcmp(stringa,sermssg,9);
if(compare_result == 0)
{
.........
}
if(compare_result < 0)
{
.........
}
if(compare_result > 0)
{
.........
}
}
|
Humberto |
|
|
Sebastian
Joined: 01 Dec 2003 Posts: 21 Location: Milan Italy
|
|
Posted: Tue Feb 21, 2006 4:06 am |
|
|
Thanks Humberto
The code working well , excuse me for my misunderstood.
There is only one problem.
When i power on the remote, the interrupts goes on one time for each one .
Why ? This is part of my main .
Code: |
void main()
{
delay_ms(1000); // Aspetto che il power supply vada a regime.
set_tris_d(0x00);
set_tris_a(0x00);
set_tris_b(0b00000111);
port_b_pullups(TRUE);
enable_interrupts(int_EXT);
enable_interrupts(int_EXT1);
enable_interrupts(int_EXT2);
ext_int_edge(H_TO_L);
ext_int_edge(1,H_TO_L);
ext_int_edge(2,H_TO_L);
enable_interrupts(GLOBAL);
//-----------------------------------------------------------------------------
stream_complete = FALSE;
//-----------------------------------------------------------------------------
while(1)
{
enable_interrupts( INT_RDA );
do
{ // Fai qualcosa mentre aspetti i dati.
output_high(WAITLED);
delay_ms(200);
output_low(WAITLED);
delay_ms(200);
}while ( !stream_complete ); //Continua fino a che stream_complete e' FALSE
|
|
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Tue Feb 21, 2006 8:08 am |
|
|
Quote: |
When i power on the remote, the interrupts goes on one time for each one.
|
We doesn't know what are you talking about. You didn't mention anything regarding a remote.
Humberto |
|
|
Sebastian
Joined: 01 Dec 2003 Posts: 21 Location: Milan Italy
|
|
Posted: Tue Feb 21, 2006 9:13 am |
|
|
The remote rs 232 perform this operations.
Transmit six different command by means # int_ext and other two command by # int_ext1 and # int_ext2 to one slave board.
Slave answer always the same string to confirm the correct action request.
This string is compared for led indication.
Code: |
#if defined(__PCH__)
#include <18F452.h>
#include <string.h> // Per usare strcmp.
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7,ERRORS)
#endif
#include <input.c>
#define STX 0x02 // carattere STX
#define ETX 0x03 // carattere ETX
#define AD 0xAD // carattere 173 ¡
#define SEMICOLON 0x3B // carattere 3b ;
#define BUTTON1 PIN_B0 // Pulsante comando 1
#define BUTTON2 PIN_B1 // Pulsante comando 2
#define BUTTON3 PIN_B2 // Pulsante comando 3
#define LED1 PIN_D0 //
#define LED2 PIN_D1 //
#define LED3 PIN_D2 //
#define LED4 PIN_D3 //
#define LED5 PIN_D4 //
#define LED6 PIN_D5 //
#define LEDB PIN_D6 //
#define LEDC PIN_D7 //
#define LEDA PIN_A0 //
#define WAITLED PIN_A1 //
//------------------------------------------------------------------------------
#define BUFFER_SIZE 9
//------------------------------------------------------------------------------
// VARIABLES GLOBALS
static int8 char_rcved, data_valid, next_in;
static int8 buffer_overflow, stream_complete;
static int8 sermssg[BUFFER_SIZE];
char k;
char y,w;
signed int x=-1;
int interrupt_flag,z;
static int8 stringa[10]= {STX,'0','0','0','1','1',SEMICOLON,AD,ETX,'\0'};
BYTE CONST TABLE1[6] ={'1','2','3','4','5','6'};
BYTE CONST TABLE2[6] ={'\xFF','\x80','\x81','\x82','\x83','\x84'};
//-------------------------------------------------------------------
void CompareStrings()
{
signed int8 compare_result;
delay_ms(300); // Per vedere tra una ricezione e l'altra .
//-------------------------------------------------------------------Cosa ricevo ?
//for ( z = 0; z<BUFFER_SIZE; z++) // < Perche' parto da zero cosi l'ultimo
// { k= sermssg[z]; // carattere e' ETX.
// printf("%c",k);
// }
//-------------------------------------------------------------------
compare_result = memcmp(stringa,sermssg,9);
if(compare_result == 0)
{
output_high(LEDA);
}
if(compare_result < 0)
{
output_high(WAITLED);
}
if(compare_result > 0)
{
output_high(WAITLED);
}
}
//------------------------------------------------------------------
void Comando()
{
output_a(0x00);
x++;
if (x<=5)
{
y= TABLE2[x];
w= TABLE1[x];
printf("\x2");
printf("0001wdloa;");
printf("%c",w);
printf(";");
printf("%c",y);
printf("\x3");
}
else {
x=-1;
}
}//void Profilo
//------------------------------------------------------------------Led
void Led()
{
if
(x==0){
output_low(LED6);
output_high(LED1);
}
else if
(x==1){
output_low(LED1);
output_high(LED2);
}
else if
(x==2){
output_low(LED2);
output_high(LED3);
}
else if
(x==3){
output_low(LED3);
output_high(LED4);
}
else if
(x==4){
output_low(LED4);
output_high(LED5);
}
else if
(x==5){
output_low(LED5);
output_high(LED6);
}
}
//------------------------------------------------------------------------
#INT_RDA
void isr_serial_rcv()
{
char_rcved = getc(); // Memorizza caratteri ricevuti.
if ( char_rcved == STX )
{ next_in = 0;
data_valid = TRUE;
buffer_overflow = FALSE;
}
if ( data_valid )
{ sermssg[next_in] = char_rcved;
next_in++;
if ( char_rcved == ETX )
{ data_valid = FALSE;
sermssg[next_in] = '\0';
stream_complete = TRUE;
}
} // if( data_valid)
} // void isr_serial_rcv()
//------------------------------------------------------------------
# int_ext
void EXT_isr(void)
{
while(!input(BUTTON1));
Comando();
Led();
}
//------------------------------------------------------------------
# int_ext1
EXT1_isr()
{
while(!input(BUTTON2));
{
output_low(LEDB);
output_low(LEDA);
printf("\x4");
output_high(LEDC);
}
}
//------------------------------------------------------------------
# int_ext2
EXT2_isr()
{
while(!input(BUTTON3));
{
output_low(LEDC);
output_low(LEDA);
printf("\x5");
output_high(LEDB);
}
}
//-----------------------------------------------------------------------------
void main()
{
delay_ms(1000); // Aspetto che il power supply vada a regime.
set_tris_d(0x00);
set_tris_a(0x00);
set_tris_b(0b00000111);
port_b_pullups(TRUE);
enable_interrupts(int_EXT);
enable_interrupts(int_EXT1);
enable_interrupts(int_EXT2);
ext_int_edge(H_TO_L);
ext_int_edge(1,H_TO_L);
ext_int_edge(2,H_TO_L);
enable_interrupts(GLOBAL);
//-----------------------------------------------------------------------------
stream_complete = FALSE;
//-----------------------------------------------------------------------------
while(1)
{
enable_interrupts( INT_RDA );
do
{ // Fai qualcosa mentre aspetti i dati.
output_high(WAITLED);
delay_ms(200);
output_low(WAITLED);
delay_ms(200);
}while ( !stream_complete ); //Continua fino a che stream_complete e' FALSE
//-----------------------------------------------------------------------------
if ( stream_complete )
{
stream_complete = FALSE; // IMPORTANTE: Se no il programma rientra in CompareStrings();
disable_interrupts( INT_RDA );
CompareStrings();
} // if ( stream_complete )
} // while(1)
} // void main()
//------------------------------------------------------------------------------------
|
This code workig well but when i power on interrupts produce three command ,one for each one ,on port .
Why ? Thanks in advance. |
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Tue Feb 21, 2006 12:28 pm |
|
|
Quote: |
This code workig well but when i power on interrupts produce three command ,one for each one ,on port .
|
I assume you want to say "when I enable interrupts..."
You used the built-in pull ups resistor in Port_B:
port_b_pullups(TRUE);
so, you should read a voltage close to +5V on Pins B0, B1 and B2.
1) Are those voltages OK ?
2) Does this voltage get a value close to 0V when the respective switch is pressed ?
Humberto |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue Feb 21, 2006 6:21 pm |
|
|
Code: | enable_interrupts(int_EXT);
enable_interrupts(int_EXT1);
enable_interrupts(int_EXT2);
ext_int_edge(H_TO_L);
ext_int_edge(1,H_TO_L);
ext_int_edge(2,H_TO_L);
enable_interrupts(GLOBAL); | I don't know, but I find the sequence of commands a bit tricky. First you arm the interrupts and then you change the conditions for triggering the interrupt, depending on the deep internals of the PIC hardware this might work as you expect or it activates all three interrupts. I wouldn't take any chances and reverse the sequence of commands: Code: | ext_int_edge(H_TO_L);
ext_int_edge(1,H_TO_L);
ext_int_edge(2,H_TO_L);
enable_interrupts(int_EXT);
enable_interrupts(int_EXT1);
enable_interrupts(int_EXT2);
enable_interrupts(GLOBAL);
|
To be really sure you could even add a clear_interrupt command before enabling the global interrupt flag. |
|
|
Sebastian
Joined: 01 Dec 2003 Posts: 21 Location: Milan Italy
|
|
Posted: Wed Feb 22, 2006 6:53 am |
|
|
Thanks you Humberto , ckielstra i have add the following code
Code: |
#if defined(__PCH__)
#bit ext_int0 = 0xFF2.1 // INTCON REGISTER ADDRESS FF2H BIT 0
#bit ext_int1 = 0xFF0.0 // INTCON3 REGISTER ADDRESS FF0H BIT 0
#bit ext_int2 = 0xFF0.1 // INTCON3 REGISTER ADDRESS FF0H BIT 1
#endif |
and this in main
Code: |
#asm
BCF ext_int0
BCF ext_int1
BCF ext_int2
#endasm |
Now the interrupts working well. |
|
|
|
|
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
|