您的位置:首页 > 其它

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

2012-07-20 21:21 597 查看
这次介绍如何在 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 <stddef.h>
#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 <hidef.h>      /* 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);
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: