Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[PIC] transmit data via usart in pic 16f877a

Status
Not open for further replies.

Pran Kumar

Newbie level 5
Newbie level 5
Joined
Jul 22, 2015
Messages
10
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
103
can anyone help me to write a user defined function to transmit data via usart in pic 16f877a,20mhz in mikro c?
 

It is really easy, all you have to do is check the transmit buffer is empty (wait if it isn't) then put the data in the TXREG register.

Look at the existing MikroC library code for examples.

Brian.
 
thanks brian.
i have written the code and simulated it in proteus ISIS proffessional.But its not working.Can you please check and tell what's wrong with the code.
I am using PIC 16F877A ,20 MHZ @ 9600bps.


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
void USART_init();
void USART_trans_char(unsigned char x);
void USART_trans_string(char *z);
 
 
 
char AT[] = "AT\r\n";
 
 
void main()
{
 
 
        USART_init();
        Delay_ms(200);
 
 
 
        while(1) 
                 {
 
                  USART_trans_string(AT);
                  Delay_ms(1000);
 
                }
 
}
 
void USART_init()
{
   TXEN_bit=1;
   SYN_bit=0;
   SPEN_bit=1;  //
 
   SPBRG=0x1F; //9600 bps ,DECIMAL VALUE IN REGISTER 31
   TRISC.B6=1; //RC7 is Rx while RC6 is Tx
    
 
 
}
void USART_trans_char( char x)
{
    while(TRMT!==0)
    TXREG=x;
}
 
 
void USART_trans_string(char* z)
{
 while(*z)
 {
  USART_trans_char(*z++);
 }
 
}

 
Last edited by a moderator:

I don't use MikroC or Proteus so I can't compile it to be sure but I suspect the problem is either that you do not have BRGH set properly or you do not have the port bits set correctly. The data sheet states:
Bit SPEN (RCSTA<7>) and bits TRISC<7:6> have to be
set in order to configure pins RC6/TX/CK and RC7/RX/DT
as the Universal Synchronous Asynchronous Receiver
Transmitter.
so you may also have to make TRISC.B7 = 1.

Brian.
 

void USART_init()
{
TXEN_bit=1;
SYN_bit=0;
SPEN_bit=1; //

SPBRG=0x1F; //9600 bps ,DECIMAL VALUE IN REGISTER 31
TRISC.B6=1; //RC7 is Rx while RC6 is Tx

}

RC6 is TX , so an output !
TRISC.B6=0;

why do you not use mikroC UART library
and simply type
Code:
UART_Init(9600);

don't care about TRIS for UART .. UART Init, do it..
 
My experience is that you should configure any peripheral fully before you enable it. (There are some documented exceptions to this but, as I say, they are documented.) Therefore, set up the BRG before you enable the UART.
In what way is it "...not working"? It is very hard to help you if you don't tell us what works and what does not.
Also you are not handling the receive side of things. That might not be a problem BUT some MCUs will stop working if any error is detected (such as not reading a received character before the next one arrives and causing an overflow).
Susan
 
Hi,

Just to clarify if all talk about the same interface:

Did you really mean USART? Or UART?

Although not very often used, the USART is different.
For a USART you need extra clock lines and there is no need for fixed baud rates.

Klaus
 

The 16F877A is a USART but the 'S' only applies if used in synchronous mode so in this instance, where it is used asynchronously, it makes no difference.

Susan is quite right, when a character is received it is good practice to check for framing or overrun errors (FERR and OERR bits in RCSTA) and if those bits = 1, reset and re-enable the CREN bit to clear them.

I always perform a full initialization of a peripherals registers, even if the default bit states are being written back again. It may be overkill but for the sake of a few lines of code it guarantees the device is correctly configured. It may also help during debugging where you may be stopping and starting the software in a 'live' environment where the code and external signals may get out of step with each other. For example, stopping at a breakpoint while data is still arriving at the serial port will almost certainly cause an overrun error.

Brian.
 

    V

    Points: 2
    Helpful Answer Positive Rating
I have made changes in the code,still it doesn't work.I have connected the pic to a virtual terminal in proteus but i think the string is not transmitted ,as the string is not displayed on the terminal.Plz help me to find out the mistake.

Code:
void USART_init();
void USART_trans_char( char x);
void USART_trans_string(char *z);



char AT[] = "AT\r\n";


void main()
{


        USART_init();
        Delay_ms(200);



        while(1) 
                 {

                  USART_trans_string(AT);
                  Delay_ms(1000);

                }

}

void USART_init()

{

    CSRC_bit=1;
    TX9_bit=0;
    SYN_bit=0;
    BRGH_bit=0;
    SPBRG=0x1F;
    TRISC.B6=0;
    TXEN_bit=1;






}
void USART_trans_char( char x)
{
    while(TRMT==0)
    TXREG=x;
}


void USART_trans_string(char *z)
{
 while(*z)
 {
  USART_trans_char(*z++);
 }

}
 

When you single-step through the code, does it stop somewhere? Are you checking the status bits to make sure they are as expected (mainly because you are still not handling any possibly received characters and your other error checking is rudimentary).
Why are you setting the SCRC bit? That only applies to synchronous mode and you are setting the SYN bit to 0.
Where are you setting the SPEN bit? That is the one that turns on the peripheral.
How are you setting the processor speed? You say in your text that it is 20MHz but you don't show how this is set (and the config settings would not give this to you as a default). If this is not correct, then the speed of the transmitted pulses will not be correct and the terminal (virtual or otherwise) will either not pick up anything or might interpret the pulses as garbage characters.
Finally, as you are using a simulator, it could be that the simulator does not simulate this (old) processor correctly. The hardware is the only real test of whether something is working or not.
Susan
 
The code itself looks fine and should work. By process of elimination, if the code is OK the problem lies elsewhere. As Susan points out, simulators may not give accurate results, often they assume the USART is configured properly without checking it. Certainly, you should set the SPEN bit because it not only enables the USART module, it allows the USART to take control of the signal paths to the port pins.

I do not have Proteus, check the virtual terminal configured to connect directly to the PIC and is not expecting an RS232 interface. If it does, the signals will be inverted and that could account for the problem.


Brian.
 
Thanks all for your help.I have made the changes you said.But when I connect the pic 16f877a with compim in PROTEUS ISIS it shows a message telling,"CFGWORD2 NOT IMPLEMENTED".Can someone help me to find out what the problem is?Presently I am interested in transmitting a string,but I have included the function to receive data too.Please help.




Code:
      #define _XTAL_FREQ   20000000
      #define BAUDRATE 9600


   void InitUART(void);
   void SendByteSerially(unsigned char);
   unsigned char ReceiveByteSerially(void);
   void SendStringSerially(const unsigned char*);



                
// Main Function
void main(void)
{
        InitUART();                                                        // Intialize UART
    
    SendStringSerially("AT");        // Send string on UART

        INTCON.B7  = 1;                                                          // Enable global interrupts
        INTCON.B6 = 1;                                                          // Enable Peripheral Interrupts

        while(1)
        {
                // Do nothing, as Received character is echoed back in the ISR
                // If you decide to disable interrupts, then you can 
                // echo back characters by uncommenting the line below
                // SendByteSerially(ReceiveByteSerially());  //Echo Back
        }
}
void InitUART()
{
        TRISC.B6 = 0;                                           // TX Pin
        TRISC.B7 = 1;                                           // RX Pin

        SPBRG = ((_XTAL_FREQ/16)/BAUDRATE) - 1;
        TXSTA.B2 = 1;                                                 // Fast baudrate
        TXSTA.B4 = 0;                                                // Asynchronous
        RCSTA.B7  = 1;                                                // Enable serial port pins
        RCSTA.B4  = 1;                                                // Enable reception
        RCSTA.B5  = 0;                                                // No effect
        PIE1.B4 = 0;                                                // Disable tx interrupts
        PIE1.B5 = 1;                                                // Enable rx interrupts
        TXSTA.B0  = 0;                                                // 8-bit transmission
        RCSTA.B6   = 0;                                                // 8-bit reception
        TXSTA.B5  = 0;                                                // Reset transmitter
        TXSTA.B5  = 1;                                                // Enable the transmitter
}


void SendByteSerially(unsigned char Byte)  // Writes a character to the serial port
{
        while(!PIR1.B4) // wait for previous transmission to finish
        TXREG = Byte;
}

unsigned char ReceiveByteSerially( )   // Reads a character from the serial port
{
        if(RCSTA.B1) // If over run error, then reset the receiver
        {
                RCSTA.B4 = 0;
                RCSTA.B4 = 1;
        }

        while(!PIR1.B5)  // Wait for transmission to receive

        return (RCREG);
}

void SendStringSerially(const unsigned char *st)
{
        while(*st)
              {
              void  SendByteSerially(unsigned char *st);
               st++;
              }
}
void interrupt( )
{
        if(PIR1.B5)  // If UART Rx Interrupt
        {
                if(RCSTA.B1) // If over run error, then reset the receiver
                {
                        RCSTA.B4 = 0;
                        RCSTA.B4 = 1;
                }

                SendByteSerially(RCREG);        // Echo back received char
        }
}
 

hello


Why don't you use , more significatif definition
like RCIF_bit for PIR1.B5 .. etc .. more easy to understand the code .
MikroC offer this facility.

Code:
void interrupt( )
{
        if(PIR1.B5)  // If UART Rx Interrupt
        {
                if(RCSTA.B1) // If over run error, then reset the receiver
                {
                        RCSTA.B4 = 0;
                        RCSTA.B4 = 1;
                }

                SendByteSerially(RCREG);        // Echo back received char
        }
}

i am not sure when you send RCREG , you have a reading of RCREG !
in this case you don't erase the RCIF bit .. because only a reading of RCREG can RAZ this bit..
maybe use an intermediate variable like this

is RCIE_bit ON , in init ?

Code:
void interrupt( )
{
     char c1;
       if((RCIF_bit)  && (RCIE_bit)   // If UART Rx Interrupt flag + Uart interrupt authorised
        {
                if(RCSTA.B1) // If over run error, then reset the receiver
                {
                        RCSTA.B4 = 0;
                        RCSTA.B4 = 1;
                }
                c1=RCREG;
                SendByteSerially(c1);        // Echo back received char
        }
}
 
a) I have not seen configuration word in the code.
b) You have a serial transmission within interrupt service routine (ISR). ISR should run fast (small portion of code, no long loops). Although you do not work with serial buffers/fifo etc, calling the SendSerial initiates a loop until previous transmission is over.
This is not a good programming approach.
 
