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

这次介绍如何在 uC/OS-II 上实现串口驱动。

 

/*sci_ucos.h*/

#ifndef _SCI_RTOS_H_

 

#define _SCI_RTOS_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             */

/* ********************************************************************************************************* *                                               CONSTANTS ********************************************************************************************************* */

#ifndef  NUL #define  NUL                 0x00 #endif

/* ERROR CODES                                        */ #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.                         */ #define  SCI_RX_TIMEOUT        5                /* If a timeout occurred while waiting for a character*/ #define  SCI_TX_TIMEOUT        6                /* If a timeout occurred while waiting to send a char.*/

#define  SCI_PARITY_NONE       0                /* Defines for setting parity                         */ #define  SCI_PARITY_ODD        1 #define  SCI_PARITY_EVEN       2

/* ********************************************************************************************************* *                                               DATA TYPES ********************************************************************************************************* */ typedef struct {     short  RingBufRxCtr;                            /* Number of characters in the Rx ring buffer              */     OS_EVENT  *RingBufRxSem;                        /* Pointer to Rx semaphore                                 */     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              */     OS_EVENT  *RingBufTxSem;                        /* Pointer to Tx semaphore                                 */     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;

/**  * To obtain a character from the communications channel.  * @param port, port can be SCI0 / SCI1  * @param to,   is the amount of time (in clock ticks) that the calling function is willing to  *             wait for a character to arrive.  If you specify a timeout of 0, the function will  *             wait forever for a character to arrive.  * @param err,  is a pointer to where an error code will be placed:  *               *err is set to SCI_NO_ERR     if a character has been received  *               *err is set to SCI_RX_TIMEOUT if a timeout occurred  *               *err is set to SCI_BAD_CH     if you specify an invalid channel number  * @return  The character in the buffer (or NUL if a timeout occurred)        */ unsigned char  SCIGetCharB (unsigned char ch, unsigned short to, unsigned char *err);

 /**  * This function is called by your application to send a character on the communications  * channel.  The function will wait for the buffer to empty out if the buffer is full.  * The function returns to your application if the buffer doesn't empty within the specified  * timeout.  A timeout value of 0 means that the calling function will wait forever for the  * buffer to empty out.  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.  *  * @param port, port can be SCI0 / SCI1  * @param c     is the character to send.  * @param to    is the timeout (in clock ticks) to wait in case the buffer is full.  If you  *              specify a timeout of 0, the function will wait forever for the buffer to empty.  * @return      SCI_NO_ERR      if the character was placed in the Tx buffer  *              SCI_TX_TIMEOUT  if the buffer didn't empty within the specified timeout period  *              SCI_BAD_CH      if you specify an invalid channel number  */ unsigned char SCIPutCharB (unsigned char port, unsigned char c, unsigned short to);

/**  * 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

 

/**  * SCI(Serial Communication Interface)  Buffered Serial I/O     * @file sci_ucos.c  * @author Li Yuan  * @platform mc9s12XX  * @date 2012-7-22  * @version 1.0.1  */

#include "derivative.h"      /* derivative-specific definitions */ #include #include "includes.H" #include "sci.h" #include "sci_rtos.h"

/**  *       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 to,   is the amount of time (in clock ticks) that the calling function is willing to  *             wait for a character to arrive.  If you specify a timeout of 0, the function will  *             wait forever for a character to arrive.  * @param err,  is a pointer to where an error code will be placed:  *               *err is set to SCI_NO_ERR     if a character has been received  *               *err is set to SCI_RX_TIMEOUT if a timeout occurred  *               *err is set to SCI_BAD_CH     if you specify an invalid channel number  * @return  The character in the buffer (or NUL if a timeout occurred)        */ unsigned char  SCIGetCharB (unsigned char port, unsigned short to, INT8U *err) { #if OS_CRITICAL_METHOD == 3u                           /* Allocate storage for CPU status register     */     OS_CPU_SR  cpu_sr = 0u; #endif     unsigned char c;     unsigned char oserr;     SCI_RING_BUF *pbuf;

    switch (port)     {                                          /* Obtain pointer to communications channel */         case SCI0:              pbuf = &SCI0Buf;              break;

        case SCI1:              pbuf = &SCI1Buf;              break;

        default:              *err = SCI_BAD_CH;              return (0);     }     OSSemPend(pbuf->RingBufRxSem, to, &oserr);             /* Wait for character to arrive             */         if (oserr == OS_TIMEOUT)     {                                                      /* See if characters received within timeout*/         *err = SCI_RX_TIMEOUT;                            /* No, return error code                    */         return (NUL);     }     else     {         OS_ENTER_CRITICAL();         pbuf->RingBufRxCtr--;                              /* Yes, decrement character count           */         c = *pbuf->RingBufRxOutPtr++;                      /* Get character from buffer                */         if (pbuf->RingBufRxOutPtr == &pbuf->RingBufRx[SCI_RX_BUF_SIZE]) {     /* Wrap OUT pointer     */             pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0];         }         OS_EXIT_CRITICAL();         *err = SCI_NO_ERR;         return (c);     } }

 /**  * This function is called by your application to send a character on the communications  * channel.  The function will wait for the buffer to empty out if the buffer is full.  * The function returns to your application if the buffer doesn't empty within the specified  * timeout.  A timeout value of 0 means that the calling function will wait forever for the  * buffer to empty out.  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.  *  * @param port, port can be SCI0 / SCI1  * @param c     is the character to send.  * @param to    is the timeout (in clock ticks) to wait in case the buffer is full.  If you  *              specify a timeout of 0, the function will wait forever for the buffer to empty.  * @return      SCI_NO_ERR      if the character was placed in the Tx buffer  *              SCI_TX_TIMEOUT  if the buffer didn't empty within the specified timeout period  *              SCI_BAD_CH      if you specify an invalid channel number  */ unsigned char SCIPutCharB (unsigned char port, unsigned char c, unsigned short to) { #if OS_CRITICAL_METHOD == 3u                              /* Allocate storage for CPU status register */     OS_CPU_SR  cpu_sr = 0u; #endif

    SCI_RING_BUF *pbuf;     unsigned char oserr;     switch (port)     {                                                     /* Obtain pointer to communications channel */         case SCI0:              pbuf = &SCI0Buf;              break;

        case SCI1:              pbuf = &SCI1Buf;              break;

        default:              return (SCI_BAD_CH);     }

    OSSemPend(pbuf->RingBufTxSem, to, &oserr);             /* Wait for space in Tx buffer              */     if (oserr == OS_TIMEOUT)     {         return (SCI_TX_TIMEOUT);                           /* Timed out, return error code             */     }     OS_ENTER_CRITICAL();     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();     return (SCI_NO_ERR); }

/**  * To initialize the communications module.  * You must call this function before calling any other functions.  */ void  SCIBufferInit (void) {     SCI_RING_BUF *pbuf;

    pbuf                  = &SCI0Buf;                      /* Initialize the ring buffer for SCI0     */     pbuf->RingBufRxCtr    = 0;     pbuf->RingBufRxInPtr  = &pbuf->RingBufRx[0];     pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0];     pbuf->RingBufRxSem    = OSSemCreate(0);     pbuf->RingBufTxCtr    = 0;     pbuf->RingBufTxInPtr  = &pbuf->RingBufTx[0];     pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0];     pbuf->RingBufTxSem    = OSSemCreate(SCI_TX_BUF_SIZE);

    pbuf                  = &SCI1Buf;                     /* Initialize the ring buffer for SCI1     */     pbuf->RingBufRxCtr    = 0;     pbuf->RingBufRxInPtr  = &pbuf->RingBufRx[0];     pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0];     pbuf->RingBufRxSem    = OSSemCreate(0);     pbuf->RingBufTxCtr    = 0;     pbuf->RingBufTxInPtr  = &pbuf->RingBufTx[0];     pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0];     pbuf->RingBufTxSem    = OSSemCreate(SCI_TX_BUF_SIZE); }

/**  * 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) {

#if OS_CRITICAL_METHOD == 3u                           /* Allocate storage for CPU status register     */     OS_CPU_SR  cpu_sr = 0u; #endif     unsigned char empty;     SCI_RING_BUF *pbuf;     switch (port)     {                                                     /* Obtain pointer to communications channel */         case SCI0:              pbuf = &SCI0Buf;              break;

        case SCI1:              pbuf = &SCI1Buf;              break;         default:              return (0xff);              break;     }     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) { #if OS_CRITICAL_METHOD == 3u                           /* Allocate storage for CPU status register     */     OS_CPU_SR  cpu_sr = 0u; #endif     char full;     SCI_RING_BUF *pbuf;     switch (port)     {                                                     /* Obtain pointer to communications channel */         case SCI0:              pbuf = &SCI0Buf;              break;

        case SCI1:              pbuf = &SCI1Buf;              break;

        default:              return (255);     }     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;

    switch (port)     {                                                     /* Obtain pointer to communications channel */         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];         }         (void)OSSemPost(pbuf->RingBufRxSem);               /* Indicate that character was received     */     } }

