UART

Thread Starter

Dritech

Joined Sep 21, 2011
901
Hi all,

I am using the following code for UART communication between the PC and the 18f microcontroller (on 20MHz). Can someone please tell me why not all characters are being echoed correctly when tested using PuTTY??

Rich (BB code):
void main(void)
{
    unsigned char dat;

    TXSTA = 0X24;
    RCSTA = 0X90;
    SPBRG = 0X81;

while(1)

{

while(PIR1bits.RCIF == 0); 

dat = RCREG;           

TXREG = dat;          

while(PIR1bits.TXIF == 0); 
}
 
}
 

JohnInTX

Joined Jun 26, 2012
4,787
I read your setup for a generic 18F as 9600 baud. Is that correct?
You do not show that TRISC has been configured. Per the datasheet:
The SPEN (RCSTA register) and the TRISC<7> bits
have to be set and the TRISC<6> bit must be cleared
in order to configure pins RC6/TX/CK and RC7/RX/DT
as the Universal Synchronous Asynchronous Receiver
Transmitter.


Are you setting ALL of the CONFIG bits for the processor AND initializing ALL of the I/O??

If it echoes single characters but fails on longer strings consider pacing the transmitter i.e. a little delay between characters.

A subtle problem here is that you have a required 1:1 correspondence between receive time and transmit time due to polling the registers. The added processing time of getting / putting / looping will eventually eat your sack lunch unless there is some delay between transmitted characters.
 
Last edited:

Thread Starter

Dritech

Joined Sep 21, 2011
901
Hi,
I included the TRIS part but it is still not working. I tested the MAX232 using a multimeter and it is ok. I also shorted pins 2 and 3 of the USB to serial cable and it is also working in order.

When testing the voltage on the TX and RX pins of the PIC, I am getting 5V on both of them. Is this normal?

I also tried the code below to test the TX, but it is not working:

Rich (BB code):
dat = 'm';

TXREG = dat;           //dat value is given to TXREG for transmit

while(PIR1bits.TXIF == 0); //keep looping till TXIF is high. When it is high it indicated data have been transmitted

while(1);
Are you setting ALL of the CONFIG bits for the processor AND initializing ALL of the I/O??
Below are the config settings for a 20MHz Xtal:

Rich (BB code):
#pragma config FOSC  = HSPLL_HS 
#pragma config PLLDIV = 5        
#pragma config CPUDIV = OSC1_PLL2
#pragma config USBDIV = 2         
#pragma config FCMEN  = OFF      
#pragma config IESO  = OFF      
#pragma config PWRT  = OFF    
#pragma config BOR    = ON        
#pragma config VREGEN = ON     
#pragma config WDT    = OFF    
#pragma config MCLRE  = ON      
#pragma config LVP    = OFF      
#pragma config ICPRT  = OFF     
#pragma config CP0    = OFF
Is the configuration correct please?
 

JohnInTX

Joined Jun 26, 2012
4,787
Rich (BB code):
  TRISCbits.TRISC6 = 1;
  TRISCbits.TRISC7 = 1;
Is this how to set TRIS please?
No. RC6 (TX) must be an output. TRISC6=0.

Is the configuration correct please?
I don't know. What is the PIC part number and what kind of oscillator are you using? On first glance, if you are using a 20MHz oscillator, you probably don't want the PLL as the system speed will no longer be 20MHz and your baud rate will be off.

You can further test your serial link by pulling the PIC and jumpering RC7 and RC6.. If characters are echoed, you know that the MAX232/USB serial cable are working as far as PIC UART.
 

MaxHeadRoom

Joined Jul 18, 2013
28,617
The Pic micro USART App sheet and the various examples for the 16F, 17F and 18F posted by Microchip's Dave Garbutt specify that although one is input the other an output they are both set for input.
SetupSerial:
movlw 0xc0 ; = b'11000000' set tris bits for TX and RX
iorwf TRISC, F

I only program in assembly hence the above code.
I designed around the examples and they work fine?
Max.
 

Thread Starter

Dritech

Joined Sep 21, 2011
901
Thanks for the reply.

No. RC6 (TX) must be an output. TRISC6=0.
I set them both high since it is stated in the PIC18F4550 datasheet (pg 243).

I don't know. What is the PIC part number and what kind of oscillator are you using?
I am using the PIC18F4550 with 20MHz.

On first glance, if you are using a 20MHz oscillator, you probably don't want the PLL as the system speed will no longer be 20MHz and your baud rate will be off.
So I remove "#pragma config PLLDIV = 5" or "#pragma config CPUDIV = OSC1_PLL2" ?


Regarding TXSTA.BRGH, shell I set it to high or low speed when using a baud rate of 9600? From the research I did, it shows that setting it to high speed reduces errors.
 

JohnInTX

Joined Jun 26, 2012
4,787
The Pic micro USART App sheet and the various examples for the 16F, 17F and 18F posted by Microchip's Dave Garbutt specify that although one is input the other an output they are both set for input.
SetupSerial:
movlw 0xc0 ; = b'11000000' set tris bits for TX and RX
iorwf TRISC, F

