//************************************************************
// Auther: Luke Skaff
// EET 480 - Senior Project
// Spring 2007
// Automotive engine computer (ECU) diagnostic interface
// Compiled in WinAVR
//************************************************************
//***********************************************************
// Program discription
// Sends Mode 1 command set to ECU
// Stores Mode 1 data
// Cauclates disired values from stored data
// Outputs calculated data to LCD
//***********************************************************
//***********************************************************
// For more information on project visit:
// http://www.lukeskaff.com
//***********************************************************
// Dependent librarys
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <util/delay.h>
#define F_CPU 19660800UL // CPU crystal speed 19.6608Mhz
#define FOSC 19660800UL // CPU crystal speed 19.6608Mhz
#define BAUD 8192UL // 8192 Baud rate
// ------ PORT & PIN Definitions -------
#define LCD_PORT PORTC //8-BIT LCD data lines
#define RS_PORT PORTD //Port RS line in on
#define RS 7 //Pin # of RS line
#define E_PORT PORTD //Port Enable line in on
#define E 6 //Pin # of Enable line
#define RXcontrol 5 //Pin # RX enable transistor
#define DataM 0xFF
#define Bit_Set(port,bit_num) (port = port | (0x01 << bit_num))
#define Bit_Clear(port,bit_num) (port = port & ~(0x01 << bit_num))
#define DataStreamSize 63 //Size of receiving data stream
#define CarDataSize 22 //Size of ASCII car data
unsigned char DataStream[DataStreamSize];
#define Def_Offset 3
#define DEF_ERROR1 3 + Def_Offset
#define DEF_ERROR2 4 + Def_Offset
#define DEF_ERROR3 5 + Def_Offset
#define DEF_ERROR4 6 + Def_Offset
#define DEF_ERROR5 7 + Def_Offset
#define DEF_CTS 8 + Def_Offset
#define DEF_RPM 11 + Def_Offset
#define DEF_MPH 14 + Def_Offset
#define DEF_BLM 20 + Def_Offset
#define DEF_BLM_CELL 21 + Def_Offset
#define DEF_STPS 24 + Def_Offset // Scaled Throttle Position Sensor
#define DEF_MAP 26 + Def_Offset // volts = N x (5 / 255)
// KPa = N * .369 + 10.354
#define DEF_BATT 34 + Def_Offset // volts = N / 10
unsigned char CarData_ASCII[CarDataSize];
#define DATA_CTS_2 0 //COOLANT TEMPERATURE celcius
#define DATA_CTS_1 1
#define DATA_TPS_v 2 //TPS volts
#define DATA_RPM_4 3
#define DATA_RPM_3 4
#define DATA_RPM_2 5
#define DATA_RPM_1 6
#define DATA_MPH_3 7
#define DATA_MPH_2 8
#define DATA_MPH_1 9
#define DATA_BLM_3 10
#define DATA_BLM_2 20
#define DATA_BLM_1 21
#define DATA_BLM_CELL 11
#define DATA_TPS_3 12
#define DATA_TPS_2 13
#define DATA_TPS_1 14
#define DATA_MAP_3 15
#define DATA_MAP_2 16
#define DATA_MAP_1 17
#define DATA_BATT_2 18
#define DATA_BATT_1 19
//ECU trouble codes lookup table
const unsigned char PROGMEM ErrorCode_Table[]=
{
23,22,21,16,15,14,13,12,
35,34,33,32,31,26,25,24,
51,46,45,44,43,42,41,36,
63,62,61,56,55,54,53,52,
00,00,00,00,00,66,65,64
};
//Function prototypes
void LCD_Initialize(void);
void LCD_D_Write(unsigned char);
void LCD_I_Write(unsigned char);
void LCD_Delay(void);
void USART_init(void);
void Binary_Out(unsigned char);
void Get_Car_Data(void);
//void HEX_to_ASCII(unsigned int, unsigned char &, unsigned char &, unsigned char
&, unsigned char &);
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
// ------------------------ Program Code Starts Here ----------------------------
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
//******************************************************************
//* Function: LCD_Initialize *
//* Initialize LCD *
//******************************************************************
void LCD_Initialize(void)
{
Bit_Clear(E_PORT,E); // Bring enable pin low
LCD_I_Write(0x38); // 8-Bit data transfer mode
LCD_I_Write(0x0C); // Turn display on, No cursor, No blinking
LCD_I_Write(0x01); // Display clear, Restore to upper left position
LCD_I_Write(0x06); // Address counter increment after each display
LCD_I_Write(0x02); // Set address counter to zero, move cursor to home
}
//******************************************************************
//* Function: LCD_Write *
//* Output data passed in, in data var. to LCD *
//* - Commented out, not used anymore - *
//******************************************************************
/*void LCD_Write(unsigned char data, unsigned char select)
{
Bit_Set(E_PORT,E);
if(select==0xFF)
Bit_Set(RS_PORT,RS); //LCD Data mode
else
Bit_Clear(RS_PORT,RS); //LCD Instruction mode
LCD_PORT=data;
_delay_ms(1);
Bit_Clear(E_PORT,E);
_delay_ms(1);
}
*/
//******************************************************************
//* Function: LCD_D_Write *
//* Output data passed in, in data var. to LCD *
//******************************************************************
void LCD_D_Write(unsigned char data)
{
Bit_Set(E_PORT,E);
Bit_Set(RS_PORT,RS); //LCD Data mode
LCD_PORT=data;
LCD_Delay();
Bit_Clear(E_PORT,E);
LCD_Delay();
//******************************************************************
//* Function: LCD_I_Write *
//* Output data passed in, in data var. to LCD *
//******************************************************************
void LCD_I_Write(unsigned char data)
{
Bit_Set(E_PORT,E);
Bit_Clear(RS_PORT,RS); //LCD Instruction mode
LCD_PORT=data;
LCD_Delay();
Bit_Clear(E_PORT,E);
LCD_Delay();
//******************************************************************
//* Function: LCD_Delay *
//* Relay function used for LCD communication *
//******************************************************************
void LCD_Delay(void)
{
_delay_ms(1);
}
//******************************************************************
//* Function: USART_init *
//* Enable and Initialize UART *
//******************************************************************
void USART_init(void)
{
// Set the USART baudrate registers for 8192, UBRR=149
UBRR0H = 0;
UBRR0L = 149; // Set for 4800 for PC testing
//255 = 4800 baud
//149 = 8192 buad
//127 = 9600 baud
//UCSRnA - USART Control and Status Register A
// Enable 2x speed change, 0=16 divider 1=8 divider
/*
Bit 7 MSB
R RXCn -> USART Receive Complete
0 TXCn -> TXCn: USART Transmit Complete
R UDREn -> USART Data Register Empty
R FEn -> Frame Error
R DORn -> Data OverRun
R UPEn -> USART Parity Error
0 U2Xn -> Double the USART Transmission Speed, 0=16 divider 1=8 divider
0 MPCMn -> Multi-processor Communication Mode
Bit 0 LSB
*/
UCSR0A = (0<<U2X0);
// UCSRnB - USART Control and Status Register n B
// Enable receiver
/*
Bit 7 MSB
RXCIE0 = 0 Receive Interrupt disabled
TXCIE0 = 0 Transmit Interrupt disabled
UDRIE0 = 0 Interupt disabled
RXEN0 = 1 Receive enabled
TXEN0 = 1 Transmit enabled
UCSZ02 = 0 8-bit mode
RXB80 = 0 9'th RX data bit when using 9-bit UART
TXB80 = 0 9'th TX data bit when using 9-bit UART
Bit 0 LSB
*/
UCSR0B =(1<<RXEN0)|(1<<TXEN0);
// UCSRnC - USART Control and Status Register n C
// Set the USART to asynchronous at 8 bits no parity and 1 stop bits
/*
Bit 7 MSB
0 UMSEL01 |
0 UMSEL00 |-> Async
0 UPM01 |
0 UPM00 |-> No parity
0 USBS0 -> 1 stop bits;
1 UCSZ01 |
1 UCSZ00 |-> 8-bit
0 UCPOL0 -> Reciving data sampled on fallign edge
Bit 0 LSB
*/
UCSR0C =(0<<UMSEL01)|(0<<UMSEL00)|(0<<UPM01)|(0<<UPM00)|(0<<USBS0)|
(1<<UCSZ01)|(1<<UCSZ00)|(0<<UCPOL0);
//******************************************************************
//* Function: Binary_Out *
//* Outputs any passed in variable to LCD in binary *
//* - Used for debugging - *
//* - Commented out, not used in final working code - *
//******************************************************************
/*
void Out_Binary(unsigned char data)
{
for(unsigned char bitn = 8 ; bitn > 0 ; bitn--)
{
if( data & ( 1 << (bitn-1) ) )
LCD_Write(0x31,0xFF); // Output 1 to LCD
else
LCD_Write(0x30,0xFF); // Output 0 to LCD
}
}
*/
//*******************************************************************
//* Function: USART_Receive *
//* Waits for incoming data on USART then returns it to the calling *
//* function *
//* - Commented out, not used in final working code - *
//*******************************************************************
/*
unsigned char USART_Receive(void)
{
// Wait for data to be received
while ( !(UCSR0A & (1<<RXC0)) );
// Get and return received data from buffer
return UDR0;
}
*/
//******************************************************************
//* Function: USART_Transmit *
//* Transmit data *
//* datastream array until array is full *
//******************************************************************
void USART_Transmit(unsigned char data)
{
// Wait for empty transmit buffer
while ( !( UCSR0A & (1<<UDRE0)) );
// Put data into buffer, sends the data
UDR0 = data;
// Wait for empty transmit buffer
while ( !( UCSR0A & (1<<UDRE0)) );
}
//******************************************************************
//* Function: Get_Car_Data *
//* Waits for incoming data on USART then puts received char into *
//* datastream array until array is full *
//******************************************************************
void Get_Car_Data(void)
{
unsigned int timeout;
Bit_Set(PORTD,RXcontrol); //Lockout recieve pin
//Mode 1 command set
USART_Transmit(0xF4);
USART_Transmit(0x56);
USART_Transmit(0x01);
USART_Transmit(0xB5);
Bit_Clear(PORTD,RXcontrol); //Open up recieve pin
for(unsigned char i = 0 ; i < DataStreamSize ; i++)
{
timeout=0; // Reset timeout to zero
// Wait for data to be received if data not recived in timout period
// then exit loop
while( !(UCSR0A & (1<<RXC0) ) && (timeout < 12000) )
{
timeout++;
}
// Get and return received data from buffer
if(timeout == 12000)
DataStream[i]=0; // If timeout load 0 into datastream value
else
DataStream[i]=UDR0; // Otherwise load recieved value
}
Bit_Set(PORTD,RXcontrol); //Lockout recieve pin
}
//******************************************************************
//* Function: Flash_LEDs *
//* - Used for debugging - *
//* - Commented out, not used in final working code - *
//******************************************************************
/*
void Flash_LEDs()
{
for(int i=0 ; i<20 ; i++ )
{
PORTA=0x00;
_delay_ms(1000);
PORTA=0xFF;
_delay_ms(1000);
}
}
*/
//******************************************************************
//* Function: HEX_to_ASCII *
//* Convert inputed 8-bit HEX data to 4 ANSII digits for LCD *
//******************************************************************
void HEXtoASCII(unsigned int Hex_Input,unsigned char *digit4, unsigned char
*digit3, unsigned char *digit2, unsigned char *digit1)
{
// Clear varaibles
*digit4 = 0x00;
*digit3 = 0x00;
*digit2 = 0x00;
*digit1 = 0x00;
while(Hex_Input >= 1000)
{
Hex_Input=Hex_Input - 1000;
*digit4 = *digit4 + 0x01;
}
while(Hex_Input >= 100)
{
Hex_Input=Hex_Input - 100;
*digit3 = *digit3 + 0x01;
}
while(Hex_Input >= 10)
{
Hex_Input=Hex_Input - 10;
*digit2 = *digit2 + 0x01;
}
*digit1 = Hex_Input; //remainder
// Convert to ASCII, OR with 0x30 produces ASCII
*digit4 = *digit4 | 0x30;
*digit3 = *digit3 | 0x30;
*digit2 = *digit2 | 0x30;
*digit1 = *digit1 | 0x30;
}
//******************************************************************
//* Function: Calculate_CarData *
//* Convert raw data from data stream to real numbers and put in *
//* ASCII format *
//******************************************************************
void Calculate_CarData()
{
unsigned char ignore;
unsigned int temp;
// Calculate coolant tempature
temp = DataStream[DEF_CTS] * 0.75 - 40;
HEXtoASCII(temp,&ignore, &ignore, &CarData_ASCII[DATA_CTS_2],
&CarData_ASCII[DATA_CTS_1]);
// Calculate RPM
temp = DataStream[DEF_RPM]*25;
HEXtoASCII(temp,&CarData_ASCII[DATA_RPM_4], &CarData_ASCII[DATA_RPM_3],
&CarData_ASCII[DATA_RPM_2], &CarData_ASCII[DATA_RPM_1]);
// Calculate MPH
temp = DataStream[DEF_MPH] / 1;
HEXtoASCII(temp,&ignore, &CarData_ASCII[DATA_MPH_3], &CarData_ASCII[DATA_MPH_2],
&CarData_ASCII[DATA_MPH_1]);
// Calculate Block Learn Multiplier (BLM)
temp = DataStream[DEF_BLM];
HEXtoASCII(temp,&ignore, &CarData_ASCII[DATA_BLM_3], &CarData_ASCII[DATA_BLM_2],
&CarData_ASCII[DATA_BLM_1]);
// Calculate Throttle Position Sensor (TPS) percent
temp = DataStream[DEF_STPS] / 2.56;
HEXtoASCII(temp,&ignore, &CarData_ASCII[DATA_TPS_3], &CarData_ASCII[DATA_TPS_2],
&CarData_ASCII[DATA_TPS_1]);
// Calculate Manifold Air Pressure (MAP)
temp = (DataStream[DEF_MAP] * 0.369) + 10.354;
HEXtoASCII(temp,&ignore, &CarData_ASCII[DATA_MAP_3], &CarData_ASCII[DATA_MAP_2],
&CarData_ASCII[DATA_MAP_1]);
// Calculate Battery voltage
temp = DataStream[DEF_BATT] / 10;
HEXtoASCII(temp,&ignore, &ignore, &CarData_ASCII[DATA_BATT_2],
&CarData_ASCII[DATA_BATT_1]);
//******************************************************************
//* Function: Output_CarData() *
//* Output calcualted car data and trouble codes to LCD *
//******************************************************************
void Output_CarData()
{
unsigned char ignore;
unsigned int ErrorCode;
unsigned char bitn=0;
unsigned char code_2, code_1;
unsigned char error_bit, error_byte;
LCD_I_Write(0x02); // Set address counter to zero, move cursor to home
LCD_D_Write('R');
LCD_D_Write('P');
LCD_D_Write('M');
LCD_D_Write(' ');
LCD_D_Write(CarData_ASCII[DATA_RPM_4]);
LCD_D_Write(CarData_ASCII[DATA_RPM_3]);
LCD_D_Write(CarData_ASCII[DATA_RPM_2]);
LCD_D_Write(CarData_ASCII[DATA_RPM_1]);
LCD_D_Write(' '); //Space
LCD_D_Write(' '); //Space
LCD_D_Write(' '); //Space
LCD_D_Write('M');
LCD_D_Write('P');
LCD_D_Write('H');
LCD_D_Write(' ');
LCD_D_Write(CarData_ASCII[DATA_MPH_3]);
LCD_D_Write(CarData_ASCII[DATA_MPH_2]);
LCD_D_Write(CarData_ASCII[DATA_MPH_1]);
LCD_D_Write(' '); //Space
LCD_D_Write(' '); //Space
LCD_D_Write('B');
LCD_D_Write('L');
LCD_D_Write('M');
LCD_D_Write(' ');
LCD_D_Write(CarData_ASCII[DATA_BLM_3]);
LCD_D_Write(CarData_ASCII[DATA_BLM_2]);
LCD_D_Write(CarData_ASCII[DATA_BLM_1]);
LCD_D_Write(' '); //Space
LCD_D_Write(' '); //Space
LCD_D_Write(' '); //Space
LCD_D_Write(' '); //Space
LCD_D_Write('C');
LCD_D_Write('T');
LCD_D_Write('S');
LCD_D_Write(' ');
LCD_D_Write(CarData_ASCII[DATA_CTS_2]);
LCD_D_Write(CarData_ASCII[DATA_CTS_1]);
LCD_D_Write('C');
LCD_D_Write(' ');
LCD_D_Write(' '); //Space
LCD_D_Write('M');
LCD_D_Write('A');
LCD_D_Write('P');
LCD_D_Write(' ');
LCD_D_Write(CarData_ASCII[DATA_MAP_3]);
LCD_D_Write(CarData_ASCII[DATA_MAP_2]);
LCD_D_Write(CarData_ASCII[DATA_MAP_1]);
LCD_D_Write(' '); //Space
LCD_D_Write(' '); //Space
LCD_D_Write(' '); //Space
LCD_D_Write(' '); //Space
LCD_D_Write('T');
LCD_D_Write('P');
LCD_D_Write('S');
LCD_D_Write(' ');
LCD_D_Write(CarData_ASCII[DATA_TPS_3]);
LCD_D_Write(CarData_ASCII[DATA_TPS_2]);
LCD_D_Write(CarData_ASCII[DATA_TPS_1]);
LCD_D_Write('%');
LCD_D_Write(' '); //Space
LCD_D_Write('B');
LCD_D_Write('A');
LCD_D_Write('T');
LCD_D_Write('T');
LCD_D_Write(' ');
LCD_D_Write(CarData_ASCII[DATA_BATT_2]);
LCD_D_Write(CarData_ASCII[DATA_BATT_1]);
LCD_D_Write('V');
LCD_D_Write(' ');
LCD_D_Write(' ');
LCD_D_Write(' ');
error_bit=0; //Reset error bit to zero
//*************************
// Check for Trouble Codes
//*************************
for(error_byte = DEF_ERROR1 ; error_byte < DEF_ERROR5 ; error_byte++)
{
for(bitn = 0 ; bitn < 7 ; bitn++)
{
//If error bit in datastream is 1 then ouput trouble code
if(DataStream[error_byte] & ( 1 << (bitn) ) )
{
ErrorCode = (unsigned char)pgm_read_byte(&ErrorCode_Table[error_bit]);
if(ErrorCode != 0) //If error code is 0 ignore trouble code
{
ErrorCode = (unsigned
char)pgm_read_byte(&ErrorCode_Table[error_bit]);
HEXtoASCII(ErrorCode,&ignore, &ignore, &code_2, &code_1);
LCD_D_Write(code_2);
LCD_D_Write(code_1);
LCD_D_Write(' ');
}
}
error_bit = error_bit + 1; //Increment error bit number
}
}
//******************************************************************
//* Function: main *
//* Main control function *
//******************************************************************
int main (void)
{
DDRA = 0xFF; // Configure PORTA as output
DDRC = 0xFF; // Configure PORTC as output
DDRD = (1<<PD1)|(1<<PD5)|(1<<PD6)|(1<<PD7); // Configure PORTD
USART_init(); //Initialize USART
LCD_Initialize(); //Initialize LCD
// Loop forever
while(1)
{
Get_Car_Data();
Calculate_CarData();
Output_CarData();
}
while(1)
;
}// End of main