/************************************************************************* LEVELR.C This program is level sensor. It transmits in a variant of 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 | 14 ---------- | | | |-6--- in from Seatalk (transistor buffer) | | | |-13-- LCD D4 | 16F628 |-12-- LCD D3 | |-11-- LCD D2 | |-10-- LCD D1 | |-9--- LCD EN 8MHz XTAL-15-| |-8--- LCD RS XTAL-16-| | ---------- 5 | Gnd ***************************************************************************/ /* The following include should contain 16F84 or 16F628. */ #include < 16F628.h > #include < jonsinc.h > #fuses HS, NOPROTECT, NOPUT, NOWDT, BROWNOUT, MCLR, NOLVP // LCD STUFF #define LCD_D7 PIN_B7 #define LCD_D6 PIN_B6 #define LCD_D5 PIN_B5 #define LCD_D4 PIN_B4 #define LCD_EN PIN_B3 #define LCD_RS PIN_B2 #define FIRST_LINE 0x00 #define SECOND_LINE 0x40 #define THIRD_LINE 0x10 #define FOURTH_LINE 0x50 #define CLEAR_DISP 0x01 #define CURS_ON 0x0e #define CURS_OFF 0x0c #define NINTH_BIT 7 #define SEATALK_MSGNUM 0xFE #define NUL 0 #use delay ( clock = 8000000 ) #use standard_io ( B ) #use standard_io ( A ) #use rs232 ( BAUD = 4800, RCV = PIN_B0, BITS = 9, ERRORS ) // proto statements void LCD_Init ( void ); void LCD_SetPosition ( unsigned int cX ); void LCD_PutChar ( unsigned int cX ); void LCD_PutCmd ( unsigned int cX ); void LCD_PulseEnable ( void ); void LCD_SetData ( unsigned int cX ); //***************************************************************** // MAIN CODE void main ( void ) { char cCmd, cCnt, cAdr, cLevel, cError; // INITIAL MESSAGE delay_ms ( 200 ); // wait enough time after Vdd rise LCD_Init(); LCD_PutCmd ( CLEAR_DISP ); LCD_SetPosition ( FIRST_LINE + 0 ); printf ( LCD_PutChar, "TANK LEVELS" ); LCD_SetPosition ( SECOND_LINE + 0 ); printf ( LCD_PutChar, "Water 1" ); LCD_SetPosition ( THIRD_LINE + 0 ); printf ( LCD_PutChar, "Water 2" ); LCD_SetPosition ( FOURTH_LINE + 0 ); printf ( LCD_PutChar, "Waste" ); while ( TRUE ) { cCmd = NUL; while ( cCmd != SEATALK_MSGNUM ) { cCmd = getc(); } if ( ( bit_test ( rs232_errors, NINTH_BIT ) == HIGH ) ) { cCnt = getc(); // get count bit if ( ( bit_test ( rs232_errors, NINTH_BIT ) == HIGH ) ) { cError = YES; // should not have received a command byte here } if ( cCnt != 0x01 ) { cError = YES; // count should have been 01 } cAdr = getc(); // get address bit if ( ( bit_test ( rs232_errors, NINTH_BIT ) == HIGH ) ) { cError = YES; // should not have received a command byte here } cLevel = getc(); // get level bit if ( ( bit_test ( rs232_errors, NINTH_BIT ) == HIGH ) ) { cError = YES; // should not have received a command byte here } switch ( cAdr & 0x03 ) // mask on address bits 0 & 1 { case 0x00: { LCD_SetPosition ( SECOND_LINE + 8 ); break; } case 0x01: { LCD_SetPosition ( THIRD_LINE + 8 ); break; } case 0x02: { LCD_SetPosition ( FOURTH_LINE + 8 ); break; } case 0x03: { // error } } printf ( LCD_PutChar, "%3u%%", cLevel ); } } } //***************************************************************************** void LCD_Init ( void ) { LCD_SetData ( 0x00 ); 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 } 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(); } void LCD_PutChar ( unsigned int cX ) { // this subroutine works specifically for 4-bit Port A 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 ); } 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(); } void LCD_PulseEnable ( void ) { output_high ( LCD_EN ); delay_us ( 10 ); output_low ( LCD_EN ); delay_ms ( 5 ); } void LCD_SetData ( unsigned int cX ) { output_bit ( LCD_D4, cX & 0x01 ); output_bit ( LCD_D5, cX & 0x02 ); output_bit ( LCD_D6, cX & 0x04 ); output_bit ( LCD_D7, cX & 0x08 ); }