MPLAB C linking

Thread Starter

powzoom

Joined Jan 18, 2009
41
I'm using MPLAB with the HI-TECH C light compiler. The chip is a 16F688.

I'm trying to build a frequency meter. The code that controls the lcd screen works fine when all the code is in one file. If I copy/paste all the lcd code from my main .c to another .c and link it, it does not work. It will compile with no errors but the device fails to communicate with the lcd even though its the same exact code.

Am I missing something? I took all the functions and definitions, put them in a separate .c file and tried to link it, #include "lcd.c" No errors, but it doesn't work.
 

Thread Starter

powzoom

Joined Jan 18, 2009
41
I've done a few tests and I think I know what's wrong. Any changes to the ports are not working. Ex. Created a function to set RC4 high. Called it from main.c and it didn't work. However, I made a function that didn't try to change the ports, it just squared a number. That worked. So the code is linking, it's just not able to change the output pins for some reason.
 

BMorse

Joined Sep 26, 2009
2,675
I've done a few tests and I think I know what's wrong. Any changes to the ports are not working. Ex. Created a function to set RC4 high. Called it from main.c and it didn't work. However, I made a function that didn't try to change the ports, it just squared a number. That worked. So the code is linking, it's just not able to change the output pins for some reason.
can you post your code??

Did you use header files for each c file? Normally when linking files you should include the header file for each c file you want compiled with your project....

so it should be "#include lcd.h" not "#include lcd.c"

My .02
 

Thread Starter

powzoom

Joined Jan 18, 2009
41
The main file

Rich (BB code):
#include <pic.h>
//#include <p16F688.inc>
#include <htc.h>
#include "string.h"

__CONFIG (HS & WDTDIS & MCLRDIS & UNPROTECT);

#define PIC_CLK 20000000
#include "delay.c"
#include "LCD.c"


//****************************************
//****************************************
// LC_Meter Defines ***********************

#define testbit_on(data,bitno) ((data>>bitno)&0x01)
//#define CLEAR 0x01

//****************************************
//****************************************
// Functions ***********************


void PIC_INIT(void);


//****************************************
//****************************************
// Main ***********************

bit counting = 0;
unsigned int sec = 0;
unsigned int min = 0;
unsigned long count = 0;
unsigned long result = 0;
unsigned int T1count = 0;

char run = 1;

void main ()
{

	    DelayMs(200);
        
        PIC_INIT();
        LCD_INIT();

        OPTION = 0b00111000;

		 // bit 4 sets prescale to WDT so bits<2:0> = 0 mean 1:1 ratio
   		T0IE = 1; //enable TMR0 overflow interrupts
        ei(); // enable global interupts
		
		T1GSS = 1;
		T1CON = 0b10100001; // set up timer1
		TMR1IE = 1;
		PEIE = 1;

		TMR0 = 0;
		T1count = 0;
		count = 0;
		TMR0 = 0;

		
	
		LCD_CMD(CLEAR);
		LCD_LONG(999999);
		DelayS(2);
		//counting = 1;

		RC4 = 1;
		RC5 = 0;

        while (run==1)
        {           
		  	LCD_CMD(CLEAR);
			LCD_STRING("Counting...");
			result = 0;
			counting = 1;
			count = 0;
			TMR0 = 0;	
			T1count=0;
			TMR1IF = 0;			
			TMR1H = 0;
			TMR1L = 0;
			while (counting)
			{
			}

			LCD_CMD(CLEAR);
			LCD_LONG(result);
			
			RC4 = RC4 ^ 1;  //XOR to swap from 1 to 0
			RC5 = RC5 ^ 1;

//			LCD_Flip();

			DelayS(2);

        }
}
        

void PIC_INIT()
{
        // ADC off, all digital I/O
        ANSEL = 0;
        CMCON0=0x07;
         
        // PORT direction register
        TRISA = 0b00000100;
        TRISC = 0b00000000;
}



//****************************************
//****************************************
// Interrupt stuff ***********************
lcd.c

Rich (BB code):
#ifndef LCD_C
#define LCD_C


#include "lcd.h"

//*************************************
//************************************
// LCD STUFF *************************

