Software for PIC 16F876

Hello, I want to built a simple datalogger with a PIC 16F876, and found a nice schema on the net. My problem: te software (source) is written in "C", but i need a hex files to program the PIC processor. I have playing with JAL, but i have not a "C" knowledge. Can someone help me, and "translate" the C to hex ?

Thanks

*/

#include #device ADC=10 #include #fuses XT, NOPROTECT, NOPUT, NOWDT, NOBROWNOUT, NOLVP, NOCPD, NOWRT

/* 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 */ #define EEPROM_ADDRESS long int #define EEPROM_BYTE_SIZE 8192 #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, cSel; static char cMenuDecSwitchOn, cMenuSwitchCount; static char cSelIncSwitchOn, cSelectSwitchCount;

void main ( void ) { 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 ( 2000 ); LCD_PutCmd ( CLEAR_DISP ); LCD_Init(); LCD_SetPosition ( LINE_1 + 4 ); printf ( LCD_PutChar, "Jon Fick" ); LCD_SetPosition ( LINE_2 + 4 ); printf ( LCD_PutChar, "03/01/04" ); delay_ms ( 2000 ); LCD_PutCmd ( CLEAR_DISP );

/* RESTORE PREVIOUS STATE */ cRange = read_eeprom ( RANGE ); SetRange ( NO ); /* set range, 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 */ }

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 */

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 screen */ CheckSwitches(); /* check and do any switch activity */ CheckSample(); /* check if it's time to sample ADC */ } }

/******************************************************************************/

#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++ == 0 ) /* 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++ == 0 ) /* 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 CheckSwitches ( void ) { char cX, cDigit, cDigitPointer, cDone; long iX, iY, iVal, iPlace;

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 */ }

if ( cLogging == NO ) { cSel = 2 * input ( SEL0 ) + input ( SEL1 ); /* determine state of SEL inputs, (unused at present) */ }

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" ); LCD_SetPosition ( LINE_1 + 7 ); SetRange ( YES ); /* set range, display */ while ( TRUE ) { if ( cSelIncSwitchOn == YES ) { cSelIncSwitchOn = NO; break; } if ( cMenuDecSwitchOn == YES ) { 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 range */ 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 position 7 */ 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 ( "rnrn Sample interval -- %lu seconds", 256 * read_eeprom ( SAMPLE_INTERVAL_HI ) + read_eeprom ( SAMPLE_INTERVAL_LO ) ); printf ( "rn Number of samples- %lu", iY ); printf ( "rnrnSampletVolts" ); printf ( "rn------t-----rn" ); 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 ( "%lutO/Lrn", iX ); /* out-of-range */ } else { printf ( "%lut%1.2frn", 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 PrintMenu ( void ) { LCD_SetPosition ( LINE_1 + 15 ); if ( cLogging == NO ) /* if not logging at this time */ { printf ( LCD_PutChar, " " ); /* blank symbol */ } else /* if presently logging */ { if ( cLoggingIndicatorFlag == ON ) /* turned on once per second by interrupt */ { cToggleFlag ^= 1; /* toggle the symbol */ if ( cToggleFlag == 1 ) { printf ( LCD_PutChar, "%c", 255 ); /* symbol */ } else { printf ( LCD_PutChar, " " ); /* blank */ } cLoggingIndicatorFlag = OFF; } } 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; } } if ( cAdcFlag == ON ) /* if interrupt signalled an ADC reading */ { DisplayVolts ( read_adc(), 5 ); /* read ADC, send raw data to display routine at position 3 */ cAdcFlag = OFF; } }

void SetRange ( BYTE cDisplay ) { switch ( cRange ) { case ( 0 ): /* if 5V range */ { output_float ( RANGE_SHUNT ); /* open shunt pulldown

*/ if ( cDisplay == YES ) { printf ( LCD_PutChar, "5V " ); /* 5V scale */ } break; } case ( 1 ): /* if 14V range */ { output_low ( RANGE_SHUNT ); /* pull shunt resistor down */ if ( cDisplay == YES ) { printf ( LCD_PutChar, "14V" ); /* 14V scale */ } break; } default: /* anything else is 5V range */ { output_float ( RANGE_SHUNT ); /* open shunt pulldown */ if ( cDisplay == YES ) { printf ( LCD_PutChar, "5V " ); /* 5V scale */ } break; } } }

