/*********************************************************************************
DATALOG5.C
With interrupt button on dump routine (both buttons pressed.)
This is a data logger. It has a 5V and 14V ADC input and collects (with
the 24LC128 EEPROM memory) 8192 samples. Control and display is done
via two pushbuttons and and LCD display. Data dump can be viewed on
the display or sent to a terminal via 9600 baud RS232.
WORKING CODE
--------- ---------
+5--20-|Vdd B0|-----21->-6-|SCL* | *Pullups required
+5---1-|Mclr B1|-----22->-5-|SDA* | on SCL and SDA.
Gnd---8-|Vss | | 24LC128 |
Gnd--19-|Vss | +5-8-|Vdd |
4MHz--10-|Xtal | Gnd-4-|Vss | --------
---9-|Xtal | Gnd-7-|Wp | Gnd-20-|EN |
| | Gnd-1-|A0 | Gnd-21-|SD |
| 16F876 | Gnd-2-|A1 | Gnd-11-|Vss |
| | Gnd-3-|A2 | +5-12-|Vcc |
POT | | --------- | |
©-10K--13-|C2 | | |
In--10K-*-------2-|A0 B3|-24-->----9600 baud------------7-|IN OUT|-4-->-Tx
| | | |
-Menu/Dec --11-|C0 | | MAX235 |
-Select/Inc --12-|C1 | --------
| | ---------
| C3|-----14--11-|D4 |
| C4|-----15--12-|D5 |
| C5|-----16--13-|D6 |
| C6|-----17--14-|D7 |
| | | |-3--20K pot (contrast)
| B5|-----26---6-|EN |
| B6|-----27---4-|RS |
| | | |
| | +5-2-| |
| | Gnd-1-| |
| | Gnd-5-| |
| | | DISPLAY |
--------- ---------
*********************************************************************************/
#include < 16F876.H >
#device ADC=10
#include < jonsinc.h >
#fuses XT, NOPROTECT, NOPUT, NOWDT, NOBROWNOUT, NOLVP, NOCPD, NOWRT
// ADC
#define VDD 5.00
// INTERNAL EEPROM ASSIGNMENTS
#define SAMPLE_INTERVAL_HI 0
#define SAMPLE_INTERVAL_LO 1
#define SAMPLE_COUNT_HI 2
#define SAMPLE_COUNT_LO 3
#define LOGGING_STATE 4
#define RANGE 5
// EXTERNAL EEPROM ASSIGNMENTS 128Kbit EEPROM is 16384 bytes
#define EEPROM_BYTE_SIZE 16384
#define EEPROM_SCL PIN_B0
#define EEPROM_SDA PIN_B1
// LCD STUFF
#define LCD_D0 PIN_C3
#define LCD_D1 PIN_C4
#define LCD_D2 PIN_C5
#define LCD_D3 PIN_C6
#define LCD_EN PIN_B5
#define LCD_RS PIN_B6
#define LINE_1 0x00
#define LINE_2 0x40
#define CLEAR_DISP 0x01
#define MENU_DEC_SWITCH PIN_C0
#define SELECT_INC_SWITCH PIN_C1
#define RANGE_SHUNT PIN_C2
#define SEL0 PIN_B2
#define SEL1 PIN_B4
#define MINIMUM_INTERVAL 1
#define STATE_START 0
#define STATE_STOP 1
#define STATE_STATUS 2
#define STATE_RESET 3
#define STATE_RANGE 4
#define STATE_INTERVAL 5
#define STATE_VIEW 6
#define STATE_DUMP 7
#define MAX_MENU_STATE 7
#define hi(x) (*(&x+1))
#use delay ( clock=4000000 )
#use standard_io ( A )
#use standard_io ( B )
#use standard_io ( C )
#use rs232 ( baud=9600, xmit=PIN_B3 )
#use i2c ( master, scl=EEPROM_SCL, sda=EEPROM_SDA )
void PrintMenu ( void ); // protos
void init_ext_eeprom ( void );
void write_ext_eeprom ( long int lngAddress, BYTE intData );
BYTE read_ext_eeprom ( long int lngAddress );
void SetTime ( void );
void CheckSample ( void );
void CheckSwitches ( void );
char GetEchoNumChar ( void );
void LCD_Init ( void );
void LCD_SetPosition ( unsigned int cX );
void LCD_PutChar ( unsigned int cX );
void LCD_PutCmd ( unsigned int cX );
void LCD_PulseEnable ( void );
void LCD_SetData ( unsigned int cX );
void DisplayVolts ( long iAdcValue, char cLoc );
float ScaleAdc ( long iValue );
void SetRange ( BYTE cDisplay );
static long iIntervalCount, iIntervalTrigger, iSampleCount;
static char cLogging, cSampleFlag, cLedCount;
static char cLoggingIndicatorFlag, cAdcFlag, cToggleFlag;
static char cInterruptCount, cViewing;
static char cMenuState, cSelectFlag, cRange;
static char cMenuDecSwitchOn, cMenuSwitchCount;
static char cSelIncSwitchOn, cSelectSwitchCount;
//****************************************************************************
#int_rtcc
void TimerInterrupt ( void ) // 32.768mS tic, ~30 interrupts per second
{
if ( cInterruptCount++ == 30 ) // if one second yet
{
cAdcFlag = ON; // allow write to display
cInterruptCount = 0;
if ( cLogging == YES )
{
cLoggingIndicatorFlag = ON; // time to toggle "running" indicator on display
}
if ( ( iIntervalCount++ == iIntervalTrigger - 1 ) && ( cLogging == YES ) ) // if sample time yet
{
cSampleFlag = ON; // signal time to sample
iIntervalCount = 0; // start count over
}
}
if ( input ( MENU_DEC_SWITCH ) == LOW )
{
if ( cMenuSwitchCount++ == 1 ) // debounce for 30mS, (was 2)
{
cMenuDecSwitchOn = YES; // signal that switch was pressed
cMenuSwitchCount = cViewing ? 252 : 240; // set up for auto repeat (faster if viewing)
}
}
else
{
cMenuSwitchCount = 0; // switch up, restart
}
if ( input ( SELECT_INC_SWITCH ) == LOW )
{
if ( cSelectSwitchCount++ == 1 ) // debounce for 30mS (was 2)
{
cSelIncSwitchOn = YES; // signal that switch was pressed
cSelectSwitchCount = cViewing ? 252 : 240; // set up for auto repeat (faster if viewing)
}
}
else
{
cSelectSwitchCount = 0; // switch is up, restart count
}
set_rtcc ( 4 ); // restart at adjusted value for 1-second accuracy
}
//*****************************************************************************
void main ( void )
{
delay_ms ( 200 ); // wait enough time after VDD rise
output_float ( RANGE_SHUNT );
init_ext_eeprom(); // set SDA and SCL to float
setup_counters ( RTCC_INTERNAL, RTCC_DIV_128 ); // 31mS roll
LCD_Init();
LCD_PutCmd ( CLEAR_DISP );
LCD_SetPosition ( LINE_1 + 2 );
printf ( LCD_PutChar, "DATA LOGGER" );
LCD_SetPosition ( LINE_2 + 2 );
printf ( LCD_PutChar, "%4lu samples", EEPROM_BYTE_SIZE / 2 );
delay_ms ( 1000 );
LCD_PutCmd ( CLEAR_DISP ); LCD_Init();
LCD_SetPosition ( LINE_1 + 4 );
printf ( LCD_PutChar, "Jon Fick" );
LCD_SetPosition ( LINE_2 + 4 );
printf ( LCD_PutChar, "01/12/07" );
delay_ms ( 1000 );
LCD_PutCmd ( CLEAR_DISP );
// SETUP
setup_ccp1 ( CCP_OFF );
setup_ccp2 ( CCP_OFF );
setup_adc_ports ( RA0_ANALOG ); // these three statements set up the ADC
setup_adc ( ADC_CLOCK_INTERNAL ); // clock source
set_adc_channel ( 0 ); // select channel
enable_interrupts ( INT_RTCC ); // turn on timer interrupt
enable_interrupts ( GLOBAL ); // enable interrupts
// RESTORE PREVIOUS STATE
cRange = read_eeprom ( RANGE );
if ( cRange >= 2 )
{
cRange = 0; // reset to default
}
SetRange ( NO ); // set range according to cRange, don't display
iSampleCount = ( 256 * read_eeprom ( SAMPLE_COUNT_HI ) ) + read_eeprom ( SAMPLE_COUNT_LO );
cLogging = read_eeprom ( LOGGING_STATE ); // get existing state
iIntervalTrigger = ( 256 * read_eeprom ( SAMPLE_INTERVAL_HI ) ) + read_eeprom ( SAMPLE_INTERVAL_LO );
if ( iIntervalTrigger == 0 )
{
iIntervalTrigger = 1; // preset to at least 1 second sample interval
}
// INITIALIZE VARIABLES
cSelectFlag = OFF;
cToggleFlag = 0;
cMenuDecSwitchOn = OFF;
cSelIncSwitchOn = OFF;
cMenuSwitchCount = 0;
cSelectSwitchCount = 0;
cMenuState = ( cLogging == YES ) ? STATE_STOP : STATE_START; // set first menu
while ( TRUE ) // do forever
{
PrintMenu(); // display screens and voltage
CheckSwitches(); // check and do any switch activity
CheckSample(); // check if it's time to sample and store ADC
}
}
//****************************************************************************
void PrintMenu ( void )
{
// ACTIVITY INDICATOR
LCD_SetPosition ( LINE_1 + 15 );
if ( cLogging == NO ) // if not logging at this time
{
printf ( LCD_PutChar, " " ); // blank symbol for activity indicator
}
else // if presently logging
{
if ( cLoggingIndicatorFlag == ON ) // turned on once per second by interrupt
{
cToggleFlag ^= 1; // toggle the activity indicator symbol
if ( cToggleFlag == 1 )
{
printf ( LCD_PutChar, "%c", 255 ); // 255 symbol
}
else
{
printf ( LCD_PutChar, " " ); // blank symbol
}
cLoggingIndicatorFlag = OFF;
}
}
// PRINT LOWER LINE OF MENU
LCD_SetPosition ( LINE_2 + 0 );
switch ( cMenuState )
{
case STATE_START:
{
if ( cLogging == YES ) // don't display while logging
{
cMenuState++; // point to next menu
break;
}
printf ( LCD_PutChar, "Next START" );
break;
}
case STATE_STOP:
{
if ( cLogging == NO ) // don't display if not logging
{
cMenuState++; // point to next menu
break;
}
printf ( LCD_PutChar, "#%04lu", iSampleCount );
LCD_SetPosition ( LINE_2 + 11 );
printf ( LCD_PutChar, " STOP" );
break;
}
case STATE_INTERVAL:
{
if ( cLogging == YES ) // prevent changing while logging
{
cMenuState++; // point to next menu
break;
}
printf ( LCD_PutChar, "Next INTERVAL" );
break;
}
case STATE_STATUS:
{
printf ( LCD_PutChar, "Next STATUS" );
break;
}
case STATE_VIEW:
{
printf ( LCD_PutChar, "Next VIEW" );
break;
}
case STATE_DUMP:
{
printf ( LCD_PutChar, "Next UPLOAD" );
break;
}
case STATE_RESET:
{
if ( cLogging == YES ) // prevent changing while logging
{
cMenuState++; // point to next menu
break;
}
printf ( LCD_PutChar, "Next RESET" );
break;
}
case STATE_RANGE:
{
if ( cLogging == YES ) // prevent changing while logging
{
cMenuState++; // point to next menu
break;
}
printf ( LCD_PutChar, "Next RANGE" );
break;
}
}
// DISPLAY VOLTS
if ( cAdcFlag == ON ) // if interrupt signalled an ADC reading
{
DisplayVolts ( read_adc(), 5 ); // read ADC, send raw data to display at location 5
cAdcFlag = OFF;
}
}
void CheckSwitches ( void )
{
char cX, cDigit, cDigitPointer, cDone;
long iX, iY, iVal, iPlace;
// INCREMENT/DECREMENT
if ( cMenuDecSwitchOn == YES ) // if interrupt caught the switch press
{
if ( cMenuState++ >= MAX_MENU_STATE ) // if at maximum
{
cMenuState = 0; // roll
}
cMenuDecSwitchOn = NO; // turn back off
}
if ( cSelIncSwitchOn == YES ) // if interrupt caught the switch press
{
cSelectFlag = ON;
cSelIncSwitchOn = NO; // turn back off
}
// PRINT MENU (upper line and sometimes overwrite lower line)
switch ( cMenuState )
{
case ( STATE_START ):
{
if ( cSelectFlag == ON ) // if switch is pressed
{
cSelectFlag = OFF; // turn flag off
if ( iSampleCount >= ( EEPROM_BYTE_SIZE / 2 ) ) // already at end of memory
{
LCD_PutCmd ( CLEAR_DISP );
LCD_SetPosition ( LINE_1 + 2);
printf ( LCD_PutChar, "MEMORY FULL" );
LCD_SetPosition ( LINE_2 + 2 );
printf ( LCD_PutChar, "%4lu samples", iSampleCount );
delay_ms ( 1000 );
LCD_PutCmd ( CLEAR_DISP );
cMenuDecSwitchOn = NO;
cSelIncSwitchOn = NO;
cMenuState = STATE_START; // menu displays "START"
}
else // if OK to start
{
cLogging = YES;
write_eeprom ( LOGGING_STATE, YES );
write_eeprom ( RANGE, cRange );
cSampleFlag = ON; // immediate sample
cInterruptCount = 0; // synchronize interrupt timing from here
iIntervalCount = 0; // synchronize
cMenuState = STATE_STOP; // menu displays "STOP"
break;
}
}
}
case ( STATE_STOP ):
{
if ( cSelectFlag == ON ) // if switch is pressed
{
cSelectFlag = OFF; // turn flag off
cLogging = NO;
write_eeprom ( LOGGING_STATE, NO );
cMenuState = STATE_START; // menu displays "START"
break;
}
}
case ( STATE_RESET ):
{
if ( cSelectFlag == ON ) // if switch is pressed
{
cSelectFlag = OFF; // turn flag off
write_eeprom ( SAMPLE_COUNT_HI, 0 );
write_eeprom ( SAMPLE_COUNT_LO, 0 );
iSampleCount = 0;
cLogging = NO;
LCD_PutCmd ( CLEAR_DISP );
LCD_SetPosition ( LINE_1 + 0 );
printf ( LCD_PutChar, "Reset..." );
delay_ms ( 1000 );
LCD_SetPosition ( LINE_1 + 8 );
printf ( LCD_PutChar, "complete" );
delay_ms ( 1000 );
LCD_PutCmd ( CLEAR_DISP );
cMenuDecSwitchOn = NO;
cSelIncSwitchOn = NO;
cMenuState = STATE_START; // menu displays "START"
break;
}
}
case ( STATE_STATUS ):
{
if ( cSelectFlag == ON ) // if switch is pressed
{
cSelectFlag = OFF; // turn flag off
LCD_PutCmd ( CLEAR_DISP );
LCD_SetPosition ( LINE_1 );
printf ( LCD_PutChar, "Interval: %lus", 256 * read_eeprom ( SAMPLE_INTERVAL_HI ) + read_eeprom ( SAMPLE_INTERVAL_LO ) );
LCD_SetPosition ( LINE_2 );
printf ( LCD_PutChar, "Samples: %lu", 256 * read_eeprom ( SAMPLE_COUNT_HI ) + read_eeprom ( SAMPLE_COUNT_LO ) );
delay_ms ( 2000 );
LCD_PutCmd ( CLEAR_DISP );
cMenuDecSwitchOn = NO;
cSelIncSwitchOn = NO;
cMenuState = STATE_START; // menu displays "LOG"
break;
}
}
case ( STATE_RANGE ):
{
if ( cSelectFlag == ON ) // if switch is pressed
{
cSelectFlag = OFF; // turn flag off
LCD_PutCmd ( CLEAR_DISP );
LCD_SetPosition ( LINE_2 + 0 );
printf ( LCD_PutChar, "CHANGE Return" );
SetRange ( YES ); // set and display present range according to cRange
while ( TRUE )
{
if ( cSelIncSwitchOn == YES ) // if RETURN button is pressed
{
cSelIncSwitchOn = NO;
break; // done selecting
}
if ( cMenuDecSwitchOn == YES ) // if CHANGE button is pressed
{
cMenuDecSwitchOn = NO;
if ( ++cRange >= 2 ) // increment and wrap
{
cRange = 0;
}
LCD_SetPosition ( LINE_1 + 7 );
SetRange ( YES ); // set range, display
}
}
write_eeprom ( RANGE, cRange ); // save final selected range
LCD_PutCmd ( CLEAR_DISP );
cMenuState = STATE_START; // menu displays "START"
break;
}
}
case ( STATE_INTERVAL ):
{
if ( cSelectFlag == ON ) // if switch is pressed
{
cSelectFlag = OFF; // turn flag off
LCD_PutCmd ( CLEAR_DISP );
LCD_SetPosition ( LINE_1 );
printf ( LCD_PutChar, "Presently %05lus", iIntervalTrigger );
LCD_SetPosition ( LINE_2 + 0 );
printf ( LCD_PutChar, "DIGIT 00000s INC" );
cX = LINE_2 + 6; // point to beginning of zeros
LCD_SetPosition ( cX );
LCD_PutCmd ( 0x0E ); // display ON, cursor on, no blink
cDigit = 0;
cDigitPointer = 0;
iX = 0;
iPlace = 10000;
while ( TRUE )
{
if ( cSelIncSwitchOn == YES )
{
if ( ++cDigit > 9 ) // increment digit
{
cDigit = 0; // roll
}
cSelIncSwitchOn = NO;
cSelIncSwitchOn = NO;
LCD_SetPosition ( cX + cDigitPointer ); // set cursor to this digit
printf ( LCD_PutChar, "%u", cDigit ); // display the digit
LCD_SetPosition ( cX + cDigitPointer ); // set cursor back to this digit
}
if ( cMenuDecSwitchOn == YES )
{
cMenuDecSwitchOn = NO;
iX += cDigit * iPlace; // add in to total
iPlace /= 10; // point to next place value down
cDigit = 0; // zero digit again
if ( ++cDigitPointer == 5 ) // point to next digit
{
break;
}
LCD_SetPosition ( cX + cDigitPointer );
}
}
if ( iX != 0 ) // if number was updated
{
write_eeprom ( SAMPLE_INTERVAL_HI, iX / 256 ); // store high byte
write_eeprom ( SAMPLE_INTERVAL_LO, iX % 256 ); // store low byte
iIntervalTrigger = iX; // update interval
}
LCD_PutCmd ( 0x0E ); // display ON, cursor off, no blink
LCD_PutCmd ( CLEAR_DISP );
cMenuState = STATE_START; // menu displays "LOG"
break;
}
}
case ( STATE_VIEW ):
{
if ( cSelectFlag == ON ) // if switch is pressed
{
cSelectFlag = OFF; // turn flag off
iX = 0; // zero sample number
iY = ( read_eeprom ( SAMPLE_COUNT_HI ) * 256 ) + read_eeprom ( SAMPLE_COUNT_LO );
cRange = read_eeprom ( RANGE ); // used stored range
LCD_PutCmd ( CLEAR_DISP );
cDone = NO;
if ( iY != 0 ) // if any samples at all
{
LCD_SetPosition ( LINE_1 );
printf ( LCD_PutChar, "#" );
LCD_SetPosition ( LINE_2 );
printf ( LCD_PutChar, "DEC BothDone INC" );
while ( cDone == NO )
{
LCD_SetPosition ( LINE_1 + 1 );
printf ( LCD_PutChar, "%04lu", iX ); // display sample number
iPlace = ( read_ext_eeprom ( iX * 2 ) * 256 ) + read_ext_eeprom ( ( iX * 2 ) + 1 ); // retrieve data from EEPROM
DisplayVolts ( iPlace, 10 ); // display data at location 10
while ( TRUE )
{
cViewing = ON;
if ( ( input ( MENU_DEC_SWITCH ) == LOW ) && ( input ( SELECT_INC_SWITCH ) == LOW ) )
{
cDone = YES;
break;
}
if ( cMenuDecSwitchOn == YES )
{
cMenuDecSwitchOn = NO;
if ( iX-- == 0 )
{
iX = iY - 1; // roll negative
}
break;
}
if ( cSelIncSwitchOn == YES )
{
cSelIncSwitchOn = NO;
if ( iX++ >= ( iY - 1 ) )
{
iX = 0; // roll positive
}
break;
}
}
cViewing = OFF;
}
}
else
{
LCD_SetPosition ( LINE_1 );
printf ( LCD_PutChar, "No samples yet!" );
delay_ms ( 1000 );
}
LCD_PutCmd ( CLEAR_DISP );
cMenuState = STATE_START; // menu displays "LOG"
break;
}
}
case ( STATE_DUMP ):
{
if ( cSelectFlag == ON ) // if switch is pressed
{
cSelectFlag = OFF; // turn flag off
iY = ( read_eeprom ( SAMPLE_COUNT_HI ) * 256 ) + read_eeprom ( SAMPLE_COUNT_LO ); // get number of samples
cRange = read_eeprom ( RANGE ); // used stored range
LCD_PutCmd ( CLEAR_DISP );
cDone = NO;
if ( iY != 0 ) // if any samples at all
{
LCD_SetPosition ( LINE_1 + 0 );
printf ( LCD_PutChar, "Dump 9600-8-N-1 " );
LCD_SetPosition ( LINE_2 );
printf ( LCD_PutChar, " Both=Stop " );
disable_interrupts ( GLOBAL ); // turn off during async
printf ( "\r\n\r\n Sample interval -- %lu seconds", 256 * read_eeprom ( SAMPLE_INTERVAL_HI ) + read_eeprom ( SAMPLE_INTERVAL_LO ) );
printf ( "\r\n Number of samples- %lu", iY );
printf ( "\r\n\r\nSample\tVolts" );
printf ( "\r\n------\t-----\r\n" );
for ( iX = 0; iX < iY; iX++ )
{
if ( ( input ( MENU_DEC_SWITCH ) == LOW ) && ( input ( SELECT_INC_SWITCH ) == LOW ) )
{
cDone = YES;
break;
}
iVal = ( read_ext_eeprom ( iX * 2 ) * 256 ) + read_ext_eeprom ( ( iX * 2 ) + 1 ); // get sample data
if ( iVal == 0x3FF )
{
printf ( "%lu\tO/L\r\n", iX ); // out-of-range
}
else
{
printf ( "%lu\t%1.2f\r\n", iX, ScaleAdc ( iVal ) ); // send data sample
}
delay_ms ( 1 ); // avoids text glitches in output stream
}
enable_interrupts ( GLOBAL ); // turn on again
}
else
{
LCD_SetPosition ( LINE_1 );
printf ( LCD_PutChar, "No samples yet!" );
delay_ms ( 1000 );
}
delay_ms ( 1000 ); // allow time to view 9600 baud msg, etc.
LCD_PutCmd ( CLEAR_DISP );
cMenuState = STATE_START; // menu displays "LOG"
break;
}
}
}
}
void SetRange ( BYTE cDisplay )
{
LCD_SetPosition ( LINE_1 + 3 );
switch ( cRange )
{
case ( 0 ): // if 5V range
{
output_float ( RANGE_SHUNT ); // let shunt resistor float
if ( cDisplay == YES )
{
printf ( LCD_PutChar, "Range: 5V " ); // 5V scale
}
break;
}
case ( 1 ): // if 14V range
{
output_low ( RANGE_SHUNT ); // pull shunt resistor down
if ( cDisplay == YES )
{
printf ( LCD_PutChar, "Range: 14V" ); // 14V scale
}
break;
}
}
}
void CheckSample ( void )
{
long iVal;
if ( cSampleFlag == ON ) // if time to sample
{
if ( iSampleCount >= ( EEPROM_BYTE_SIZE / 2 ) ) // if at end of memory
{
cLogging = NO; // stop any further logging
write_eeprom ( LOGGING_STATE, NO );
cMenuState = STATE_STATUS; // display status menu next
}
else // if not at end of memory
{
iVal = read_adc();
write_ext_eeprom ( iSampleCount * 2, iVal / 256 ); // write high data to external EEPROM
write_ext_eeprom ( ( iSampleCount * 2 ) + 1, iVal % 256 ); // write low data
iSampleCount++; // point to next memory location
write_eeprom ( SAMPLE_COUNT_HI, ( char ) ( iSampleCount / 256 ) ); // save sample count to internal EEPROM
write_eeprom ( SAMPLE_COUNT_LO, ( char ) ( iSampleCount % 256 ) );
}
cSampleFlag = OFF; // reset flag, interrupt turns on again later
}
}
void init_ext_eeprom ( void )
{
output_float ( EEPROM_SCL );
output_float ( EEPROM_SDA );
}
void write_ext_eeprom ( long int lngAddress, BYTE intData )
{
i2c_start();
i2c_write ( 0xa0 ); // set up for writing address and data, chip address 000
i2c_write ( hi ( lngAddress ) ); // write high address
i2c_write ( lngAddress ); // write low address
i2c_write ( intData ); // write data
i2c_stop();
delay_ms ( 11 );
}
BYTE read_ext_eeprom ( long int lngAddress )
{
BYTE intData;
i2c_start();
i2c_write ( 0xa0 ); // set up for writing address, chip address 000
i2c_write ( hi ( lngAddress ) ); // write high address
i2c_write ( lngAddress ); // write low address
i2c_start();
i2c_write ( 0xa1 ); // set up for reading data, chip address 000
intData = i2c_read ( 0 ); // read data
i2c_stop();
return ( intData );
}
char GetEchoNumChar ( void )
{
char cX;
while ( TRUE )
{
// cX = getc(); // wait for character
cX = getc();
if ( ( cX >= '0' ) && ( cX <= '9' ) ) // check bounds
{
break;
}
}
putc ( cX ); // echo to screen
return ( cX - 0x30 ); // adjust to numeric
}
void DisplayVolts ( long iAdcValue, char cLoc )
{
float fX;
LCD_SetPosition ( LINE_1 + cLoc );
if ( iAdcValue == 0x3FF )
{
printf ( LCD_PutChar, " O/L " ); // out of range
}
else
{
fX = ScaleAdc ( iAdcValue );
printf ( LCD_PutChar, "%2.2fV ", fX ); // display data sample
}
}
float ScaleAdc ( long iValue )
{
float fScale, fX;
switch ( cRange )
{
case ( 0 ):
{
fScale = VDD; // 5V scale
break;
}
case ( 1 ):
{
fScale = 14; // 14V scale
break;
}
}
return ( ( ( float ) iValue ) / 1023 * fScale ); // scale to proper range, 1023 leaves room for out-of-range
}
// LCD FUNCTIONS =================================
void LCD_Init ( void )
{
LCD_SetData ( 0x00 );
delay_ms ( 200 ); // wait enough time after Vdd rise
output_low ( LCD_RS );
LCD_SetData ( 0x03 ); // init with specific nibbles to start 4-bit mode
LCD_PulseEnable();
LCD_PulseEnable();
LCD_PulseEnable();
LCD_SetData ( 0x02 ); // set 4-bit interface
LCD_PulseEnable(); // send dual nibbles hereafter, MSN first
LCD_PutCmd ( 0x2C ); // function set (all lines, 5x7 characters)
LCD_PutCmd ( 0x0C ); // display ON, cursor off, no blink
LCD_PutCmd ( 0x01 ); // clear display
LCD_PutCmd ( 0x06 ); // entry mode set, increment
}
void LCD_SetPosition ( unsigned int cX )
{
// this subroutine works specifically for 4-bit Port A
LCD_SetData ( swap ( cX ) | 0x08 );
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) );
LCD_PulseEnable();
}
void LCD_PutChar ( unsigned int cX )
{
// this subroutine works specifically for 4-bit Port A
output_high ( LCD_RS );
LCD_SetData ( swap ( cX ) ); // send high nibble
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) ); // send low nibble
LCD_PulseEnable();
output_low ( LCD_RS );
}
void LCD_PutCmd ( unsigned int cX )
{
// this subroutine works specifically for 4-bit Port A
LCD_SetData ( swap ( cX ) ); // send high nibble
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) ); // send low nibble
LCD_PulseEnable();
}
void LCD_PulseEnable ( void )
{
output_high ( LCD_EN );
delay_us ( 10 );
output_low ( LCD_EN );
delay_ms ( 5 );
}
void LCD_SetData ( unsigned int cX )
{
output_bit ( LCD_D0, cX & 0x01 );
output_bit ( LCD_D1, cX & 0x02 );
output_bit ( LCD_D2, cX & 0x04 );
output_bit ( LCD_D3, cX & 0x08 );
}