|
|
View previous topic :: View next topic |
Author |
Message |
GDetienne
Joined: 20 Sep 2003 Posts: 47 Location: Brussel - Belgium
|
16F88 and RS232 |
Posted: Sat Feb 26, 2005 2:53 am |
|
|
I have question about 16F88, RS232 and PCH 3.217.
I write the following test program (To do short, I don't give the LCD routine). Code: |
#include <16F88.h>
#fuses NOWDT,INTRC_IO, MCLR, BROWNOUT, NOLVP, PUT, NOPROTECT
#device *=16
#use delay(clock = 8000000)
#use rs232 (baud=4800,parity=N,xmit=PIN_B5,rcv=PIN_B2, errors )
#define LINE_1 0x00
#define LINE_2 0x40
#define CLEAR_DISP 0x01
#define LCD_D0 PIN_A0 //DB4
#define LCD_D1 PIN_A1 //DB5
#define LCD_D2 PIN_A2 //DB6
#define LCD_D3 PIN_A3 //DB7
#define LCD_EN PIN_A6 //enable
#define LCD_RS PIN_A7 // rs
const char Title [] = "Title";
char cRS232;
char cString[12];
#separate void LCD_Init ( void );
#separate void LCD_SetPosition ( unsigned int cX );
#separate void LCD_PutChar ( unsigned int cX );
#separate void LCD_PutCmd ( unsigned int cX );
#separate void LCD_PulseEnable ( void );
#separate void LCD_SetData ( unsigned int cX );
#separate void Erase_SecondLine ( void );
#use fast_io ( A )
#use standard_io ( B )
/***** Interrupts ****/
#int_rda
void SerialInterrupt (void)
{
cRS232=1;
fgets (cString);
}
void main()
{
port_b_pullups(TRUE);
setup_adc_ports(NO_ANALOGS);
set_tris_a ( 0x00 );
delay_ms (100);
cRS232 = 0;
LCD_Init ( ) ;
LCD_PutCmd ( CLEAR_DISP );
LCD_SetPosition (LINE_1);
printf(LCD_PutChar,"%s ", Title);
enable_interrupts (int_rda);
enable_interrupts (global);
while(1)
{
if (cRS232 == 1)
{
disable_interrupts (int_rda);
LCD_SetPosition (LINE_2);
printf(LCD_PutChar,"%s ", cString);
cRS232 = 0;
enable_interrupts (int_rda);
}
}
}
|
I read string within the interrupt and, in the main, I print it to the LCD. All work fine.
Now, the Pic don't send data and I wish use the pin B5 as output for Led control. I change the code in the use RS232 statement and nothing in hardware.
Code: | #use rs232 (baud=4800,parity=N,rcv=PIN_B2, errors )
|
The manual say that is possible. But ....
- the string is not send to my LCD,
- when I compare both LST files, I see that the code for use RS232 statement without tx pin is bigger than in other case.
I think that the Pic don't work with interrupt communication but with software communication. I don't found this confirmation in the manual.
Could you confirm ? Is it normal or not ?
Have a nice week end.
Thanks and regard. |
|
|
Ttelmah Guest
|
|
Posted: Sat Feb 26, 2005 3:20 am |
|
|
When you change the RS232 definition, you automatically switch to using software RS232. Your original form is the 'correct' way to code to use the hardware UART. Understand, that if you code as originally written, and then never send anything to the transmit output, there is nothing to stop you using the pin for other things, and that no code is actually generated for the transmit pin, till it is used. By removing the reference to the transmit pin, you force the compiler to use the software RS232, so the code grows.
With the software RS232, 'int_rda', is never going to occur. Hence it will not work.
In the original code, I would change to buffering the serial, rather than using 'fgets'. The problem is that if garbage arrives at the RS232 input, that does not include a 'end of line' character, the code will remain hung inside the interrupt. Also if the string that arrives is larger than the string space you have allocated, the data will overrun, and overwrite other variables in memory, causing chaos. What you have will only work if the data is always 'right'....
Best Wishes |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Feb 26, 2005 3:23 am |
|
|
Or to give a short answer, you can't split the hardware serial port.
It's all or nothing.
The 16F88 data sheet shows this in the section on the RCSTA register:
Code: | bit 7 SPEN: Serial Port Enable bit
1 = Serial port enabled (configures RB2/SDO/RX/DT and
RB5/SS/TX/CK pins as serial port pins)
0 = Serial port disabled |
Because of this, when you use the following line, the compiler creates a
software UART receiver:
Code: | #use rs232 (baud=4800,parity=N,rcv=PIN_B2, errors ) |
|
|
|
GDetienne
Joined: 20 Sep 2003 Posts: 47 Location: Brussel - Belgium
|
Thanks |
Posted: Sat Feb 26, 2005 4:52 am |
|
|
Thanks for your quick answer. That confirm what I think but with correct reasons.
Two questions :
- could you confirm that I can use the Tx port for Led control if I am sure not use it for transmit.
- I use fgets (cString) in my interrupt. Till now I try with caracters without garbage. I agree with you, it's better to change it for security. Do you think the best is a ring buffer or go out the interrupt after a fixed number of caracters ? What is your experience ? The length of my string is not constant but lower than 10 caracters.
Thanks a lot Ttelmah and PCM programmer (and others) for your advies.
Guy |
|
|
Ttelmah Guest
|
|
Posted: Sat Feb 26, 2005 7:45 am |
|
|
A ring buffer is a 'good' solution. However you might (assuming you want to always deal with a complete 'string' in the main code), consider a linear buffer. With this you just start adding characters to a string area in memory, and throw them away if the string gets too long (you lose data from the 'end', whereas with a ring buffer you normally lose it from the 'front' in the event of an overflow). When you see the terminator character, you set the flag to say you have a complete string, add a 'null' to the buffer, and it is just sitting there waiting in the buffer. With this you only need one counter. Effectively it'd behave exactly like the fgets, but with a limited size, and with the characters only added one at a time (to avoid sitting in the interrupt routine waiting for the string to arrive).
Yes, you can just use the output pin for another operation. Since the compiler does not actually generate the 'Tx' code, till you write something with putc, there is no problem. :-)
Code: |
char cRS232;
char cString[12];
#define cEOS (13)
#int_rda
void SerialInterrupt (void) {
static int8 ctr;
int8 temp;
temp=getc();
if (temp=cEOS) {
cString[ctr]='\0';
cRS232=true;
ctr=0;
return;
}
cString[ctr]=temp;
if (ctr<11) {
ctr+=1;
}
}
|
This should behave very like your existing program, except that if more than 11 characters arrive before the end of string character is seen, the trailing characters will just overwrite each other, and the routine will be called for each character in turn.
Best Wishes |
|
|
GDetienne
Joined: 20 Sep 2003 Posts: 47 Location: Brussel - Belgium
|
Thanks |
Posted: Sat Feb 26, 2005 8:34 am |
|
|
Thanks a lot. I have some directions to improve my self.
Thanks. |
|
|
|
|
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
|