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.

Trying to convert source code to work on pic18f452

Status
Not open for further replies.

icefire91

Newbie level 6
Joined
Sep 2, 2011
Messages
11
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,351
hi,
I am trying to convert a source code from this website "http://www.flyelectric.ukgateway.net/pic-lcd1.htm" but i am stuck at the #pragma because of the different configuration between
the two pic. This source code is for pic16f688. Can anyone guide me. please
 

Code:
//PREPROCESSOR section ========================================================

#include <system.h>			//Generic device include (actual device set in Settings/Target)
#include <stdlib.h>			//Needed for Integer to ASCII conversion (uitoa)

//Core configuration option_regs:
#pragma DATA _CONFIG, _FCMEN_OFF & _IESO_OFF & _BOD_ON & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTOSCIO
#pragma CLOCK_FREQ 4000000


//VARIABLES section ===========================================================

#define disp	portc			//Defines 'disp' as PortC
								//Wired as: RC5=RW, RC4=RS, RC3=D7, RC2=D6, RC1=D5, RC0=D4
							
#define e 		porta.5			//Defines 'e' as the LCD Enable pin on RA5 (Pin2)

typedef unsigned char 	u8;		//Defines u8 as an unsigned char type (8bits)x 666
typedef signed   char	s8;		//Defines s8 as an signed char type (8bits)
typedef unsigned short 	u16;	//Defines u16 as an unsigned short type (16bits)
typedef unsigned int	i16;	//Defines i16 as an unsigned short integer (16bits)
typedef unsigned long 	u32;	//Defines u32 as an unsigned long type (32bits)

u16	result_a;						//Result of ADC conversions (amps)
u16	result_v;						//Result of ADC conversions (volts)

void write_data();					//Function to write to EEPROM for testing
void measure();						//Function to run ADC for amps and volts
void lcd (u8 high, u8 low, u8 rs);	//Function to send characters and instructions to LCD


//FUNCTIONS section ===========================================================

void write_data()				//Function to write to EEPROM flash memory
{
	intcon.7 = 0;				//Disable all interrupts while writing to memory
    pir1.7 = 0;					//EEIF: Clear this bit which gets set after each write
	
	eecon2 = 0x55;				//Required before writing to memory
	eecon2 = 0xAA;				//Required before writing to memory
	eecon1.1 = 1;				//WR: Writes data eedata to address eeadr

	while(eecon1.1==1);			//Wait for write to complete (becomes 0 when complete)

	eeadr++;					//Increment the address by 1 for next write (8 bit 0-255)
	
    intcon.7 = 1;				//Enable interrupts again
}

//------------------------------------------------------------------------------

void measure ()				//Function to trigger ADC conversions to measure voltage and amps
{
	u8 i;	//Counter

//Current	

	//Select channel
		adcon0.4 = 0;				//Makes AN2 (pin11) channel active
		adcon0.3 = 1;				// part of above
		adcon0.2 = 0;				// part of above

    //Run ADC
		for(i=0; i<1; i++);			//Delay for acquisition capacitor to charge (1 = ~14uS)
		pir1.6 = 0;					//Clear the ADC Complete flag
		adcon0.1 = 1;				//GO: Start ADC acquisition
		while(adcon0.1==1);			//Wait for conversion to complete (becomes 0)
		
	//Merge results
		MAKESHORT (result_a, adresl, adresh);

	
//Volts

	//Select channel
		adcon0.4 = 0;				//Makes AN3 (pin3) channel active
		adcon0.3 = 1;				// part of above
		adcon0.2 = 1;				// part of above
		
    //Run ADC
		for(i=0; i<1; i++);			//Delay for acquisition capacitor to charge (1 = ~14uS)
		pir1.6 = 0;					//Clear the ADC Complete flag
		adcon0.1 = 1;				//GO: Start ADC acquisition
		while(adcon0.1==1);			//Wait for conversion to complete (becomes 0)
		
	//Merge results
		MAKESHORT (result_v, adresl, adresh);
}

//-----------------------------------------------------------------------------

void lcd (u8 high, u8 low, u8 rs)	//Sends characters and instructions to LCD
									//'high' is first nibble
									//'low' the second (99 prevents it from being sent)
									//'rs' is made high when 1 (for writing characters)
									//'rs' is made low when 0 (for instructions)
									//'disp' represents Port C (RS then 4 data pins)
{
	if(rs==1) rs <<= 4;			//Converts 1 to 0b10000 to make 5th pin in Port C high
	
	e=1;						//Set Enable high before writing
	disp = rs + high;			//Sets Port C RS setting (5th pin) + 1st nibble (lower 4 pins)
	nop();						//Brief delay
	e=0;						//Execute by pulling low
	nop();
	
	if(low==99)					//If low = 99, don't send 2nd nibble (ie: still in 8bit mode)
	{
		delay_ms(1);			//Pause for last E to complete
		return;					//Exits function
	}
	
	e=1;
	disp = rs + low;			//2nd nibble
	nop();
	e=0;		  
	delay_ms(1);
}	
		
