A basic library for RS485 communication
Embed:
(wiki syntax)
Show/hide line numbers
RS485.cpp
00001 #include "RS485.h" 00002 #include <stdarg.h> 00003 00004 typedef unsigned int word; 00005 typedef uint8_t byte; 00006 typedef uint8_t boolean; 00007 typedef void (*voidFuncPtr)(void); 00008 Timer lapse; 00009 const byte STX = '\2'; 00010 const byte ETX = '\3'; 00011 00012 RS485::RS485(PinName tx, PinName rx, PinName dere) 00013 : BufferedSerial(tx, rx) 00014 { 00015 return; 00016 } 00017 00018 00019 byte RS485::crc8(const byte *addr, byte len) 00020 { 00021 byte crc = 0; 00022 while (len--) 00023 { 00024 byte inbyte = *addr++; 00025 for (byte i = 8; i; i--) 00026 { 00027 byte mix = (crc ^ inbyte) & 0x01; 00028 crc >>= 1; 00029 if (mix) 00030 crc ^= 0x8C; 00031 inbyte >>= 1; 00032 } // end of for 00033 } // end of while 00034 return crc; 00035 } // end of crc8 00036 00037 void RS485::sendComplemented( const byte what) 00038 { 00039 byte c ; 00040 // first nibble 00041 c = what >> 4; 00042 putc((c << 4) | (c ^ 0x0F)); 00043 00044 // second nibble 00045 c = what & 0x0F; 00046 putc((c << 4) | (c ^ 0x0F)); 00047 } // end of sendComplemented 00048 00049 00050 void RS485::sendMsg(const byte * data, const byte length) 00051 { 00052 putc(STX); // STX 00053 for (byte i = 0; i < length; i++) 00054 sendComplemented (data[i]); 00055 putc(ETX); // ETX 00056 sendComplemented(crc8(data, length)); 00057 } // end of sendMsg 00058 00059 // receive a message, maximum "length" bytes, timeout after "timeout" clock_mseconds 00060 // if nothing received, or an error (eg. bad CRC, bad data) return 0 00061 // otherwise, returns length of received data 00062 byte RS485::recvMsg (byte * data, // buffer to receive into 00063 const byte length, // maximum buffer size 00064 unsigned long timeout) // clock_mseconds before timing out 00065 { 00066 00067 unsigned long start_time = lapse.read_ms(); 00068 00069 bool have_stx = false; 00070 00071 // variables below are set when we get an STX 00072 bool have_etx; 00073 byte input_pos; 00074 bool first_nibble; 00075 byte current_byte; 00076 00077 while (lapse.read_ms() - start_time < timeout) 00078 { 00079 if (readable() > 0) 00080 { 00081 byte inByte = getc(); 00082 00083 switch (inByte) 00084 { 00085 00086 case STX: // start of text 00087 have_stx = true; 00088 have_etx = false; 00089 input_pos = 0; 00090 first_nibble = true; 00091 start_time = lapse.read_ms(); // reset timeout period 00092 break; 00093 00094 case ETX: // end of text 00095 have_etx = true; 00096 break; 00097 00098 default: 00099 // wait until packet officially starts 00100 if (!have_stx) 00101 break; 00102 00103 // check byte is in valid form (4 bits followed by 4 bits complemented) 00104 if ((inByte >> 4) != ((inByte & 0x0F) ^ 0x0F) ) 00105 return 0; // bad character 00106 00107 // convert back 00108 inByte >>= 4; 00109 00110 // high-order nibble? 00111 if (first_nibble) 00112 { 00113 current_byte = inByte; 00114 first_nibble = false; 00115 break; 00116 } // end of first nibble 00117 00118 // low-order nibble 00119 current_byte <<= 4; 00120 current_byte |= inByte; 00121 first_nibble = true; 00122 00123 // if we have the ETX this must be the CRC 00124 if (have_etx) 00125 { 00126 if (crc8 (data, input_pos) != current_byte) 00127 return 0; // bad crc 00128 return input_pos; // return received length 00129 } // end if have ETX already 00130 00131 // keep adding if not full 00132 if (input_pos < length) 00133 data [input_pos++] = current_byte; 00134 else 00135 return 0; // overflow 00136 break; 00137 00138 } // end of switch 00139 } // end of incoming data 00140 } // end of while not timed out 00141 00142 return 0; // timeout 00143 } // end of recvMsg
Generated on Tue Jul 12 2022 20:26:33 by
