Electrical – C project for PIC won’t build when I call user defined functions


So I am trying to set up a UART serial connection, and I have a function called UART_INIT to initialise my UART, however when I try to call it my project won't build and I can't see why. If I just copy the code from the function into the main, it works fine, so it's not what I'm doing inside the function that's the problem, it's the actual act calling of the function. It compiles fine when I define the function, but not when I then try to use it.

I also have functions to transmit data and when I call them, I have the same problem. I'm using some code from a UART tutorial as a template but a different PIC and tweaked (just using the transmit bit of the code for the time being). The example compiles fine so it's almost certainly something I'm doing but honestly have no idea what.

The error it's giving me is

BUILD FAILED (exit value 2, total time: 304ms)

I'm building a project for a PIC12F1822 and using MPLAB v3.35 with the XC8 compiler.

Here's my code below:

// PIC12F1822 Configuration Bit Settings

// 'C' source line config statements

#pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = ON // PLL Enable (4x PLL enabled)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = ON // Low-Voltage Programming Enable (Low-voltage programming enabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv) {

    //set oscillator speed
    OSCCONbits.IRCF = 0b1110;

    //if replace this line with the code from the function, it works fine

    //doesn't build with the line below either
    //USART_puts("Init complete!\n");

    return (EXIT_SUCCESS);

void USART_init(void)
    //Enabling transmitter

    TXSTAbits.TXEN = 1; // enable transmitter
    TXSTAbits.SYNC = 0; // Asynchronous mode
    RCSTAbits.SPEN = 1; //Enables USART
    TRISAbits.TRISA0 = 1; // TX pin is input (automatically configured)

    //set up baud rate
    TXSTAbits.BRGH = 1; // high baud rate mode
    SPBRGL = 207; //speed register 

    RCSTAbits.SPEN = 1; // enable USART


void USART_putc(unsigned char c)
    while (!TXSTAbits.TRMT); // wait until transmit shift register is empty
    TXREG = c; // write character to TXREG and start transmission

void USART_puts(unsigned char *s)
    while (*s)
        USART_putc(*s); // send character pointed to by s
        s++; // increase pointer location to the next character

This is the example code which works.


Best Answer

The difference between the working code and your code is that the functions in the working code are declared and defined before they are used.

The C compiler must see the function prototype before it knows how to generate correct code. If not, it will guess, and in this case, the guess is wrong.

You can solve that by either moving the functions, or better yet, add function prototypes before your main:

void USART_init(void);

int main( void )

void USART_init(void)
    //Enabling transmitter

The standard solution which helps both readability and development is to put all the USART functions in one file, usart.c, and then create a corresponding header file, usart.h. The header file would look like this:

#ifndef USART_H
#define USART_H

void USART_init(void);
void USART_putc(unsigned char c);
void USART_puts(unsigned char *s);

#endif /* USART_H */

Now you only have to #include "usart.h" at the top of your main file, and every other file where you want to use it. The #ifndef/#define/#endif are include guards and pointless in this case, but often put there for good measure to protect against problems that could come from including the same file multiple times.