|
|
View previous topic :: View next topic |
Author |
Message |
Thomas Hauff Guest
|
TTL serial link? |
Posted: Mon Mar 24, 2003 8:47 am |
|
|
Hello All
I’m not having to good of luck!
What I’m trying to do is a TTL serial link.
The link is only one direction that is one PIC16F876 to another PIC16F876.
The max distance is 6’ so I think that this will work just fine.
Will I know that it will work because I have had it working some?
But it will not work consistently.
This is what I have the xmit PIC is using pin B2 to transmit on and the receive PIC is receiving on pin C7. I also have the two system grounds connected to each other.
This is what is happening is that some times the receiving PIC will work just fine.
This is only just after start up and this is not consistent.
I can never get it to work if I start the receiver and then start the transmitter.
The transmitter hardware and software are all ways consistent and working I have tested this on another system.
It is like the receiver interrupting is not working or getting hung up.
The heartbeat LED are working all the time so I know that the PIC is running.
I have some of the LCD lines on port C but this is C0 to C3.
Will this be an issues with C7 my receive pin?
Will some of you guys look at this code and see if I’m missing some thing.
Thank you
Main Code:
#include <16F876.h>
#device PIC16F876 *=16
//#device CCSICD=True
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#include <lcdcal.c>
#use rs232(baud=2400, xmit=PIN_C6, rcv=PIN_C7)
#define BUFFER_SIZE 32
byte buffer[BUFFER_SIZE];
byte next_in = 0;
byte next_out = 0;
#define HB_Low output_low(Pin_A5) //LED on pin 7 A5 output low
#define HB_High output_high(Pin_A5) //LED on pin 7 A5 output high
#define ints_per_ms 30 //The number of times that timer0 interrupts for 300ms heartbeat
#define bkbhit (next_in!=next_out)
static short int HBLED;
static int ms_count = ints_per_ms; //Set ms count for the 500ms heartbeat
#int_RDA
void serial_isr() {
int t;
buffer[next_in]=getc();
t=next_in;
next_in=(next_in+1) \% BUFFER_SIZE;
if(next_in==next_out)
next_in=t; // Buffer full !!
}
#int_timer0
void heart_timer0() //This is the interrupt handler for the heartbeat
{
if ( --ms_count == 0 ) {
ms_count = ints_per_ms; //Reset the Ms counter for interrupt
if (HBLED == True) { //Test if Heartbeat LED is on
HB_Low; //Turns off HeartBeat LED
HBLED = False; //Set HBLED flag to false LED off
}
else { //Heartbeat LED is off
HB_High; //Turns on HeartBeat LED
HBLED = True; //Set HBLED true to false LED off
}
}
}
//Do not use getc in this program!!!
//Use this function to get serial input data
byte bgetc() { //Function used to get data from serial buffer
byte c;
while(!bkbhit) ;
c=buffer[next_out];
next_out=(next_out+1) \% BUFFER_SIZE;
return(c);
}
main() {
// port_b_pullups(TRUE); //Turns on week pulls up on port B for
lcd_init();
enable_interrupts(global);
enable_interrupts(int_RDA);
enable_interrupts(INT_Timer0); //Turns On Timer0 interrupt for Heartbeat LED
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256 ); //Setup timer0 for button debounce
set_timer0(195); //Set timer0 for 10ms interrupt 9.984e-3 error for 10ms is 16us
lcd_putc(" Calibration Display");
delay_ms(3000);
printf(lcd_putc,"\f" );
while(bkbhit)
lcd_putc( bgetc() );
Delay_ms(500);
printf(lcd_putc,"\f" );
while (TRUE) {
delay_ms(50);
while(bkbhit)
lcd_putc( bgetc() );
}//While True
}//Main
LCD Driver Code:
// As defined in the following structure the pin connection is as follows:
// A0 enable
// A1 rs
// A2 rw
// C0 D4
// C1 D5
// C2 D6
// C3 D7
//
// LCD pins D0-D3 are not used.
struct lcd_pin_map { // This structure is overlayed
int data : 4; // on to an I/O port to gain
// boolean unused; // access to the LCD pins.
// boolean unused; // The bits are allocated from
// boolean unused; // low order up. ENABLE will
// boolean unused; // be pin B0.
} lcd;
/* Use #byte to assign variables to a RAM locations */
#use fast_io ( A ) /* don't set TRIS on each I/O statement */
#byte PORT_A = 5 /* set variable that maps to memory */
#byte lcd = 7 // Data lines on to port c (at address 7)
#bit enable = PORT_A.0
#bit rs = PORT_A.1
#bit rw = PORT_A.2
#define set_tris_lcd(x) set_tris_c(x)
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40 // LCD RAM address for the second line
byte CONST LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6};
// These bytes need to be sent to the LCD
// to start it up.
// The following are used for setting
// the I/O port direction register.
STRUCT lcd_pin_map const LCD_WRITE = {0x0}; // For write mode all pins are out
STRUCT lcd_pin_map const LCD_READ = {0xF}; // For read mode data pins are in
byte lcd_read_byte() {
byte low,high;
set_tris_lcd(LCD_READ);
rw = 1;
delay_cycles(1);
enable = 1;
delay_cycles(1);
high = lcd.data;
enable = 0;
delay_cycles(1);
enable = 1;
delay_us(1);
low = lcd.data;
enable = 0;
set_tris_lcd(LCD_WRITE);
return( (high<<4) | low);
}
void lcd_send_nibble( byte n ) {
lcd.data = n;
delay_cycles(1);
enable = 1;
delay_us(2);
enable = 0;
}
void lcd_send_byte( byte address, byte n ) {
rs = 0;
while ( bit_test(lcd_read_byte(),7) ) ;
rs = address;
delay_cycles(1);
rw = 0;
delay_cycles(1);
enable = 0;
lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}
void lcd_init() {
byte i;
set_tris_A( 0x00 );
set_tris_lcd(LCD_WRITE);
rs = 0;
rw = 0;
enable = 0;
delay_ms(15);
for(i=1;i<=3;++i) {
lcd_send_nibble(3);
delay_ms(5);
}
lcd_send_nibble(2);
for(i=0;i<=3;++i)
lcd_send_byte(0,LCD_INIT_STRING[i]);
}
void lcd_gotoxy( byte x, byte y) {
byte address;
if(y!=1)
address=lcd_line_two;
else
address=0;
address+=x-1;
lcd_send_byte(0,0x80|address);
}
void lcd_putc( char c) {
switch (c) {
case '\f' : lcd_send_byte(0,1);
delay_ms(2);
break;
case '\n' : lcd_gotoxy(1,2); break;
case '\b' : lcd_send_byte(0,0x10); break;
default : lcd_send_byte(1,c); break;
}
}
char lcd_getc( byte x, byte y) {
char value;
lcd_gotoxy(x,y);
rs=1;
value = lcd_read_byte();
rs=0;
return(value);
}
___________________________
This message was ported from CCS's old forum
Original Post ID: 12998 |
|
|
R.J.Hamlett Guest
|
Re: TTL serial link? |
Posted: Mon Mar 24, 2003 9:11 am |
|
|
:=Hello All
:=I’m not having to good of luck!
:=What I’m trying to do is a TTL serial link.
:=The link is only one direction that is one PIC16F876 to another PIC16F876.
:=The max distance is 6’ so I think that this will work just fine.
:=Will I know that it will work because I have had it working some?
:=But it will not work consistently.
:=This is what I have the xmit PIC is using pin B2 to transmit on and the receive PIC is receiving on pin C7. I also have the two system grounds connected to each other.
:=This is what is happening is that some times the receiving PIC will work just fine.
:=This is only just after start up and this is not consistent.
:=I can never get it to work if I start the receiver and then start the transmitter.
:=The transmitter hardware and software are all ways consistent and working I have tested this on another system.
:=It is like the receiver interrupting is not working or getting hung up.
:=The heartbeat LED are working all the time so I know that the PIC is running.
:=I have some of the LCD lines on port C but this is C0 to C3.
:=Will this be an issues with C7 my receive pin?
:=Will some of you guys look at this code and see if I’m missing some thing.
:=
:=Thank you
:=
:=Main Code:
:=#include <16F876.h>
:=#device PIC16F876 *=16
:=//#device CCSICD=True
:=#fuses HS,NOWDT,NOPROTECT,NOLVP
:=#use delay(clock=20000000)
:=
:=#include <lcdcal.c>
:=
:=#use rs232(baud=2400, xmit=PIN_C6, rcv=PIN_C7)
:=#define BUFFER_SIZE 32
:=byte buffer[BUFFER_SIZE];
:=byte next_in = 0;
:=byte next_out = 0;
:=
:=
:=
:=#define HB_Low output_low(Pin_A5) //LED on pin 7 A5 output low
:=#define HB_High output_high(Pin_A5) //LED on pin 7 A5 output high
:=#define ints_per_ms 30 //The number of times that timer0 interrupts for 300ms heartbeat
:=#define bkbhit (next_in!=next_out)
:=
:=static short int HBLED;
:=static int ms_count = ints_per_ms; //Set ms count for the 500ms heartbeat
:=
:=#int_RDA
:=void serial_isr() {
:= int t;
:=
:= buffer[next_in]=getc();
:= t=next_in;
:= next_in=(next_in+1) \% BUFFER_SIZE;
:= if(next_in==next_out)
:= next_in=t; // Buffer full !!
:=}
:=
:=#int_timer0
:=void heart_timer0() //This is the interrupt handler for the heartbeat
:={
:= if ( --ms_count == 0 ) {
:= ms_count = ints_per_ms; //Reset the Ms counter for interrupt
:=
:= if (HBLED == True) { //Test if Heartbeat LED is on
:= HB_Low; //Turns off HeartBeat LED
:= HBLED = False; //Set HBLED flag to false LED off
:= }
:= else { //Heartbeat LED is off
:= HB_High; //Turns on HeartBeat LED
:= HBLED = True; //Set HBLED true to false LED off
:= }
:= }
:=}
:=
:=
:=//Do not use getc in this program!!!
:=//Use this function to get serial input data
:=byte bgetc() { //Function used to get data from serial buffer
:= byte c;
:= while(!bkbhit) ;
:= c=buffer[next_out];
:= next_out=(next_out+1) \% BUFFER_SIZE;
:= return(c);
:=}
:=
:=
:=
:=main() {
:=
:=// port_b_pullups(TRUE); //Turns on week pulls up on port B for
:=
:= lcd_init();
:=
:= enable_interrupts(global);
:= enable_interrupts(int_RDA);
:= enable_interrupts(INT_Timer0); //Turns On Timer0 interrupt for Heartbeat LED
:=
:= setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256 ); //Setup timer0 for button debounce
:= set_timer0(195); //Set timer0 for 10ms interrupt 9.984e-3 error for 10ms is 16us
:=
:= lcd_putc(" Calibration Display");
:= delay_ms(3000);
:= printf(lcd_putc,"\f" );
:= while(bkbhit)
:= lcd_putc( bgetc() );
:= Delay_ms(500);
:= printf(lcd_putc,"\f" );
:=
:=while (TRUE) {
:= delay_ms(50);
:= while(bkbhit)
:= lcd_putc( bgetc() );
:=
:= }//While True
:=}//Main
:=
:=
:=LCD Driver Code:
:=
:=// As defined in the following structure the pin connection is as follows:
:=// A0 enable
:=// A1 rs
:=// A2 rw
:=// C0 D4
:=// C1 D5
:=// C2 D6
:=// C3 D7
:=//
:=// LCD pins D0-D3 are not used.
:=
:=
:=struct lcd_pin_map { // This structure is overlayed
:= int data : 4; // on to an I/O port to gain
:=// boolean unused; // access to the LCD pins.
:=// boolean unused; // The bits are allocated from
:=// boolean unused; // low order up. ENABLE will
:=// boolean unused; // be pin B0.
:= } lcd;
:=
:=/* Use #byte to assign variables to a RAM locations */
:=#use fast_io ( A ) /* don't set TRIS on each I/O statement */
:=#byte PORT_A = 5 /* set variable that maps to memory */
:=#byte lcd = 7 // Data lines on to port c (at address 7)
:=#bit enable = PORT_A.0
:=#bit rs = PORT_A.1
:=#bit rw = PORT_A.2
:=
:=#define set_tris_lcd(x) set_tris_c(x)
:=
:=#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines
:=#define lcd_line_two 0x40 // LCD RAM address for the second line
:=
:=
:=byte CONST LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6};
:= // These bytes need to be sent to the LCD
:= // to start it up.
:=
:= // The following are used for setting
:= // the I/O port direction register.
:=
:=STRUCT lcd_pin_map const LCD_WRITE = {0x0}; // For write mode all pins are out
:=STRUCT lcd_pin_map const LCD_READ = {0xF}; // For read mode data pins are in
:=
:=
:=
:=
:=byte lcd_read_byte() {
:=byte low,high;
:= set_tris_lcd(LCD_READ);
:= rw = 1;
:= delay_cycles(1);
:= enable = 1;
:= delay_cycles(1);
:= high = lcd.data;
:= enable = 0;
:= delay_cycles(1);
:= enable = 1;
:= delay_us(1);
:= low = lcd.data;
:= enable = 0;
:= set_tris_lcd(LCD_WRITE);
:= return( (high<<4) | low);
:=}
:=
:=
:=void lcd_send_nibble( byte n ) {
:= lcd.data = n;
:= delay_cycles(1);
:= enable = 1;
:= delay_us(2);
:= enable = 0;
:=}
:=
:=
:=void lcd_send_byte( byte address, byte n ) {
:=
:= rs = 0;
:= while ( bit_test(lcd_read_byte(),7) ) ;
:= rs = address;
:= delay_cycles(1);
:= rw = 0;
:= delay_cycles(1);
:= enable = 0;
:= lcd_send_nibble(n >> 4);
:= lcd_send_nibble(n & 0xf);
:=}
:=
:=
:=void lcd_init() {
:=byte i;
:= set_tris_A( 0x00 );
:= set_tris_lcd(LCD_WRITE);
:= rs = 0;
:= rw = 0;
:= enable = 0;
:= delay_ms(15);
:= for(i=1;i<=3;++i) {
:= lcd_send_nibble(3);
:= delay_ms(5);
:= }
:= lcd_send_nibble(2);
:= for(i=0;i<=3;++i)
:= lcd_send_byte(0,LCD_INIT_STRING[i]);
:=}
:=
:=
:=void lcd_gotoxy( byte x, byte y) {
:=byte address;
:=
:= if(y!=1)
:= address=lcd_line_two;
:= else
:= address=0;
:= address+=x-1;
:= lcd_send_byte(0,0x80|address);
:=}
:=
:=void lcd_putc( char c) {
:= switch (c) {
:= case '\f' : lcd_send_byte(0,1);
:= delay_ms(2);
:= break;
:= case '\n' : lcd_gotoxy(1,2); break;
:= case '\b' : lcd_send_byte(0,0x10); break;
:= default : lcd_send_byte(1,c); break;
:= }
:=}
:=
:=char lcd_getc( byte x, byte y) {
:= char value;
:=
:= lcd_gotoxy(x,y);
:= rs=1;
:= value = lcd_read_byte();
:= rs=0;
:= return(value);
:=}
I think your first problem, is the handling initialisation. What you should do, is have a pull up resistor on the serial line. RS232 idles (at the TTL connections), high. Now with your system, if the receiver wakes up before the transmitter, the line will be floating, till the port pull up is enabled at the transmitter, and the receiver will either see garbage, or a continuous low. This then can leave the receiver in a confused state when the transmitter finally starts.
The second point (which relates to the first), is that if the hardware UART sees characters, before your handler is enabled, or you do not handle the data fast enough, and overrun error can get set. If this happens, the port will stop receiving, till this condition is cleared. You can detect this, by either testing the OERR bit directly, or using the 'ERRORS' ability in the RS232 code. You should add a detect and clear for this, into your receive handler (I suspect this is what is preventing the startup, with the error being set and never cleared).
You are doing a 'set_tris' operation on port C, but have not selected 'fast_io'. Your TRIS will be being overwritten by the default behaviour, and this may well cause unexpected behaviour.
Best Wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 12999 |
|
|
Thomas Hauff Guest
|
Re: TTL serial link? |
Posted: Mon Mar 24, 2003 9:43 am |
|
|
:=I think your first problem, is the handling initialisation. What you should do, is have a pull up resistor on the serial line. RS232 idles (at the TTL connections), high. Now with your system, if the receiver wakes up before the transmitter, the line will be floating, till the port pull up is enabled at the transmitter, and the receiver will either see garbage, or a continuous low. This then can leave the receiver in a confused state when the transmitter finally starts.
:=The second point (which relates to the first), is that if the hardware UART sees characters, before your handler is enabled, or you do not handle the data fast enough, and overrun error can get set. If this happens, the port will stop receiving, till this condition is cleared. You can detect this, by either testing the OERR bit directly, or using the 'ERRORS' ability in the RS232 code. You should add a detect and clear for this, into your receive handler (I suspect this is what is preventing the startup, with the error being set and never cleared).
:=You are doing a 'set_tris' operation on port C, but have not selected 'fast_io'. Your TRIS will be being overwritten by the default behaviour, and this may well cause unexpected behaviour.
:=
:=Best Wishes
Thank You so much for the fast reply R.J. Hamlett
Ok will a 5K or 10K resistor provide enough current for a pull on the RS232 receiver line?
I’m trying to keep the required power down.
Would you be so kind to post an example of testing the OERR bit directly and a example of using this ‘ERRORS’ for the #use RS232 statement.
Do you have any suggestion on the ‘set_tris_c’ issues?
Thank you so much Tom
___________________________
This message was ported from CCS's old forum
Original Post ID: 13003 |
|
|
Steve H Guest
|
Input resistance... |
Posted: Mon Mar 24, 2003 1:55 pm |
|
|
Looking at a Maxim MAX232 data sheet you can see thre receiver input resistance listed as 3-7 k ohms. This is probably typical of all RS232 chips out there.
So if you use 3k on a 5 volt supply you will only get 2.5 volts at the receiver, this is just barely above the MAX232's maximum input threshold of 2.4 volts.
Steve H.
___________________________
This message was ported from CCS's old forum
Original Post ID: 13019 |
|
|
Sherpa Doug Guest
|
Re: Input resistance... |
Posted: Mon Mar 24, 2003 2:07 pm |
|
|
:=Looking at a Maxim MAX232 data sheet you can see thre receiver input resistance listed as 3-7 k ohms. This is probably typical of all RS232 chips out there.
:=
:=So if you use 3k on a 5 volt supply you will only get 2.5 volts at the receiver, this is just barely above the MAX232's maximum input threshold of 2.4 volts.
:=
:=Steve H.
I believe that 3-7k is on the RS232 side of the chip. The TTL side of the chip should be a standard TTL input which is much higher than 3-7k. I don't think that Mr Hauff is using any converter chips. He is just connecting one PIC pin to another with a piece of wire. So a 10K resistor should be fine.
___________________________
This message was ported from CCS's old forum
Original Post ID: 13022 |
|
|
Thomas Hauff Guest
|
Re: Chacking OERR bit? |
Posted: Mon Mar 24, 2003 2:41 pm |
|
|
Hello All
I did not have any luck with the pull up resistor but I have to get it solder in I just used clip leads for now.
Also on luck with the ‘ERRORS’ word in the #use RS232 statement.
So moving to testing of the OERR bit this is the code I’m have written what do you guys think.
Is this the right road?
#byte RCSTA = 0x18
if (bit_test(RCSTA,1)){
bit_clear(RCSTA,4);
bit_set(RCSTA,4);
}
Thank you all!
Tom
___________________________
This message was ported from CCS's old forum
Original Post ID: 13025 |
|
|
Steve H Guest
|
Oops 2 |
Posted: Mon Mar 24, 2003 3:13 pm |
|
|
I misread the post. I thought it said PIC to PC connection.
Nevermind!
I'll go hide under my rock now ;-)
Steve H.
___________________________
This message was ported from CCS's old forum
Original Post ID: 13028 |
|
|
R.J.Hamlett Guest
|
Re: TTL serial link? |
Posted: Mon Mar 24, 2003 4:10 pm |
|
|
:=:=I think your first problem, is the handling initialisation. What you should do, is have a pull up resistor on the serial line. RS232 idles (at the TTL connections), high. Now with your system, if the receiver wakes up before the transmitter, the line will be floating, till the port pull up is enabled at the transmitter, and the receiver will either see garbage, or a continuous low. This then can leave the receiver in a confused state when the transmitter finally starts.
:=:=The second point (which relates to the first), is that if the hardware UART sees characters, before your handler is enabled, or you do not handle the data fast enough, and overrun error can get set. If this happens, the port will stop receiving, till this condition is cleared. You can detect this, by either testing the OERR bit directly, or using the 'ERRORS' ability in the RS232 code. You should add a detect and clear for this, into your receive handler (I suspect this is what is preventing the startup, with the error being set and never cleared).
:=:=You are doing a 'set_tris' operation on port C, but have not selected 'fast_io'. Your TRIS will be being overwritten by the default behaviour, and this may well cause unexpected behaviour.
:=:=
:=:=Best Wishes
:=
:=Thank You so much for the fast reply R.J. Hamlett
:=Ok will a 5K or 10K resistor provide enough current for a pull on the RS232 receiver line?
:=I’m trying to keep the required power down.
:=Would you be so kind to post an example of testing the OERR bit directly and a example of using this ‘ERRORS’ for the #use RS232 statement.
:=Do you have any suggestion on the ‘set_tris_c’ issues?
:=
:=Thank you so much Tom
A search in the archives here, should find the OERR handler. I posted an example a while ago, and there have been several other threads with this data (look for people talking about having problems with the serial port).
The resistor should be fine (it is only to ensure the line is actually high when undriven). Also since the RS232 idles high, very little power will be drawn.
Best Wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 13029 |
|
|
R.J.Hamlett Guest
|
Re: Chacking OERR bit? |
Posted: Mon Mar 24, 2003 4:17 pm |
|
|
:=Hello All
:=I did not have any luck with the pull up resistor but I have to get it solder in I just used clip leads for now.
:=Also on luck with the ‘ERRORS’ word in the #use RS232 statement.
:=So moving to testing of the OERR bit this is the code I’m have written what do you guys think.
:=Is this the right road?
:=
:=#byte RCSTA = 0x18
:=
:=if (bit_test(RCSTA,1)){
:= bit_clear(RCSTA,4);
:= bit_set(RCSTA,4);
:= }
:=
:=Thank you all!
:=Tom
Looks fine. :-)
Remember you can code the same as bits, which I think makes the intention clearer. So:
#bit OERR = 0x18.1
#bit CREN = 0x18.4
if (OERR) {
CREN=false;
CREN=true;
}
May be clearer in the future.
Also you must ensure you remove at least one character from the input buffer (technically there are three waiting if this bit is set), or the fault will recur.
Best Wishes
___________________________
This message was ported from CCS's old forum
Original Post ID: 13030 |
|
|
|
|
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
|