|
|
View previous topic :: View next topic |
Author |
Message |
bwgames
Joined: 21 Jul 2005 Posts: 36
|
Garbage in on Software RS232 |
Posted: Tue Jul 04, 2006 8:10 am |
|
|
I'm using two PIC18F452 with 40Mhz clocks (crystal).
They both have wireless radio links connected to the hardware UART that use a serial protocol.
I can communicate between them fine. The problem comes when I set up a software UART to connect one of the boards to a PC.
Due to the fast clock speed, the only speed I could get satisfactory reception was 115,200 baud.
I can transmit data from the PIC to the PC fine, however any character I send from the PC to the PIC is garbage.
It is definitely a problem with the software UART/PC as the radio transmission link works fine (this has been tested by setting the PIC to transmit a character across the radio and for the receiving PIC to echo a string when that particular character is received).
Code is posted below - can anyone see any possible reasons why?
PIC connected to PC
Code: |
//******************************************************************************
// INCLUDE FILES
#define Fosc 40000000 // I'm using a 40 MHz crystal
#include <18F452.h>
#device *=16 ADC=8
//-------------------------------------------------------------------------------------
// DEFINES
#define WireTX PIN_B0
#define WireRX PIN_B1
//-------------------------------------------------------------------------------------
// COMPILER DIRECTIVES and HARDWARE CONFIGURATION
#use delay(clock = Fosc)
#fuses EC_IO // EC Oscillator with RA6 configured as DIO
#fuses NOOSCSEN // Oscillator System Clock Switch Disabled
#fuses NODEBUG // No Background Debugger
#fuses NOLVP // Low Voltage ICSP Disabled
#fuses NOPROTECT // No Code Protect
#fuses NOWDT // No onboard watchdog
#fuses PUT // Power Up Timer Enabled
#fuses BROWNOUT // Brown Out Reset enabled
#use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7, ERRORS, STREAM=Wireless)
#use rs232(baud=115200, xmit=WireTX, rcv=WireRX, ERRORS, STREAM=Computer)
#byte RCREG = 0x1A
//-------------------------------------------------------------------------------------
// GLOBALS
static char *c;
int term=0;
//-------------------------------------------------------------------------------------
//Code to add a timeout facility to getc, taken from CCS helpfile
short timeout_error;
char timed_getc() {
long timeout;
timeout_error=FALSE;
timeout=0;
while(!kbhit(Wireless)&&(++timeout<50000)) // 1/2 second
delay_us(10);
if(kbhit())
return(fgetc(Wireless));
else {
timeout_error=TRUE;
return(0);
}
}
void clear_usart_receiver(void) {
char d;
d = RCREG;
d = RCREG;
d = RCREG;
}
// MAIN PROGRAM & SETUP
void main()
{
fprintf(Computer,"Receiver online\n\r\n\r");
while(TRUE) {
while(kbhit(Computer)==0)
{
delay_us(1);
output_high(PIN_E2);
}
c = fgetc(Computer);
// delay_ms(50); //Introduced a 50ms delay in case the half duplex requirement of the software UART was the problem - this made no difference
fputc(c,Wireless);
output_low(PIN_E2);
while(1)
{
output_low(PIN_E2);
c = timed_getc();
if(c==0)
{
fprintf(Computer,"Time out.\n\r\n\r");
break;
output_high(PIN_E2);
}
fputc(c,Computer);
} //end of while1
c=0;
} //end of while TRUE
} //End of main
|
PIC only connected to wireless:
Code: |
//******************************************************************************
// INCLUDE FILES
#define Fosc 40000000 // I'm using a 40 MHz crystal
#include <18F452.h>
#device *=16 ADC=8
//-------------------------------------------------------------------------------------
// DEFINES
#define WireTX PIN_B0
#define WireRX PIN_B1
//-------------------------------------------------------------------------------------
// COMPILER DIRECTIVES and HARDWARE CONFIGURATION
#use delay(clock = Fosc)
#fuses EC_IO // EC Oscillator with RA6 configured as DIO
#fuses NOOSCSEN // Oscillator System Clock Switch Disabled
#fuses NODEBUG // No Background Debugger
#fuses NOLVP // Low Voltage ICSP Disabled
#fuses NOPROTECT // No Code Protect
#fuses NOWDT // No onboard watchdog
#fuses PUT // Power Up Timer Enabled
#fuses BROWNOUT // Brown Out Reset enabled
#use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7, ERRORS, STREAM=Wireless)
#byte RCREG = 0x1A
//-------------------------------------------------------------------------------------
// GLOBALS
static char *c;
int count=0;
short timeout_error;
char timed_getc() {
long timeout;
timeout_error=FALSE;
timeout=0;
while(!kbhit(Wireless)&&(++timeout<50000)) // 1/2 second
delay_us(10);
if(kbhit())
return(fgetc(Wireless));
else {
timeout_error=TRUE;
return(0);
}
}
void clear_usart_receiver(void)
{
char d;
d = RCREG;
d = RCREG;
d = RCREG;
}
//-------------------------------------------------------------------------------------
// MAIN PROGRAM & SETUP
void main()
{
while(1)
{
if(kbhit(Wireless))
{
c = getc();
delay_ms(500); //Introduced a delay between character reception and re-transmission just in case of the software UART on the receiving PIC causing a problem.
ascii(c);
fprintf(Wireless, "%c key pressed (COUNT = %d)\n\r",c, count);
output_high(PIN_E2);
delay_ms(100);
output_low(PIN_E2);
clear_usart_receiver();
count++;
}
} //End of while(1)
} //End of main
|
Any help would be great...
Thanks. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Tue Jul 04, 2006 8:57 am |
|
|
Do you have an RS232 transceiver between the PIC and the PC? Something like a MAX232. |
|
|
bwgames
Joined: 21 Jul 2005 Posts: 36
|
|
Posted: Tue Jul 04, 2006 9:12 am |
|
|
Yes. Receiving data from the PIC works fine, its just sending thats the problem. |
|
|
Ttelmah Guest
|
|
Posted: Tue Jul 04, 2006 9:19 am |
|
|
The problem is that you cannot use the 'timed getc', at this high rate, with the code as shown. For software serial, the code basically has to be waiting for the first bit to arrive, or no more than a fraction of a bit time 'late', in reaching this point. Each loop in the timed getc, is over 10uSec in length (10usec in the delay, plus the time needed to check the input, and update/check the counter). The bit time of the 115200bps communication, is only 8.68uSec, so you will completely miss the start bit most of the time...
You need to drop the loop time to only a couple of uSec (delay_us(1)), and then it should work.
Realistically, for a timed_getc, with the software serial, at such a high rate, you might be 'better off', using a hardware timer, setting a flag when this triggers, and just waiting while this flag is untrue and no serial is seen.
Best Wishes |
|
|
bwgames
Joined: 21 Jul 2005 Posts: 36
|
|
Posted: Wed Jul 05, 2006 2:44 am |
|
|
Thanks for the info. That definitely seemed to be it.. however I still have this problem.
I changed the code to launch straight into getc()
Code: |
....
fprintf(Computer,"Receiver online\n\r\n\r");
while(TRUE) {
c = fgetc(Computer);
fputc(c,Wireless);
while(1)
c = timed_getc();
....
|
but I still get garbage...?
I've never had anything successfully transmitted from PC to PIC using software.
How would I go about using a hardware timer?
Doing an echo of the character read in from PIC shows garbage too:
Code: |
c = fgetc(Computer);
fprintf(Computer,"Character read in: %c\n\r\n\r", c);
|
This is really stumping me... |
|
|
Ttelmah Guest
|
|
Posted: Wed Jul 05, 2006 3:17 am |
|
|
You will.
It is the delay in the _timed_getc_ function, that will still cause the problem. You must be waiting for _each_ character (not just the first), and the time delay in the timed_getc function, is just too long. As written, it is aimed at data rates like 9600bps, where a few uSec error will not matter, not for use at 115200bps.
something like this ought to work:
Code: |
//in the global stuff at the head of the program
#byte INTCON=0xFF2
#bit TMR0IF=INTCON.2
char timed_getc(void) {
timeout_error=FALSE;
disable_interrups(GLOBAL);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_128);
//This sets timer0, to overflow in about 0.8 seconds. Change the
//prescaler to get different times.
set_timer0(0);
clear_interrupt(INT_TIMER0);
while (!kbhit(Wireless)) {
//If timer0 overflows, this flag will become set, aborting the wait
if (TMR0IF) {
timeout_error=TRUE;
return(0);
}
}
//If you get this far, kbhit has been seen. Save time, and read.
return(fgetc(Wireless));
}
|
Best Wishes |
|
|
bwgames
Joined: 21 Jul 2005 Posts: 36
|
|
Posted: Wed Jul 05, 2006 4:02 am |
|
|
There was a typo in "
disable_interrups(GLOBAL); " which I've fixed, however clear_interrupt doesn't appear to be recognised.
I'm guessing you could use
TMR0IF = 0; instead? Tried that and it compiles fine.
However, I seem to have misled everyone.
I'm having no problems reading from/to the wireless.
The problem comes when I'm waiting for input from the PC.
I've adapted your timed_getc to work with the computer input as follows:
Code: |
char timed_getc_computer(void) {
timeout_error=FALSE;
disable_interrupts(GLOBAL);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_128);
//This sets timer0, to overflow in about 0.8 seconds. Change the
//prescaler to get different times.
set_timer0(0);
TMR0IF = 0; // Clear Timer 0 interrupt flag
while (!kbhit(Computer)) {
//If timer0 overflows, this flag will become set, aborting the wait
if (TMR0IF) {
timeout_error=TRUE;
return(0);
}
}
//If you get this far, kbhit has been seen. Save time, and read.
return(fgetc(Computer));
}
|
and similarly for wireless, but I still get garbage, even when I do a simple test such as what I pasted earlier:
Code: |
do
{
c = timed_getc_computer();
} while(c == 0);
fprintf(Computer,"Character read in: %c\n\r\n\r", c);
|
|
|
|
|
|
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
|