Using CRC to detect errors on a byte basis doesn't make sense. CRC's are typically used on a multi-byte, or muti-word basis, sometimes referred to as a frame.
The math behind CRC's is based on polynomial division with binary coefficients. The raw message is the dividend, and the divisor is the generator, or CRC polynomial.
A good generator polynomial will 1) detect all single bit errors, 2) detect all double bit errors within a frame, 3) detect all odd number of errors, 4) detect all burst errors of length r or less, where r is the length of the CRC, 5) detect many burst errors of length >r, and 6) detects greater than 99.9% of all errors.
This being the case any of the many commonly used CRC polynomials (CRC-8, CRC-16, CRC-16, CRC-CCITT) will suffice for most applications - for any but the most impaired channels.
With CRC (as opposed to forward error correcting, FEC codes), your application needs be able to 1) live with a dropped message, or 2) have a means (handshake or acknowledge) to have the sender re-transmit a dropped message.
CRCs in Serial Comm
In serial communication links, a CRC can be generated using a Linear Feedback Shift Register (LFSR). The serial bit stream is fed into one end of the LFSR, clocked (or shifted through) and at the end of this process the output of the LFSR is the CRC. The diagram below shows this process at a high level:

The diagram below shows an implementation I used to send variable length messages composed of 16-bit words from one unit to another.

This is an implementation of the CRC16-CCITT CRC, 
A couple of words of caution, speaking from experience. Both ends of the communication link need to agree on the bit order (MSB or LSB first), initial value for the LFSR (all 0's or all 1's), whether or not data bits are reflected, and whether or not the CRC is complimented before it is appended to the message