extern void LCD_INIT(void)
{
        LCD_CLR_DATA();
        LCD_CLR_CONTROL();

        // wait for lcd
        DelayMs(100);
        //reset lcd
		P_DATA = (P_DATA & data_mask) | 0x03;
		//P_DATA = 0x03;
        P_CONTROL = 0x00;
        LCD_ENABLE();
        DelayMs(20);
        // do it 2 more times
        LCD_ENABLE();
        DelayMs(15);
        LCD_ENABLE();
        DelayMs(10);
        // set 4-bit mode
        P_DATA = (P_DATA & data_mask) | 0x02;
		//P_DATA = 0x02;
        LCD_ENABLE();
        DelayMs(10);

        // now in 4-bit mode
        LCD_CMD(0x28); // 2line 4-bit
        LCD_CMD(0x08); // Display Off
        LCD_CMD(0x01); // Clear
        LCD_CMD(0x06); // Set Entry
        LCD_CMD(0x0C); // Display on, blink and cursor off
        LCD_CMD(0x80); // Set DDRAM address
        
}

extern void LCD_CLR_CONTROL()
{
	RS = 0;
	EN = 0;
}

extern void LCD_CLR_DATA()
{
	D4 = 0;
	D5 = 0;
	D6 = 0;
	D7 = 0;

}

extern void LCD_ENABLE()
{
        EN=1;
        asm("nop");
        EN=0;
        asm("nop");
}


extern void LCD_CMD(unsigned char cmd)
{
        unsigned char temp = 0;

        // swap then xor to get only high nibble
        temp = cmd;
        temp = (temp >> 4) | (temp << 4); 
        temp = temp & 0x0F;
        P_DATA = (P_DATA & data_mask) | temp;
		//P_DATA = temp;
        RS=0;
        LCD_ENABLE();
        
        // now the lower nibble
        temp = cmd;
        temp = temp & 0x0F;
        P_DATA = (P_DATA & data_mask) | temp;
		//P_DATA = temp;
        RS=0;
        LCD_ENABLE();

        //add a delay
        DelayMs(2);                

}

extern void LCD_CHAR(unsigned char cmd)
{
        unsigned char temp = 0;

        // swap then xor to get only high nibble
        temp = cmd;
        temp = (temp >> 4) | (temp << 4); 
        temp = temp & 0x0F;
        P_DATA = (P_DATA & data_mask) | temp;
		//P_DATA = temp;
        RS=1;
        LCD_ENABLE();
        
        // now the lower nibble
        temp = cmd;
        temp = temp & 0x0F;
        P_DATA = (P_DATA & data_mask) | temp;
		//P_DATA = temp;
        RS=1;
        LCD_ENABLE();

        //add a delay
        DelayMs(2);                
        //set RS back to 0
        RS=0;

}

extern void LCD_STRING(unsigned char *var)
{
     while(*var)              //till string ends
       LCD_CHAR(*var++);  //send characters one by one
}

extern void LCD_INT(unsigned int num)
{
        //        Break down the original number into the thousands, hundreds, tens,
        //        and ones places and then immediately write that value to the LCD
		
        unsigned char tenthousands = 0;
        unsigned char thousands = 0;
        unsigned char hundreds = 0;
        unsigned char tens        = 0;
        unsigned char ones = 0;

        tenthousands = num / 10000;
        LCD_CHAR(tenthousands + 0x030);  //add 0x30 b/c thats where ascii 0 starts

        thousands = (num - tenthousands*10000)/1000;
        LCD_CHAR(thousands + 0x030);

        hundreds = (num - tenthousands*10000 - thousands*1000)/100;
        LCD_CHAR(hundreds + 0x030);

        tens = (num - tenthousands*10000 - thousands*1000 - hundreds*100)/10;
        LCD_CHAR(tens + 0x030);

        ones = (num - tenthousands*10000 - thousands*1000 - hundreds*100 - tens*10);
        LCD_CHAR(ones + 0x030);
}