// 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)     {                                          /* Obtain pointer to communications channel */         case SCI0:              pbuf = &SCI0Buf;              break;

        case SCI1:              pbuf = &SCI1Buf;              break;

        default:              *err = SCI_BAD_CH;              return (0);     }     if (pbuf->RingBufTxCtr > 0) {                          /* See if buffer is empty                   */         pbuf->RingBufTxCtr--;                              /* No, decrement character count            */         c = *pbuf->RingBufTxOutPtr++;                      /* Get character from buffer                */         if (pbuf->RingBufTxOutPtr == &pbuf->RingBufTx[SCI_TX_BUF_SIZE]) {     /* Wrap OUT pointer     */             pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0];         }         (void)OSSemPost(pbuf->RingBufTxSem);               /* Indicate that character will be sent     */         *err = SCI_NO_ERR;         return (c);                                        /* Characters are still available           */     } else {         *err = SCI_TX_EMPTY;         return (NUL);                                      /* Buffer is empty                          */     } }

void SCI0_ISR_Handler(void) {     char status;     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                            SCIDisTxInt(SCI0);         }         else         {             SCI0DRL = data;        // Yes, Send character                             }                                               }     }

void SCI1_ISR_Handler (void) {     char status;     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                            SCIDisTxInt(SCI1);         }         else         {             SCI1DRL = data;        // Yes, Send character                             }                                               } }

 

#pragma CODE_SEG NON_BANKED interrupt VectorNumber_Vsci0 void SCI0_ISR(void) {

#if defined( __BANKED__) || defined(__LARGE__) || defined(__PPAGE__)     __asm ldaa   PPAGE;           //  3~, Get current value of PPAGE register                                    __asm psha;                   //  2~, Push PPAGE register onto current task's stack #endif          __asm inc OSIntNesting;      //OSIntNesting++;

    //if (OSIntNesting == 1)     //{     //    OSTCBCur->OSTCBStkPtr = Stack Pointer ;     //}     __asm     {       ldab OSIntNesting                 cmpb #$01                        bne SCI0ISR1       

      ldx OSTCBCur                 sts 0, x   SCI0ISR1:                                                         }

#if defined( __BANKED__) || defined(__LARGE__) || defined(__PPAGE__)        __asm call SCI0_ISR_Handler;     __asm call OSIntExit;   #else     __asm jsr SCI0_ISR_Handler;       __asm jsr OSIntExit; #endif 

#if defined( __BANKED__) || defined(__LARGE__) || defined(__PPAGE__)     __asm pula;                   // 3~, Get value of PPAGE register     __asm staa PPAGE;             // 3~, Store into CPU's PPAGE register                                #endif

}   

interrupt VectorNumber_Vsci1 void SCI1_ISR(void) {

#if defined( __BANKED__) || defined(__LARGE__) || defined(__PPAGE__)     __asm ldaa   PPAGE;           //  3~, Get current value of PPAGE register                                    __asm psha;                   //  2~, Push PPAGE register onto current task's stack #endif          __asm inc OSIntNesting;      //OSIntNesting++;

    //if (OSIntNesting == 1)     //{     //    OSTCBCur->OSTCBStkPtr = Stack Pointer ;     //}     __asm     {       ldab OSIntNesting                 cmpb #$01                        bne SCI1ISR1       

      ldx OSTCBCur                 sts 0, x   SCI1ISR1:                                                         }

#if defined( __BANKED__) || defined(__LARGE__) || defined(__PPAGE__)        __asm call SCI1_ISR_Handler;     __asm call OSIntExit;   #else     __asm jsr SCI1_ISR_Handler;       __asm jsr OSIntExit; #endif

#if defined( __BANKED__) || defined(__LARGE__) || defined(__PPAGE__)     __asm pula;                   // 3~, Get value of PPAGE register     __asm staa PPAGE;             // 3~, Store into CPU's PPAGE register                                #endif

 

下面给个简单的例子:

#include       /* common defines and macros */ #include "derivative.h"      /* derivative-specific definitions */

#include  "INCLUDES.H" #include  "crg.h" #include  "sci.h" #include  "sci_rtos.h"

OS_STK  AppStartTaskStk[64];

static void  AppStartTask (void *pdata);

void main(void) {     /* put your own code here */     OS_CPU_SR cpu_sr;

    CRGInit();     CRGSetRTIFreqency(0x54);  // 200Hz

    EnableInterrupts;         OS_ENTER_CRITICAL() ;     SCIInit(SCI0) ;     SCIInit(SCI1) ;     OS_EXIT_CRITICAL() ;         OSInit();          SCISetIEBit(SCI0, SCI_RIE) ;     SCISetIEBit(SCI1, SCI_RIE) ;     SCIBufferInit();         (void) OSTaskCreate(AppStartTask, (void *)0x4321, (void *)&AppStartTaskStk[63], 0);     (void)OSStart();         for(;;)     {         _FEED_COP(); /* feeds the dog */     } /* loop forever */         /* please make sure that you never leave main */ }

static void  AppStartTask (void *pdata) {     INT8U err;     char C;     (void) pdata;     for(;;)     {         C = SCIGetCharB(SCI1, 0, &err);         if(err == SCI_NO_ERR)        (void) SCIPutCharB (SCI1, C, 0);     } }

 


 

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