这里给个利用串口收发中断的实现.
首先是头文件:
/* sci_buffered.h */
#ifndef _SCI_BUFFERED_H_ #define _SCI_BUFFERED_H_
#define SCI_RX_BUF_SIZE 64 /* Number of characters in Rx ring buffer */ #define SCI_TX_BUF_SIZE 64 /* Number of characters in Tx ring buffer */
#define SCI_NO_ERR 0 /* Function call was successful */ #define SCI_BAD_CH 1 /* Invalid communications port channel */ #define SCI_RX_EMPTY 2 /* Rx buffer is empty, no character available */ #define SCI_TX_FULL 3 /* Tx buffer is full, could not deposit character */ #define SCI_TX_EMPTY 4 /* If the Tx buffer is empty. */
/** * To obtain a character from the communications channel. * @param port, port can be SCI0 / SCI1 * @param err, is a pointer to where an error code will be placed: * *err is set to SCI_NO_ERR if a character is available * *err is set to SCI_RX_EMPTY if the Rx buffer is empty * *err is set to SCI_BAD_CH if you have specified an invalid channel * @return The received char if err == SCI_NO_ERR */ unsigned char SCIGetCharB (unsigned char port, unsigned char *err);
/** * To send a character on the communications channel. * The character to send is first inserted into the Tx buffer and will be sent by * the Tx ISR. If this is the first character placed into the buffer, the Tx ISR will be * enabled. If the Tx buffer is full, the character will not be sent (i.e. it will be lost) * * @param port, port can be SCI0 / SCI1 * @return COMM_NO_ERR if the function was successful (the buffer was not full) * COMM_TX_FULL if the buffer was full * COMM_BAD_CH if you have specified an incorrect channel */ unsigned char SCIPutCharB (unsigned char port, unsigned char c);
/** * To initialize the communications module. * You must call this function before calling any other functions. */ void SCIBufferInit (void);
/** * To see if any character is available from the communications channel. * * @param port, port can be SCI0 / SCI1 * @return If at least one character is available, the function returns * FALSE(0) otherwise, the function returns TRUE(1). */ unsigned char SCIBufferIsEmpty (unsigned char port);
/** * To see if any more characters can be placed in the Tx buffer. * In other words, this function check to see if the Tx buffer is full. * * @param port, port can be SCI0 / SCI1 * @return If the buffer is full, the function returns TRUE * otherwise, the function returns FALSE. */ unsigned char SCIBufferIsFull (unsigned char port);
#endif
然后 是 c 文件.
/** * SCI(Serial Communication Interface) Buffered Serial I/O * @file sci_buffered.c * @author Li Yuan * @platform mc9s12XX * @date 2012-7-22 * @version 1.0.1 */
#include "derivative.h" /* derivative-specific definitions */ #include
//#define OS_ENTER_CRITICAL() _asm ("pshc; sei") //#define OS_EXIT_CRITICAL() _asm ("pulc")
#define OS_ENTER_CRITICAL() _asm ("tpa; sei; staa cpu_sr") #define OS_EXIT_CRITICAL() _asm ("ldaa cpu_sr; tap")
/** * DATA TYPES */ typedef struct { short RingBufRxCtr; /* Number of characters in the Rx ring buffer */ unsigned char *RingBufRxInPtr; /* Pointer to where next character will be inserted */ unsigned char *RingBufRxOutPtr; /* Pointer from where next character will be extracted */ unsigned char RingBufRx[SCI_RX_BUF_SIZE]; /* Ring buffer character storage (Rx) */ short RingBufTxCtr; /* Number of characters in the Tx ring buffer */ unsigned char *RingBufTxInPtr; /* Pointer to where next character will be inserted */ unsigned char *RingBufTxOutPtr; /* Pointer from where next character will be extracted */ unsigned char RingBufTx[SCI_TX_BUF_SIZE]; /* Ring buffer character storage (Tx) */ } SCI_RING_BUF;
/** * GLOBAL VARIABLES */
SCI_RING_BUF SCI0Buf; SCI_RING_BUF SCI1Buf;
/** * To obtain a character from the communications channel. * @param port, port can be SCI0 / SCI1 * @param err, is a pointer to where an error code will be placed: * *err is set to SCI_NO_ERR if a character is available * *err is set to SCI_RX_EMPTY if the Rx buffer is empty * *err is set to SCI_BAD_CH if you have specified an invalid channel * @return The received char if err == SCI_NO_ERR */ unsigned char SCIGetCharB (unsigned char port, unsigned char *err) { unsigned char cpu_sr; unsigned char c; SCI_RING_BUF *pbuf; /* Obtain pointer to communications channel */ switch (port) { case SCI0: pbuf = &SCI0Buf; break;
case SCI1: pbuf = &SCI1Buf; break;
default: *err = SCI_BAD_CH; return (0); } OS_ENTER_CRITICAL(); if (pbuf->RingBufRxCtr > 0) /* See if buffer is empty */ { pbuf->RingBufRxCtr--; /* No, decrement character count */ c = *pbuf->RingBufRxOutPtr++; /* Get character from buffer */ if (pbuf->RingBufRxOutPtr == &pbuf->RingBufRx[SCI_RX_BUF_SIZE]) { pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0]; /* Wrap OUT pointer */ } OS_EXIT_CRITICAL(); *err = SCI_NO_ERR; return (c); } else { OS_EXIT_CRITICAL(); *err = SCI_RX_EMPTY; c = 0; /* Buffer is empty, return 0 */ return (c); } }
/** * To send a character on the communications channel. * The character to send is first inserted into the Tx buffer and will be sent by * the Tx ISR. If this is the first character placed into the buffer, the Tx ISR will be * enabled. If the Tx buffer is full, the character will not be sent (i.e. it will be lost) * * @param port, port can be SCI0 / SCI1 * @return COMM_NO_ERR if the function was successful (the buffer was not full) * COMM_TX_FULL if the buffer was full * COMM_BAD_CH if you have specified an incorrect channel */ unsigned char SCIPutCharB (unsigned char port, unsigned char c) { unsigned char cpu_sr; SCI_RING_BUF *pbuf; /* Obtain pointer to communications channel */ switch (port) { case SCI0: pbuf = &SCI0Buf; break;
case SCI1: pbuf = &SCI1Buf; break;
default: return (SCI_BAD_CH); }
OS_ENTER_CRITICAL(); if (pbuf->RingBufTxCtr < SCI_TX_BUF_SIZE)/* See if buffer is full */ { pbuf->RingBufTxCtr++; /* No, increment character count */ *pbuf->RingBufTxInPtr++ = c; /* Put character into buffer */ if (pbuf->RingBufTxInPtr == &pbuf->RingBufTx[SCI_TX_BUF_SIZE]) { pbuf->RingBufTxInPtr = &pbuf->RingBufTx[0]; /* Wrap IN pointer */ } if (pbuf->RingBufTxCtr == 1) { /* See if this is the first character */ SCIEnableTxInt(port); /* Yes, Enable Tx interrupts */ OS_EXIT_CRITICAL(); } else { OS_EXIT_CRITICAL(); } return (SCI_NO_ERR); } else { OS_EXIT_CRITICAL(); return (SCI_TX_FULL); } }
/** * To initialize the communications module. * You must call this function before calling any other functions. */ void SCIBufferInit (void) { SCI_RING_BUF *pbuf; /* Initialize the ring buffer for SCI0 */ pbuf = &SCI0Buf; pbuf->RingBufRxCtr = 0; pbuf->RingBufRxInPtr = &pbuf->RingBufRx[0]; pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0]; pbuf->RingBufTxCtr = 0; pbuf->RingBufTxInPtr = &pbuf->RingBufTx[0]; pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0]; /* Initialize the ring buffer for SCI1 */ pbuf = &SCI1Buf; pbuf->RingBufRxCtr = 0; pbuf->RingBufRxInPtr = &pbuf->RingBufRx[0]; pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0]; pbuf->RingBufTxCtr = 0; pbuf->RingBufTxInPtr = &pbuf->RingBufTx[0]; pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0]; }
/** * To see if any character is available from the communications channel. * * @param port, port can be SCI0 / SCI1 * @return If at least one character is available, the function returns * FALSE(0) otherwise, the function returns TRUE(1). */ unsigned char SCIBufferIsEmpty (unsigned char port) { unsigned char cpu_sr; unsigned char empty; SCI_RING_BUF *pbuf; /* Obtain pointer to communications channel */ switch (port) { case SCI0: pbuf = &SCI0Buf; break;
case SCI1: pbuf = &SCI1Buf; break;
default: return (1); } OS_ENTER_CRITICAL(); if (pbuf->RingBufRxCtr > 0) /* See if buffer is empty */ { empty = 0; /* Buffer is NOT empty */ } else { empty = 1; /* Buffer is empty */ } OS_EXIT_CRITICAL(); return (empty); }
/** * To see if any more characters can be placed in the Tx buffer. * In other words, this function check to see if the Tx buffer is full. * * @param port, port can be SCI0 / SCI1 * @return If the buffer is full, the function returns TRUE * otherwise, the function returns FALSE. */ unsigned char SCIBufferIsFull (unsigned char port) { unsigned char cpu_sr; char full; SCI_RING_BUF *pbuf; /* Obtain pointer to communications channel */ switch (port) { case SCI0: pbuf = &SCI0Buf; break;
case SCI1: pbuf = &SCI1Buf; break;
default: return (1); } OS_ENTER_CRITICAL(); if (pbuf->RingBufTxCtr < SCI_TX_BUF_SIZE) { /* See if buffer is full */ full = 0; /* Buffer is NOT full */ } else { full = 1; /* Buffer is full */ } OS_EXIT_CRITICAL(); return (full); }
// This function is called by the Rx ISR to insert a character into the receive ring buffer. static void SCIPutRxChar (unsigned char port, unsigned char c) { SCI_RING_BUF *pbuf; /* Obtain pointer to communications channel */ switch (port) { case SCI0: pbuf = &SCI0Buf; break;
case SCI1: pbuf = &SCI1Buf; break;
default: return; } if (pbuf->RingBufRxCtr < SCI_RX_BUF_SIZE) /* See if buffer is full */ { pbuf->RingBufRxCtr++; /* No, increment character count */ *pbuf->RingBufRxInPtr++ = c; /* Put character into buffer */ if (pbuf->RingBufRxInPtr == &pbuf->RingBufRx[SCI_RX_BUF_SIZE]) { /* Wrap IN pointer */ pbuf->RingBufRxInPtr = &pbuf->RingBufRx[0]; } } }
// This function is called by the Tx ISR to extract the next character from the Tx buffer. // The function returns FALSE if the buffer is empty after the character is extracted from // the buffer. This is done to signal the Tx ISR to disable interrupts because this is the // last character to send. static unsigned char SCIGetTxChar (unsigned char port, unsigned char *err) { unsigned char c; SCI_RING_BUF *pbuf;
switch (port) { case SCI0: pbuf = &SCI0Buf; break;
case SCI1: pbuf = &SCI1Buf; break;
default: *err = SCI_BAD_CH; return (0); } /* See if buffer is empty */ if (pbuf->RingBufTxCtr > 0) { pbuf->RingBufTxCtr--; /* No, decrement character count */ c = *pbuf->RingBufTxOutPtr++; /* Get character from buffer */ if (pbuf->RingBufTxOutPtr == &pbuf->RingBufTx[SCI_TX_BUF_SIZE]) { pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0]; /* Wrap OUT pointer */ } *err = SCI_NO_ERR; return (c); /* Characters are still available */ } else { *err = SCI_TX_EMPTY; return (0); /* Buffer is empty */ } }
interrupt VectorNumber_Vsci0 void SCI0_ISR(void) { char status; unsigned char data; unsigned char err; status = SCI0SR1; if(status & 0x0F) // 0x1F = 0001 1111, if status is not Receive Data Reg Full Flag { // See if we have some kind of error // Clear interrupt (do nothing about it!) data = SCI0DRL; } else if(status & 0x20) //Receive Data Reg Full Flag { data = SCI0DRL; SCIPutRxChar(SCI0, data); // Insert received character into buffer } else if(status & 0x80) { data = SCIGetTxChar(SCI0, &err); // Get next character to send. if (err == SCI_TX_EMPTY) { // Do we have anymore characters to send ? // No, Disable Tx interrupts SCI0CR2_SCTIE = 0; SCI0CR2_TCIE = 0; } else { SCI0DRL = data; // Yes, Send character } } }
interrupt VectorNumber_Vsci1 void SCI1_ISR(void) { char status; unsigned char data; unsigned char err; status = SCI1SR1; if(status & 0x0F) // 0x1F = 0001 1111, if status is not Receive Data Reg Full Flag { // See if we have some kind of error // Clear interrupt (do nothing about it!) data = SCI1DRL; } else if(status & 0x20) //Receive Data Reg Full Flag { data = SCI1DRL; SCIPutRxChar(SCI1, data); // Insert received character into buffer } else if(status & 0x80) { data = SCIGetTxChar(SCI1, &err); // Get next character to send. if (err == SCI_TX_EMPTY) { // Do we have anymore characters to send ? // No, Disable Tx interrupts SCI1CR2_SCTIE = 0; SCI1CR2_TCIE = 0; } else { SCI1DRL = data; // Yes, Send character } } }
最后给个例子说明用法:
#include /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */
#include "sci.h"
#include "sci_buffered.h"
void main(void) { /* put your own code here */ unsigned char C, err; long l = 0x1234L; int i = 0x5678; CRGInit (); SCIInit (SCI0); SCIInit (SCI1); SCIBufferInit(); SCISetIEBit (SCI0, SCI_RIE); SCISetIEBit (SCI1, SCI_RIE);
EnableInterrupts; SCIPutShortBigEndian (SCI1, i); SCIPutShortLittleEndian (SCI1, i); SCIPutLongBigEndian (SCI1, l); SCIPutLongLittleEndian (SCI1, l); for(;;) { _FEED_COP(); /* feeds the dog */ C = SCIGetCharB(SCI1, &err); if(err == SCI_NO_ERR) { SCIPutCharB(SCI1, C); } } /* loop forever */ /* please make sure that you never leave main */ }
例子很简单,就不多解释了。下一篇介绍在实时操作系统 uC/OS-II 上实现串口驱动。