extern void LCD_LONG(unsigned long num)
{
        //        Break down the original number into the thousands, hundreds, tens,
        //        and ones places and then immediately write that value to the LCD
		
		unsigned char billions = 0;
		unsigned char hundredmillions = 0;
		unsigned char tenmillions = 0;
		unsigned char millions = 0;
		unsigned char hundredthousands = 0;
        unsigned char tenthousands = 0;
        unsigned char thousands = 0;
        unsigned char hundreds = 0;
        unsigned char tens   = 0;
        unsigned char ones = 0;

		unsigned long temp = num;

		billions = num / 1000000000;
        LCD_CHAR(billions + 0x030);  //add 0x30 b/c thats where ascii 0 starts
		temp = temp - (billions*1000000000); //temp = num - last decimal digit

		hundredmillions = temp / 100000000;
        LCD_CHAR(hundredmillions + 0x030);  //add 0x30 b/c thats where ascii 0 starts
		temp = temp - (hundredmillions*100000000); //temp = num - last 2decimal digit

		tenmillions = temp / 10000000;
        LCD_CHAR(tenmillions + 0x030);  //add 0x30 b/c thats where ascii 0 starts
		temp = temp - (tenmillions*10000000); //temp = num - last 3decimal digit
	
		millions = temp/ 1000000;
        LCD_CHAR(millions + 0x030);  //add 0x30 b/c thats where ascii 0 starts
		temp = temp - (millions*1000000); //temp = num - last 4 digits
	
		hundredthousands = temp / 100000;
        LCD_CHAR(hundredthousands + 0x030);  //add 0x30 b/c thats where ascii 0 starts
		temp = temp - (hundredthousands*100000);

        tenthousands = temp / 10000;
        LCD_CHAR(tenthousands + 0x030);  //add 0x30 b/c thats where ascii 0 starts
		temp = temp - (tenthousands*10000);

        thousands = temp/1000;
        LCD_CHAR(thousands + 0x030);
		temp = temp - (thousands*1000);

        hundreds = temp/100;
        LCD_CHAR(hundreds + 0x030);
		temp = temp - (hundreds*100);

        tens = temp/10;
        LCD_CHAR(tens + 0x030);
		temp = temp - (tens*10);

        ones = temp;
        LCD_CHAR(ones + 0x030);
}


#endif
lcd.h

Rich (BB code):
#ifndef LCD_H
#define LCD_H

//****************************************
//****************************************
// LCD Defines ***********************
#define MAXPOSX	     16
#define MAXPOSY	      2

#define RS 		RA0
#define RW		RA1
#define EN		RA2 

#define D4		RC0
#define D5		RC1
#define D6		RC2
#define D7		RC3

#define P_DATA         PORTC
#define data_mask 		0b11110000  //used data ports on RC are 0, rest 1
#define P_CONTROL 		PORTA
#define control_mask	0b11111100 // used control ports on RA are 0

#define CLEAR 0x01

/////////////////////////////


extern void LCD_INIT(void);
extern void LCD_CHAR(unsigned char cmd);
extern void LCD_STRING(unsigned char *var);
extern void LCD_CMD(unsigned char cmd);
extern void LCD_ENABLE();
extern void LCD_INT(unsigned int num);
extern void LCD_LONG(unsigned long num);
extern void LCD_CLR_CONTROL();
extern void LCD_CLR_DATA();

#endif
 

Thread Starter

powzoom

Joined Jan 18, 2009
41
And the original working code

Rich (BB code):
#include <pic.h>
//#include <p16F688.inc>
#include <htc.h>
#include "string.h"

__CONFIG (HS & WDTDIS & MCLRDIS & UNPROTECT);

#define PIC_CLK 20000000
#include "delay.c"
#include "test2.c"

//****************************************
//****************************************
// LCD Defines ***********************
#define MAXPOSX             16
#define MAXPOSY              2

#define RS                 RA0
//RW to ground
#define EN                RA1 

#define D4                RC0
#define D5                RC1
#define D6                RC2
#define D7                RC3

#define P_DATA         PORTC
#define data_mask 		0b11110000  //used data ports on RC are 0, rest 1
#define P_CONTROL 		PORTA
#define control_mask	0b11111100 // used control ports on RA are 0

#define CLEAR 0x01

//****************************************
//****************************************
// LC_Meter Defines ***********************

#define testbit_on(data,bitno) ((data>>bitno)&0x01)





//****************************************
//****************************************
// Functions ***********************

void LCD_INIT(void);
void PIC_INIT(void);
void Clear(void);
void LCD_CHAR(unsigned char cmd);
void LCD_STRING(unsigned char *var);
void LCD_CMD(unsigned char cmd);
void LCD_ENABLE();
void LCD_INT(unsigned int num);
void LCD_LONG(unsigned long num);
void LCD_CLR_CONTROL();
void LCD_CLR_DATA();


