|
|
View previous topic :: View next topic |
Author |
Message |
michaelb[logged out] Guest
|
RF Module Message Corruption |
Posted: Sun Jan 29, 2006 4:51 pm |
|
|
Hi,
I'm sending data between an RF Solutions AM-RT4-433 transmitter and a AM-RR3-433. I am sending data between two PIC16F877A's over the UART's using 300 baud. Viewing the incoming singal directly from the receiver it is fine, however once gone through the PIC it is corrupted. Using 4MHz crystal and PCWH 3.212 if that is of any use. Thanks in advance for any help.
Kind Regards,
Michael
Data Sent:
Code: | printf("%c", 0xBA); // LAM - something for the RX's USART to "lock onto"
printf("%c", 0xBE); // LAM - something for the RX's USART to "lock onto"
printf("%c", 0xFA); // LAM - something for the RX's USART to "lock onto"
printf("%c", 0xCE); // LAM - something for the RX's USART to "lock onto"
printf("UUUUDUaUtUaU UHUeUrUeU\rU\n"); |
Lot's of preamble just to make sure
Data Received:
Code: |
UUUWU]U=UUoU5U5UU@
or
UUUWU]U=UUoU5U5UU
Something like that
|
My code is
Code: | #include <16F877.h> //PIC16F877A Device
#device *=16 //Use 16 Bit Pointers
#fuses HS,NOWDT,NOPROTECT,NOLVP //Set Fuses
#use delay(clock=4000000) //20MHz Clock
#use rs232(baud=300, xmit=PIN_C6, rcv=PIN_C7, ERRORS) //Configure RS232 Comms
#define esc 0x1B //Terminal Escape Character
#byte RCREG = 0x1A
//Function Prototypes
void cls(); //Clear Terminal Screen
//Global Variables
int line_complete = 0;
#INT_RDA //Serial RX Interrupt
RDA_isr()
{
char real;
real = getc();
printf("%c", real);
}
void main()
{
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
cls();
printf("Listening\r\n");
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA);
while(1)
{
while(!line_complete) //Wait for sentence to be completed
{
#asm
NOP
#endasm
}
}
}
void cls(void) //Send clear command to terminal
{
printf("%c[2J",esc);
} |
|
|
|
libor
Joined: 14 Dec 2004 Posts: 288 Location: Hungary
|
|
Posted: Sun Jan 29, 2006 7:54 pm |
|
|
Don't use printf() in the interrupt handler routines. Just quickly store the incoming data in an array and print them in a not timing-sensitive function. Printf() takes a long time to execute, you are missing some action on the RX line during its execution. |
|
|
ak6dn
Joined: 08 Jan 2006 Posts: 23 Location: Saratoga, CA USA
|
re: RF module message corruption |
Posted: Sun Jan 29, 2006 11:14 pm |
|
|
Attached is a little section of test code that I use on the transmit side where I'm sending data from a PIC16F877A to a PC serial port. The link is thru a Laipac TLP315A/RLP315A pair of wireless modules. The below code works just fine.
A key point to note is that most of these direct digital RF modules have not only maximum data rates (4800baud for this module) BUT also minimum data rates (400baud for this module). The transmit code below will send characters from the buffer if there are any, and if none it will send a sync/idle character of 0xF0.
I chose 0xF0 as the idle character specifically because it has EXACTLY one falling edge per character, so syncing up the receiver is totally unambiguous (including the odd parity which I use, but this is optional).
On the receive side I just discard all 0xF0 characters as 'filler' (and I know my transmit state machine will never send 0xF0 accidentally).
The issue of NOT using printf in your receive intr routine is a key point. I would also check to see if the '300baud' rate is supported as a data rate thru your modules. This seems to be somewhat on the low side to me, and you could easily be violating the min data rate of your modules.
Code: | #include <16F877A.h>
#fuses XT,WDT,PUT,NOPROTECT,NOCPD,NOWRT,NOLVP,NOBROWNOUT,NODEBUG
#use delay (clock=3686400)
#use rs232 (baud=4800, bits=8, parity=O, errors, xmit=PIN_C6, rcv=PIN_C7)
// global data
#define TX_BUFFER_SIZE 16
char tx_buffer[TX_BUFFER_SIZE];
int8 tx_buffer_in = 0; // index of last char placed in buffer
int8 tx_buffer_out = 0; // index of last char transmitted
// transmit interrupt service
#int_tbe
void serialtx_isr (void)
{
// check for presence of char to transmit
if (tx_buffer_in == tx_buffer_out) {
// nope, send idle flag
putc(0xF0);
} else {
// transmit char at current buffer position
putc(tx_buffer[tx_buffer_out]);
// put seen flag at just transmitted character (debug/sanity)
tx_buffer[tx_buffer_out] = '!';
// bump index to next slot, modulo buffer size
tx_buffer_out = (tx_buffer_out+1) % TX_BUFFER_SIZE;
// and done
}
return;
}
// add a character to the transmit buffer
void bputc (char c)
{
int8 index;
// bump buffer position pointer
index = (tx_buffer_in+1) % TX_BUFFER_SIZE;
// if in/out indices collide, buffer is full, must wait
while (index == tx_buffer_out) delay_us(100);
// put current char in buffer
tx_buffer[tx_buffer_in] = c;
// bump input index for real
tx_buffer_in = index;
// and done
restart_wdt();
return;
}
// Main program
void main (void)
{
int8 i;
// configure I/O pins
set_tris_a(0x00);
set_tris_b(0x00);
set_tris_c(0x00);
set_tris_d(0x00);
set_tris_e(0x00);
// watchdog
setup_wdt(WDT_2304MS);
// allow interrupts
enable_interrupts(int_tbe);
enable_interrupts(global);
// loop forever
for (;;) {
// do something
for (i = 0; i < 56; i++) {
switch (i % 8) {
case 0: printf(bputc, "\r\n"); break;
case 1: printf(bputc, "a"); break;
case 2: printf(bputc, "bcd"); break;
case 3: printf(bputc, "efghijklmnopqrstuvwxyz"); break;
case 4: printf(bputc, "0123456789"); break;
case 5: printf(bputc, "( )"); break;
default: break;
}
delay_ms(40);
}
// wait until all char transmitted
while (tx_buffer_in != tx_buffer_out) { delay_ms(5); restart_wdt(); }
} // for (;;)
// should never get here...
reset_cpu();
}
|
|
|
|
michaelb
Joined: 28 Nov 2005 Posts: 17
|
|
Posted: Mon Jan 30, 2006 3:44 am |
|
|
Thanks for the suggestions. I've tried them out, but still to no avail I'm afraid.
The min/ max data rate is 50 - 2000 Hz, I thought 1 baud may be higher than 1 Hz as it involves transitions so kept the baudrate low. I've now increased it to 1200. I should mention that the supposed TTL/CMOS output of the RF module did not seem to trigger the PIC's UART, so i've looped it back on itself through a MAX233 (i.e. TTL-RS232 back to RS232 - TTL), as this seems to work. Below is the code I've now changed it to. Any help is extremely welcome.
Code: |
#include <16F877.h> //PIC16F877A Device
#device *=16 //Use 16 Bit Pointers
#fuses HS,NOWDT,NOPROTECT,NOLVP //Set Fuses
#use delay(clock=4000000) //20MHz Clock
#use rs232(baud=1200, xmit=PIN_C6, rcv=PIN_C7, ERRORS) //Configure RS232 Comms
#define esc 0x1B //Terminal Escape Character
#byte RCREG = 0x1A
#byte RCSTA=0x18
#define SPEN_BIT 7
#define OERR_BIT 1
#define FERR_BIT 2
#define CREN_BIT 4
//Function Prototypes
void cls(); //Clear Terminal Screen
void clear_usart_receiver(void); //Clear USART Receiver RX Buffers
void reset_uart(void); //Reset hardware USART
//Global Variables
int line_complete = 0;
char buffer[30];
int buffer_pointer = 0;
int data_valid = 0;
#INT_RDA //Serial RX Interrupt
RDA_isr()
{
char real;
real = getc();
if((real == 'U') && (data_valid == 0))
{
data_valid = 1;
}
else if((real == '\r') || (real == '\n'))
{
data_valid = 0;
line_complete = 1;
}
if(data_valid)
{
buffer[buffer_pointer] = real;
buffer_pointer++;
}
if(buffer_pointer >= 29)
{
data_valid = 0;
line_complete = 1;
}
}
void main()
{
int i=0;
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
cls();
printf("Listening\r\n");
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA);
while(1)
{
while(!line_complete) //Wait for sentence to be completed
{
#asm
NOP
#endasm
}
if(line_complete)
{
disable_interrupts(INT_RDA);
printf("DONE\r\n");
for(i=0;i < buffer_pointer;i++)
{
putc(buffer[i]);
}
clear_usart_receiver();
reset_uart();
line_complete = 0;
buffer_pointer = 0;
enable_interrupts(INT_RDA);
}
}
}
void cls(void) //Send clear command to terminal
{
printf("%c[2J",esc);
}
void clear_usart_receiver(void) //Clear UART Receive Buffers
{
char c;
c = RCREG;
c = RCREG;
c = RCREG;
}
void reset_uart(void) //Reset the USART
{
bit_clear(RCSTA, SPEN_BIT); // Reset the serial port
bit_clear(RCSTA, OERR_BIT);
bit_clear(RCSTA, FERR_BIT);
bit_clear(RCSTA, CREN_BIT);
delay_ms(1);
bit_set(RCSTA, SPEN_BIT);
bit_set(RCSTA, CREN_BIT);
delay_ms(1);
}
|
As the \r\n characters are never detected by the PIC, the ouput is only ever printed when the buffer reaches the limit. Terminal output looks like this:
Code: |
UUUW=o5ՑUUUW=oDONE
or
UUUW=o5UUUW=oDONE
|
Usually the top line is received, but the fact that it does sometimes vary is concerning. |
|
|
michaelb
Joined: 28 Nov 2005 Posts: 17
|
|
Posted: Mon Jan 30, 2006 4:28 am |
|
|
Fixed now. I've been very silly... got my MAX233 wiring messed up. Thanks for everyone's input.
Michael |
|
|
|
|
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
|