/**************************************************************************** TACHTC.c This program is a tachometer transmitter. It transmits in Seatalk(tm) network protocol. The following Seatalk protocol is extracted from Thomas Knauf's web site: www.thomasknauf.de/seatalk.htm Message protocol * Each 4800 baud message contains between 3 and 18 characters: * COMMAND byte (the only byte with the command-bit set) ATTRIBUTE byte, specifying the total length of the message in the least significant nibble: Most significant 4 bits: 0 or part of a data value Least significant 4 bits: Number of additional bytes beyond the mandatory data byte DATA byte (mandatory, meaning than the smallest message is 3 bytes) DATA bytes (optional, up to 15 additional data bytes, meaning that longest messages is 18 bytes) Serial Data Transmission 11 bits are transmitted for each byte: * 1 Start bit (0V) * 8 Data Bits (least significant bit transmitted first, bit ON = +12V) * 1 Command/Data bit (+12V if command byte, 0V if other) * 1 Stop bit (+12V) Collision Management Bus should be idle for at least 2mS (+12V for at least 10/4800 seconds). Listens to it's own transmission and recognizes when its message has been corrupted by a second talker. In this case it abandons the remaining bytes in the message, waits for the bus to become free again, and then retransmits the whole message. CODES ------------------------------ FE 01 0x yy Tank address x is yy percent full +5 +5 | | 14 4 ---------- | |-17-- out to Seatalk (transistor driver) | |-18-- in from Seatalk (transistor buffer) | | IN ----9-| | | 16F628 | | | ADR ---12-|A0 | ADR ---13-|A1 | 4MHz XTAL-15-| A2|-1--- LED XTAL-16-| | ---------- 5 | Gnd ***************************************************************************/ /* The following include should contain 16F84 or 16F628. */ #include < 16F628.h > #include < jonsinc.h > #fuses HS, NOPROTECT, PUT, NOWDT, BROWNOUT, NOMCLR, NOLVP #use fast_io ( A ) #use standard_io ( B ) #use delay ( clock = 8000000, restart_wdt ) #byte PORT_A = 5 #byte PORT_B = 6 #bit TX_OUT = PORT_A.0 #bit RX_IN = PORT_A.1 #bit LED = PORT_A.2 #define ADDR_0 PIN_B6 #define ADDR_1 PIN_B7 #define SEATALK_MSGNUM 0xFD #define CMD 1 #define DATA 0 // TACHOMETER DEFINES ================ #define START_TACH 0 #define RUN_TACH 1 #define DONE_TACH 2 // Pulley factor is alternator pulley diameter divided by crank pulley diameter #define ENGINE_DIA 3.625 #define ALT_DIA 2.875 #define PULLEY_FACTOR ALT_DIA/ENGINE_DIA // Obtain from manufacturers data sheet (6, 8, 10, etc.) #define ALTERNATOR_POLES 10 void SendMsg ( int32 int32Data ); char SendByte ( char cError, char cCommand, char cData ); char SendBit ( cBit ); void CheckBus ( void ); static char cAddress; static char cBuffer [ 10 ]; void main ( void ) { char cX, cY, cLed; char cCnt; float fRpm; int32 int32Count; long iLevel; delay_ms ( 150 ); // wait for 75mS nom PUT TX_OUT = LOW; // allow output to float LED = LOW; set_tris_a ( 0b11111010 ); // A0, A2 are outputs, A1 is input output_low ( PROBE_POWER ); // default off setup_counters ( RTCC_INTERNAL, WDT_2304MS ); // 256 * 4uS = 1.024mS timer wrap port_b_pullups ( TRUE ); cAddress = input_b(); cAddress &= 0b11000000; // mask on bits 6 and 7 cAddress >>= 6; // shift address to 0 bit index for ( cY = 0; cY < cAddress + 1; cY++ ) // blink the card address upon initialization { for ( cX = 0; cX < 5; cX++ ) { LED = ON; delay_ms ( 18 ); LED = OFF; delay_ms ( 18 ); } delay_ms ( 200 ); } for ( cX = 0; cX < 10; cX++ ) { cBuffer [ cX ] = 0; // initialize averaging buffer } for ( cX = 0; cX < cAddress; cX++ ) { delay_ms ( 5 ); // variable startup delay based on address } cLed = LOW; while ( TRUE ) // do forever { restart_wdt(); enable_interrupts ( INT_CCP1 ); // CCP1 interrupt cTachState = DONE_TACH; if ( !cSkip ) // do until button is pressed { int32Count = 0; for ( cCnt = 0; cCnt < 20; cCnt++ ) // accumulate 20 readings { cTachState = START_TACH; // allow interrupt to start while ( cTachState != DONE_TACH ) // wait for timing to complete { if ( get_timer1() > 60000 ) // timeout counter //??? divide this by 8 since 8 prescaler is being used??? { iTachCount = 0; // zero everything out int32Count = 0; break; // don't wait any longer } } int32Count += iTachCount; // otherwise accumulate } int32Count /= 20; // get average of those 20 readings } disable_interrupts ( INT_CCP1 ); // CCP1 interrupt } SendMsg ( iLevel ); LED = cLed; delay_ms ( 1000 ); cLed ^= 1; } } void SendMsg ( int32 int32Data ) { char cData0, cData1, cData2, cData3, cError; cData0 = ( char ) ( int32Data & 0x000000ff ); cData1 = ( char ) ( ( int32Data / 256 ) & 0x000000ff ); cData2 = ( char ) ( ( int32Data / 65536 ) & 0x000000ff ); cData3 = ( char ) ( ( int32Data / 167772216 ) & 0x000000ff ); do { CheckBus(); //wait for bus to be idle cError = SendByte ( NO, CMD, SEATALK_MSGNUM ); // command cError = SendByte ( cError, DATA, 0x04 ); // 4 extra data bytes (7 total) cError = SendByte ( cError, DATA, cAddress ); // card address cError = SendByte ( cError, DATA, cData0 ); // data cError = SendByte ( cError, DATA, cData1 ); cError = SendByte ( cError, DATA, cData2 ); cError = SendByte ( cError, DATA, cData3 ); } while ( cError == YES ); // repeat if message was corrupted } char SendByte ( char cError, char cCommand, char cData ) { char cX; if ( cError != YES ) { cError = SendBit ( HIGH ); // start bit (0V) for ( cX = 0; cX < 8; cX++ ) { cError = SendBit ( ~cData & 0x01 ); // LSB data bit cData >>= 1; // shift right } cError = SendBit ( cCommand ? LOW : HIGH ); // set if command byte, clear if data byte cError = SendBit ( LOW ); // stop bit (+12V) } return ( cError ); } char SendBit ( cBit ) { char cX, cY; // this code adjusted to give 208uS bit times (4800 baud) TX_OUT = cBit; // send bit to output for ( cX = 0; cX < 8; cX++ ) { delay_us ( 14 ); if ( RX_IN == !cBit ) // check if output bit is corrupted by another talker { return ( HIGH ); // return collision error } } return ( LOW ); // return no error } void CheckBus ( void ) { char cX; for ( cX = 0; cX < 255; cX++ ) // assumes output is floating to +12V for ~5mS { if ( RX_IN == HIGH ) // check if output bit is corrupted by another talker { cX = 0; // reset count to zero restart_wdt(); // CCS compiler doesn't put CLRWDT into short delay_us, apparently } delay_us ( 7 ); } }