//****************************************
//****************************************
// Main ***********************

bit counting = 0;
unsigned int sec = 0;
unsigned int min = 0;
unsigned long count = 0;
unsigned long result = 0;
unsigned int T1count = 0;

void main ()
{
		char run = 1;

	    DelayMs(200);
        
        PIC_INIT();
        LCD_INIT();


        OPTION = 0b00111000;


	    // bit 4 sets prescale to WDT so bits<2:0> = 0 mean 1:1 ratio
   		T0IE = 1; //enable TMR0 overflow interrupts
        ei(); // enable global interupts
		
		T1GSS = 1;
		T1CON = 0b10100001; // set up timer1
		TMR1IE = 1;
		PEIE = 1;

		TMR0 = 0;
		T1count = 0;
		count = 0;
		TMR0 = 0;
		
	
		LCD_CMD(CLEAR);
		long k = times2(4999);
		LCD_LONG(k);
		DelayS(2);
		//counting = 1;

		RC4 = 1;
		RC5 = 0;

        while (run==1)
        {           
		  	LCD_CMD(CLEAR);
			LCD_STRING("Counting...");
			result = 0;
			counting = 1;
			count = 0;
			TMR0 = 0;	
			T1count=0;
			TMR1IF = 0;			
			TMR1H = 0;
			TMR1L = 0;
			while (counting)
			{
			}

			LCD_CMD(CLEAR);
			LCD_LONG(result);
			
			RC4 = RC4 ^ 1;  //XOR to swap from 1 to 0
			RC5 = RC5 ^ 1;

			DelayS(2);

        }
}
        

void PIC_INIT()
{
        // ADC off, all digital I/O
        ANSEL = 0;
        CMCON0=0x07;
         
        // PORT direction register
        TRISA = 0b00000100;
        TRISC = 0b00000000;
}

//*************************************
//************************************
// LCD STUFF *************************

void LCD_INIT()
{
        LCD_CLR_DATA();
        LCD_CLR_CONTROL();

        // wait for lcd
        DelayMs(100);
        //reset lcd
		P_DATA = (P_DATA & data_mask) | 0x03;
		//P_DATA = 0x03;
        P_CONTROL = 0x00;
        LCD_ENABLE();
        DelayMs(20);
        // do it 2 more times
        LCD_ENABLE();
        DelayMs(15);
        LCD_ENABLE();
        DelayMs(10);
        // set 4-bit mode
        P_DATA = (P_DATA & data_mask) | 0x02;
		//P_DATA = 0x02;
        LCD_ENABLE();
        DelayMs(10);

        // now in 4-bit mode
        LCD_CMD(0x28); // 2line 4-bit
        LCD_CMD(0x08); // Display Off
        LCD_CMD(0x01); // Clear
        LCD_CMD(0x06); // Set Entry
        LCD_CMD(0x0C); // Display on, blink and cursor off
        LCD_CMD(0x80); // Set DDRAM address
        
}

void LCD_CLR_CONTROL()
{
	RS = 0;
	EN = 0;
}

void LCD_CLR_DATA()
{
	D4 = 0;
	D5 = 0;
	D6 = 0;
	D7 = 0;

}

void LCD_ENABLE()
{
        EN=1;
        asm("nop");
        EN=0;
        asm("nop");
}


void LCD_CMD(unsigned char cmd)
{
        unsigned char temp = 0;

        // swap then xor to get only high nibble
        temp = cmd;
        temp = (temp >> 4) | (temp << 4); 
        temp = temp & 0x0F;
        P_DATA = (P_DATA & data_mask) | temp;
		//P_DATA = temp;
        RS=0;
        LCD_ENABLE();
        
        // now the lower nibble
        temp = cmd;
        temp = temp & 0x0F;
        P_DATA = (P_DATA & data_mask) | temp;
		//P_DATA = temp;
        RS=0;
        LCD_ENABLE();

        //add a delay
        DelayMs(2);                

}

