/* MegaView VFD Display Program for MS-II */ /* v1.0 - initial operational version v1.1 - fixed lockup problem when incr/ decr inputs */ #include #include #include #include "defs.h" #include "Gp32.h" #pragma DATA_SEG _DATA_ZEROPAGE // To use Celsius instead of Farenheit, define below as 1 // and change the DispVarUpperStrng to CLT(C) and MAT(C) #define DISPLAY 0 #define CONTROL 1 #define NO_DISP_BYTES_FROM_ECU 82 #define NO_CTRL_BYTES_FROM_ECU 1306 #define NUM_CTL_VARIABLES 15 #define CHR 0 #define UCH 1 #define SHT 2 #define USH 3 #define ULG 4 #define FLT 5 #define MAX_COLS 20 #define MAX_VFD_STRLEN strlen(DispVarUpperStrng) /*============================ PORT VARIABLES ================================*/ /* The Address of all Ports Data Registers */ volatile U8* PortDataReg[] = { pPTA, pPTB, pPTC, pPTD, pPTE }; /* The Address of all Ports Data Registers */ volatile U8* PortDirecReg[] = { pDDRA, pDDRB, pDDRC, pDDRD, pDDRE }; /****************************************************************************** * Macro : PortRead * Description : Reads a data bit from a port. * * Input Parameters: U8 PortId * port identifier : PORT_A,PORT_B,PORT_C,PORT_D * PORT_E,PORT_F,PORT_G,PORT_H * U8 Bit * The Bit of the port to read from * * Return Value : U8 Value * The value of the port bit * ******************************************************************************/ #define PortRead(PortId, Bit) (((*PortDataReg[PortId]) & (0x1 << Bit)) >> Bit) /****************************************************************************** * Macro : PortSetDir * Description : Configures all the Port's Direction pins as input or output pins. * * Input Parameters : * 1. U8 PortId Port Identifier: * PORT_A,PORT_B,PORT_C,PORT_D * PORT_E,PORT_F,POR_G,PORT_H * 2. U8 IoMode: * The mode (INPUT/OUTPUT) of the port * * Return Value : None * * Example : Port a configure as an input: * PortSetDir(PORT_A,INPUT); * Port a configure as an output: * PortSetDir(PORT_A,OUTPUT_PORT); * ******************************************************************************/ #define PortSetDir(PortId,IoMode) (*PortDirecReg[PortId]) = IoMode /****************************************************************************** * Macro : PortWrite * Description : Write a data bit to a port. * * Input Parameters: 1. U8 PortId Port Identifier: * PORT_A,PORT_B,PORT_C,PORT_D * PORT_E,PORT_F,PORT_G,PORT_H * 2. U8 Bit * The bit # of the port to write to * ******************************************************************************/ #define PortSet(PortId, Bit) (*PortDataReg[PortId]) |= (0x1 << Bit) #define PortClr(PortId, Bit) (*PortDataReg[PortId]) &= ~(0x1 << Bit) U8 select,freeze,mode,modeChange; U8 ibyte,no_xbytes,xmtbuf[10],rcvbuf[NO_DISP_BYTES_FROM_ECU + 2]; U16 irbyte,no_rbytes; U8 controlRcv,curr_var_no; U8 irpm,ikpa,VFDDisp_flg; const U8 *DispVarUpperStrng; // display variables U8 alarm_alt; short colix; union all_types { char chr; U8 uch; short sht; float flt; } control_var_val; U8 ctl_var_ecu_val, ctl_var_ecu_val2; U8 debounce,TmpUnits,get_config; short changed_ctl_var; U8 incr_count,decr_count; U8 dim,rcv_timeout,sem,CnvtSw; #pragma DATA_SEG DEFAULT #include "table.h" #include "asc_table.h" const U8 FDispVarUpperStrng[] = { " SECS ENGINE WRMENRCH ACCENRCH RPM PW1(MS) ADV(DG) COIL(MS) IACPOS\ BARO(KPA) MAP(KPA) CLT(F) MAT(F) TPS(V) BAT(V) AFR AFRTGT\ EGOCOR(%) AIRCOR(%)\ BARCOR(%) VECOR(%) WRMCOR(%) ACCOR(MS) DECEL(%) GAMMA(%) CLDADV(DG)" }; const U8 CDispVarUpperStrng[] = { " SECS ENGINE WRMENRCH ACCENRCH RPM PW1(MS) ADV(DG) COIL(MS) IACPOS\ BARO(KPA) MAP(KPA) CLT(C) MAT(C) TPS(V) BAT(V) AFR AFRTGT\ EGOCOR(%) AIRCOR(%)\ BARCOR(%) VECOR(%) WRMCOR(%) ACCOR(MS) DECEL(%) GAMMA(%) CLDADV(DG)" }; const U8 DispVarLowerStrng[] = { " \ \ \ " }; const U8 SelectStrng[MAX_COLS + 1] = {" Selected: "}; const U8 BlnkStrng[MAX_COLS + 1] = {" "}; const U8 CtlVarStrng[NUM_CTL_VARIABLES][MAX_COLS + 2] = { "CRNK ENRCH_L=%4.1f ms", "CRNK ENRCH_H=%4.1f ms", " AFT WRM PCT=%3u ", " AFT WRM EVTS=%3u ", " IACSTART=%3u ", " PRIME PLSE=%4.1f ms ", " REQFUEL=%4.1f ms ", " DIVIDER=%3u ", " ALTERNATE=%3u ", " INJOPEN=%4.1f ms ", " BATTFAC=%4.1f ms ", " INJPWMT=%4.1f ms ", " INJPWMPD=%5.3f ms ", " INJPWDTY=%3u ", " ADV OFFSET=%4.1f deg" }; const U16 ctl_var_offset[NUM_CTL_VARIABLES] = { 1116, 1117, 1118, 1119, 1113, 1158, 1144, 1146, 1147, 1148, 1152, 1149, 1150, 1151, 328 }; const U8 ctl_var_type[NUM_CTL_VARIABLES] = { FLT,FLT,UCH,UCH, UCH,FLT,FLT,UCH, UCH,FLT,FLT,FLT, FLT,UCH,FLT }; const short diva[5] = {1,10,100,1000,10000}; U8 VFDLower[sizeof(DispVarLowerStrng)]; // Prototypes void SystemInit(void); void SciInit(void); interrupt void SciTxIntHand(void); interrupt void SciRxIntHand(void); void PortAInit(void); void PortBInit(void); void PortCInit(void); void PortDInit(void); void KbiInit(void); interrupt void KbiHand(void); void ModeIsr(void); void ModeChange(void); void SelectIsr(void); void IncrIsr(void); void DecrIsr(void); interrupt void GetDispIsr(void); void VFDInit(void); void VFDDisplay(void); void VFDConvert(void); void itoa(short value, U8 *bufi, U8 width, U8 prec); void VFDsprintf(U8 *bufo, U8 type, U8 neg, U8 width, U8 *bufi, U8 alarm); void VFDSend(char line, char col, char value); void VFDData(char value); void main(void) { U8 ix,jx,kx; // Configure system and set up clock SystemInit(); // Set up rs232 SciInit(); // Initialize variables modeChange = 0; select = 0; freeze = 0; colix = 0; DispVarUpperStrng = FDispVarUpperStrng; strcpy(VFDLower, DispVarLowerStrng); VFDDisp_flg = 0; debounce = 0; alarm_alt = 0; rcv_timeout = 0; sem = 0; // Set up VFD control line I/O PortBInit(); PortCInit(); PortDInit(); // Delay while power stabilizes, allow MS and VFD to come up for(ix=0;ix<5;ix++) { for(jx=0;jx<200;jx++) { for(kx=0;kx<200;kx++) { asm nop; } } } // Enable CPU Global Interrupts asm CLI; // Set up VFD dim = PortRead(PORT_B,0); VFDInit(); // Set up buttons (Inputs - enable pullups) PortAInit(); KbiInit(); // enable interrupts mode = CONTROL; // Set up and turn on 4 Hz interrupt timer (Timebase Module) TBCR = 0x10; // set 4 Hz TBCR |= 0x06; // turn on and enable interrupt // Get config data from ECU get_config = 1; curr_var_no = 0; incr_count = 0; decr_count = 0; ibyte = 0; irbyte = 0; xmtbuf[0] = 'v'; no_xbytes = 1; SCC2 |= SCI_Tx_INT_ENABLE; // enable xmit empty interrupt ix = SCS1; SCDR = xmtbuf[0]; while(get_config); mode = DISPLAY; // idle while(1) { if(VFDDisp_flg) { VFDDisplay(); VFDDisp_flg = 0; } if(mode == CONTROL) { // incr/scroll button auto repeat if(incr_count >= 2) { incr_count = 1; if(!select) { debounce = 0; sem = 1; IncrIsr(); sem = 0; } } if(decr_count >= 2) { decr_count = 1; if(!select) { debounce = 0; sem = 1; DecrIsr(); sem = 0; } } } } // end while(1) } interrupt void SwiHand(void) { } interrupt void NullHand(void) { } /*================================== VARIABLES ================================*/ /* gPllLockState - Global Var that hold the PLL lock state PLL_LOCKED or PLL_UNLOCKED; */ static char gPllLockState = PLL_UNLOCKED; /****************************************************************************** * FUNCTION : SystemInit * System Initialization ******************************************************************************/ void SystemInit(void) { #define DELAY_TIME 10 U8 i; /* Set the CONFIG1 Option Register */ CONFIG1 = ( COP_TIMOUT_LONG | /* Set the COP rate */ LVI_DISABLE_IN_STOP | /* Set the LVI mode during stop mode */ LVI_RESET_DISABLE | /* (MOR=CONFIG1) Set the LVI Reset Enable Bit */ LVI_POWERD_DISABLE | /* (MOR=CONFIG1) Set the LVI Power Enable Bit */ LVI_IN_5_V | /* Set the LVI to 5v/3v operating voltage */ SLOW_RECOVERY_FROM_STOP | /* Set fast/slow recover time from stop mode */ MOR_STOP_ENABLE | /* (MOR=CONFIG1) Set the stop mode */ DISABLE_COP_MODULE ); /* (MOR=CONFIG1) Set the COP module */ /* Set oscillator mode during stop mode */ CONFIG2 = ( OSCI_IN_STOP_DISABLE | SCI_INTERNAL_BUS_CLOCK ); /* set the baud rate source for the sci */ /* Initialize the IRQ Status and Control Register */ ISCR = ( IRQ1_ENABLE | /* Enable/disable IRQ */ IRQ_FALLING_EDGE_AND_LEVEL /* IRQ signal Sensitivity */ ); /* Init the PLL Bandwidth Control Register */ PBWC = ( PLL_AUTOMATIC_CONTROL /* Set The AUTO - Automatic Bandwidth Control Bit */ ); /* The PLL control register (PCTL) contains the interrupt enable and flag bits, the on/off switch, and the base clock selector bit. */ PCTL &= ~PLL_ON; /* Turn off to set up bus freq = 7.3728 MHz */ PCTL |= 0x2; PMSH =0x3; PMSL = 0x84; PMRS = 0xC0; PMDS = 0x1; PCTL = ( PLL_INTERRUPT_DISABLED | /* Set PLLIE - PLL Interrupt Enable Bit */ PLL_ON ); /* Set PLLON - PLL On/Off Bit */ /* After toggling BCS, it may take up to three CGMXCLK and three CGMVCLK cycles to complete the transition from one source clock to the other. */ for ( i = 0 ; i < DELAY_TIME ; i++ ); /* Delay */ PCTL |= PLL_VCO_ENABLE ; /* Set BCS - Base Clock Select Bit */ for ( i = 0 ; i < DELAY_TIME ; i++ ); /* Delay */ /* Break Module */ /* Init the SIM Break Flag Control Register */ SBFCR = STATUS_BITS_NOT_CLEARABLE; return; } /****************************************************************************** * FUNCTION : SciInit * Initial for the Sci module ******************************************************************************/ void SciInit(void) { CONFIG2 |= SCI_INTERNAL_BUS_CLOCK; /* set the clock source for the baud rate */ SCC1 = ENABLE_SCI; /* Enable the sci module */ SCC1 |= ( SCI_LOOP_DISABLE | /* Enable/disable loop mode */ SCI_TRANSMIT_UNINVERTED | /* Transmit character inverted/not inverted */ SCI_8_BIT_DATA | /* Set character length to 8/9 bits */ SCI_IDLE_WAKEUP | /* Wakeup by address mark/idle line */ SCI_IDLE_AFTER_START | /* Begin idle character bit count after stop/start bit */ SCI_DISABLE_PARITY | /* Enable/disable parity function */ SCI_ODD_PARITY ); /* Select odd/even as parity */ /* This register initialize interrupts request activate the transmitter and receiver and wakeup mode */ SCC2 = ( SCI_Tx_INT_DISABLE | /* Enable/disable transmitter empty interrupt */ SCI_INT_TRAN_COMP_DISABLE | /* Enable/disable transmitter complete interrupt */ SCI_Rx_INT_DISABLE | /* Enable/disable receiver full interrupt */ SCI_INT_IDLE_DISABLE | /* Enable/disable receiver idle interrupt */ SCI_TRANSMITTER_ENABLE | /* Enable/disable transmitter */ SCI_RECEIVER_ENABLE | /* Enable/disable receiver */ SCI_RWU_NORMAL ); /* Enable/disable wakeup mode */ /* This register initialize the DMA services and error interrupts */ SCC3 = ( SCI_DMA_FOR_REC_DISABLE | /* Enable/disable receive DMA service */ SCI_DMA_FOR_TRAN_DISABLE | /* Enable/disable transfer DMA service */ SCI_INT_REC_OVERUN_DISABLE | /* Enable/disable receiver overrun interrupt */ SCI_INT_REC_NOISE_DISABLE | /* Enable/disable receiver noise error interrupt */ SCI_INT_REC_FRAME_DISABLE | /* Enable/disable receiver frame error interrupt */ SCI_INT_REC_PARITY_DISABLE ); /* Enable/disable receiver parity error interrupt */ /* This register sets baud rate to 115200 at bus freq = 7.3728 MHz */ // SCBR = ( SCI_PD_DIV_BY_3 | SCI_BD_DIV_BY_4 ); SCBR = 0x00; } /****************************************************************************** * FUNCTION : SciTxIntHand * Transmitter interrupt handler, cpu will get here when TEIE bit set in * SCC2 ******************************************************************************/ interrupt void SciTxIntHand(void) { // Enter here when the rs232 transmit buffer is empty U8 Status ; U16 ix; ibyte++; if(ibyte < no_xbytes) { if(no_xbytes > 2)for(ix=0;ix < 4000;ix++); // clear status register (by read) to allow next interrupt Status=SCS1; // transfer transmit byte from buffer to register SCDR = xmtbuf[ibyte]; } else { // Done transmitting - kill transmit interrupts SCC2 &= (~SCI_Tx_INT_ENABLE); SCC2 &= (~SCI_INT_TRAN_COMP_ENABLE); if(mode == DISPLAY) { // Display mode // Set up to receive the requested display data irbyte = 0; no_rbytes = NO_DISP_BYTES_FROM_ECU; SCC2 |= SCI_Rx_INT_ENABLE; // enable receiver full interrupt } else if(xmtbuf[0] != 'b') { // Control mode // Set up to receive the requested control data irbyte = 0; no_rbytes = NO_CTRL_BYTES_FROM_ECU; rcv_timeout = 1; SCC2 |= SCI_Rx_INT_ENABLE; // enable receiver full interrupt } } return; } /****************************************************************************** * FUNCTION : SciRxIntHand * Receiver interrupt handler ******************************************************************************/ interrupt void SciRxIntHand(void) { U8 Status,readbuf; // Enter here when have received rs232 byte // clear status register to allow next interrupt Status = SCS1; // transfer received byte from register to buffer readbuf = SCDR; if(get_config) { if(irbyte == 1137) TmpUnits = readbuf; if(TmpUnits == 1) DispVarUpperStrng = CDispVarUpperStrng; } else if(mode == DISPLAY) rcvbuf[irbyte] = readbuf; else { if (irbyte == ctl_var_offset[curr_var_no]) rcvbuf[0] = readbuf; if ((irbyte == 1145) || (irbyte == 329)) { if(irbyte == ctl_var_offset[curr_var_no] + 1) rcvbuf[1] = readbuf; // 2nd half (lsb) of ReqFuel, AdvOffset } } irbyte++; if(irbyte < no_rbytes) { return; } else { // Done receiving - kill receive interrupt enable SCC2 &= (~SCI_Rx_INT_ENABLE); rcv_timeout = 0; if(get_config) { get_config = 0; return; } if(mode == CONTROL) controlRcv = 1; // Check if mode change desired. If so, can change mode now // without getting ecu comms out of synch if(modeChange) { ModeChange(); } else { // convert data to engineering units, put in VFD // display string, and write/ scroll across VFD VFDDisp_flg = 1; } } return; } /****************************************************************************** * FUNCTION : PortAInit * Port A Initialization ******************************************************************************/ void PortAInit(void) { /* Set global Var with Registers Address */ PortDirecReg[PORT_A] = pDDRA ; PortDataReg[PORT_A] = pPTA ; /* Set all Data Pin to 0 */ PTA = 0; /* Set Data direction Port to input for bits 0-3 */ DDRA = 0xF0; /* Set Pullup Enables for bits 0 - 3 (buttons) Bit 0 Scroll Left/ Decrease Bit 1 Scroll Right/ Increase Bit 2 Select/ Freeze Bit 3 Mode Button */ PTAPUE = 0x0F; } /****************************************************************************** * FUNCTION : PortBInit * Port B Initialization ******************************************************************************/ void PortBInit(void) { /* Set global Var with Registers Address */ PortDirecReg[PORT_B] = pDDRB ; PortDataReg[PORT_B] = pPTB ; /* Set all Data Pin to 0 */ PTB = 0; /* Set Data direction Port to: input for bit 0; outputs for bits 4-6 VFD Control lines: Bit 0 Dimming Bit 4 Enable Bit 5 R/W Bit 6 RS */ DDRB = 0xFE; } /****************************************************************************** * FUNCTION : PortCInit * Port C Initialization ******************************************************************************/ void PortCInit(void) { /* Set global Var with Registers Address */ PortDirecReg[PORT_C] = pDDRC ; PortDataReg[PORT_C] = pPTC ; /* Set all Data Pin to 0 */ PTC = 0; /* Set Data direction Port to ouputs for bits 0-3 VFD data bits: Bit 0 DB4 Bit 1 DB5 Bit 2 DB6 Bit 3 DB7 */ DDRC = 0xFF; } /****************************************************************************** * FUNCTION : PortDInit * Port D Initialization ******************************************************************************/ void PortDInit(void) { /* Set global Var with Registers Address */ PortDirecReg[PORT_D] = pDDRD ; PortDataReg[PORT_D] = pPTD ; /* Set all Data Pin to 0 */ PTD = 0; /* Set Data direction Port to output for bit 4 */ DDRD = 0xFF; // LCD contrast } /****************************************************************************** * FUNCTION : KbiInit * Kbi initialization ******************************************************************************/ #define KbiWriteAcknowledge() INTKBSCR |= ( KBI_ACKNOWLEDGE ) void KbiInit(void) { /* Initialize status and control register */ INTKBSCR = ( DISABLE_KBI_INT | /* Set the musk interrupt bit */ KBI_INT_ON_FALLING); /* Set the sensitivity of the keyboard */ /* Initialize the keyboard interrupt register */ INTKBIER = ( ENABLE_KBI_INT_0 | /* Enable/Disable keyboard interrupt 0 */ ENABLE_KBI_INT_1 | /* Enable/Disable keyboard interrupt 1 */ ENABLE_KBI_INT_2 | /* Enable/Disable keyboard interrupt 2 */ ENABLE_KBI_INT_3 | /* Enable/Disable keyboard interrupt 3 */ DISABLE_KBI_INT_4 | /* Enable/Disable keyboard interrupt 4 */ DISABLE_KBI_INT_5 | /* Enable/Disable keyboard interrupt 5 */ DISABLE_KBI_INT_6 | /* Enable/Disable keyboard interrupt 6 */ DISABLE_KBI_INT_7 ); /* Enable/Disable keyboard interrupt 7 */ KbiWriteAcknowledge(); /* Enable the keyboard interrupts */ INTKBSCR &= ~( DISABLE_KBI_INT ); /* clear the musk interrupt bit */ return; } /****************************************************************************** * FUNCTION : KbiHand * KBI interrupt Handler ******************************************************************************/ interrupt void KbiHand(void) { U8 Status; if(!debounce) { debounce = 2; /* Determine which button pushed */ if(PortRead(PORT_A,3) == 0) ModeIsr(); else if(PortRead(PORT_A,2) == 0) SelectIsr(); else if(PortRead(PORT_A,1) == 0) { if(!sem)IncrIsr(); } else if(PortRead(PORT_A,0) == 0) { if(!sem)DecrIsr(); } } else Status = PortRead(PORT_A,0); // read to clear /* Write an Acknowledge to clear the interrupt flag */ KbiWriteAcknowledge(); return; } void ModeIsr(void) { // Enter here when push Mode button if(mode == DISPLAY) { // Set flag so when current rs232 rcv transaction done, will // call ModeChange modeChange = 1; } else { if(!controlRcv) { // havn't got ctl data yet from ecu // Set flag so when current rs232 rcv transaction done, will // call ModeChange modeChange = 1; } else { ModeChange(); } } return; } void ModeChange(void) { U8 Status; modeChange = 0; if(mode == DISPLAY) { // Switch to Control Mode mode = CONTROL; select = 0; controlRcv = 0; // havn't got ctl data yet from ecu // Transmit request for all control variable values ibyte = 0; xmtbuf[0] = 'v'; no_xbytes = 1; SCC2 |= SCI_Tx_INT_ENABLE; // enable xmt empty interrupt Status = SCS1; SCDR = xmtbuf[0]; } else { // Switch to Display Mode mode = DISPLAY; if(!freeze) colix = 0; strcpy(VFDLower, DispVarLowerStrng); VFDDisp_flg = 0; } return; } void SelectIsr(void) { char col; U8 Status; // Enter here when push freeze/select button' if(mode == DISPLAY) { freeze = 1 - freeze; } else { // Control Mode select = 1 - select; if(select) { changed_ctl_var = 0; // Indicate Control is Selected, so // incr/decr will change value. // send out top line for(col=0; col < MAX_COLS; col++) { VFDSend(0,col,SelectStrng[col]); } } else { // Have just unselected - check if have made a net change if(changed_ctl_var) { // Burn change into flash ibyte = 0; xmtbuf[0] = 'b'; no_xbytes = 1; SCC2 |= SCI_Tx_INT_ENABLE; // enable xmt empty interrupt Status = SCS1; SCDR = xmtbuf[0]; } // Indicate Control is Not Selected, so // incr/decr will cause scrolling // send out top line for(col=0; col < MAX_COLS; col++) { VFDSend(0,col,BlnkStrng[col]); } } } return; } void IncrIsr(void) { // Enter here when push incr or scroll right button short test; float testf; U8 Status; if(mode == DISPLAY)return; if(select && !rcv_timeout) { // control variable has been selected, // therefore want to increase value changed_ctl_var++; if(ctl_var_type[curr_var_no] == UCH) { test = control_var_val.uch + 1; if((curr_var_no == 8) && (test > 1))test = 0; // alternate if((curr_var_no == 13) && (test > 100))test = 100; // InjPWMDty if(test < 256) control_var_val.uch = (U8)test; } else if(ctl_var_type[curr_var_no] == FLT) { testf = control_var_val.flt + 0.1; control_var_val.flt = testf; } controlRcv = 0; // havn't got ctl data yet from ecu rcv_timeout = 1; // Transmit request to write, then rdbk all ctl vars ibyte = 0; xmtbuf[0] = 'w'; xmtbuf[1] = (U8)(ctl_var_offset[curr_var_no] >> 8); // msb xmtbuf[2] = (U8)ctl_var_offset[curr_var_no]; // lsb xmtbuf[3] = 0x00; // no data bytes - msb xmtbuf[4] = 0x01; // no data bytes - lsb CnvtSw = 2; VFDConvert(); // This takes control_var_val and converts // to ECU units (ctl_var_ecu_val) xmtbuf[5] = ctl_var_ecu_val; if((curr_var_no != 6) && (curr_var_no != 14)) { no_xbytes = 6; } else { xmtbuf[4] = 0x02; // no data bytes - lsb xmtbuf[6] = ctl_var_ecu_val2; // lsb no_xbytes = 7; } xmtbuf[no_xbytes] = 'v'; no_xbytes++; SCC2 |= SCI_INT_TRAN_COMP_ENABLE; // enable xmit complete interrupt Status = SCS1; SCDR = xmtbuf[0]; } else { // control variable not selected, therefore want // to scroll right if(!rcv_timeout) { curr_var_no++; if(curr_var_no >= NUM_CTL_VARIABLES) curr_var_no = 0; controlRcv = 0; // havn't got ctl data yet from ecu // Transmit request for all control variable values ibyte = 0; xmtbuf[0] = 'v'; no_xbytes = 1; SCC2 |= SCI_Tx_INT_ENABLE; // enable xmit empty interrupt Status = SCS1; SCDR = xmtbuf[0]; } } return; } void DecrIsr(void) { // Enter here when push decr or scroll left button short test; float testf; U8 Status; if(mode == DISPLAY)return; if(select && !rcv_timeout) { // control variable has been selected, // therefore want to decrease value changed_ctl_var--; if(ctl_var_type[curr_var_no] == UCH) { test = control_var_val.uch - 1; if((curr_var_no == 8) && (test < 0))test = 1; // alternate if(test >= 0) control_var_val.uch = (U8)test; } else if(ctl_var_type[curr_var_no] == FLT) { testf = control_var_val.flt - 0.1; if((curr_var_no != 14) && (testf < 0.0))testf = 0.0; // adv_offset can be - control_var_val.flt = testf; } controlRcv = 0; // havn't got ctl data yet from ecu rcv_timeout = 1; // Transmit request to write, then rdbk all ctl vars ibyte = 0; xmtbuf[0] = 'w'; xmtbuf[1] = (U8)(ctl_var_offset[curr_var_no] >> 8); // msb xmtbuf[2] = (U8)ctl_var_offset[curr_var_no]; // lsb xmtbuf[3] = 0x00; // no data bytes - msb xmtbuf[4] = 0x01; // no data bytes - lsb CnvtSw = 2; VFDConvert(); // This takes control_var_val and converts // to ECU units (ctl_var_ecu_val) xmtbuf[5] = ctl_var_ecu_val; if((curr_var_no != 6) && (curr_var_no != 14)) { no_xbytes = 6; } else { xmtbuf[4] = 0x02; // no data bytes - lsb xmtbuf[6] = ctl_var_ecu_val2; no_xbytes = 7; } xmtbuf[no_xbytes] = 'v'; no_xbytes++; SCC2 |= SCI_INT_TRAN_COMP_ENABLE; // enable xmit complete interrupt Status = SCS1; SCDR = xmtbuf[0]; } else { // control variable not selected, therefore want // to scroll left if(!rcv_timeout) { if(curr_var_no == 0) curr_var_no = NUM_CTL_VARIABLES; curr_var_no--; controlRcv = 0; // havn't got ctl data yet from ecu // Transmit request for all control variable values ibyte = 0; xmtbuf[0] = 'v'; no_xbytes = 1; SCC2 |= SCI_Tx_INT_ENABLE; // enable xmit empty interrupt Status = SCS1; SCDR = xmtbuf[0]; } } return; } interrupt void GetDispIsr(void) { U8 Status; // Enter here every 0.25 seconds // acknowledge TBM interrupt (to clear interrupt flag) TBCR |= 0x08; if(debounce > 0)debounce--; // incr/scroll button auto repeat if(mode == CONTROL) { if(PortRead(PORT_A,1) == 0) incr_count++; else incr_count = 0; if(PortRead(PORT_A,0) == 0) decr_count++; else decr_count = 0; } // Check for receiver timeout if(rcv_timeout) { rcv_timeout++; if(rcv_timeout > 8) { // 2 sec timeout // Re-transmit ibyte = 0; SCC2 |= SCI_INT_TRAN_COMP_ENABLE; // enable xmit complete interrupt Status = SCS1; SCDR = xmtbuf[0]; } } if(mode != DISPLAY) return; // Set up to transmit request for all display data. // At end of transmit, will automatically set up for // receiving the data, then displaying it. ibyte = 0; xmtbuf[0] = 'a'; no_xbytes = 1; SCC2 |= SCI_Tx_INT_ENABLE; // enable xmit empty interrupt Status = SCS1; SCDR = xmtbuf[0]; return; } void VFDInit(void) { // RS = R/W = EN = 0 PortClr(PORT_B, 4); // EN PortClr(PORT_B, 5); // R/W PortClr(PORT_B, 6); // RS VFDData(0x33); // check if want to dim if(dim) { PortSet(PORT_B,6); // set RS=1 VFDData(0x02); // 50% brightness PortClr(PORT_B,6); // restore RS=0 } VFDData(0x32); // 4 bit data, 2 lines, 5x7 dots VFDData(0x28); // ??????? VFDData(0x06); // Turn on cursor VFDData(0x0C); // Clear display VFDData(0x01); return; } void VFDDisplay(void) { // This subroutine converts receive buffer data from ECU // to engineering data, formats it into VFD display strings, // and writes/ scrolls it across the VFD display. char col; short coljx; if(mode == DISPLAY) { // Display mode CnvtSw = 0; VFDConvert(); // This takes rcvbuf and converts to // display variable values, then puts in VFDLower if(!freeze) { colix++; if(colix >= MAX_VFD_STRLEN)colix=0; } coljx = colix; for(col=0; col < MAX_COLS; col++) { VFDSend(0,col,DispVarUpperStrng[coljx]); VFDSend(1,col,VFDLower[coljx]); coljx++; if(coljx >= MAX_VFD_STRLEN)coljx=0; } } else { // Control mode CnvtSw = 1; VFDConvert(); // This takes rcvbuf and converts/sets // value of current control variable // Display the control variable if(ctl_var_type[curr_var_no] == UCH) sprintf(VFDLower, &CtlVarStrng[curr_var_no][0], control_var_val.uch); else if(ctl_var_type[curr_var_no] == SHT) sprintf(VFDLower, &CtlVarStrng[curr_var_no][0], control_var_val.sht); else if(ctl_var_type[curr_var_no] == FLT) sprintf(VFDLower, &CtlVarStrng[curr_var_no][0], control_var_val.flt); // Send out VFD lines for(col=0; col < MAX_COLS; col++) { if(select) VFDSend(0,col,SelectStrng[col]); else VFDSend(0,col,BlnkStrng[col]); VFDSend(1,col,VFDLower[col]); } } return; } void VFDConvert(void) { U8 status,itmp,neg,alarm; short tmps; unsigned short tmpu; if(CnvtSw == 0) { // convert ECU data to display (engineering) units alarm_alt = 1 - alarm_alt; tmpu = (rcvbuf[0] << 8) + rcvbuf[1]; // seconds itoa(tmpu,&VFDLower[0],5,0); status = rcvbuf[11]; // ignore 10 = squirt if((status & 0x03) == 0) // engine (bits 0,1) VFDsprintf(&VFDLower[9], 0, 0, 5, " OFF ",0); else if((status & 0x03) == 1) VFDsprintf(&VFDLower[9], 0, 0, 5, " RUN ",0); else VFDsprintf(&VFDLower[9], 0, 0, 5, "CRANK",0); if((status & 0x0C) == 0) // warm enrich (bits 2,3) VFDsprintf(&VFDLower[18], 0, 0, 5, " OFF ",0); else if(((status & 0x0C) >> 2) == 1) VFDsprintf(&VFDLower[18], 0, 0, 5, "START",0); else VFDsprintf(&VFDLower[18], 0, 0, 5, " ON ",0); if((status & 0x30) == 0) // accel enrich (bits 4,5) VFDsprintf(&VFDLower[27], 0, 0, 5, " OFF ",0); else if(((status & 0x30) >> 4) == 1) VFDsprintf(&VFDLower[27], 0, 0, 5, "ACCEL",0); else VFDsprintf(&VFDLower[27], 0, 0, 5, "DECEL",0); tmpu = (rcvbuf[6] << 8) + rcvbuf[7]; // rpm itoa(tmpu,&VFDLower[35],5,0); tmpu = (rcvbuf[2] << 8) + rcvbuf[3]; itmp = (U8)(tmpu / (U8)100); // pw1 (msx10) VFDsprintf(&VFDLower[42], 2, 0, 4, &itmp,0); tmps = (rcvbuf[8] << 8) + rcvbuf[9]; if(tmps >= 0) neg = 0; else { tmps = -tmps; neg = 1; } itmp = (U8)(tmps / (U8)10); // adv deg VFDsprintf(&VFDLower[50], 1, neg, 3, &itmp,0); itmp = rcvbuf[63]; // coil_dur (msx10) VFDsprintf(&VFDLower[59], 2, 0, 4, &itmp,0); itmp = rcvbuf[55]; // iacstep (max 255 steps displayed) VFDsprintf(&VFDLower[68], 1, 0, 3, &itmp,0); tmpu = (rcvbuf[16] << 8) + rcvbuf[17]; itmp = (U8)(tmpu / (U8)10); // baro (kpa) if(alarm_alt && ((itmp < 70) || (itmp > 130))) // baro out of range alarm = 1; else alarm = 0; VFDsprintf(&VFDLower[76], 1, 0, 3, &itmp,0); tmpu = (rcvbuf[18] << 8) + rcvbuf[19]; itmp = (U8)(tmpu / (U8)10); // map (kpa) if(alarm_alt && ((itmp == 0) || (itmp == 255))) // railed alarm = 1; else alarm = 0; VFDsprintf(&VFDLower[86], 1, 0, 3, &itmp,alarm); tmps = (rcvbuf[22] << 8) + rcvbuf[23]; if(TmpUnits == 0) { // Farenheit if(alarm_alt && ((tmps <= -400) || (tmps >= 2150))) // temp out of range/ overheat alarm = 1; else alarm = 0; } else { // Celsius if(alarm_alt && ((tmps <= -400) || (tmps >= 1010))) // temp out of range/ overheat alarm = 1; else alarm = 0; } if(tmps >= 0) neg = 0; else { tmps = -tmps; neg = 1; } itmp = (U8)(tmps / (U8)10); // clt (F or C) VFDsprintf(&VFDLower[93], 1, neg, 3, &itmp,alarm); tmps = (rcvbuf[20] << 8) + rcvbuf[21]; if(TmpUnits == 0) { // Farenheit if(alarm_alt && ((tmps <= -400) || (tmps >= 2150))) // temp out of range/ overheat alarm = 1; else alarm = 0; } else { // Celsius if(alarm_alt && ((tmps <= -400) || (tmps >= 1010))) // temp out of range/ overheat alarm = 1; else alarm = 0; } if(tmps >= 0) neg = 0; else { tmps = -tmps; neg = 1; } itmp = (U8)(tmps / (U8)10); // mat (F or C) VFDsprintf(&VFDLower[100], 1, neg, 3, &itmp,alarm); tmpu = (rcvbuf[24] << 8) + rcvbuf[25]; itmp = (U8)(tmpu / (U8)10); // tps (Vx10) VFDsprintf(&VFDLower[107], 2, 0, 4, &itmp,0); itmp = rcvbuf[27]; // batt (Vx10) if(alarm_alt && ((itmp < 90) || (itmp > 160))) // out of range alarm = 1; else alarm = 0; VFDsprintf(&VFDLower[114], 2, 0, 4, &itmp,alarm); itmp = rcvbuf[29]; // ego1 (afrx10) if(alarm_alt && ((itmp < 80) || (itmp > 220))) // out of range alarm = 1; else alarm = 0; VFDsprintf(&VFDLower[120], 2, 0, 4, &itmp,alarm); VFDsprintf(&VFDLower[127], 2, 0, 4, &rcvbuf[12],0); // afrtgt1 itmp = rcvbuf[35]; // egocor1 (%) (max of 255 displayed) VFDsprintf(&VFDLower[136], 1, 0, 3, &itmp,0); itmp = rcvbuf[39]; // aircor (%) (max of 255 displayed) VFDsprintf(&VFDLower[146], 1, 0, 3, &itmp,0); itmp = rcvbuf[47]; // barocor (%) (max of 255 displayed) VFDsprintf(&VFDLower[156], 1, 0, 3, &itmp,0); itmp = rcvbuf[51]; // ve1 (%) (max of 255 displayed) VFDsprintf(&VFDLower[166], 1, 0, 3, &itmp,0); itmp = rcvbuf[41]; // warmcor (%) (max of 255 displayed) VFDsprintf(&VFDLower[176], 1, 0, 3, &itmp,0); itmp = rcvbuf[43]; // tpsaccel (msx10) (max of 25.5 displayed) VFDsprintf(&VFDLower[185], 2, 0, 4, &itmp,0); itmp = rcvbuf[45]; // tpsfuelcut (%) (max of 255 displayed) VFDsprintf(&VFDLower[195], 1, 0, 3, &itmp,0); itmp = rcvbuf[49]; // gammae (%) (max of 255 displayed) VFDsprintf(&VFDLower[205], 1, 0, 3, &itmp,0); tmps = (rcvbuf[56] << 8) + rcvbuf[57]; if(tmps >= 0) neg = 0; else { tmps = -tmps; neg = 1; } itmp = (U8)(tmps / (U8)10); // cold_adv (deg) VFDsprintf(&VFDLower[214], 1, neg, 3, &itmp,0); } else if(CnvtSw == 1) { // convert control data from ecu to display data switch(curr_var_no) { case 0: case 1: control_var_val.flt = (float)rcvbuf[0] * 0.1; // CWU,CWH break; // (msx10->ms) case 2: case 3: case 4: control_var_val.uch = rcvbuf[0]; // AWEV,AVC,IACStart break; case 5: control_var_val.flt = (float)rcvbuf[0] * 0.1; // PrimeP break; // (msx10->ms) case 6: tmpu = (rcvbuf[0] << 8) + rcvbuf[1]; // ReqFuel (usec -> ms) control_var_val.flt = (float)tmpu * 0.001; break; case 7: case 8: control_var_val.uch = rcvbuf[0]; // divider, alternate break; case 9: case 10: case 11: control_var_val.flt = (float)rcvbuf[0] * 0.1; // InjOpen, // BattFac, InjPWMTim (msx10 -> ms) break; case 12: control_var_val.flt = (float)rcvbuf[0] * 0.001; // InjPWMPd break; // (msx10->ms) case 13: control_var_val.uch = rcvbuf[0]; // InjPWMDty break; case 14: tmps = (rcvbuf[0] << 8) + rcvbuf[1]; // Adv Offset (degx10-> deg) control_var_val.flt = (float)tmps * 0.1; } // end switch } else if(CnvtSw == 2) { // convert display control data to ecu data switch(curr_var_no) { case 0: case 1: // CWU, CWH (ms -> msx10) ctl_var_ecu_val = (U8)(control_var_val.flt * 10.001); break; case 2: case 3: case 4: // AWEV, AWC, IACStart ctl_var_ecu_val = control_var_val.uch; break; case 5: // PrimeP (ms -> msx10) ctl_var_ecu_val = (U8)(control_var_val.flt * 10.001); break; case 6: // ReqFuel (ms -> usec) tmpu = (U16)(control_var_val.flt * 1000.001); ctl_var_ecu_val = (U8)(tmpu >> 8); // msb ctl_var_ecu_val2 = (U8)(tmpu & 0x00FF); // lsb break; case 7: case 8: // divider, alternate ctl_var_ecu_val = control_var_val.uch; break; case 9: case 10: case 11: // InjOpen, Batfac, InjPWMTim (ms -> msx10) ctl_var_ecu_val = (U8)(control_var_val.flt * 10.001); break; case 12: // InjPWMPd (ms -> usec) ctl_var_ecu_val = (U8)(control_var_val.flt * 1000.001); break; case 13: // InjPWMDty ctl_var_ecu_val = control_var_val.uch; break; case 14: // Adv Offset (deg-> degx10) tmps = (short)(control_var_val.flt * 10.001); ctl_var_ecu_val = (U8)(tmps >> 8); // msb ctl_var_ecu_val2 = (U8)(tmps & 0x00FF); // lsb } // end switch } // end main else return; } void itoa(short value, U8 *bufi, U8 width, U8 prec) { short tmp2; U8 ix,kx,lz; unsigned short div,tmp1; // value = "width digits . prec digits" // width + prec <= 5 lz = 1; kx = 0; tmp2 = value; if(tmp2 < 0) { tmp2 = -tmp2; bufi[kx] = '-'; kx++; } div = diva[width-1]; for(ix=width + prec; ix > prec; ix--) { tmp1 = tmp2 / div; // leading digit tmp2 = tmp2 % div; // remainder if((tmp1 == 0) && lz) // blank leading zeros bufi[kx] = ' '; else { bufi[kx] = 48 + tmp1; lz = 0; } kx++; div /= 10; } if(!prec)return; bufi[kx] = '.'; kx++; for(ix=prec; ix > 0; ix--) { tmp1 = tmp2 / div; // leading digit tmp2 = tmp2 % div; // remainder kx++; bufi[kx] = 48 + tmp1; div /= 10; } return; } void VFDsprintf(U8 *bufo, U8 type, U8 neg, U8 width, U8 *bufi, U8 alarm) { U8 ix; if(!alarm) { if(type == 0) { // string for(ix=0;ix < width; ix++) { bufo[ix] = bufi[ix]; } } else if (type == 1) { // char if(neg) { bufo[0] = '-'; bufo[1] = asc_cnvt_tbl2[bufi[0]]; bufo[2] = asc_cnvt_tbl1[bufi[0]]; } else { bufo[0] = asc_cnvt_tbl3[bufi[0]]; bufo[1] = asc_cnvt_tbl2[bufi[0]]; bufo[2] = asc_cnvt_tbl1[bufi[0]]; } } else if (type == 2) { // float bufo[0] = asc_cnvt_tbl3[bufi[0]]; bufo[1] = asc_cnvt_tbl2[bufi[0]]; bufo[2] = '.'; bufo[3] = asc_cnvt_tbl1[bufi[0]]; } } else { bufo[0] = ' '; bufo[1] = ' '; bufo[2] = ' '; if(type == 2) bufo[3] = ' '; } return; } void VFDSend(char line, char col, char value) { // Set up to send a byte to VFD character RAM PortClr(PORT_B, 4); // EN = 0 PortClr(PORT_B, 5); // R/~W = 0 (write operation) PortClr(PORT_B, 6); // RS = 0 (sending an instruction) // send address of where cursor/ data byte will go // format of byte is 0x1lcccccc where l = line # (0,1) // and cccccc = 6-bit col #. VFDData(0x80 | (line << 6) | col); // Send position // Send data byte PortSet(PORT_B, 6); // RS = 1 (sending a data byte) VFDData(value); return; } void VFDData(char value) { U8 ix; // data bit 4 (PTC0) if(value & 0x10) PortSet(PORT_C, 0); else PortClr(PORT_C, 0); // data bit 5 (PTC1) if(value & 0x20) PortSet(PORT_C, 1); else PortClr(PORT_C, 1); // data bit 6 (PTC2) if(value & 0x40) PortSet(PORT_C, 2); else PortClr(PORT_C, 2); // data bit 7 (PTC3) if(value & 0x80) PortSet(PORT_C, 3); else PortClr(PORT_C, 3); for(ix=0; ix < 245; ix++); //delay to let data settle PortSet(PORT_B, 4); // set enable line to send over // delay > .5 us to satisfy VFD timing reqts. for(ix=0; ix < 5; ix++) { asm nop; } PortClr(PORT_B, 4); // unset enable to set up for next xmt // delay > .5 us to satisfy VFD timing reqts. for(ix=0; ix < 5; ix++) { asm nop; } // data bit 0 (PTC0) if(value & 0x01) PortSet(PORT_C, 0); else PortClr(PORT_C, 0); // data bit 1 (PTC1) if(value & 0x02) PortSet(PORT_C, 1); else PortClr(PORT_C, 1); // data bit 2 (PTC2) if(value & 0x04) PortSet(PORT_C, 2); else PortClr(PORT_C, 2); // data bit 3 (PTC3) if(value & 0x08) PortSet(PORT_C, 3); else PortClr(PORT_C, 3); for(ix=0; ix < 245; ix++); //delay to let data settle PortSet(PORT_B, 4); // set enable line to send over // delay > .5 us to satisfy VFD timing reqts. for(ix=0; ix < 5; ix++) { asm nop; } PortClr(PORT_B, 4); // unset enable to set up for next xmt // delay > .5 us to satisfy VFD timing reqts. for(ix=0; ix < 5; ix++) { asm nop; } return; }