void CheckSample ( void ) { long iVal;

if ( cSampleFlag == ON ) /* if time to sample */ { if ( iSampleCount >= ( EEPROM_BYTE_SIZE / 2 ) ) /* at end of memory */ { cLogging = NO; /* stop any further logging */ write_eeprom ( LOGGING_STATE, NO ); cMenuState = STATE_STATUS; /* display status menu next

*/ } else { iVal = read_adc(); /* iVal = iSampleCount; only for testing */ 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

Reply to
Frits
Loading thread data ...

Hello, I want to built a simple datalogger with a PIC 16F876, and found a nice schema on the net. My problem: te software (source) is written in "C", but i need a hex files to program the PIC processor. I have playing with JAL, but i have not a "C" knowledge. Can someone help me, and "translate" the C to hex ?

Thanks

*/

#include #device ADC=10 #include #fuses XT, NOPROTECT, NOPUT, NOWDT, NOBROWNOUT, NOLVP, NOCPD, NOWRT

/* 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 */ #define EEPROM_ADDRESS long int #define EEPROM_BYTE_SIZE 8192 #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, cSel; static char cMenuDecSwitchOn, cMenuSwitchCount; static char cSelIncSwitchOn, cSelectSwitchCount;

void main ( void ) { 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 ( 2000 ); LCD_PutCmd ( CLEAR_DISP ); LCD_Init(); LCD_SetPosition ( LINE_1 + 4 ); printf ( LCD_PutChar, "Jon Fick" ); LCD_SetPosition ( LINE_2 + 4 ); printf ( LCD_PutChar, "03/01/04" ); delay_ms ( 2000 ); LCD_PutCmd ( CLEAR_DISP );

/* RESTORE PREVIOUS STATE */ cRange = read_eeprom ( RANGE ); SetRange ( NO ); /* set range, 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 */ }

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 */

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 screen */ CheckSwitches(); /* check and do any switch activity */ CheckSample(); /* check if it's time to sample ADC */ } }

/******************************************************************************/

#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++ == 0 ) /* 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++ == 0 ) /* 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 CheckSwitches ( void ) { char cX, cDigit, cDigitPointer, cDone; long iX, iY, iVal, iPlace;

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 */ }

if ( cLogging == NO ) { cSel = 2 * input ( SEL0 ) + input ( SEL1 ); /* determine state of SEL inputs, (unused at present) */ }

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" ); LCD_SetPosition ( LINE_1 + 7 ); SetRange ( YES ); /* set range, display */ while ( TRUE ) { if ( cSelIncSwitchOn == YES ) { cSelIncSwitchOn = NO; break; } if ( cMenuDecSwitchOn == YES ) { 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 range */ 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 position 7 */ 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 ( "rnrn Sample interval -- %lu seconds", 256 * read_eeprom ( SAMPLE_INTERVAL_HI ) + read_eeprom ( SAMPLE_INTERVAL_LO ) ); printf ( "rn Number of samples- %lu", iY ); printf ( "rnrnSampletVolts" ); printf ( "rn------t-----rn" ); 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 ( "%lutO/Lrn", iX ); /* out-of-range */ } else { printf ( "%lut%1.2frn", 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 PrintMenu ( void ) { LCD_SetPosition ( LINE_1 + 15 ); if ( cLogging == NO ) /* if not logging at this time */ { printf ( LCD_PutChar, " " ); /* blank symbol */ } else /* if presently logging */ { if ( cLoggingIndicatorFlag == ON ) /* turned on once per second by interrupt */ { cToggleFlag ^= 1; /* toggle the symbol */ if ( cToggleFlag == 1 ) { printf ( LCD_PutChar, "%c", 255 ); /* symbol */ } else { printf ( LCD_PutChar, " " ); /* blank */ } cLoggingIndicatorFlag = OFF; } } 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; } } if ( cAdcFlag == ON ) /* if interrupt signalled an ADC reading */ { DisplayVolts ( read_adc(), 5 ); /* read ADC, send raw data to display routine at position 3 */ cAdcFlag = OFF; } }

void SetRange ( BYTE cDisplay ) { switch ( cRange ) { case ( 0 ): /* if 5V range */ { output_float ( RANGE_SHUNT ); /* open shunt pulldown

*/ if ( cDisplay == YES ) { printf ( LCD_PutChar, "5V " ); /* 5V scale */ } break; } case ( 1 ): /* if 14V range */ { output_low ( RANGE_SHUNT ); /* pull shunt resistor down */ if ( cDisplay == YES ) { printf ( LCD_PutChar, "14V" ); /* 14V scale */ } break; } default: /* anything else is 5V range */ { output_float ( RANGE_SHUNT ); /* open shunt pulldown */ if ( cDisplay == YES ) { printf ( LCD_PutChar, "5V " ); /* 5V scale */ } break; } } }

void CheckSample ( void ) { long iVal;

if ( cSampleFlag == ON ) /* if time to sample */ { if ( iSampleCount >= ( EEPROM_BYTE_SIZE / 2 ) ) /* at end of memory */ { cLogging = NO; /* stop any further logging */ write_eeprom ( LOGGING_STATE, NO ); cMenuState = STATE_STATUS; /* display status menu next

*/ } else { iVal = read_adc(); /* iVal = iSampleCount; only for testing */ 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

Reply to
Frits

< SNIP SOURCE CODE >

Hello,

You can download a free PIC C compiler from here:

formatting link

It does have some restrictions, but it's okay for most projects. I'm not sure if it supports the PIC16F876 though. If it doesn't, then you will need to consider a different PIC. The PIC16F877 is supported and should be capable of doing whatever the PIC16F876 is doing. Although the pin numbers of the 2 pics is different. The PIC16F877 has 40 pins and has more I/O ports than the PIC16F876. You'll have to check the data sheets, but the pin names should be the same for both devices.

The C compiler should have some tutorials with it, which will tell you how to produce the hex file. You can also find plenty of online tutorials. It's pretty straightforward to produce the hex file once you have the source code.

Good luck,

Craig Homepage:

formatting link

Reply to
Craig

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.