I only program in assembly hence the above code.
I designed around the examples and they work fine?
Max.
Some do and some don't. The paste in blue above was from the 18F452. This is from the 16F887:
Setting the TXEN bit of the TXSTA register enables the
transmitter circuitry of the EUSART. Clearing the SYNC
bit of the TXSTA register configures the EUSART for
asynchronous operation. Setting the SPEN bit of the
RCSTA register enables the EUSART and
automatically configures the TX/CK I/O pin as an output
.
If the TX/CK pin is shared with an analog peripheral the
analog I/O function must be disabled by clearing the
corresponding ANSEL bit
.
OP: ANSEL.. Check it out.
Looking at the 18F4550:
The pins of the Enhanced USART are multiplexed
with PORTC. In order to configure RC6/TX/CK and
RC7/RX/DT/SDO as an EUSART:
• SPEN bit (RCSTA<7>) must be set (= 1)
• TRISC<7> bit must be set (= 1)
• TRISC<6> bit must be set (= 1)
Different again.
I'm not sure I've used the latter one or why setting the unidirectional TX pin to output would be a problem but.. Moral, read that datasheet.
 

JohnInTX

Joined Jun 26, 2012
4,787
So I remove "#pragma config PLLDIV = 5" or "#pragma config CPUDIV = OSC1_PLL2" ?
Regarding TXSTA.BRGH, shell I set it to high or low speed when using a baud rate of 9600? From the research I did, it shows that setting it to high speed reduces errors.
Ahh... for this one HS_PLL with CPU_DIV1:0 = 00 should generate a 20MHz clock. (Ref TABLE2-3, line 1) I don't know what value OSC1_PLL2 sets. Build your code and look at the configuration bits in MPLAB to see or check the compiler documentation. PLL_DIV drives the USB so should not be an issue here. I haven't used the 4550 so just reading the datasheet.. BRGH=1 is better (fewer errors).

BTW, if you are going to use the USB, uCHIP says the system XTAL must be 6MHz or 48MHz with the processor clock derived from that. DISREGARD. They say an internal clock of 6MHz or 48MHz for the USB.., presumably derived from the external clock.

Looking at the pin descriptions for RC6/7 in Table 10-5, we see the requirement that the 'User must configure as an output'. This is at odds with my earlier blue paste from section 20.0 which says that it should be an input. Go figure. I'd clear TRISC.6 for now.

A good test would be to
1) verify the RS232 link as described above (remove PIC, jumper TX/RX, verify echo)
2) Verify the system speed by toggling an I/O pin and looking at a scope, or use some long delay that you can see and time with a stopwatch (clock setup errors are liable to be gross and the time way off)
3) Write a simple routine to initialize the USART, send 'U' once and halt while(1) until reset. 'U' is nice because it toggles each bit in the data and if you have a scope makes it easy to determine the baud rate (104us/bit for 9600). If you don't get 'U', try other baud rates on the receive. If you have some clock divider off by a factor of 2/4 etc, you'll be running at some other but legitimate baudrate i.e. clock off by *2, baud will be 19200 etc.

EDIT: Use MCLR/ to reset/resend the 'U' so that the MAX232 stays powered up.

How's that?
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
Cool! I actually found a PIC-DEM FS USB Demo Board in my cabinet. It uses a 4550 and 20MHz external xtal so looks like you are on the right path.

BTW: what did you finally arrive at re: TRISC.6?
 
Last edited:

Thread Starter

Dritech

Joined Sep 21, 2011
901
Hi again,

I wanted to use UART to interface Visual Studio with the PIC microcontroller. Now, lets assume that there are twenty buttons on the Visual Studio. Does that mean that I have to do twenty IF conditions (as below)?

Is there another method which is more neat and efficient?

Rich (BB code):
If(data == 'a')
{
Turn motor 1 clockwise
}
If(data == 'b')
{
Turn motor 1 counter clockwise
}
If(data == 'c')
{
Turn LED on
}
............................
............................
 

Thread Starter

Dritech

Joined Sep 21, 2011
901
Hi,

Never heard of switch statements. I did some research, but what are the main advantage of using switch statements in this case?
 

JohnInTX

Joined Jun 26, 2012
4,787
The advantage is just what you were asking about.. cleaner code.

Rich (BB code):
 switch(data){
  case 'a': Turn motor clockwise;
   break;
 case 'b': Turn motor counterclockwise;
   break;
 case 'c': Turn LED on;
   break;
 .... and so on
 default: Stop everything;
} // switch
The switch statement compares the argument (data) with each case and executes code from there to a break; or the end of the switch. default is optional and executes code when none of the cases match the argument.
I am presuming you are using C or some variant of it..
 

Thread Starter

Dritech

Joined Sep 21, 2011
901
Can you have long instructions when using switch statements?

For example:

Rich (BB code):
case 'a': 

Turn motor clockwise; 
Call delay;
Go to check sensor function;
Display on LCD;

Break;
 

JohnInTX

Joined Jun 26, 2012
4,787
Yup. Just like you've written. Everything from the case match to the next break gets executed, as many statements as you want. It will also flow into the next case without a break - which has its uses too:

Rich (BB code):
switch (data){
 case 'a':
 case 'A': do as much as you want... on upper or lower case A until break..
 break; // end of a/A processing

 case 'b': perform this only on 'b' then flow to 'B'
 case 'B': do this on 'B' or 'b' (lower case 'b' code flows into it (no break)
 break; // end of b/B processing
}// switch
 
Top