//===========================================================================

void main()					//main program
{
//Declare local variables
	u16 i;					//Variable for counters
	i16	digits;				//Temporary variable for selecting individual digits to display
	u8	buff[8];			//Array for storing Unsigned Integer to ASCII conversions
	u32	amps;				//Variable for determining the amps measured
	u8	amps_old;			//Previous measurement
	u32	volts;				//Variable for determining the voltage measured
	u8	volts_old;			//Previous measurement
	s8	diff;				//Difference between values (used to determine jitter)
	bit	jitter;				//Jitter flag

//Initialise all ports, etc
	porta=0; portc=0;			//Start low
	volts=0; amps=0;
	volts_old=0; amps_old=0;
	
//Main port settings (1=Input 0=Output)
	trisa = 0;					//Port A all output except...
	trisa.2 = 1;				//RA2 (Pin11) 	AN2		Current measurement
	trisa.3 = 1;				//RA3 (Pin3) 	AN3		Voltage measurement
	
	trisc = 0;					//Port C all output (only writing to LCD, not reading)
	
//ADC port settings (1=Analog 0=Digital)
	ansel = 0;					//All digital except...
	ansel.2 = 1;				//RA2 (Pin11) 	AN2		Amps
	ansel.3 = 1;				//RA3 (Pin3) 	AN3		Volts
	
//Static ADC settings
    adcon0.7 = 1;				//ADFM	Right justify results
    adcon0.6 = 0;				//VCFG	Use Vdd for reference voltage
    adcon0.0 = 1;				//ADON	AD module enabled
    adcon1 = 101;				//AD	Conversion Clock Fosc/16
    pie1.6 = 0;					//ADC	interrupts disabled
		  
//Static EEPROM data logging settings
    eecon1.7 = 0;				//EEPGD: Access data memory
    eecon1.3 = 0;				//WRERR: clear on startup in case previously set
	eecon1.2 = 1;				//WREN: enable writing to memory

	eeadr=0;					//First address for writing to EEPROM (testing)

	
//------------------------------------------------------------------------------

//Initialise LCD

	//LCD starts in 8bit mode by default
	//However, only the upper 4 data lines are physically connected in the circuit
	//So while in 8bit mode, only the upper 4 bits are sent (until changed to 4bit mode)
	//The parameter '99' prevents the LCD function from sending the 2nd nibble

	delay_ms(250);				//Wait for LCD to start

//'Set Function' (in 8bit mode)
	//Send instruction three times to stabilise display (selects default 8bit mode)
		for(i=0; i<3; i++)
		{
			lcd (0b0011, 99, 0);//8bit interface length, 99=no 2nd nibble, RS=0
			delay_ms(1);		//Extra delay to aid initialisation
		}
	
	//'Set Function' again
	//Send instruction to select 4bit mode
		lcd (0b0010, 99, 0);	//4bit interface length, no 2nd nibble
		delay_ms(1);
		
//From here all instructions and data writes require two 4bit nibbles
	 
	//'Set Function' (full instruction)
	//Set interface length characteristics
		lcd (0b0010, 0b1000, 0);	//4bit, 2 display lines, 5x7 font
		delay_ms(1);
		
	//'Display Clear' and return cursor to home position
		lcd (0b0000, 0b0001, 0);	//Clear display
		delay_ms(1);				//Requires 1.6ms delay in total (1ms exists in lcd function)
		
	//'Set Entry Mode'
	//Cursor auto-increment direction
		lcd (0b0000, 0b0100, 0);	//Decrement cursor (left) after writing; don't shift display
		//lcd (0b0000, 0b0110, 0);	//Increment cursor (right) after writing; don't shift display
		delay_ms(1);
	
	//'Cursor/Display Shift'
	//Set cursor move direction
		lcd (0b0001, 0b0000, 0);	//Decrement address and moves cursor left
		delay_ms(1);
	
	//'Display ON'
	//Enable display/cursor
		lcd (0b0000, 0b1100, 0);	//Display on, cursor off, blinking off
		//lcd (0b0000, 0b1111, 0);	//Display on, cursor on, blinking on
		delay_ms(1);
	
//-----------------------------------------------------------------------------

    while(1)
    {

//Measure Current and Voltage (must be done at same time since they interract)

	amps = 0; volts = 0;	//Initialise variables
					
	for(i=0; i<16; i++)		//Measure and sum both 16 times to smooth results
	{
		measure();			//Runs ADC and populates 'results' variables
		amps  += result_a;	//Sums each measurement
		volts += result_v;	//Sums each measurement
	}
	
//-----------------------------------------------------------------------------

//Determine Current

	//PSU has a 0.1ohm current sense resistor
	//The voltage drop across this is proportional to current through it
	// eg: 1A yields a 0.1v drop (1 x 0.1)
	//Op amp gain is calibrated with 1A to yield ADC result of 100
	// ie: this requires an output from the op amp of 0.488v (100 / 1023 * 4.99v)
	// (5v regulator used supplies 4.99v)
	//This means that 1 ADC step is 0.01A, ie: intended to be displayed direct on LCD
	// eg: ADC value of 1 displays as 0.01A, ADC 10 = 0.10, ADC 100 = 1.00, ADC 1000 = 10.00A
	//Note that the output of LM358N cannot exceed ~3.5v from a 5v supply
	// (Vdd - 1.5v common mode limit)
	//So op amp will peak at ~7A (PSU is rated to 5A so not a constraint)
	//  (7 x 0.1 = 0.7v x ~5 gain = 3.5v max)
		
	amps /= 16;	//16 measurements taken above so average results to smooth readings
		
	
//-----------------------------------------------------------------------------

//Determine Voltage
	
	volts <<= 9;		//Scale up measurement to improve accuracy of conversion to actual volts
						//An arbitray 'big' multiplier but chosen via spreadsheet to optimise
						//Voltage already comprises sum of 16 measurements
						//Increased further by 2 to power 9 (512) (PIC does shifts quickly)
						//Effect is 'volts' is now x8192 larger than a single measure (16 x 512)
						//x100 thereof is to change value to 'hundredths' to avoid decimals
						//x81.92 allows larger resistor divider factor below to improve its accuracy
						//100x81.92 = 8192
	
	volts += 3809;		//'Round up' to compensate for the fact that the PIC always rounds down
						//Value is not critical but same number used in next step seems appropriate
						//Modelled in spreadsheet to prove that it improves measurement accuracy
	
	volts /= 3809;		//Scale down for resistor divider ratio and ADC step value
						//Voltages are sampled over a 2k7 resistor in series with 9k1
						//2k7/11k8 resistors = 0.22881 (measured voltages are reduced by this)
						//  (10v in actually yields 2.268v so actual ratio is 0.2268)
						//5v/1023 ADC steps = 0.004888 (reference voltage per ADC step)
						//  (Regulator in prototype actually yields 4.99v = 0.004878 v/step)
						//0.2268/0.004878 = 46.49627 (ADC steps per measured volt)
						//Scale up by 81.92 to improve accuracy (46.49627 * 81.92 = 3808.9744)
						//  (ADC value was increased by 81.92 above so it get 'reversed' here)
						
	/*
	Example:	11v should yield an ADC value of 511 (11 x 0.2268 / 0.04878)
				* 16   = 8,176 		(16 measurements summed to smooth results)
				* 512  = 4,186,112
				+ 3809 = 4,189,921
				/ 3809 = 1100
				Program displays this as 11.00
	Note: PIC can only measure to 0.02v with chosen resistor divider ratio
		  So other examples may be out by 0.01 or 0.02v
		  ie: no worse than the inherent accuracy of the device
	*/

	volts -= (amps/10);	//Adjust for losses in current sense resister
						//Circuit has a 'low side' Rsense
						//PIC is grounded on one side (true ground) and PSUs output is on other
						//The voltage measurement is between true ground and positive
						// so is different to the output by the voltage drop through Rsense
						//Each ADC step current measurement represents 0.01A
						//With 0.1ohm Rsense, loss is 0.001v per ADC step (0.1ohm x 0.01A)
						//Eg: 1A = 100 ADC value = 0.1v loss (ie: over-reading by 10 hundreths)
	
						
//-----------------------------------------------------------------------------

//Display Current
	
	digits = (i16)amps;		//Casts result to 16bit integer to convert to ASCII
							//An interger is required by the uitoa_dec function called below

	if(digits<=1023)		//Display results if in valid range
	{
	
	//Check for jitter (difference between last measurement and latest one)
		diff = (s8)( (u8)amps - amps_old);	//Also casts variable correctly
			
	//Set jitter flag if change in measurement is just jitter (ie: changes by 1 step)
	//Note: this relies on jitter being > 1 step occasionally to allow display to update
	//ie: if voltage kept changing by exactly 1 step, display would never get updated
	//In practice this does not appear to cause any adverse effects
		if 		(diff == -1) jitter=1;	//-1 = Jitter
		else if (diff == 1)  jitter=1;	//+1 = Jitter
		else jitter=0;					//Set flag to 0 if not jitter
	
		if(jitter==0)			//No jitter (ie: a valid new measurement)
		{
		
		//We need individual decimals for display on LCD
		//So, first convert to ASCII using special BoostC function
		//Generates individual ASCII bytes (in an array) for each decimal character
		//eg: '12' becomes 0x31 and 0x32 which are ASCII hex for decimals 1 and 2
		//By deducting 0x30 we are left with a single numeral (eg: 1 and 2) to send to LCD
		//'uitoa_dec' is name of function being called
		//'buff' is a buffer array into which results of conversion are stored
		//'digits' is the integer being converted
		//'b' is number of ASCII bytes to be created
		
			uitoa_dec (buff, digits, 4);	//Populates buffer array with ASCII characters
		
			lcd (0b1100, 0b0101, 0);		//Move cursor to 14th position (ie: address 0x45)
											//1st bit (1) sets address mode; next 7bits are address
		
			lcd (6, 1, 1);					//'a' for Amps; program writes backwards (right to left)
											//'6' and '1' are req'd nibbles for 'a'; '1' = RS high
		
			buff[3] -= 0x30;				//Hundreths (convert ASCII to single characters)
			lcd (3, buff[3], 1);			//1st nibble 3, 2nd nibble 0-9, 1 to make RS high
			
			buff[2] -= 0x30;				//Tenths
			lcd (3, buff[2], 1);
			
			lcd (2, 14, 1);					//'.' for decimal
			
			if (digits>99)					//Only display a character if > 0.99v
			{
				buff[1] -= 0x30;			//0-9
				lcd(3,buff[1],1);
			}
			else lcd(2, 0, 1);				//Clear character (in case one existed before)
			
			if (digits>999)					//Only display a character if > 9.99v
			{
				buff[0] -= 0x30;			//Tens
				lcd(3,buff[0],1);
			}
			else lcd(2, 0, 1);				//Clear character
		}
	}
	
	else						//Display error message if out of range
	{
		lcd (0b1100, 0b0101, 0);//Move cursor to 14th position (ie: address 0x45)
		lcd(2,0,1);				//Clear character
		lcd(3,1,1);				//1
		lcd(7,2,1);				//r
		lcd(7,2,1);				//r
		lcd(4,5,1);				//E
	}
	
	amps_old = (u8)amps;			//Save last measurement (to determine jitter)
	
//-----------------------------------------------------------------------------

//Display Voltage

	digits = (i16)volts;			//Casts V measurement to 16bit integer to convert to ASCII
	
	if(digits<=2200 && amps<=1023)	//Display results if in valid range (PSU goes to 21v)
	{
	
	//Check for jitter (same as above)
		diff = (s8)( (u8)volts - volts_old);
			
	//Set jitter flag (same as above)
		if 		(diff == -1) jitter=1;	//-1 = Jitter
		else if (diff == 1)  jitter=1;	//+1 = Jitter
		else jitter=0;					//Set flag to 0 if not jitter
	
		if(jitter==0)			//No jitter (ie: a valid new measurement)
		{
			uitoa_dec (buff, digits, 4);	//Populates buffer array with ASCII characters
		
			lcd (0b1000, 0b0111, 0);		//Move cursor to 8th position (ie: address 0x07)
		
			lcd (7, 6, 1);					//'v' for volts
		
			buff[3] -= 0x30;				//Hundreths (converts ASCII to single characters)
			lcd (3, buff[3], 1);
			
			buff[2] -= 0x30;				//Tenths
			lcd (3, buff[2], 1);
			
			lcd (2, 14, 1);					//'.' for decimal
			
			if (digits>99)					//Only display a character if > 0.99v
			{
				buff[1] -= 0x30;			//0-9
				lcd(3,buff[1],1);
			}
			else lcd(2, 0, 1);				//Clear character (in case one existed before)
			
			if (digits>999)					//Only display a character if > 9.99v
			{
				buff[0] -= 0x30;			//Tens
				lcd(3,buff[0],1);			
			}
			else lcd(2, 0, 1);				//Clear character
		}
	}
		
	else						//Display error message if out of range
	{
		lcd (0b1000, 0b0111, 0);//Move cursor to 8th position (ie: address 0x07)
		lcd(2,0,1);				//Clear character
		lcd(3,2,1);				//2
		lcd(7,2,1);				//r
		lcd(7,2,1);				//r
		lcd(4,5,1);				//E
	}

	volts_old = (u8)volts;			//Save last measurement (to determine jitter)


	}									//end while
}										//end main
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top