void LCD_CHAR(unsigned char cmd)
{
        unsigned char temp = 0;

        // swap then xor to get only high nibble
        temp = cmd;
        temp = (temp >> 4) | (temp << 4); 
        temp = temp & 0x0F;
        P_DATA = (P_DATA & data_mask) | temp;
		//P_DATA = temp;
        RS=1;
        LCD_ENABLE();
        
        // now the lower nibble
        temp = cmd;
        temp = temp & 0x0F;
        P_DATA = (P_DATA & data_mask) | temp;
		//P_DATA = temp;
        RS=1;
        LCD_ENABLE();

        //add a delay
        DelayMs(2);                
        //set RS back to 0
        RS=0;

}

void LCD_STRING(unsigned char *var)
{
     while(*var)              //till string ends
       LCD_CHAR(*var++);  //send characters one by one
}

void LCD_INT(unsigned int num)
{
        //        Break down the original number into the thousands, hundreds, tens,
        //        and ones places and then immediately write that value to the LCD
		
        unsigned char tenthousands = 0;
        unsigned char thousands = 0;
        unsigned char hundreds = 0;
        unsigned char tens        = 0;
        unsigned char ones = 0;

        tenthousands = num / 10000;
        LCD_CHAR(tenthousands + 0x030);  //add 0x30 b/c thats where ascii 0 starts

        thousands = (num - tenthousands*10000)/1000;
        LCD_CHAR(thousands + 0x030);

        hundreds = (num - tenthousands*10000 - thousands*1000)/100;
        LCD_CHAR(hundreds + 0x030);

        tens = (num - tenthousands*10000 - thousands*1000 - hundreds*100)/10;
        LCD_CHAR(tens + 0x030);

        ones = (num - tenthousands*10000 - thousands*1000 - hundreds*100 - tens*10);
        LCD_CHAR(ones + 0x030);
}

void LCD_LONG(unsigned long num)
{
        //        Break down the original number into the thousands, hundreds, tens,
        //        and ones places and then immediately write that value to the LCD
		
		unsigned char billions = 0;
		unsigned char hundredmillions = 0;
		unsigned char tenmillions = 0;
		unsigned char millions = 0;
		unsigned char hundredthousands = 0;
        unsigned char tenthousands = 0;
        unsigned char thousands = 0;
        unsigned char hundreds = 0;
        unsigned char tens   = 0;
        unsigned char ones = 0;

		unsigned long temp = num;

		billions = num / 1000000000;
        LCD_CHAR(billions + 0x030);  //add 0x30 b/c thats where ascii 0 starts
		temp = temp - (billions*1000000000); //temp = num - last decimal digit

		hundredmillions = temp / 100000000;
        LCD_CHAR(hundredmillions + 0x030);  //add 0x30 b/c thats where ascii 0 starts
		temp = temp - (hundredmillions*100000000); //temp = num - last 2decimal digit

		tenmillions = temp / 10000000;
        LCD_CHAR(tenmillions + 0x030);  //add 0x30 b/c thats where ascii 0 starts
		temp = temp - (tenmillions*10000000); //temp = num - last 3decimal digit
	
		millions = temp/ 1000000;
        LCD_CHAR(millions + 0x030);  //add 0x30 b/c thats where ascii 0 starts
		temp = temp - (millions*1000000); //temp = num - last 4 digits
	
		hundredthousands = temp / 100000;
        LCD_CHAR(hundredthousands + 0x030);  //add 0x30 b/c thats where ascii 0 starts
		temp = temp - (hundredthousands*100000);

        tenthousands = temp / 10000;
        LCD_CHAR(tenthousands + 0x030);  //add 0x30 b/c thats where ascii 0 starts
		temp = temp - (tenthousands*10000);

        thousands = temp/1000;
        LCD_CHAR(thousands + 0x030);
		temp = temp - (thousands*1000);

        hundreds = temp/100;
        LCD_CHAR(hundreds + 0x030);
		temp = temp - (hundreds*100);

        tens = temp/10;
        LCD_CHAR(tens + 0x030);
		temp = temp - (tens*10);

        ones = temp;
        LCD_CHAR(ones + 0x030);
}

//****************************************
//****************************************
// Interrupt stuff ***********************
 

AlexR

Joined Jan 16, 2008
732
I'm surprised it doesn't work yet throws up no errors when compiled but in any case you could try the following.
Add "#include <htc.h>" to your lcd.c file,
Add '#include "lcd.h" to your main file
Do not include lcd.c in the main file but rather add it to the source file list in MPLAB
 
Top