In addition to the above comments on your code:
- I would suggest that you clear the IF before you set the corresponding IE bit; should not be necessary as the registers are initialised this way on power-on but a good idea in your case as you are sending characters (and therefore suing the peripheral) before you enable the interrupts
- you should initialise the interrupts, then initialise the device and then use it
- if you read the data sheet for the asynchronous transmit, you will see a note on page 115 that says that enabling the transmitter will set the TXIF bit. This is so the ISR can being any buffered transmissions but you need to be aware of this and handle the situation in your ISR
- when you intialise the USART, set all configuration bits before you set the RCSTA,SPEN bit - I've mentioned this before
- there is a lot of redundant code - there is little point in clearing and then setting the TXEN bit
- you need to learn how to write 'while' loops. You code:
Code:
	while(!PIR1.TXIF) // wait for previous transmission to finish
	TXREG = Byte;
has the assignment to TXREG within the while loop. If you want to wait for a condition then you need to either as "{}" or ";" after the while loop and before any following instruction
- as above, you need to clear the IF flag yourself when it is set
- it is better to wait for the TRMT to be set to show that the transmit buffer is clear instead of the TXIF bit - this will let you send the first value in a sequence correctly
- I'm not sure about the compiler you are using but my experience is that no compiler will use a #define to set the compiler clock frequency (as in _XTAL_FREQ). That #define is used for the XC16 (and probably other compilers) in the delay functions so they can be told what you have set the clock to using other instructions.)
- why are you using the high speed BRG? The baud rate errors are much higher relative to those using the low speed

All in all I would take a step back and make sure that you are running at the clock speed you think you are by using the old 'flash a LED' program and time the pulses. Once you know the clock is right, then initialise the UART and simply send a character over and over in the main loop. When that is working, start adding the reception, echoing, string sending and receiving and other parts of your code.
My guess is that you are struggling with some of the basic concepts of programming a PIC device (that is not an unkind comment - they have a steep learning curve to begin with) and you need to make sure that you have the fundamentals correct first. Otherwise you will be struggling for a long time to get what is really a straight forward program to work.
Susan
 
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top