|
|
View previous topic :: View next topic |
Author |
Message |
TokTok
Joined: 22 Jan 2014 Posts: 35
|
RS232 get between PIC18F2580 and Telegisis Zigbee module |
Posted: Wed Jan 22, 2014 4:29 am |
|
|
Hi all,
I’m attempting to establish RS232 comms between a PIC18f2580 and a zigbee module i.e. the ETRX357HR as seen here http://www.telegesis.com/downloads/general/TG-ETRX35x-PM-010-100.pdf. Before describing the problem I can confirm I’m able to send and receive the data between the PIC and the PC through the MAX232 transceiver.
Also before posting this message through breaking down in terms of hardware/board connections, I can confirm I’ve successfully hooked up the PIC to the zigbee module and also all is well with the circuitry related to the zigbee module.
Now to my problem - essentially my problem is with the receiving of characters from the zigbee module after successfully sending a basic AT command. As per the zigbee module’s AT command manual see page 10 here http://www.telegesis.com/downloads/general/tg-etrx-r212-commands.pdf, the expected response after sending the command AT is an OK.
As seen in my code below, I’ve used fgets() to receive the response from the zigbee module into a char array called etrx_response. I can confirm something is received into this char array as I check if its size is greater than zero.
Once I do this is use the standard C method strcmp() to compare if the number of characters in the received response are larger than or equal to the desired response. Assuming this is true I then use the standard C method strstr() to check if OK exists in the received response i.e. the earlier mentioned variable etrx_response. If it exists I simply flash a specific LED 4 times and if it doesn’t I retry the process once. If continue not to receive OK after the second time of asking I then continuously flash an LED.
I’ve gone through numerous threads e.g. those below on various forums identifying potential errors with RS232 comms but no success:
http://www.ccsinfo.com/forum/viewtopic.php?p=182489
http://www.ccsinfo.com/forum/viewtopic.php?t=36796&start=7
http://www.ccsinfo.com/forum/viewtopic.php?t=40120&postdays=0&postorder=asc&start=15
http://www.ccsinfo.com/forum/viewtopic.php?t=17563&start=6
http://www.ccsinfo.com/forum/viewtopic.php?t=36796
http://www.ccsinfo.com/forum/viewtopic.php?t=37869&start=3
http://www.ccsinfo.com/forum/viewtopic.php?t=36796&start=7
https://www.ccsinfo.com/forum/viewtopic.php?p=55575
Below is my code:
Code: |
#include<18F2580.h>
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#fuses XT,PUT,NOBROWNOUT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=19200,parity=N,xmit=PIN_C6,rcv=PIN_C7, ERRORS ))
/* ERRORS i.e. added above - Used to cause the compiler to keep receive errors in the variable RS232_ERRORS and to reset errors when they occur.*/
#byte TRISA = 0xC1
#byte TRISB = 0XF0
#byte TRISC = 0X80
#define SYNC_LED PIN_B2
#define DATA_LED PIN_B3
// Declare 'string' array to hold the response from the ETRX357HR module
char etrx_response[], desired_etrx_response[] = "OK";
int8 etrx_response_length = 0, etrx_response_flag = 0, i = 0, etrx_to_PIC_serial_comms_response = 0;
/* Step 2 - zigbee related - Send an AT command in this case the AT command. Save the response in a string or char array and check the last two characters are equals to OK.
If the last two characters are equals to OK then flash the SYNC_LED twice. If the last two characters are NOT equals to OK then flash the SYNC_LED three times.*/
int check_etrx_to_PIC_serial_comms();
/* Step 2 - zigbee related - Send an AT command in this case the AT command. Save the response in a string or char array and check the last two characters are equals to OK.
If the last two characters are equals to OK then flash the SYNC_LED twice. If the last two characters are NOT equals to OK then flash the SYNC_LED three times.*/
int check_etrx_to_PIC_serial_comms() {
// Send the AT command for the first time
printf("AT\r\n");
// Get the response from the RX pin of the PIC
fgets(etrx_response);
//
delay_ms(500);
// Obtain the length of the array holding the ETRX module response
etrx_response_length = sizeof(etrx_response);
// Checking if the response is greater than zero or less than and take respective action
if(etrx_response_length > 0 ) {
// Flash the sync LED 2 times confirming to user that a response was obtained from the ETRX module
for (i = 0; i < 2; i++) {
output_high(SYNC_LED);
delay_ms(1500);
output_low(SYNC_LED);
delay_ms(1500);
}
/* Compare the etrx response to the desired etrx response to determine the following:
if Return value is < 0 then it indicates etrx_response has LESS chars than desired_etrx_response
if Return value is > 0 then it indicates etrx_response has MORE chars than desired_etrx_response
if Return value if = 0 then it indicates etrx response is equal to desired etrx response*/
if( (strcmp(etrx_response, desired_etrx_response) == 0) | (strcmp(etrx_response, desired_etrx_response) > 0) ) {
/* Since we know that the etrx_response has MORE chars than desired_etrx_response or etrx_response is equal to desired_etrx_response
we then check if OK actually exists in the etrx_response. We use the strstr function to locate the first occurrence of the
desired_etrx_response in the erx_response and return a pointer to the beginning of the first occurrence of the desired_etrx_response in
the desired_etrx_response*/
if(strstr(etrx_response, desired_etrx_response) != NULL) {
/* Since the return pointer is NOT EQUAL to NULL then, flash the sync LED 4 times to signify to user
that all is well with the comms between the PIC and the ETRX module */
for (i = 0; i < 4; i++) {
output_high(SYNC_LED);
delay_ms(350);
output_low(SYNC_LED);
delay_ms(350);
}
// Set the etrx_response_flag to one to signify that all is well with the comms between the PIC and the ETRX module
etrx_response_flag = 1;
} else {
/* Temporary - Continously flash the SYNC_LED to signify to user that the desired_etrx_response does not exist in the etrx_response hence the return value is NULL
while(1) {
output_high(SYNC_LED);
delay_ms(500);
output_low(SYNC_LED);
delay_ms(500);
} */
// ------------------------------------
/*RETRY THE ESTABLISHING OF COMMS BETWEEN PIC AND ETRX ONLY ONCE AFTER WE HAVE ESTABLISHED THAT
desired_etrx_response DOES NOT EXIST IN etrx_response HENCE THE RETRUN VALUE IS NULL */
// Reset the ETRX module using the PIC
printf("AT&F\r\n");
//
delay_ms(500);
// Re-send the AT command
printf("AT\r\n");
// Get the response from the RX pin of the PIC
fgets(etrx_response);
// Obtain the length of the array holding the ETRX module response
etrx_response_length = sizeof(etrx_response);
// Checking if the response is greater than zero or less than and take respective action
if(etrx_response_length > 0 ) {
// Flash the sync LED 2 times confirming to user that a response was obtained from the ETRX module
for (i = 0; i < 2; i++) {
output_high(SYNC_LED);
delay_ms(1500);
output_low(SYNC_LED);
delay_ms(1500);
}
/* Compare the etrx response to the desired etrx response to determine the following:
if Return value is < 0 then it indicates etrx_response has LESS chars than desired_etrx_response
if Return value is > 0 then it indicates etrx_response has MORE chars than desired_etrx_response
if Return value if = 0 then it indicates etrx response is equal to desired etrx response*/
if( (strcmp(etrx_response, desired_etrx_response) == 0) | (strcmp(etrx_response, desired_etrx_response) > 0) ) {
/* Since we know that the etrx_response has MORE chars than desired_etrx_response or etrx_response is equal to desired_etrx_response
we then check if OK actually exists in the etrx_response. We use the strstr function to locate the first occurrence of the
desired_etrx_response in the erx_response and return a pointer to the beginning of the first occurrence of the desired_etrx_response in
the desired_etrx_response*/
if(strstr(etrx_response, desired_etrx_response) != NULL) {
/* Since the return pointer is NOT EQUAL to NULL then, flash the sync LED 4 times to signify to user
that all is well with the comms between the PIC and the ETRX module */
for (i = 0; i < 4; i++) {
output_high(SYNC_LED);
delay_ms(350);
output_low(SYNC_LED);
delay_ms(350);
}
// Set the etrx_response_flag to one to signify that all is well with the comms between the PIC and the ETRX module
etrx_response_flag = 1;
} else if(strstr(etrx_response, desired_etrx_response) == NULL) {
// Set the etrx_response_flag to 0 to signify that all is NOT well with the comms between the PIC and the ETRX module
etrx_response_flag = 0;
}
} else if(strcmp(etrx_response, desired_etrx_response) < 0) {
// Set the etrx_response_flag to 0 to signify that all is NOT well with the comms between the PIC and the ETRX module
etrx_response_flag = 0;
}
} else {
// Set the etrx_response_flag to 0 to signify that all is NOT well with the comms between the PIC and the ETRX module
etrx_response_flag = 0;
}
// ------------------------------------
}
} else if(strcmp(etrx_response, desired_etrx_response) < 0) {
// Set the etrx_response_flag to 0 to signify that all is NOT well with the comms between the PIC and the ETRX module
etrx_response_flag = 0;
}
} else {
// Set the etrx_response_flag to 0 to signify that all is NOT well with the comms between the PIC and the ETRX module
etrx_response_flag = 0;
}
return etrx_response_flag;
}
///////////////////////////////////////
// Main method
///////////////////////////////////////
void main() {
/* Hardware initialisation - Set the port pins to outputs/inputs */
set_tris_a(TRISA);
set_tris_b(TRISB);
set_tris_c(TRISC);
/* Step 2 - Send an AT command in this case the 'AT' command. Save the response in a string or char array and check the last two characters are equals to OK.*/
etrx_to_PIC_serial_comms_response = check_etrx_to_PIC_serial_comms();
/* Take necessary action based on the check i.e. flashing the sync LED twice for successful comms and continously for unsuccessful comms */
if(etrx_to_PIC_serial_comms_response == 1) {
while(1) {
output_high(DATA_LED);
delay_ms(350);
output_low(DATA_LED);
delay_ms(350);
}
} else {
/* Temporary - Contionously flash the SYNC_LED to indicate to user that the etrx_response has less chars than the desired_etrx_response
or that the desired_etrx_response does not exist in the etrx_response hence the return value is NULL }*/
while(1) {
output_high(SYNC_LED);
delay_ms(350);
output_low(SYNC_LED);
delay_ms(350);
}
}
}
|
My development profile is as follows:
MPLAB IDE Version 8.91.00
Compiler: CCS C
I really appreciate any help as I’ve been stuck on this issue for days.
Alex.
Last edited by TokTok on Fri Jan 24, 2014 7:53 am; edited 2 times in total |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9244 Location: Greensville,Ontario
|
|
Posted: Wed Jan 22, 2014 8:02 am |
|
|
couple of comments.
1) please use the 'code' option to include your program in the message. It'll display a LOT easier! I also like indenting of code as well.
2) this line....
fgets(etrx_response);
may not be correct.
this is the format according to the manual.
value = fgets (string, stream);
'stream' is optional(defaults to last USE RS232(...) )
though they never say what 'value' is for! it might be the # of rcvd characters,I haven't tried.
3) fgets(..) will wait forever for the carriage return....might be a problem
4)make your program simpler..get rid of all the strcmp,tests, etc. simply send the AT command, rcv the result and display either to a local LCD or send to PC terminal program. It'll really help debugging what is going on.If your PIC doesn't have a 2nd UART, CCS will allow any pin to be a xmt pin(just add max232 !).
5) have a look at the ex_sisr.c program to use buffers and interrupts for serial communications.
6) with rs232(), there's an option for 'timeout',very powerful for serial 'lockups'.
hth
jay |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jan 22, 2014 10:42 am |
|
|
Quote: | #byte TRISA = 0xC1
#byte TRISB = 0XF0
#byte TRISC = 0X80
set_tris_a(TRISA);
set_tris_b(TRISB);
set_tris_c(TRISC); |
Incorrect usage of #byte. Look it up in the CCS manual. You really
want #define, and with no '=' symbol in it. Also, don't use register
names for program-specific constant #define values. Use TRISA_INIT
or TRISA_VALUE, etc.
Quote: | char etrx_response[]
fgets(etrx_response);
|
Major bug. String declared with no storage size defined. The compiler
will not automatically allocate storage for you. It will over-write your
other variables. Put in the array size, and make it big enough to hold
all expected input and then some more, for safety. |
|
|
TokTok
Joined: 22 Jan 2014 Posts: 35
|
RS232 get between PIC18F2580 and Telegisis Zigbee module |
Posted: Fri Jan 24, 2014 7:48 am |
|
|
Hi all,
@PCM programmer: thanks for the very good reply. Regarding your suggestions:
I changed the code below:
Quote: | #byte TRISA = 0xC1
#byte TRISB = 0XF0
#byte TRISC = 0X80
set_tris_a(TRISA);
set_tris_b(TRISB);
set_tris_c(TRISC); |
to the following:
Code: | #define TRISA_INIT 0xC1
#define TRISB_INIT 0XF0
#define TRISC_INIT 0X80
/* Hardware initialisation - Set the port pins to outputs/inputs */
set_tris_a(TRISA_INIT);
set_tris_b(TRISB_INIT);
set_tris_c(TRISC_INIT); |
I also assigned the char arrays with sizes as seen below in my code.
@temtronic: Also thanks for the very good reply. Regarding your suggestions:
1) please use the 'code' option to include your program in the message. It'll display a LOT easier! I also like indenting of code as well. - I'll make sure I do this next time.
2) Regarding using fgets (string, stream); over fgets(etrx_response) I've read the manual and indeed the type for value isn't given but I suspect too it is the received char. I attempted using fgets (string, stream); over fgets(etrx_response) and it made no difference.
3) I don't know how avoid a long wait for a carriage return - any ideas?
4) make your program simpler..get rid of all the strcmp ..... I've done this as you can see from the code and took the approach of creating a 'new' Tx and Rx pins for comms between my PC and the PIC. Using the code below, I can confirm that independently the PC and the PIC communicate using these 'new' Tx and Rx pins i.e. pins A3 and A4.
Code: | #use delay(clock = FREQ_OSC)
#use rs232(baud=9600,xmit=pin_c6,rcv=pin_c7,errors)
#int_rda
void rda_isr(void)
{
char c;
c = getc();
putc(c);//send to pc to test interrupt receives data,but show nothing
}
//================================
void main()
{
delay_ms(2000);
printf("hello world\n\n");//show on hyperterminal ok
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
while(1);
} |
When I run the code to communicate between the PIC and the zigbee module when I display the response from the zigbee module i.e. the result of fgets() on my PC terminal program instead of I receiving OK dot I get dots. How can this be possible?
6) with rs232(), there's an option for 'timeout',very powerful for serial 'lockups'. - I attempted adding the timeout but it made no difference. I'm still unable to determine whether i receive the desired result from the zigbee module which is an OK.
5) have a look at the ex_sisr.c program to use buffers and interrupts for serial communications. I will have a look at the ex_sisr.cprogram but in the meantime having gone through the AN774 document to understand interrupts in order to execute the Interrupt-driven Circular buffer approach, I have successfully enabled the INT_RDA interrupt as an attempt to receive the data from my zigbee module (ETRX357HR) but I’ve been unsuccessful in the receiving of data.
I can confirm that I’m successfully sending the data i.e. an AT command from the PIC to the zigbee module and that I’m receiving something through the use of a multimeter which indicates a voltage drop on the Tx and Rx pins of the PIC as of when the printf() and gets() functions are executed.
Also I can confirm it is not a hardware issue as I’ve gone back to basics and used the following code to communicate between my PC and the PIC through a MAX232 chip. The code below worked perfectly.
My problem is I seem to be unable to read the data I suspect I’m receiving form the zigbee module. Specifically I feel I’m encountering either a framing or overrun error as described in the AN 774 document. To deal with this how can one use the transmit and receive interrupt related registers to check if the receive buffer is full i.e. two bytes are inside it and if so do not accept the receiving of a third byte as this will cause the overrun problem.
Based on the AN774 document I get the concept behind the setting up of the interrupt specifically the transmit and receive interrupts as per page 18 of the AN774 document.
Essentially my line of thinking to interrogate the USART receiving process and successfully collect the incoming data after enabling the INT_RDA interrupt as seen in my code is as follows:
Step 1 – Check the OERR for an overrun error to find out whether or not the FIFO buffer is full with two bytes or not. Clear the CRERN i.e. the receive enable bit and enabling it again. If an overrun error is detected then request a re-transmission of the data. Using functions in the CSS compiler how can this be done?
Step 2 – Check for the occurrence of a FRAMING error by checking the respective byte error flag. If a framing error is detected then request a re-transmission of the data. Using functions in the CSS compiler how can this be done?
Step 3 - Enable the RCIF bit of the PIR1 register to check the availability of data in the RCREG. This should help in confirming whether or not the all the data has been read from the RCREG. Using functions in the CSS compiler how can this be done?
Based on the result from STEP 3 above if the RCIF bit of the PIR1 register is ONE I can confirm that data is available in RCREG hence I can comfortably compare the data in RCREG to my desired result e.g. to confirm the response from the zigbee AT command I sent is equal to the string OK as I’m in my current code.
Below is my latest code:
Code: | #include<18F2580.h>
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#fuses XT,PUT,NOBROWNOUT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=19200, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8, ERRORS, stream=SERIAL_ZIGBEE)
#use rs232(baud=9600, parity=N, xmit=PIN_A4, rcv=PIN_A5, bits=8, ERRORS, stream=SERIAL_PC)
/* ERRORS i.e. added above - Used to cause the compiler to keep receive errors in the variable RS232_ERRORS and to reset errors when they occur.*/
#define TRISA_INIT 0xC1
#define TRISB_INIT 0XF0
#define TRISC_INIT 0X80
#define TX2 PIN_A4
#define RX2 PIN_A5
// Declare 'string' array to hold the response from the ETRX357HR module
char value[], etrx_response[50], desired_etrx_response[50] = "OK";
int8 etrx_response_length = 0, etrx_response_flag = 0, i = 0, etrx_to_PIC_serial_comms_response = 0;
/* Step 1 - Flash the DATA_LED twice to confirm the PIC is up and running.*/
void check_pic_flash_data_led_twice();
/* Step 2 - zigbee related - Send an AT command in this case the AT command. Save the response in a string or char array and check the last two characters are equals to OK.
If the last two characters are equals to OK then flash the SYNC_LED twice. If the last two characters are NOT equals to OK then flash the SYNC_LED three times.*/
int check_etrx_to_PIC_serial_comms();
//Step 1 - Flash the DATA_LED twice to confirm the PIC is up and running.
void check_pic_flash_data_led_twice() {
for (i = 0; i < 2; i++) {
output_high(DATA_LED);
delay_ms(500);
output_low(DATA_LED);
delay_ms(500);
}
}
/* Step 2 - zigbee related - Send an AT command in this case the AT command. Save the response in a string or char array and check the last two characters are equals to OK. */
#INT_RDA
void gets_etrx_response()
{
// Get the response from the RX pin of the PIC
fgets(etrx_response, SERIAL_ZIGBEE);
}
///////////////////////////////////////
// Main method
///////////////////////////////////////
void main() {
/* Hardware initialisation - Set the port pins to outputs/inputs */
set_tris_a(TRISA_INIT);
set_tris_b(TRISB_INIT);
set_tris_c(TRISC_INIT);
/* Step 1 - Flash the LED twice to confirm the PIC is up and running i.e. the expected voltages have been obtained */
check_pic_flash_data_led_twice();
#use rs232(baud=19200, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8, ERRORS, stream=SERIAL_ZIGBEE)
// Send the AT command for the first time
puts("AT\r\n", SERIAL_ZIGBEE);
/* Step 2 - Enable the received data ready */
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
disable_interrupts(INT_RDA);
disable_interrupts(GLOBAL);
#use rs232(baud=9600, parity=N, xmit=TX2, rcv=RX2, bits=8, ERRORS, stream=SERIAL_PC)
//
puts(etrx_response, SERIAL_PC);
}
|
Apologies if the questions sound basic but any advice is helpful .. I’ve been stuck on the issue for 5 consecutive days. |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Fri Jan 24, 2014 8:26 am |
|
|
Hi,
Your serial interrupt and data reception strategy is completely bogus! Study and implement 'ex_sisr.c'! This suggestion was NOT just some idle comment made in passing - it's crucial!
John |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9244 Location: Greensville,Ontario
|
|
Posted: Fri Jan 24, 2014 8:33 am |
|
|
quick comment.
re: the result of fgets() on my PC terminal program instead of I receiving OK dot I get dots. How can this be possible?
The PC needs the MAX232 chip for proper RS232 communications.
The ZigBEE module might not,instead is TTL serial.
You may have a wiring issue? or baudrate?
I just got 3 Xbees(zigbees) in today, will 'play' with them later...
hth
jay |
|
|
TokTok
Joined: 22 Jan 2014 Posts: 35
|
|
Posted: Mon Jan 27, 2014 7:32 am |
|
|
Hi all,
@temtronic: thanks for the reply. I'm only utilising the MAX232 for comms between the PIC and my PC and as I mentioned the code below works fine i.e. I receive the char I type in from the keyboard.
Code: | #include<18F2580.h>
#fuses XT,PUT,NOBROWNOUT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, STOP = 1, bits=8, ERRORS)
#int_rda
void rda_isr(void)
{
char c;
c = getc(); // Get character from PC
putc(c); // Send it back to the PC
}
//========================
void main()
{
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
}
|
@ezflr: thanks for the reply. Having gone through the ex_sisr.c I do realise my comms strategy was wrong. I've studied the ex_sisr.C and gone back to basics with it i.e. I'm utilisng the code firstly for comms between the PIC and the PC as opposed to the zigbee module.
I understand the logic behind the code particularly the interrupt method i.e. serial_isr and the bgetc() method.
Below is the ex_sisr.code I adjusted but I cant seem why I constantly get dots or essentially rubbish whenever the Code: | printf("\r\n\Running...\r\n"); | is executed.
I believe on the terminal emulator on my PC when the Code: | printf("\r\n\Running...\r\n"); | statement in the do - while loop is executed I should be seeing Buffered data =>
Code: | #include <18F2580.h> //18F4520
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#define BUFFER_SIZE 32
BYTE buffer[BUFFER_SIZE];
BYTE next_in = 0;
BYTE next_out = 0;
#int_rda
void serial_isr() {
int t;
buffer[next_in]=fgetc();
t=next_in;
next_in=(next_in+1) % BUFFER_SIZE;
if(next_in==next_out)
next_in=t; // Buffer full !!
}
#define bkbhit (next_in!=next_out)
BYTE bgetc() {
BYTE c;
while(!bkbhit);
c=buffer[next_out];
next_out=(next_out+1) % BUFFER_SIZE;
return(c);
}
void main() {
enable_interrupts(int_rda);
//#if defined(__PCD__)
//enable_interrupts(intr_global);
//#else
enable_interrupts(global);
//#endif
printf("\r\n\Running...\r\n");
// The program will delay for 10 seconds and then display
// any data that came in during the 10 second delay
do {
delay_ms(10000);
printf("\r\nBuffered data => ");
while(bkbhit)
putc( bgetc() );
} while (TRUE);
} |
I believe if I understand as to why I keep receiving rubbish then I should be able to move into comms between the PIC and my zigbee module (ETRX357HR).
Apologies once more if my question sounds basic. |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Mon Jan 27, 2014 8:05 am |
|
|
Hi TokTok,
You really need to learn effective troubleshooting, and implement a step-by-step approach to solving the problems you observe! It's not
really rocket science, but you do need to think in a logical manner!
For starters, the serial communications hardware implementation between the PIC-to-PC, and the PIC-to-Zigbee are totally different. Thus, you need
to stop thinking that "if one works, the other should too....."
In your most recent post, the first program works, and prints data to the PC correctly, but the second one does not, right? OK, so what is different? A
quick look shows that the #fuses and #use rs232 lines are different between the two programs. Is that significant? I don't know, but it would
take all of 10 seconds to find out! OK, now how about putting the offending printf from the non-working program into the working program?
See, a lot of things you should be trying on your own to 'bracket' the problem and understand what is going on!
Now, regarding the Zigbee module. Are you using the 'raw' module, or do you have one soldered to a breakout board? If it's on a board, are there
other components on the board? If so, post a datasheet!
Finally, what is the Vcc of your PIC? What is the Vcc you are applying to the Zigbee module? In spite of your assurances to the contrary, my guess
is that you've got a hardware issue and a software issue as well. Oh, please describe your interface between the Zigbee module and the PIC.
Which PIC pins are connected to which Zigbee pins?
EDIT - You are using 'fgetc()' in the 2nd program without specifying a stream name. That is a big mistake, and I wonder if you even tried to
compile that code???
John |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9244 Location: Greensville,Ontario
|
|
Posted: Mon Jan 27, 2014 10:11 am |
|
|
hopefully you're running the PIC/zigbee at 3 volts! zigbee is a 3 volt device, will NOT like 5 volts....poof...magic smoke wil come out !!!
I know xbee and 18F46k33 run nice at 3.4 volts, using USB<>TTL module to supply com to PC and power to PIC/xbee devices.
hth
jay |
|
|
TokTok
Joined: 22 Jan 2014 Posts: 35
|
|
Posted: Mon Jan 27, 2014 10:21 am |
|
|
Hi John,
Thanks for the reply and apologies if some of my questions were annoying. I've conducted the following tests with the working code but using the printf().
1 - I attempted calling the putc() independently as shown in the code below and this was successful i.e. after every 3 seconds Z was displayed.
Code: |
#include<18F2580.h>
#fuses XT,PUT,NOBROWNOUT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, STOP = 1, bits=8, ERRORS)
char c;
//========================
void main()
{
c = 'Z';
while(1) {
putc(c);
delay_ms(3000);
}
}
|
2 - Swapping putc() with printf() in the interrupt method. The ouctcome was the same,
Code: |
#include<18F2580.h>
#fuses XT,PUT,NOBROWNOUT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, STOP = 1, bits=8, ERRORS)
#int_rda
void rda_isr(void)
{
char c;
c = getc(); // Get character from PC
//putc(c); // Send it back to the PC
printf("\r\n" + c + "\r\n");
}
//========================
void main()
{
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
} |
3 - As seen below, changing the fuses statements in non-working code to the same as the working code using and not using fgetc() and stream but this produced the same outcome i.e. dots:
Code: |
#include <18F2580.h> //18F4520
#fuses XT,PUT,NOBROWNOUT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, STOP = 1, bits=8, ERRORS, stream=SERIAL_ZIGBEE)
#define BUFFER_SIZE 32
BYTE buffer[BUFFER_SIZE];
BYTE next_in = 0;
BYTE next_out = 0;
#int_rda
void serial_isr() {
int t;
buffer[next_in]=fgetc(SERIAL_ZIGBEE);
t=next_in;
next_in=(next_in+1) % BUFFER_SIZE;
if(next_in==next_out)
next_in=t; // Buffer full !!
}
#define bkbhit (next_in!=next_out)
BYTE bgetc() {
BYTE c;
while(!bkbhit);
c=buffer[next_out];
next_out=(next_out+1) % BUFFER_SIZE;
return(c);
}
void main() {
enable_interrupts(int_rda);
//#if defined(__PCD__)
//enable_interrupts(intr_global);
//#else
enable_interrupts(global);
//#endif
printf("\r\n\Running...\r\n");
// The program will delay for 10 seconds and then display
// any data that came in during the 10 second delay
do {
delay_ms(10000);
printf("\r\nBuffered data => ");
while(bkbhit)
putc( bgetc() );
} while (TRUE);
}
|
On the PC I'm using the CoolTerm emulator which has worked OK so far.
From the above it means printf() isn't working out for me.
As for the zigbee module i.e. ETRX357HR, it is mounted on a zigbee development board which comes as part of the development kit please have a look at the following links:
Zigbee module datasheet: http://www.telegesis.com/downloads/general/TG-ETRX35x-PM-010-100.pdf
http://www.telegesis.com/ETRX3-development-Kit.htm.
http://www.texim-europe.com/news/785
http://www.glynstore.com/products/Telegesis-ETRX3-Zigbee-Development-Kit.html
The required sub-circuit for the zigbee module is all done on the zigbee development board hence apart from the two wires for the Tx and Rx which have been soldered to the respective Rx and Tx header pins, nothing has been soldered onto the zigbee module development board. That's the reason why I hard suspect it could be a hardware issue on the zigbee side.
Regarding the comms connections, the Tx of the zigbee module is connected to the Rx or PIN18 of the PIC18F2580 and the Rx of the zigbee module is connected to the Tx or PIN 17 of the PIC18F2580.
Regarding the voltage levels on the various pins:
Zigbee module:
Vcc - 3.36v - this is within the expected nominal Vcc value as per the datasheet
Rx - 3.84v (when no receiving is taking place) - this is within the expected nominal Vcc value as per the datasheet
Tx - 34 (when no transmission is taking place) - this is within the expected nominal Vcc value as per the datasheet
PIC18F2580:
Vcc - 4.99v - this is within the expected nominal Vcc value as per the datasheet
Rx - 3.84v (when no receiving is taking place) - this is within the expected nominal Vcc value as per the datsheet
Tx - 3.34v (when no transmission is taking place) - this is within the expected nominal Vcc value as per the datasheet
The link below is the schematic drawing with regards to my PIC and zigbee connections (please note that I only connected up the Tx and Rx of the zigbee module as the rest of the zigbee module sub-circuit is on the development board whereby the module is mounted to). At this stage of my development for the purpose of simplicity, only connections to the PIC are the power, ground, the crystal oscillator and the zigbee module.
https://1d563b1a-a-62cb3a1a-s-sites.googlegroups.com/site/bgedsadownloads/PIC18F2580toETRX357HR.png?attachauth=ANoY7cqQnj1BMwp4YoL2xDe4Yt0-5xNJTVi8htZcrAvcBdYuSkjN0-dp4NtO2RTFRNVE58WTH4iqFf2ptAIZZ1--kubEUj_Z5cVby4PmSGnmeDZR-qqMh9F5xSKeXF--wx8_NhwDopwPOYfkL67d8hrNqvryeRAUewmd1ZpNvD7DCXIow6ysZSngZlLwRrr7GOQPv7WYl2Dui4nNIC6u1rEGa3gB04P_J8_UrcueiGFEYWKMduXAPvg%3D&attredirects=0
Once again i truly appreciate your replies as they are helping me move closer to successfully reading the RS232 responses plus if I've made a trivial oversight please accept my apologies. |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Mon Jan 27, 2014 11:25 am |
|
|
Hi Toktok,
Frankly, I kind of regret getting into this thread because you've bitten off a rather formidable project for a rank newbie.
You have got to break this problem up into manageable pieces if you have any hope of getting it to work! To start, you need to forget about the Zigbee
module for the time being. The first step is to understand and get working the 'ex_sisr.c' using your PC and terminal emulator.
You do know that your PIC has only one hardware serial port, right? For now you should connect this port to your PC via the MAX232 interface IC you
mentioned earlier. Get 'ex_sisr.c' working 100% like this first!
Later, you can re-task the hardware serial port to your Zigbee module, and define a software serial port on the PIC for status messages sent to
the PC.
Running the Zigbee and the PIC at different voltages *might* be a big problem. Are you sure the Zigbee Rx input is 5V tolerant? Are you sure
the Zigbee Tx output swings high enough to trigger the PIC Rx input? Again, forget this for now, and get the buffered serial working with the PC first!
Essentially, you've got to get the last piece of code you posted in your most recent reply working using the PIC hardware serial port connected to your PC.
John |
|
|
TokTok
Joined: 22 Jan 2014 Posts: 35
|
|
Posted: Tue Jan 28, 2014 3:28 am |
|
|
Hi John,
Thanks for the message.
I'll concentrate on breaking down and making the ex_sisr.c code work before going back into the PIC - zigbee comms.
I've read up on the voltages levels regarding the PIC and zigbee modules and indeed the Tx and Rx pins are meant to be the same as I've also confirmed this by checking the voltages on PIC + zigbee products previously delivered by my organisation.
Thanks. |
|
|
TokTok
Joined: 22 Jan 2014 Posts: 35
|
|
Posted: Tue Jan 28, 2014 9:27 am |
|
|
Hi all,
I've carefully studied the ex_sisr.c program to further understand the use of interrupts and the use of a buffer within the serial comms domain in CCS C.
Firstly I broke down the code focusing only on the interrupt function as seen in the code below:
Code: |
#include<18F2580.h>
#fuses XT,PUT,NOBROWNOUT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, STOP = 1, bits=8, ERRORS)
#define BUFFER_SIZE 32
BYTE buffer[BUFFER_SIZE];
BYTE next_in = 0;
BYTE next_out = 0;
#int_rda
void serial_isr() {
int t;
// Based on every buffer increment count assign incoming character to specific buffer element
buffer[next_in]=getc();
// Based on every buffer increment count attempt to transmit what is received. Through the terminal program I can see the above received char.
putc(buffer[next_in]);
// Assign next_in to t e.g. in the first buffer increment count as next_in is zero, t is equals to zero.
t=next_in;
// Increment the buffer increment count by one and divide increment result with buffer size and assign the division remainder to
// next_in - e.g. In the first buffer increment count next_in = (0+1) % 32 hence next_in = 1.
next_in = (next_in+1) % BUFFER_SIZE;
// Compare value of next_in to next_out and if next_in==next_out i.e. if the modulus result which is next_in is equal to next out which is zero
// then assign t to next_in essentially representing that the bufffer is full.
if(next_in == next_out)
next_in=t; // Buffer full !!
}
void main() {
// Enable the receive data interrupt
enable_interrupts(int_rda);
enable_interrupts(global);
}
|
The above code ran successfully and I can confirm that on my terminal program I could see the char that I was entering being returned by the putc() I inserted in the interrupt function.
My understanding of the interrupt function can be seen in the comments.
I continued studying the rest of the code and as mentioned earlier my understanding is noted in the comments.
Code: |
#include<18F2580.h>
#fuses XT,PUT,NOBROWNOUT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, STOP = 1, bits=8, ERRORS)
#define BUFFER_SIZE 32
BYTE buffer[BUFFER_SIZE];
BYTE next_in = 0;
BYTE next_out = 0;
#int_rda
void serial_isr() {
int t;
// Based on every buffer increment count assign incoming character to specific buffer element
buffer[next_in]=getc();
// Based on every buffer increment count attempt to transmit what is received. Through the terminal program I can see the above received char.
putc(buffer[next_in]);
// Assign next_in to t e.g. in the first buffer increment count as next_in is zero, t is equals to zero.
t=next_in;
// Increment the buffer increment count by one and divide increment result with buffer size and assign the division remainder to
// next_in - e.g. In the first buffer increment count next_in = (0+1) % 32 hence next_in = 1.
next_in = (next_in+1) % BUFFER_SIZE;
// Compare value of next_in to next_out and if next_in==next_out i.e. if the modulus result which is next_in is equal to next out which is zero
// then assign t to next_in essentially representing that the bufffer is full.
if(next_in == next_out)
next_in=t; // Buffer full !!
}
// Define bkbhit as next_in!=next_out
#define bkbhit (next_in!=next_out)
// Function bgetc returns a byte
BYTE bgetc() {
// Create a local byte variable
BYTE c;
// While !bkbhit i.e. while the following next_in != next_out condition is NOT TRUE meaning
// while next_in (which represents the current loop count)
// is equals to next_out which is 0 which means the buffer is full, then through the incrementing of next_out assign each element of the
// buffer to the byte c i.e. c = buffer[next_out];
while(!bkbhit);
c=buffer[next_out];
next_out=(next_out+1) % BUFFER_SIZE;
return(c);
}
void main() {
// Enable the receive data interrupt
enable_interrupts(int_rda);
enable_interrupts(global);
// I commented out printf as it sends dots doesn't work
//printf("\r\n\Running...\r\n");
// The program will delay for 10 seconds and then display
// any data that came in during the 10 second delay
do {
delay_ms(10000);
// I commented out printf as it sends dots doesn't work
//printf("\r\nBuffered data => ");
// While next_in is not equal to next_out meaning while the remainder between the current position in the buffer and the buffer size in NOT equal to zero
// which the means the buffer is not full then get the charcter using function bgetc() from the buffer and send it across using putc()
while(bkbhit)
putc( bgetc() ); // At the moment I'm unable to print the value on y terminal emulator
} while (TRUE);
}
|
In any way based on my comments I'm I misunderstanding any section of the code.
If not is it right to say that the BYTE returned by bgetc() is the desired outcome of the program.
When I run the full program above I receive no char (i.e. the same char I sent) when I send a char through my terminal program. This after playing around with the buffer size.
Apologies once again if my comments or question sound basic.
Alex.
Last edited by TokTok on Tue Jan 28, 2014 9:37 am; edited 1 time in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19541
|
|
Posted: Tue Jan 28, 2014 9:34 am |
|
|
Problem here is time.
It takes just on 1mSec to receive a character.
It also takes the same to send a character.
You are now sending the character _both_ in the interrupt, and the main. So for every 1mSec character that arrives, you have 2msec of transmission taking place. Doesn't fit.....
There is no point in delaying for ten seconds. Get rid of the print in the interrupt handler, and just start sending whenever a character is in the buffer.
Also, because putc, is used both inside and outside an interrupt, interrupts _will_ be disabled when it is used outside.
Then if you PC is set to 'echo', for every character sent, it'll be echoed back by the PIC _twice_, and then each echoed by the PC, result 'garbage'..... |
|
|
TokTok
Joined: 22 Jan 2014 Posts: 35
|
|
Posted: Tue Jan 28, 2014 10:34 am |
|
|
Hi Ttelmah,
Thanks for the very informative reply.
Regarding your comments:
It takes just on 1mSec to receive a character.
It also takes the same to send a character.
You are now sending the character _both_ in the interrupt, and the main. So for every 1mSec character that arrives, you have 2msec of transmission taking place. Doesn't fit....
I've eliminated the print in the interrupt handler meaning only the print in the main will be called meaning only one msec of receiving are taking place respectively.
There is no point in delaying for ten seconds. Get rid of the print in the interrupt handler, and just start sending whenever a character is in the buffer.
I've eliminated the delay and as mentioned the print in the interrupt routine and in my main I only print our any char received through the interrupt. I assume this ensures the interrupt in the main remains enabled.
Then if you PC is set to 'echo', for every character sent, it'll be echoed back by the PIC _twice_, and then each echoed by the PC, result 'garbage'.....
I'm using CoolTerm as my terminal emulator and in the receive option of the settings I've selected "Capture local echo".
Below is the adjusted code:
Code: |
#include<18F2580.h>
#fuses XT,PUT,NOBROWNOUT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, STOP = 1, bits=8, ERRORS)
#define BUFFER_SIZE 32
BYTE buffer[BUFFER_SIZE];
BYTE next_in = 0;
BYTE next_out = 0;
#int_rda
void serial_isr() {
int t;
// Based on every buffer increment count assign incoming character to specific buffer element
buffer[next_in]=getc();
// Assign next_in to t e.g. in the first buffer increment count as next_in is zero, t is equals to zero.
t=next_in;
// Increment the buffer increment count by one and divide increment result with buffer size and assign the division remainder to
// next_in - e.g. In the first buffer increment count next_in = (0+1) % 32 hence next_in = 1.
next_in = (next_in+1) % BUFFER_SIZE;
// Compare value of next_in to next_out and if next_in==next_out i.e. if the modulus result which is next_in is equal to next out which is zero
// then assign t to next_in essentially representing that the bufffer is full.
if(next_in == next_out)
next_in = t; // Buffer full !!
}
// Define bkbhit as next_in!=next_out
#define bkbhit (next_in!=next_out)
// Function bgetc returns a byte
BYTE bgetc() {
// Create a local byte variable
BYTE c;
// While !bkbhit i.e. while the following next_in != next_out condition is NOT TRUE meaning
// while next_in (which represents the current loop count)
// is equals to next_out which is 0 which means the buffer is full, then through the incrementing of next_out assign each element of the
// buffer to the byte c i.e. c = buffer[next_out];
while(!bkbhit);
c=buffer[next_out];
next_out=(next_out+1) % BUFFER_SIZE;
return(c);
}
void main() {
// Enable the receive data interrupt
enable_interrupts(int_rda);
enable_interrupts(global);
do {
// While next_in is not equal to next_out meaning while the remainder between the current position in the buffer and the buffer size in NOT equal to zero
// which the means the buffer is not full then get the charcter using function bgetc() from the buffer and send it across using putc()
while(bkbhit)
putc( bgetc() ); // At the moment I'm unable to print the value on my terminal emulator
} while (TRUE);
}
|
The above adjustments have enabled for the first time the print or putc() in the main function successfully.
Assuming I'm right in mentioning this is it possible to do the following using the result from bgetc():
1 - perform a comparison e.g. if(bgetc() =='w') then flash a specific LED twice
2 - Is it possible to modify the program so as to then send a string e.g. an AT command and using the interrupts in the same manner receive a response that isn't a single character/that is a string? I ask as after going back to basic to establish comms between the PIC and the PC I would like to establish comms between my PIC and a zigbee module (which is not connected in any whatsoever to the current PIC - PC setup). |
|
|
|
|
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
|