Functions | |
uns8 | bin2Hex (uns8 x) |
uns8 | even_7bit_parity (uns8 in) |
Change 7th bit (MSB) to give even parity. | |
uns8 | odd_7bit_parity (uns8 in) |
Change 7th bit (MSB) to give od parity. | |
uns8 | serial_getc (void) |
Retrieve a character from the serial port. | |
void | serial_print_int (uns16 i) |
Print a 16 bit number to the serial port. | |
void | serial_print_int_hex (uns8 i) |
Print an 8 bit number in hex to the serial port. | |
void | serial_print_int_hex_16bit (uns16 i) |
Print a 16 bit number in hex to the serial port. | |
void | serial_print_nl () |
Print a newline. | |
void | serial_print_spc () |
Print a space. | |
void | serial_print_str (rom char *str) |
void | serial_print_str (char *str) |
Print a string out to the serial port. | |
void | serial_print_var (char *str, uns16 i) |
void | serial_putc (uns8 c) |
Transmit a single character. | |
uns8 | serial_rx_avail () |
Tests if the serial rx fifo has a character available. | |
void | serial_rx_isr () |
Serial receive interrupt service routine. | |
void | serial_setup (uns8 req_spbrg) |
Configure the pic for serial communicaitons. | |
uns8 | serial_tx_empty () |
Tests if the serial tx fifo is empty. | |
void | serial_tx_isr () |
Serial transmit interrupt service routine. | |
Variables | |
uns8 | rx_buffer [SERIAL_RX_BUFFER_SIZE] |
uns8 | rx_end = 0 |
uns8 | rx_start = 0 |
uns8 | tx_buffer [SERIAL_TX_BUFFER_SIZE] |
uns8 | tx_end = 0 |
uns8 | tx_start = 0 |
uns8 bin2Hex | ( | uns8 | x | ) | [inline] |
uns8 even_7bit_parity | ( | uns8 | in | ) |
00063 { 00064 00065 uns8 t; 00066 00067 //return ((((((in)^(((in)<<4)|((in)>>4)))+0x41)|0x7C)+2)&0x80); 00068 00069 00070 asm { 00071 00072 bcf _in,7 ;assume the parity is even 00073 ;Note: for odd parity, use bsf 00074 ; assume the bits in byte_to_send are abcdefgh 00075 00076 swapf _in,W ;W = efghabcd 00077 xorwf _in,W ;W = ea.fb.gc.hd.ea.fb.gc.hd 00078 ; where ea means e^a, etc 00079 movwf _t ; 00080 rlf _t,F ;t = fb.gc.hd.ea.fb.gc.hd.?? 00081 rlf _t,F ;t = gc.hd.ea.fb.gc.hd.??.ea 00082 xorwf _t,F ;t = gcea.hdfb.gcea.hdfb.gcea.?.? 00083 ;again, gcea means g^c^e^a 00084 rlf _t,W ;w = hdfb.gcea.hdfb.gcea.hdfb.?.fb 00085 xorwf _t,W ;w = abcdefgh.abcdefgh..... 00086 ;ie, the upper 5-bits of w each contain 00087 ;the parity calculation. 00088 andlw 0x80 ;We only need one of them 00089 bcf _in,7 ;set bit 7 to 0 in preparation for or-ing with our result 00090 iorwf _in,F ;copy it to the MSB of the byte to send. 00091 00092 } 00093 return in; 00094 00095 00096 }
uns8 odd_7bit_parity | ( | uns8 | in | ) |
00100 { 00101 00102 uns8 t; 00103 00104 asm { 00105 bsf _in,7 ;assume the parity is odd 00106 00107 ; assume the bits in "in" are abcdefgh 00108 00109 swapf _in,W ;W = efghabcd 00110 xorwf _in,W ;W = ea.fb.gc.hd.ea.fb.gc.hd 00111 ; where ea means e^a, etc 00112 movwf _t ; 00113 rlf _t,F ;t = fb.gc.hd.ea.fb.gc.hd.?? 00114 rlf _t,F ;t = gc.hd.ea.fb.gc.hd.??.ea 00115 xorwf _t,F ;t = gcea.hdfb.gcea.hdfb.gcea.?.? 00116 ;again, gcea means g^c^e^a 00117 rlf _t,W ;w = hdfb.gcea.hdfb.gcea.hdfb.?.fb 00118 xorwf _t,W ;w = abcdefgh.abcdefgh..... 00119 ;ie, the upper 5-bits of w each contain 00120 ;the parity calculation. 00121 andlw 0x80 ;We only need one of them 00122 bcf _in,7 ;set bit 7 to 0 in preparation for or-ing with our result 00123 iorwf _in,F ;copy it to the MSB of the byte to send. 00124 } 00125 return in; 00126 }
uns8 serial_getc | ( | void | ) |
Retrieve character from the serial port. Note that if there is nothing in the fifo, this function will wait until a character is received - and this will never happen if interrupts are turned off when this is called! So, be careful not to call getc during a critical section or during an ISR unless* you're sure there's something in the fifo. You can do this by calling the serial_rx_avail() routine. In any other situation, you can call getc() and happily wait for a character to arrive.
00341 { 00342 uns8 rx_char, rx_next; 00343 00344 while(rx_end == rx_start); // wait until there is something received 00345 00346 start_crit_sec(); // make sure nobody else can muck with the buffer 00347 00348 rx_char = rx_buffer[rx_start]; // get character from the front of the buffer 00349 rx_start++; // increment fifo start 00350 if (rx_start == SERIAL_RX_BUFFER_SIZE) { // if we're at the end 00351 rx_start = 0; // then wrap to the beginning 00352 } 00353 00354 end_crit_sec(); // now they can muck with the buffer 00355 00356 return (rx_char); // return the result we first thought of 00357 00358 } // -- getc
void serial_print_int | ( | uns16 | i | ) |
Print a 16 bit unsigned number in decimal to the serial port
i | the 16 bit number to be printed |
00386 { 00387 00388 char buffer[6]; // up to 5 characters plus \0 00389 uns8 count = 5; 00390 buffer[5] = '\0'; 00391 do { 00392 count--; 00393 buffer[count] = '0' + i % 10; 00394 i = i / 10; 00395 } while (i > 0); 00396 while (buffer[count]) { 00397 serial_putc(buffer[count]); 00398 count++; 00399 } 00400 //serial_print_str(&buffer[count]); // print it out 00401 // for(count = 0 ; str[count] != 0; count++) 00402 // { 00403 // } 00404 00405 }
void serial_print_int_hex | ( | uns8 | i | ) |
Print a 8 bit unsigned number in hex to the serial port
i | 8 bit number to be printed |
00407 { 00408 00409 serial_putc(bin2Hex(i >> 4)); 00410 serial_putc(bin2Hex((i & 0x0f))); 00411 00412 }
void serial_print_int_hex_16bit | ( | uns16 | i | ) |
Print a 16 bit unsigned number in hex to the serial port
i | 16 bit number to be printed |
00414 { 00415 serial_print_int_hex(i >> 8); 00416 serial_print_int_hex(i & 0xff); 00417 }
void serial_print_nl | ( | ) |
Print a new line out the serial port - if you do this often, this routine can be used to save a couple of instructions. Always helps!
00425 { 00426 serial_putc('\n'); 00427 }
void serial_print_spc | ( | ) |
Print a space out the serial port - if you do this often, this routine can be used to save a couple of instructions. Always helps!
00420 { 00421 serial_putc(' '); 00422 }
void serial_print_str | ( | rom char * | str | ) |
00374 { 00375 00376 uns8 count; 00377 00378 for(count = 0 ; str[count] != 0; count++) 00379 { 00380 serial_putc(str[count]); 00381 } 00382 }
void serial_print_str | ( | char * | str | ) |
Send a null terminated string out the serial port
str | the string to be sent |
00362 { 00363 00364 uns8 count; 00365 00366 for(count = 0 ; str[count] != 0; count++) 00367 { 00368 serial_putc(str[count]); 00369 } 00370 }
void serial_print_var | ( | char * | str, | |
uns16 | i | |||
) |
00429 { 00430 serial_print_str(str); 00431 serial_print_int(i); 00432 serial_print_nl(); 00433 }
void serial_putc | ( | uns8 | c | ) |
Sends a single character out the serial connection. It is sent straight out if possible, otherwise put into the fifo. Note that if you fill the fifo while interrupts are off (eg, in an interrupt routine or a critical section) then this routine will hang the pic, since it's waiting for an interrupt to clear the fifo, which never comes... The moral is to keep your fifo big enough or don't send too much while interrupts are off (eg, in an interrupt response routine). Of course, you *can* send things in an ISR - just don't fill the fifo up.
c | the character to transmit |
00237 { 00238 uns8 tx_next; 00239 bit my_store_gie; 00240 #ifdef SERIAL_IDE_DEBUG 00241 return; 00242 #endif 00243 00244 if ((tx_end == tx_start) && // Nothing in the fifo 00245 test_bit(pir1, TXIF)) { // And txreg is empty 00246 txreg = c; // then no need for fifo, just send straight out 00247 } else { // else put it in the fifo 00248 tx_next = tx_end + 1; // get next buffer position 00249 if (tx_next == SERIAL_TX_BUFFER_SIZE) { // if we're at the end 00250 tx_next = 0; // wrap to the beginning 00251 } 00252 #ifdef SERIAL_DISCARD_ON_TX_FULL_DURING_INT 00253 if ((!intcon.GIE) && (tx_next == tx_start)) { 00254 return; 00255 } 00256 #endif 00257 while (tx_next == tx_start) { // wait for clearing 00258 // Note, if buffer is full 00259 // this will wait for ever 00260 // if interrupts are disabled! 00261 #ifndef SERIAL_DISCARD_ON_TX_FULL_DURING_INT 00262 if (!intcon.GIE) { // we're in an interrupt 00263 serial_handle_tx_isr(); // so handle it ourselves 00264 } 00265 #endif 00266 } 00267 my_store_gie = intcon.GIE; // store interrupt state 00268 kill_interrupts(); // turn off global interrupts 00269 00270 tx_buffer[tx_end] = c; // put it in 00271 tx_end = tx_next; // move pointer along 00272 00273 set_bit(pie1, TXIE); // turn on interrupt for transmitting 00274 intcon.GIE = my_store_gie; // restore interrupt state 00275 } // -- else put it in the fifo 00276 }
uns8 serial_rx_avail | ( | void | ) |
Tests to see if the serial receive fifo has a character available. Useful to call before getc() if interrupts are not enabled in that section of code.
void serial_rx_isr | ( | void | ) |
This routine needs to be called from your interrupt() routine when the receive hardware interrupt occurs in order to put received bytes into the fifo buffer.
00301 { 00302 uns8 rx_next; 00303 00304 00305 if (test_bit(rcsta, OERR)) { // overrun error? 00306 clear_bit(rcsta, CREN); // clear error 00307 _asm { 00308 MOVF _rcreg,W // clear any received characters 00309 MOVF _rcreg,W 00310 MOVF _rcreg,W 00311 } 00312 #ifdef SERIAL_DEBUG 00313 rx_hard_overflow++; // increment error count if in debug mode 00314 #endif 00315 set_bit(rcsta, CREN); // reset error indicator 00316 } else { 00317 if (test_bit(rcsta, FERR)) { // framing error? 00318 #ifdef SERIAL_DEBUG 00319 rx_framing_error++; // increment error count if in debug mode 00320 #endif 00321 } 00322 rx_next = rx_end + 1; // get next buffer position 00323 if (rx_next == SERIAL_RX_BUFFER_SIZE) { // if we're at the end 00324 rx_next = 0; // then wrap to the beginning 00325 } 00326 if (rx_next != rx_start) { // if space in the fifo 00327 rx_buffer[rx_end] = rcreg; // put it in 00328 rx_end = rx_next; // and move pointer along 00329 } else { // else, there isn't space 00330 _asm MOVF _rcreg,W // and just clear it, we've lost it 00331 #ifdef SERIAL_DEBUG 00332 rx_soft_overflow++; // increment error count if in debug mode 00333 #endif 00334 } // -- no space in the fifo 00335 } // -- no overrun error 00336 } // -- serial_load_rx
void serial_setup | ( | uns8 | req_spbrg | ) |
Configures the pic and gets ready for interrupt-driven serial communications. Includes setting the tris bits appropriately, and getting the baud rate generator set up. After calling this you can immediately start sending and receiving bytes.
brgh | See sprg defines earlier in pic_serial.h |
00143 { 00144 #ifdef _PIC16F88 00145 set_bit(trisb, 5); 00146 set_bit(trisb, 2); 00147 #define TRIS_SET 00148 #endif 00149 #ifdef _PIC16F876A 00150 set_bit(trisc,6); 00151 set_bit(trisc,7); 00152 #define TRIS_SET 00153 #endif 00154 #ifdef _PIC18F2620 00155 set_bit(trisc,6); 00156 set_bit(trisc,7); 00157 #define TRIS_SET 00158 #endif 00159 #ifdef _PIC18F4520 00160 set_bit(trisc,6); 00161 set_bit(trisc,7); 00162 #define TRIS_SET 00163 #endif 00164 #ifdef _PIC18F4550 00165 set_bit(trisc,6); 00166 set_bit(trisc,7); 00167 #define TRIS_SET 00168 #endif 00169 #ifdef _PIC18F67J50 00170 clear_bit(trisc,6); 00171 set_bit(trisc,7); 00172 #define TRIS_SET 00173 #endif 00174 #ifdef _PIC18F25K20 00175 set_bit(trisc,6); 00176 set_bit(trisc,7); 00177 #define TRIS_SET 00178 #endif 00179 #ifdef _PIC18F26K20 00180 set_bit(trisc,6); 00181 set_bit(trisc,7); 00182 #define TRIS_SET 00183 #endif 00184 #ifdef _PIC18F14K50 00185 set_bit(trisb,5); 00186 #define TRIS_SET 00187 #endif 00188 #ifndef TRIS_SET 00189 #warning "You must set tris bits for serial use yourself, I don't know your pic" 00190 #warning "Please send your tris bits in so they can be included in the library" 00191 #endif 00192 00193 //kill_interrupts(); 00194 00195 00196 00197 txsta.BRGH = 1; // set baud rate generator (high/low speed) 00198 #ifdef BRG16_REQUIRED 00199 set_bit(baudcon, BRG16); 00200 spbrg = req_spbrg & 0xff; 00201 spbrgh = req_spbrg >> 8; 00202 #else 00203 spbrg = req_spbrg; // set serial port baud rate generator value 00204 #endif 00205 clear_bit(txsta, SYNC); // turn off syncronous reception 00206 set_bit(rcsta, SPEN); // enable serial port 00207 00208 // Configure tx 00209 00210 clear_bit(txsta, TX9); // Turn off 9 bit receiption 00211 clear_bit(txsta, TX9D); // Clear 9th bit data 00212 00213 set_bit(txsta, TXEN); // enable sending of serial data 00214 00215 // configure rx 00216 00217 clear_bit(rcsta, RX9); // disable 9 bit receiption 00218 clear_bit(rcsta, FERR); // clear any framing errors 00219 00220 _asm { // clear rcreg buffer 00221 MOVF _rcreg,W 00222 MOVF _rcreg,W 00223 MOVF _rcreg,W 00224 } 00225 00226 clear_bit(rcsta, CREN); 00227 set_bit(rcsta, CREN); // pulse low to clear any errors 00228 00229 set_bit(pie1, RCIE); // enable receive interrupt 00230 00231 }
uns8 serial_tx_empty | ( | void | ) |
void serial_tx_isr | ( | void | ) |
This routine needs to be called from your interrupt() routine when the transmit hardware interrupt occurs in order to send bytes that are waiting in the fifo buffer.
00281 { 00282 uns8 tx_next; 00283 00284 if (tx_end == tx_start) { // anything in the fifo? 00285 return; // nope 00286 } 00287 tx_next = tx_start + 1; // get next position 00288 if (tx_next == SERIAL_TX_BUFFER_SIZE) { // if we're at the end of the buffer 00289 tx_next = 0; // wrap to the beginning 00290 } 00291 if (tx_end == tx_next) { // if we've only got one character to send 00292 clear_bit(pie1, TXIE); // then turn off interrupts 00293 } 00294 txreg = tx_buffer[tx_start]; // transmit the character 00295 tx_start = tx_next; // move start position of fifo 00296 00297 } /* \ \ */
uns8 rx_buffer[SERIAL_RX_BUFFER_SIZE] |
Receive fifo
uns8 rx_end = 0 |
Receive fifo end point
uns8 rx_start = 0 |
Receive fifo start point
uns8 tx_buffer[SERIAL_TX_BUFFER_SIZE] |
Transmit fifo
uns8 tx_end = 0 |
Transmit fifo end point
uns8 tx_start = 0 |
Transmit fifo start point