您的位置:首页 > 其它

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

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