Freescale 9S12 系列单片机应用笔记(SCI)2

这里给个利用串口收发中断的实现.

 

首先是头文件:

/* 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 #include "sci.h" #include "sci_buffered.h"

//#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 上实现串口驱动。

你可能感兴趣的:(嵌入式系统)