0,0 → 1,1434 |
// Change the following to change the clock frequency |
#define CRYSTAL_FREQ 16000000 |
// Change the following to change between 16 or 20 column display |
#define DISPLAY_COLS 20 |
// Speed units are "1" (nautical knots), "2" (metric kph), or "3" (statute mph) |
#define SPEED_UNITS 1 |
|
/**************************************************************************** |
GPS18.c |
|
This program receives NMEA-0183 data from a GPS and displays it. |
Meant for large display version still in 16F876. |
Three buttons |
Automicaly resets if main loop stops (not the best solution, still don't know why it's stopping) |
|
Next: don't display GPS screens unless GPS is active |
detect display needing reset |
preset data eeprom for first-time operation |
don't display init stuff if reseting from main loop |
|
|
|
+5 +5+5 |
| | | |
20 15 2 |
---------- ---------- |
~SerIn -----18-| |-24-----11-|DB4 A Vdd | |
| |-25-----12-|DB5 | |
ADC0 ------2-| |-26-----13-|DB6 | |
ADC1 ------3-| 16F876 |-27-----14-|DB7 Vo| 3-- |
ADC2 ------5-| | | LCD | | |
| |-14------6-|EN | | |
XTAL--9-| |-15------4-|R/S | | |
XTAL-10-| |-28-FET-16-|K | | |
| | | RW Vss | | |
BUTTON 1---21-| | ---------- | |
BUTTON 2---22-| | 1 5 | |
BUTTON 3---23-| | | | | |
| | Gnd Gnd | |
| | | |
| |-11----------R/C----------- |
| | |
| | |
---------- |
8 19 |
| | |
Gnd Gnd |
|
***************************************************************************/ |
#case |
#include <16F876.h> |
#include <jonsinc.h> |
#device = *=16 ADC=10 /* allow RAM addresses over 255 */ |
|
#if ( ( CRYSTAL_FREQ < 4000000) || ( CRYSTAL_FREQ > 20000000 ) ) |
#error "CRYSTAL FREQ" not defined to between 8000000 and 20000000 |
#endif |
#if ( ( DISPLAY_COLS != 16 ) && ( DISPLAY_COLS != 20 ) ) |
#error "DISPLAY COLS" not defined to 16 or 20 |
#endif |
|
// RMC_TIME = 1 per clock megahertz, rounded |
#define RMC_TIME CRYSTAL_FREQ/1000000 |
|
#define LCD_D0 PIN_B3 |
#define LCD_D1 PIN_B4 |
#define LCD_D2 PIN_B5 |
#define LCD_D3 PIN_B6 |
#define LCD_EN PIN_C3 |
#define LCD_RS PIN_C4 |
#define RX_IN PIN_C7 |
#define BUTTON_1 PIN_B0 |
#define BUTTON_2 PIN_B1 |
#define BUTTON_3 PIN_B2 |
#define LCD_BACKLITE PIN_B7 |
#define LINE_1 0x00 |
#define LINE_2 0x40 |
#if DISPLAY_COLS == 20 |
#define LINE_3 0x14 |
#define LINE_4 0x54 |
#endif |
#if DISPLAY_COLS == 16 |
#define LINE_3 0x10 |
#define LINE_4 0x50 |
#endif |
#define CLEAR_DISP 0x01 |
#define EOF 0x00 |
#define COMMA ',' |
#define CR 13 |
#define SPACE ' ' |
#define PERIOD '.' |
#define DEGREE 0xdf |
#define DOLLAR '$' |
#define NULL 0 |
#define GPRMC_CODE 75 |
#define GPRMB_CODE 74 |
#define RX_BUFFER_SIZE 70 |
#define POSITION_SCREEN 1 |
#define WAYPOINT_SCREEN 2 |
#define BATTERY_SCREEN 3 |
#define HIDDEN_RMC 5 |
#define WARNING_MSG 0 |
#define NODATA_MSG 1 |
#define ACTIVITY_SYMBOL 0xFF |
#define MAX_VOLTS 15 |
#define EEPROM_CONTRAST 0 |
#define EEPROM_INITIAL 1 |
|
/* Set the following define to "YES" to display XOR'ed GPS sentence code */ |
/* such as GPRMC and the display will read out the value of 74. */ |
#define GET_GPS_CODE NO |
|
#separate void Display ( void ); |
#separate void LCD_Init ( void ); |
#separate void LCD_SetPosition ( unsigned int cX ); |
#separate void LCD_PutChar ( unsigned int cX ); |
#separate void LCD_PutCmd ( unsigned int cX ); |
#separate void LCD_PulseEnable ( void ); |
#separate void LCD_SetData ( unsigned int cX ); |
#separate void SkipField ( char cCnt ); |
#separate char GetField ( void ); |
#separate void InitRxBuffer ( char cCode ); |
#separate char GetRxChar ( void ); |
#separate void DisplayLatLon ( void ); |
#separate void DisplayWaypoint ( void ); |
#separate void DisplayLatitude ( char cLine ); |
#separate void DisplayLongitude ( char cLine ); |
#separate void DisplayHeading ( char cLine ); |
#separate void DisplaySpeed ( char cLine ); |
#separate void DisplaySteer ( char cLine, char cX ); |
#separate void DisplayWaypointName ( char cLine, char cX ); |
#separate void DisplayDistance ( char cLine, char cX ); |
#separate void DisplayBearing ( char cLine, char cX ); |
#separate void GetUtcAndMagVar ( void ); |
#separate long TrueToMag ( long iH ); |
#separate long FieldFiveToLong ( void ); |
#separate void DisplayAnalog ( void ); |
#separate void DisplayScaledVoltage ( long iV, char cScale ); |
#separate void DisplayArrival ( char cLine ); |
#separate void DisplayMessage ( char cMsgNum ); |
#separate void DisplayTemplateLatLon ( void ); |
#separate void DisplayTemplateWaypoint ( void ); |
#separate void DisplayTemplateAnalog ( void ); |
#separate void Delay5mS ( char cCnt ); |
|
#fuses HS, NOPROTECT, PUT, NOWDT, BROWNOUT, NOLVP, NOCPD |
#use standard_io ( A ) |
#use standard_io ( B ) |
#use standard_io ( C ) |
#use delay ( clock = CRYSTAL_FREQ ) |
#use rs232 ( baud=4800, xmit=PIN_C6, rcv=PIN_C7, ERRORS ) // XMIT must be assigned to enable hardward USART |
#priority RDA, RTCC, EXT |
|
static char cC [ 10 ]; // local buffer |
static char cTimeOut; |
static char cRxBuffer [ RX_BUFFER_SIZE ]; // Fifo |
static char cRxByteCnt; // Number of bytes in the recv fifo |
static char *cRxBufferWritePtr; // Pointers for the Rx buffer |
static char *cRxBufferReadPtr; |
static char cRxIsrState, cRxMsgTypeReceived, cRxMsgTypeDesired; |
static char cRxMsgReady, cReceiveFlag; |
static long iVar, iLastRange, iTimeOut; |
static char cVarDir, cScreenChanged, cAdcDone; |
static char cButtonPressed, cSkip, cButtonCount; |
static char cScreen, cSavedScreen, cRmcTimer1, cRmcTimer2; |
static char cToFrom [ 5 ], cIndicator, cIllumination, cRxErrorFlag; |
static char cDone, cContrast; |
|
/*******************************************************************/ |
#int_ad |
void AdcInterrupt ( void ) |
{ |
/* Gets here when ADC is done conversion, sets flag */ |
cAdcDone = YES; |
} |
|
#int_timer1 |
void Timer1Interrupt ( void ) |
{ |
/* Periodic RMC data timer, gets here every 204mS */ |
/* This routine forces RMC to run every 10 minutes to update */ |
/* magnetic variation */ |
if ( cRmcTimer1-- == 0 ) |
{ |
cRmcTimer1 = 255; // 52 seconds @ 10.240MHz |
if ( cRmcTimer2-- == 0 ) |
{ |
cRmcTimer2 = RMC_TIME; // triggers every 10 minutes |
cSavedScreen = cScreen; // save current screen type |
cScreen = HIDDEN_RMC; // force RMC to run |
} |
} |
} |
|
#int_rtcc |
void Timer0Interrupt ( void ) |
{ |
// Gets here every 16.4mS at 8MHz, 8.2mS at 16MHz |
// Handles data timeout and switch debounce. |
|
// DATA TIMEOUT TIMER |
if ( cTimeOut != 0 ) |
{ |
cTimeOut--; |
} |
|
// This timer is preset by the normal operating loop, unless the operating |
// loop stops looping, at which point iTimeOut finally decrements to zero |
// and resets CPU. |
if ( iTimeOut != 0 ) |
{ |
iTimeOut--; |
} |
else |
{ |
reset_cpu(); // force reset |
} |
|
if ( input ( BUTTON_2 ) == LOW ) // if button still pressed |
{ |
cScreen = WAYPOINT_SCREEN; |
cSkip = YES; // skip out of anything in process |
cScreenChanged = YES; // repaint complete screen |
} |
|
if ( input ( BUTTON_3 ) == LOW ) // if button still pressed |
{ |
cScreen = BATTERY_SCREEN; |
cSkip = YES; // skip out of anything in process |
cScreenChanged = YES; // repaint complete screen |
} |
|
// SWITCH DEBOUNCE |
if ( input ( BUTTON_1 ) == LOW ) // if button still pressed |
{ |
if ( cButtonCount < 255 ) // hold at 255 |
{ |
cButtonCount++; // otherwise increment |
} |
} |
else // if button is unpressed |
{ |
if ( cButtonCount > 2 ) // filter out glitches |
{ |
//If button press is greater than 3.3 seconds, cold reset |
if ( cButtonCount == 255 ) |
{ |
reset_cpu(); |
} |
if ( ( cButtonCount > 57 ) && ( cButtonCount < 255 ) ) |
{ |
if ( cScreen != HIDDEN_RMC ) // if not in the middle of getting magnetic variation |
{ |
// cIllumination ^= ON; |
output_bit ( LCD_BACKLITE, cIllumination ^= ON ); |
} |
} |
// If button press is less than 0.5 second |
if ( cButtonCount <= 57 ) |
{ |
if ( cScreen != HIDDEN_RMC ) // if not in the middle of getting magnetic variation |
{ |
//if ( cScreen++ >= BATTERY_SCREEN ) // increment to next screen |
{ |
cScreen = POSITION_SCREEN; // wrap |
} |
cSkip = YES; // skip out of anything in process |
cScreenChanged = YES; // repaint complete screen |
} |
} |
} |
cButtonCount = 0; // restart |
} |
} |
|
#int_rda |
void SerialInterrupt ( void ) |
{ |
/* |
Reads incoming data from the USART and puts in in a rolling buffer |
( but in this application, it should never roll.) |
If the buffer is full, this routine just discards the received byte. |
Not checking the LRC byte at the end of the NMEA-0183 sentence. |
*/ |
char cChar; |
|
if ( rs232_errors & 0x04 ) // get framing error bit from Rx status reg |
{ |
cRxErrorFlag = ON; |
} |
cChar = getchar(); // get char from UART, clear any errors |
|
if ( cRxByteCnt == RX_BUFFER_SIZE ) // is recv fifo full ??? |
{ |
goto done; |
} |
switch ( cRxIsrState ) |
{ |
case 0: |
{ |
if ( cChar == DOLLAR ) // if start of NMEA0183 message |
{ |
cRxByteCnt = 0; // reset byte count |
cReceiveFlag = OFF; // default to off |
cRxMsgTypeReceived = NULL; // set hashed value to null |
cRxIsrState++; // next state |
} |
break; |
} |
case 1: // five type characters to obtain |
case 2: |
case 3: |
case 4: |
case 5: |
{ |
cRxMsgTypeReceived ^= cChar; // hash in msg type |
if ( cRxIsrState++ == 5 ) // if time to check message type |
{ |
if ( cRxMsgTypeReceived == cRxMsgTypeDesired ) // if good |
{ |
cReceiveFlag = YES; // enable receiving |
cRxBufferWritePtr = cRxBuffer; // reset to beginning of buffer |
} |
else // don't want this message |
{ |
cRxIsrState = 0; // reset to look for next msg |
} |
} |
break; |
} |
case 6: |
{ |
/* Case 6 skips the comma character following msg type */ |
cRxIsrState++; |
break; |
} |
default: // remainder of characters |
{ |
if ( cReceiveFlag == YES ) // if this message is wanted |
{ |
*cRxBufferWritePtr = cChar; // put char in fifo |
cRxBufferWritePtr++; // increment pointer |
if ( cRxBufferWritePtr == ( cRxBuffer + RX_BUFFER_SIZE ) ) // pointer past end ? |
{ |
cRxBufferWritePtr = cRxBuffer; // set pointer to start of fifo |
} |
cRxByteCnt++; // Increment byte count |
if ( cChar == CR ) |
{ |
cRxMsgReady = YES; // signal that message is ready |
cReceiveFlag = NO; // no more receive |
} |
} |
} |
} |
done:; |
} |
|
/*******************************************************************/ |
|
void main ( void ) |
{ |
char cX; |
|
iTimeOut = 65535; // default to very long to get by init |
/* INITIALIZE */ |
output_float ( RX_IN ); // ensure Rx input is HiZ |
output_float ( BUTTON_1 ); // ensure switch input is HiZ |
output_float ( BUTTON_2 ); // ensure switch input is HiZ |
output_float ( BUTTON_3 ); // ensure switch input is HiZ |
output_low ( LCD_BACKLITE ); // turn off backlighting |
port_b_pullups ( ON ); // enable pullups on switches |
|
// GET SAVED SETTINGS |
cContrast = read_eeprom ( EEPROM_CONTRAST ); // get stored value |
|
// PWM is for display contrast |
setup_ccp2 ( CCP_PWM ); // set for PWM mode |
//The cycle time will be (1/clock)*4*t2div*(period+1) |
// 1/8000000 * 4 * 1 * 128 = 51.2uS = 19.5KHz |
setup_timer_2 ( T2_DIV_BY_1, 255, 1 ); // set PWM period |
// duty cycle = value*(1/clock)*t2div |
// 10 * 1/8000000 * 1 = 1.2uS |
set_pwm2_duty ( cContrast ); // set contrast duty cycle |
|
// SETUP TIMER 0 |
// Need 8-bit Timer0 to roll over every 13mS, approximately. |
// Roll time = 256 * 1 / ( clock_freq / prescaler setting / 4 ) |
#if CRYSTAL_FREQ >= 15000000 |
setup_counters ( RTCC_INTERNAL, RTCC_DIV_256 ); // ~13mS timer wrap |
#elif CRYSTAL_FREQ >= 8000000 |
setup_counters ( RTCC_INTERNAL, RTCC_DIV_128 ); // ~13mS timer wrap |
#elif CRYSTAL_FREQ < 8000000 |
setup_counters ( RTCC_INTERNAL, RTCC_DIV_64 ); // ~13mS timer wrap |
#endif |
|
// Timer 1 roll time = 65536 * 1 / ( clock_freq / prescaler setting / 4 ) |
setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_8 ); // 16-bit timer |
|
setup_adc_ports ( RA0_RA1_RA3_ANALOG ); /* these three statements set up the ADC */ |
setup_adc ( ADC_CLOCK_INTERNAL ); |
cIllumination = OFF; |
|
LCD_Init(); // set up LCD for 4-wire bus, etc. |
|
/* INIT MESSAGE */ |
#if ( DISPLAY_COLS == 20 ) |
LCD_SetPosition ( LINE_1 + 0 ); |
printf ( LCD_PutChar, " Northern Light " ); // welcome screen |
LCD_SetPosition ( LINE_2 + 2 ); |
printf ( LCD_PutChar, "Monitor/Repeater" ); |
LCD_SetPosition ( LINE_3 + 3 ); |
printf ( LCD_PutChar, "v18 06/21/03" ); |
LCD_SetPosition ( LINE_4 + 5 ); |
printf ( LCD_PutChar, "c Jon Fick" ); |
#elif ( DISPLAY_COLS == 16 ) |
LCD_SetPosition ( LINE_1 + 0); |
printf ( LCD_PutChar, " Northern Light " ); // welcome screen |
LCD_SetPosition ( LINE_2 + 2 ); |
printf ( LCD_PutChar, "GPS Repeater" ); |
LCD_SetPosition ( LINE_3 + 1 ); |
printf ( LCD_PutChar, "v18 06/21/03" ); |
LCD_SetPosition ( LINE_4 + 3 ); |
printf ( LCD_PutChar, "c Jon Fick" ); |
#endif |
delay_ms ( 1000 ); |
|
/* INSTRUCTION MESSAGE */ |
LCD_PutCmd ( CLEAR_DISP ); |
LCD_SetPosition ( LINE_1 + 0 ); |
printf ( LCD_PutChar, "BUTTONS:" ); |
LCD_SetPosition ( LINE_2 + 0 ); |
printf ( LCD_PutChar, "<-- Lat/Lon" ); |
LCD_SetPosition ( LINE_3 + 0 ); |
printf ( LCD_PutChar, "<-- Waypoint" ); |
LCD_SetPosition ( LINE_4 + 0 ); |
printf ( LCD_PutChar, "<-- Battery" ); |
delay_ms ( 2000 ); |
|
/* SETUP MODE */ |
if ( input ( BUTTON_1 ) == LOW ) // if button is pressed |
{ |
LCD_PutCmd ( CLEAR_DISP ); |
LCD_SetPosition ( LINE_1 + 0 ); |
printf ( LCD_PutChar, "Set contrast:" ); |
LCD_SetPosition ( LINE_2 + 0 ); |
printf ( LCD_PutChar, "<-- More" ); |
LCD_SetPosition ( LINE_3 + 0 ); |
printf ( LCD_PutChar, "<-- DONE" ); |
LCD_SetPosition ( LINE_4 + 0 ); |
printf ( LCD_PutChar, "<-- Less" ); |
while ( input ( BUTTON_1 ) == LOW ); // wait for switch to be released after entering SETUP mode |
cContrast = 120; // start at full contrast |
cDone = NO; |
while ( cDone == NO ) |
{ |
set_pwm2_duty ( cContrast ); // update contrast |
if ( input ( BUTTON_1 ) == LOW ) |
{ |
if ( cContrast > 0 ) |
{ |
cContrast--; // more |
} |
} |
if ( input ( BUTTON_2 ) == LOW ) |
{ |
cDone = YES; // done |
} |
if ( input ( BUTTON_3 ) == LOW ) |
{ |
if ( cContrast < 255 ) |
{ |
cContrast++; // less |
} |
} |
delay_ms ( 30 ); // autorepeat |
} |
write_eeprom ( EEPROM_CONTRAST, cContrast ); // save CONTRAST to EEPROM |
|
LCD_PutCmd ( CLEAR_DISP ); |
LCD_SetPosition ( LINE_2 + 0 ); |
printf ( LCD_PutChar, "<- Press initial" ); |
LCD_SetPosition ( LINE_3 + 0 ); |
printf ( LCD_PutChar, " bootup screen" ); |
while ( input ( BUTTON_1 ) == LOW ); // wait until button not pressed |
cX = POSITION_SCREEN; |
while ( TRUE ) |
{ |
LCD_SetPosition ( LINE_4 + 3 ); |
switch ( cX ) |
{ |
case POSITION_SCREEN: |
{ |
printf ( LCD_PutChar, "POSITION " ); |
break; |
} |
case WAYPOINT_SCREEN: |
{ |
printf ( LCD_PutChar, "WAYPOINT " ); |
break; |
} |
case BATTERY_SCREEN: |
{ |
printf ( LCD_PutChar, "BATTERY " ); |
break; |
} |
} |
delay_ms ( 750 ); |
if ( input ( BUTTON_1 ) == LOW ) // if button is pressed |
{ |
write_eeprom ( EEPROM_INITIAL, cX ); // save screen number to EEPROM |
break; |
} |
if ( cX++ == BATTERY_SCREEN ) |
{ |
cX = POSITION_SCREEN; |
} |
} |
LCD_PutCmd ( CLEAR_DISP ); |
} |
|
/* This IF/ENDIF is a tool for getting the $GP... codes */ |
/* that are used in the switch/case in the main loop. */ |
#if ( GET_GPS_CODE == YES ) |
printf ( LCD_PutChar, "%u", 'G'^'P'^'R'^'M'^'B'); |
while ( TRUE ); |
#endif |
|
/* INTERRUPTS */ |
ext_int_edge ( H_TO_L ); // set falling edge ext interrupt |
enable_interrupts ( INT_TIMER1 ); // enable Timer1 interrupt |
enable_interrupts ( INT_RDA ); // enable serial interrupt |
enable_interrupts ( INT_RTCC ); // enable Timer0 interrupt |
enable_interrupts ( INT_AD ); // enable ADC interrupt |
enable_interrupts ( GLOBAL ); // enable all interrupts |
|
/* VARIABLES */ |
iVar = NULL; // default, no variation yet |
cVarDir = SPACE; // default, no variation yet |
cRmcTimer1 = 255; // initialize to 52 seconds |
cRmcTimer2 = RMC_TIME; // trigger forced RMC after 10 minutes |
cScreen = HIDDEN_RMC; // default screen, get magnetic variation first |
cSavedScreen = read_eeprom ( EEPROM_INITIAL ); // restore initial screen |
iLastRange = 65535; // make max by default |
strcpy ( cToFrom, " " ); // blank by default |
cScreenChanged = YES; |
cIndicator = 0; |
cButtonCount = 0; |
cButtonPressed = NO; |
cRxErrorFlag = OFF; |
|
/* MAIN LOOP */ |
while ( TRUE ) |
{ |
cTimeOut = 188; // 231 * 0.013mS = 3 seconds |
switch ( cScreen ) |
{ |
case HIDDEN_RMC: |
{ |
InitRxBuffer( GPRMC_CODE ); // set code and turn on serial interrupt |
while ( ( cRxMsgReady == NO ) && ( cTimeOut != 0 ) ); |
disable_interrupts ( INT_RDA ); // ignore rest of messages |
if ( cTimeOut != 0 ) // if not timed out |
{ |
GetUtcAndMagVar(); // get and store the magnetic variation |
} |
cScreen = cSavedScreen; // revert to previous screen |
break; |
} |
case POSITION_SCREEN: |
{ |
if ( cScreenChanged == YES ) |
{ |
disable_interrupts ( INT_RDA ); |
cScreenChanged = NO; |
cSkip = NO; |
LCD_PutCmd ( CLEAR_DISP ); |
DisplayTemplateLatLon(); |
enable_interrupts ( INT_RDA ); |
} |
InitRxBuffer( GPRMC_CODE ); // set code and turn on serial interrupt |
while ( ( cRxMsgReady == NO ) && ( cTimeOut != 0 ) && ( cScreenChanged != YES ) ); |
disable_interrupts ( INT_RDA ); // ignore rest of messages |
if ( cScreenChanged == NO ) |
{ |
if ( cTimeOut != 0 ) |
{ |
DisplayLatLon(); |
} |
else |
{ |
DisplayMessage ( NODATA_MSG ); |
} |
} |
cRxErrorFlag = OFF; |
break; |
} |
case WAYPOINT_SCREEN: |
{ |
if ( cScreenChanged == YES ) |
{ |
disable_interrupts ( INT_RDA ); |
cScreenChanged = NO; |
cSkip = NO; |
LCD_PutCmd ( CLEAR_DISP ); |
DisplayTemplateWaypoint(); |
enable_interrupts ( INT_RDA ); |
} |
cSkip = NO; |
InitRxBuffer( GPRMB_CODE ); // set code and turn on serial interrupt |
while ( ( cRxMsgReady == NO ) && ( cTimeOut != 0 ) && ( cScreenChanged != YES ) ); |
disable_interrupts ( INT_RDA ); // ignore rest of messages |
if ( cScreenChanged == NO ) |
{ |
if ( cTimeOut != 0 ) |
{ |
DisplayWaypoint(); |
} |
else |
{ |
DisplayMessage ( NODATA_MSG ); |
} |
} |
break; |
} |
case BATTERY_SCREEN: |
{ |
if ( cScreenChanged == YES ) |
{ |
disable_interrupts ( INT_RDA ); |
cScreenChanged = NO; |
cSkip = NO; |
LCD_PutCmd ( CLEAR_DISP ); |
DisplayTemplateAnalog(); |
} |
DisplayAnalog(); |
break; |
} |
} |
|
// Preset timeout counter each loop; RTCC interrupt decrements, resets if zero is reached |
iTimeOut = 2000; // ~ 30 seconds |
|
/* Flashing activity indicator in lower right of screen. */ |
cIndicator ^= 1; |
#if ( DISPLAY_COLS == 20 ) |
LCD_SetPosition ( LINE_4 + 19 ); |
#elif ( DISPLAY_COLS == 16 ) |
LCD_SetPosition ( LINE_4 + 15 ); |
#endif |
if ( cIndicator == 1 ) |
{ |
printf ( LCD_PutChar, "%c", ACTIVITY_SYMBOL ); |
} |
else |
{ |
printf ( LCD_PutChar, " " ); |
} |
} |
} |
|
#separate void DisplayTemplateLatLon ( void ) |
{ |
LCD_SetPosition ( LINE_1 ); |
printf ( LCD_PutChar, "LAT" ); |
LCD_SetPosition ( LINE_2 ); |
printf ( LCD_PutChar, "LON" ); |
LCD_SetPosition ( LINE_3 ); |
#if ( DISPLAY_COLS == 20 ) |
printf ( LCD_PutChar, "SPEED" ); |
LCD_SetPosition ( LINE_4 ); |
printf ( LCD_PutChar, "HEADING" ); |
#elif ( DISPLAY_COLS == 16 ) |
printf ( LCD_PutChar, "SPD" ); |
LCD_SetPosition ( LINE_4 ); |
printf ( LCD_PutChar, "HDG" ); |
#endif |
} |
|
#separate void DisplayTemplateWaypoint ( void ) |
{ |
LCD_SetPosition ( LINE_1 ); |
#if ( DISPLAY_COLS == 20 ) |
printf ( LCD_PutChar, "WAYPOINT" ); |
#elif ( DISPLAY_COLS == 16 ) |
printf ( LCD_PutChar, "WAYPT" ); |
#endif |
LCD_SetPosition ( LINE_2 ); |
printf ( LCD_PutChar, "STEER" ); |
LCD_SetPosition ( LINE_3 ); |
printf ( LCD_PutChar, "DIST" ); |
LCD_SetPosition ( LINE_4 ); |
printf ( LCD_PutChar, "BEARING" ); |
} |
|
#separate void DisplayTemplateAnalog ( void ) |
{ |
#if ( DISPLAY_COLS == 20 ) |
LCD_SetPosition ( LINE_1 + 3 ); |
#elif ( DISPLAY_COLS == 16 ) |
LCD_SetPosition ( LINE_1 + 1 ); |
#endif |
printf ( LCD_PutChar, "BATTERY STATUS" ); |
#if ( DISPLAY_COLS == 20 ) |
LCD_SetPosition ( LINE_2 ); |
printf ( LCD_PutChar, "Primary" ); |
LCD_SetPosition ( LINE_3 ); |
printf ( LCD_PutChar, "Secondary" ); |
LCD_SetPosition ( LINE_4 ); |
printf ( LCD_PutChar, "Refrigerator" ); |
#elif ( DISPLAY_COLS == 16 ) |
LCD_SetPosition ( LINE_2 ); |
printf ( LCD_PutChar, "Main#1 " ); |
LCD_SetPosition ( LINE_3 ); |
printf ( LCD_PutChar, "Main#2 " ); |
LCD_SetPosition ( LINE_4 ); |
printf ( LCD_PutChar, "Refrig " ); |
#endif |
} |
|
#separate void DisplayLatLon ( void ) |
{ |
SkipField ( 1 ); // skip UTC |
GetField(); // A = OK, V = warning |
if ( ( cC [ 0 ] == 'A' ) && ( !cSkip ) ) |
{ |
GetField(); // LAT |
if ( !cSkip ) |
{ |
DisplayLatitude ( LINE_1 ); |
} |
GetField(); // LON |
if ( !cSkip ) |
{ |
DisplayLongitude ( LINE_2 ); |
} |
GetField(); // SPEED |
if ( !cSkip ) |
{ |
DisplaySpeed ( LINE_3 ); |
} |
GetField(); // HEADING |
if ( !cSkip ) |
{ |
DisplayHeading ( LINE_4 ); |
} |
} |
else |
{ |
DisplayMessage( WARNING_MSG ); |
} |
} |
|
#separate void DisplayWaypoint ( void ) |
{ |
char cX; |
|
GetField(); // A = OK, V = warning |
if ( ( cC [ 0 ] == 'A' ) && ( !cSkip ) ) |
{ |
cX = GetField(); // XTE |
if ( !cSkip ) |
{ |
DisplaySteer ( LINE_2, cX ); |
} |
SkipField ( 1 ); // skip origin WP ID |
GetField(); // DEST WP ID |
if ( !cSkip ) |
{ |
DisplayWaypointName ( LINE_1, cX ); |
} |
SkipField ( 4 ); // skip LAT, NS, LON, EW |
cX = GetField(); // RANGE |
if ( !cSkip ) |
{ |
DisplayDistance ( LINE_3, cX ); |
} |
cX = GetField(); // BEARING |
if ( !cSkip ) |
{ |
DisplayBearing ( LINE_4, cX ); |
} |
SkipField ( 1 ); // skip SPEED TO DEST |
GetField(); // ARRIVAL FLAG |
if ( !cSkip ) |
{ |
DisplayArrival ( LINE_1 ); // overwrite RANGE if arrived |
} |
} |
else |
{ |
DisplayMessage( WARNING_MSG ); |
} |
} |
|
#separate void DisplayAnalog ( void ) |
{ |
long iX; |
char cCnt; |
|
set_adc_channel ( 0 ); // set channel |
delay_us ( 100 ); // wait aquisition time |
cAdcDone = NO; |
if ( !cSkip ) |
{ |
#if ( DISPLAY_COLS == 20 ) |
LCD_SetPosition ( LINE_2 + 13 ); |
#elif ( DISPLAY_COLS == 16 ) |
LCD_SetPosition ( LINE_2 + 8 ); |
#endif |
DisplayScaledVoltage ( read_adc(), MAX_VOLTS ); |
printf ( LCD_PutChar, " V " ); |
} |
set_adc_channel ( 1 ); |
delay_us ( 100 ); |
cAdcDone = NO; |
if ( !cSkip ) |
{ |
#if ( DISPLAY_COLS == 20 ) |
LCD_SetPosition ( LINE_3 + 13 ); |
#elif ( DISPLAY_COLS == 16 ) |
LCD_SetPosition ( LINE_3 + 8 ); |
#endif |
DisplayScaledVoltage ( read_adc(), MAX_VOLTS ); |
printf ( LCD_PutChar, " V " ); |
} |
set_adc_channel ( 3 ); |
delay_us ( 100 ); |
cAdcDone = NO; |
if ( !cSkip ) |
{ |
#if ( DISPLAY_COLS == 20 ) |
LCD_SetPosition ( LINE_4 + 13 ); |
#elif ( DISPLAY_COLS == 16 ) |
LCD_SetPosition ( LINE_4 + 8 ); |
#endif |
DisplayScaledVoltage ( read_adc(), MAX_VOLTS ); |
printf ( LCD_PutChar, " V " ); |
} |
Delay5mS ( 100 ); // slow loop down a bit |
} |
|
#separate void GetUtcAndMagVar ( void ) |
{ |
/* |
This is a non-display version of the RMC sentence |
to get the A/V warning, the magnetic variation, and the |
magnetic direction. |
*/ |
|
GetField(); // get UTC |
GetField(); // A = OK, V = warning |
if ( cC [ 0 ] == 'A' ) |
{ |
SkipField ( 7 ); // skip fields |
GetField(); // MAGNETIC VARIATION |
iVar = FieldFiveToLong(); // save to global variable, used in other sentences |
GetField(); // EW |
cVarDir = cC [ 0 ]; // save direction |
} |
else |
{ |
iVar = NULL; // invalid |
cVarDir = SPACE; |
} |
} |
|
/******************************************************************/ |
|
#separate void DisplayScaledVoltage ( long iV, char cScale ) |
{ |
float fX; |
|
/* |
0 to 5V input at pin 2 results in 0 - 1023. This routine |
scales it to something else. |
*/ |
while ( cAdcDone == NO ); // wait for completion by ADC interrupt |
if ( iV == 1023 ) |
{ |
printf ( LCD_PutChar, "O/L" ); /* print it to the screen */ |
} |
else |
{ |
fX = ( ( float ) iV ) / 1023 * ( float ) cScale; // scale to proper range, 1023 leaves room for out-of-range |
printf ( LCD_PutChar, "%2.1f", fX ); /* print it to the screen */ |
} |
} |
|
#separate void DisplayArrival ( char cLine ) |
{ |
#if ( DISPLAY_COLS == 20 ) |
LCD_SetPosition ( cLine + 11 ); |
#elif ( DISPLAY_COLS == 16 ) |
LCD_SetPosition ( cLine + 9 ); |
#endif |
if ( cC [ 0 ] == 'A' ) |
{ |
printf ( LCD_PutChar, "Arrived" ); |
} |
else |
{ |
printf ( LCD_PutChar, " " ); |
} |
} |
|
#separate void DisplayWaypointName ( char cLine, char cX ) |
{ |
/* Displays waypoint name, pads field with blanks */ |
char cChar, cI; |
|
LCD_SetPosition ( cLine ); |
if ( cX != 0 ) |
{ |
printf ( LCD_PutChar, "\"" ); |
for ( cI = 0; cI < 6; cI++ ) |
{ |
cChar = cC [ cI ]; |
if ( cChar == EOF ) |
{ |
break; |
} |
printf ( LCD_PutChar, "%c", cChar ); |
} |
printf ( LCD_PutChar, "\"" ); |
// Blank remainder of field |
cChar = SPACE; |
for ( ; cI < 6; cI++ ) |
{ |
printf ( LCD_PutChar, "%c", cChar ); |
} |
} |
else |
{ |
printf ( LCD_PutChar, "- none -" ); |
} |
} |
|
#separate void DisplaySteer ( char cLine, char cX ) |
{ |
/* |
Displays A.BC literals, appends 'L' or 'R'. |
If less than 1.0, displays feet rather than nm. |
Doesn't display distance if on track. |
*/ |
long iX; |
char cCnt; |
|
if ( cX != 0 ) |
{ |
if ( ( cC [ 0 ] != '0' ) || ( cC [ 2 ] != '0' ) || ( cC [ 3 ] != '0' ) ) // if not 0.00 |
{ |
LCD_SetPosition ( cLine + 14 ); |
#if ( DISPLAY_COLS == 20 ) |
printf ( LCD_PutChar, " " ); // blank possible characters |
LCD_SetPosition ( cLine + 11 ); |
#elif ( DISPLAY_COLS == 16 ) |
printf ( LCD_PutChar, " " ); // blank possible characters |
LCD_SetPosition ( cLine + 8); |
#endif |
if ( cC [ 0 ] == '0' ) // if less than 1.0 nm, display as feet |
{ |
iX = ( 528 * ( long ) ( cC [ 2 ] - 0x30 ) ) + ( 52 * ( long ) ( cC [ 3 ] - 0x30 ) ); |
printf ( LCD_PutChar, "%luft ", iX ); |
} |
else // if 1.0 nm or greater, display as nautical miles |
{ |
printf ( LCD_PutChar, "%c%c%c%cmi ", cC [ 0 ], cC [ 1 ], cC [ 2 ] , cC [ 3 ] ); |
} |
GetField(); // L or R |
LCD_SetPosition ( cLine + 6 ); |
if ( cC [ 0 ] == 'L' ) |
{ |
#if ( DISPLAY_COLS == 20 ) |
printf ( LCD_PutChar, "PORT " ); |
#elif ( DISPLAY_COLS == 16 ) |
printf ( LCD_PutChar, "L" ); |
#endif |
} |
else |
{ |
#if ( DISPLAY_COLS == 20 ) |
printf ( LCD_PutChar, "STBD " ); |
#elif ( DISPLAY_COLS == 16 ) |
printf ( LCD_PutChar, "R" ); |
#endif |
} |
} |
else // if 0.00 |
{ |
#if ( DISPLAY_COLS == 20 ) |
LCD_SetPosition ( cLine + 11 ); |
printf ( LCD_PutChar, "On track " ); |
#elif ( DISPLAY_COLS == 16 ) |
LCD_SetPosition ( cLine + 6 ); |
printf ( LCD_PutChar, " On track" ); |
#endif |
GetField(); // dummy L or R |
} |
} |
else |
{ |
LCD_SetPosition ( cLine + 6 ); |
printf ( LCD_PutChar, " " ); |
} |
} |
|
#separate void DisplayDistance ( char cLine, char cX ) |
{ |
/* Format: ABC.D nautical miles */ |
char cChar, cI; |
long iThisRange; |
|
if ( cX != 0 ) // if waypoint data to display |
{ |
#if ( DISPLAY_COLS == 20 ) |
LCD_SetPosition ( cLine + 11 ); |
#elif ( DISPLAY_COLS == 16 ) |
LCD_SetPosition ( cLine + 8 ); |
#endif |
cI = 0; |
for ( cI = 0; cI < 2; cI++ ) // find first non-zero |
{ |
cChar = cC [ cI ]; |
if ( cChar != '0' ) |
{ |
break; |
} |
} |
for ( ; cI < 5; cI++ ) // display from there on |
{ |
printf ( LCD_PutChar, "%c", cC [ cI ] ); |
} |
printf ( LCD_PutChar, "nm " ); // pad with blanks |
|
/* |
The least significant character from the GPS is 0.1 nm. |
Multiply whole thing by 10 and make it type long. |
Discern if increasing (FROM) or decreasing (TO). |
*/ |
iThisRange = 1000 * ( long ) ( cC [ 0 ] - 0x30 ); |
iThisRange += 100 * ( long ) ( cC [ 1 ] - 0x30 ); |
iThisRange += 10 * ( long ) ( cC [ 2 ] - 0x30 ); |
iThisRange += ( long ) ( cC [ 4 ] - 0x30 ); |
if ( iThisRange < iLastRange ) |
{ |
#if ( DISPLAY_COLS == 20 ) |
strcpy ( cToFrom, "TO " ); |
#elif ( DISPLAY_COLS == 16 ) |
strcpy ( cToFrom, "TO" ); |
#endif |
} |
if ( iThisRange > iLastRange ) |
{ |
#if ( DISPLAY_COLS == 20 ) |
strcpy ( cToFrom, "FROM" ); |
#elif ( DISPLAY_COLS == 16 ) |
strcpy ( cToFrom, "FM" ); |
#endif |
} |
iLastRange = iThisRange; // save this range to compare next time |
LCD_SetPosition ( cLine + 5 ); |
printf ( LCD_PutChar, cToFrom ); |
} |
else |
{ |
LCD_SetPosition ( cLine + 5 ); |
#if ( DISPLAY_COLS == 20 ) |
printf ( LCD_PutChar, " " ); |
#elif ( DISPLAY_COLS == 16 ) |
printf ( LCD_PutChar, " " ); |
#endif |
} |
} |
|
#separate void DisplayBearing ( char cLine, char cX ) |
{ |
/* |
Compass variation comes from RMC sentence. If RMC has not run yet |
then "T" is displayed after bearing. |
*/ |
long iHdg; |
char cTrueIndicator; |
|
if ( cX != 0 ) // if waypoint data to display |
{ |
#if ( DISPLAY_COLS == 20 ) |
LCD_SetPosition ( cLine + 11 ); |
#elif ( DISPLAY_COLS == 16 ) |
LCD_SetPosition ( cLine + 8 ); |
#endif |
iHdg = FieldFiveToLong(); |
iHdg = TrueToMag ( iHdg ); // factor variation into heading |
if ( ( iVar == NULL ) || ( cVarDir == SPACE ) ) |
{ |
cTrueIndicator = 'T'; |
} |
else |
{ |
cTrueIndicator = ' '; |
} |
printf ( LCD_PutChar, "%lu%c%c ", iHdg, DEGREE, cTrueIndicator ); // pad with blanks |
} |
else |
{ |
#if ( DISPLAY_COLS == 20 ) |
LCD_SetPosition ( cLine + 11 ); |
printf ( LCD_PutChar, " " ); |
#elif ( DISPLAY_COLS == 16 ) |
LCD_SetPosition ( cLine + 8 ); |
printf ( LCD_PutChar, " " ); |
#endif |
} |
} |
|
#separate void DisplayLatitude ( char cLine ) |
{ |
/* Displays latitude ABCD.EF as AB CD.EF, appends 'N' or 'S' */ |
#if ( DISPLAY_COLS == 20 ) |
LCD_SetPosition ( cLine + 8 ); |
#elif ( DISPLAY_COLS == 16 ) |
LCD_SetPosition ( cLine + 5 ); |
#endif |
if ( cC [ 0 ] == '0' ) |
{ |
cC [ 0 ] = SPACE; |
} |
printf ( LCD_PutChar, "%c%c%c", cC [ 0 ], cC [ 1 ], DEGREE ); |
printf ( LCD_PutChar, "%c%c%c%c%c%c", cC [ 2 ], cC [ 3 ], cC [ 4 ], cC [ 5 ], cC [ 6 ], cC [ 7 ] ); |
GetField(); // NS |
printf ( LCD_PutChar, " %c", cC [ 0 ] ); |
} |
|
#separate void DisplayLongitude ( char cLine ) |
{ |
/* Displays longitude ABCDE.FG as ABC DE.FG, appends 'E' or 'W' */ |
#if ( DISPLAY_COLS == 20 ) |
LCD_SetPosition ( cLine + 7 ); |
#elif ( DISPLAY_COLS == 16 ) |
LCD_SetPosition ( cLine + 4 ); |
#endif |
if ( cC [ 0 ] == '0' ) |
{ |
cC [ 0 ] = SPACE; |
} |
if ( cC [ 1 ] == '0' ) |
{ |
cC [ 1 ] = SPACE; |
} |
printf ( LCD_PutChar, "%c%c%c%c", cC [ 0 ], cC [ 1 ], cC [ 2 ], DEGREE ); |
printf ( LCD_PutChar, "%c%c%c%c%c%c", cC [ 3 ], cC [ 4 ], cC [ 5 ], cC [ 6 ], cC [ 7 ], cC [ 8 ] ); |
GetField(); // EW |
printf ( LCD_PutChar, " %c", cC [ 0 ] ); |
} |
|
#separate void DisplaySpeed ( char cLine ) |
{ |
float fX; |
|
// Format ABC.D |
#if ( DISPLAY_COLS == 20 ) |
LCD_SetPosition ( cLine + 8 ); |
#elif ( DISPLAY_COLS == 16 ) |
LCD_SetPosition ( cLine + 5 ); |
#endif |
fX = 100 * ( cC [ 0 ] - 0x30 ); |
fX += 10 * ( cC [ 1 ] - 0x30 ); |
fX += 1 * ( cC [ 2 ] - 0x30 ); |
fX += 0.1 * ( cC [ 4 ] - 0x30 ); |
#if SPEED_UNITS == 2 |
fX *= 1.852; // convert knots to km/h |
#endif |
#if SPEED_UNITS == 3 |
fX *= 1.151; // convert knots to mi/h |
#endif |
printf ( LCD_PutChar, "%3.1f ", fX ); // print it to the screen |
#if SPEED_UNITS == 1 |
printf ( LCD_PutChar, "kts " ); // print it to the screen |
#endif |
#if SPEED_UNITS == 2 |
printf ( LCD_PutChar, "kph " ); // print it to the screen |
#endif |
#if SPEED_UNITS == 3 |
printf ( LCD_PutChar, "mph " ); // print it to the screen |
#endif |
} |
|
#separate void DisplayHeading ( char cLine ) |
{ |
long iHdg; |
|
#if ( DISPLAY_COLS == 20 ) |
LCD_SetPosition ( cLine + 8 ); |
#elif ( DISPLAY_COLS == 16 ) |
LCD_SetPosition ( cLine + 5 ); |
#endif |
iHdg = FieldFiveToLong(); |
SkipField ( 1 ); // skip fix date |
GetField(); // MAGNETIC VARIATION |
iVar = FieldFiveToLong(); // save to global variable, used in other sentences |
GetField(); // EW |
cVarDir = cC [ 0 ]; // save direction |
iHdg = TrueToMag ( iHdg ); // factor variation into heading |
printf ( LCD_PutChar, "%lu%c ", iHdg, DEGREE ); // pad with blanks |
} |
|
#separate long FieldFiveToLong ( void ) |
{ |
/* Converts ABC.D to long, rounds decimal up or down */ |
long iX; |
|
iX = 100 * ( long ) ( cC [ 0 ] - 0x30 ); |
iX += 10 * ( long ) ( cC [ 1 ] - 0x30 ); |
iX += ( long ) ( cC [ 2 ] - 0x30 ); |
if ( ( cC [ 3 ] == PERIOD ) && ( cC [ 4 ] >= '5' ) ) |
{ |
iX++; // round up |
} |
return ( iX ); |
} |
|
#separate long TrueToMag ( long iH ) |
{ |
/* Magnetic variation information comes from the RMC sentence */ |
|
if ( cVarDir == 'W' ) |
{ |
iH += iVar; |
} |
else |
{ |
if ( iH >= iVar ) |
{ |
iH -= iVar; // OK as-is |
} |
else |
{ |
iH = iH + 360 - iVar; // correct for below zero |
} |
} |
if ( iH >= 360 ) |
{ |
iH -= 360; |
} |
return ( iH ); |
} |
|
#separate void DisplayMessage ( char cMsgNum ) |
{ |
LCD_PutCmd ( CLEAR_DISP ); |
LCD_SetPosition ( LINE_2 ); |
switch ( cMsgNum ) |
{ |
case WARNING_MSG: |
{ |
#if ( DISPLAY_COLS == 20 ) |
printf ( LCD_PutChar, " GPS warning " ); |
#elif ( DISPLAY_COLS == 16 ) |
printf ( LCD_PutChar, " GPS warning" ); |
#endif |
break; |
} |
case NODATA_MSG: |
{ |
if ( cRxErrorFlag == OFF ) // is it a framing error problem ? |
{ |
#if ( DISPLAY_COLS == 20 ) |
printf ( LCD_PutChar, " No data from GPS" ); |
#elif ( DISPLAY_COLS == 16 ) |
printf ( LCD_PutChar, "No data from GPS" ); |
#endif |
} |
else |
{ |
#if ( DISPLAY_COLS == 20 ) |
printf ( LCD_PutChar, " Baud error" ); |
#elif ( DISPLAY_COLS == 16 ) |
printf ( LCD_PutChar, " Baud error" ); |
#endif |
cRxErrorFlag = OFF; |
} |
break; |
} |
} |
Delay5mS ( 255 ); // delay 1.25 seconds |
iVar = NULL; |
cVarDir = SPACE; // signal "no magnetic variation" yet |
cScreenChanged = YES; |
} |
|
#separate void Delay5mS ( char cCnt ) |
{ |
char cX; |
|
/* This variable-count 5mS delay is interruptable by a button press */ |
for ( cX = 0; cX < cCnt; cX++ ) |
{ |
if ( cScreenChanged == YES ) |
{ |
break; |
} |
delay_ms ( 5 ); |
} |
} |
|
#separate char GetField ( void ) |
{ |
char cX, cIndex; |
|
cX = NULL; |
cIndex = 0; |
while ( !cSkip ) |
{ |
cX = GetRxChar(); |
if ( ( cX == COMMA ) || ( cX == CR ) ) |
{ |
break; |
} |
cC [ cIndex++ ] = cX; |
} |
cC [ cIndex ] = EOF; |
return ( cIndex ); // return number of characters in field |
} |
|
#separate void SkipField ( char cCnt ) |
{ |
char cX; |
|
for ( cX = 0; cX < cCnt; cX++ ) |
{ |
while ( GetRxChar() != COMMA ); |
} |
} |
|
/* RS232 FUNCTIONS ================================================== */ |
|
#separate void InitRxBuffer ( char cCode ) |
{ |
disable_interrupts ( INT_RDA ); |
cRxBufferWritePtr = cRxBuffer; // point to beginning of buffer |
cRxBufferReadPtr = cRxBuffer; |
cRxByteCnt = 0; |
cRxIsrState = 0; |
cRxMsgReady = NO; |
cRxMsgTypeDesired = cCode; |
enable_interrupts ( INT_RDA ); |
} |
|
#separate char GetRxChar ( void ) |
{ |
// Get the next available byte in the recv fifo. |
// Call this function ONLY if the recv fifo contains data. |
char cValue; |
|
cValue = 0; |
if ( cRxByteCnt > 0 ) // For safety, check if there is any data |
{ |
cValue = *cRxBufferReadPtr++; // Read byte from fifo |
if ( cRxBufferReadPtr == ( cRxBuffer + RX_BUFFER_SIZE ) ) // Did tail ptr wrap ? |
{ |
cRxBufferReadPtr = cRxBuffer; // If so, reset it to start of buffer |
} |
cRxByteCnt--; // Decrement byte count |
} |
return ( cValue ); |
} |
|
/* LCD FUNCTIONS ================================= */ |
|
#separate 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 & scroll left */ |
} |
|
#separate 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(); |
} |
|
#separate void LCD_PutChar ( unsigned int cX ) |
{ |
/* this subroutine works specifically for 4-bit Port A */ |
if ( !cSkip ) |
{ |
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 ); |
} |
} |
|
#separate 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(); |
} |
|
#separate void LCD_PulseEnable ( void ) |
{ |
output_high ( LCD_EN ); |
delay_us ( 3 ); // was 10 |
output_low ( LCD_EN ); |
delay_ms ( 3 ); // was 5 |
} |
|
#separate 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 ); |
} |
|