MC9S12XEP100 SCI(UART)驱动程序2

来源:互联网 发布:powermill10软件下载 编辑:程序博客网 时间:2024/06/05 10:06

忙着毕设,很久没有写文章了,终于答辩完了,得了个校优秀毕业设计。毕设做的是个智能接口模块,用一周时间入门了MC9S12XEP100的开发,又用一周时间入门了uC/OS-II嵌入式操作系统,在做毕设的过程中学到了很多,现在把一些工具发上来分享。


首先先发一个自己封装的MC9S12XEP100的SCI模块(也就是UART模块)的驱动。这些代码参考了 Li Yuan http://blog.csdn.net/liyuanbhu/article/details/7764851 的代码,整个代码风格是按照uCOS-II操作系统源码的风格来写的,在此表示感谢。
目前还不是特别完整完善,但基本使用是没有问题了。
在上一章中已经发了硬件驱动部分,这里发下基于uCOS-II嵌入式操作系统的驱动部分以及顺便说下怎么用。
首先要记得到上一章中把两个文件存了,顺便还要把.h文件中的

SCI_UCOS_MODULE_ENABLE 后面改为 TRUE 以开启RTOS(嵌入式操作系统)驱动部分。

目前这个版本已经支持所有8个SCI口了。
首先是按照uCOS-II操作系统的要求写的中断服务程序。

;********************************************************************************************************;                                               uC/OS-II;                                         The Real-Time Kernel;;                         (c) Copyright 2002, Jean J. Labrosse, Weston, FL;                                          All Rights Reserved;;;                                       PAGED S12X Specific code;                                            (CODEWARRIOR);; File         : SCI_uCos.s; By           : Lin Shijun(http://blog.csdn.net/lin_strong);; Notes        : THIS FILE *MUST* BE LINKED INTO NON_BANKED MEMORY! 这个文件必须放在非分页内存中;                    modified according to uC/OS-II's example.  依据uC/OS-II的模版修改。;********************************************************************************************************NON_BANKED:       section;********************************************************************************************************;                                           I/O PORT ADDRESSES   I/O口地址;********************************************************************************************************PPAGE:            equ    $0015         ; Addres of PPAGE register (assuming MC9S12XEP100 part)RPAGE:            equ    $0016         ; Addres of RPAGE register (assuming MC9S12XEP100 part)EPAGE:            equ    $0017         ; Addres of EPAGE register (assuming MC9S12XEP100 part)GPAGE:            equ    $0010         ; Addres of GPAGE register (assuming MC9S12XEP100 part);********************************************************************************************************;                                          PUBLIC DECLARATIONS   公开声明;********************************************************************************************************    xdef   SCI0_RxTxISR    xdef   SCI1_RxTxISR    xdef   SCI2_RxTxISR    xdef   SCI3_RxTxISR    xdef   SCI4_RxTxISR    xdef   SCI5_RxTxISR    xdef   SCI6_RxTxISR    xdef   SCI7_RxTxISR;********************************************************************************************************;                                         EXTERNAL DECLARATIONS  外部声明;********************************************************************************************************    xref   OSIntExit    xref   OSIntNesting    xref   OSTCBCur    xref   SCI0_ISR_Handler    xref   SCI1_ISR_Handler    xref   SCI2_ISR_Handler    xref   SCI3_ISR_Handler    xref   SCI4_ISR_Handler    xref   SCI5_ISR_Handler    xref   SCI6_ISR_Handler    xref   SCI7_ISR_Handler;********************************************************************************************************;                                           SCI RxTx ISR;; Description : This routine is the uC/Probe RxTx interrupt service routine;; Arguments   : none;; Notes       : 1) All USER interrupts should be modeled EXACTLY like this where the only;                  line to be modified is the call to your ISR_Handler and perhaps the call to;                  the label name SCI0_ISR_Handler.;********************************************************************************************************SCI0_RxTxISR:    ldaa   GPAGE                       ; Get current value of GPAGE register    psha                               ; Push GPAGE register onto current task's stack    ldaa   EPAGE                       ; Get current value of EPAGE register    psha                               ; Push EPAGE register onto current task's stack    ldaa   RPAGE                       ; Get current value of RPAGE register    psha                               ; Push RPAGE register onto current task's stack    ldaa   PPAGE                       ; Get current value of PPAGE register    psha                               ; Push PPAGE register onto current task's stack    inc    OSIntNesting                ; Notify uC/OS-II about ISR    ldab   OSIntNesting                ; if (OSIntNesting == 1) {    cmpb   #$01    bne    SCI0_RxTxISR1    ldy    OSTCBCur                    ;     OSTCBCur->OSTCBStkPtr = Stack Pointer    sts    0,y                         ; }SCI0_RxTxISR1:    call   SCI0_ISR_Handler  ; Call TxRx ISR handler. (See SCI_uCos.c);   cli                               ; Optionally enable interrupts to allow interrupt nesting    call   OSIntExit                  ; Notify uC/OS-II about end of ISR, a context switch may occur from within OSIntExit().    pula                               ; Get value of PPAGE register    staa   PPAGE                       ; Store into CPU's PPAGE register    pula                               ; Get value of RPAGE register    staa   RPAGE                       ; Store into CPU's RPAGE register    pula                               ; Get value of EPAGE register    staa   EPAGE                       ; Store into CPU's EPAGE register    pula                               ; Get value of GPAGE register    staa   GPAGE                       ; Store into CPU's GPAGE register    rti                               ; Return from interrupt to interrupted task.SCI1_RxTxISR:    ldaa   GPAGE                       ; Get current value of GPAGE register    psha                               ; Push GPAGE register onto current task's stack    ldaa   EPAGE                       ; Get current value of EPAGE register    psha                               ; Push EPAGE register onto current task's stack    ldaa   RPAGE                       ; Get current value of RPAGE register    psha                               ; Push RPAGE register onto current task's stack    ldaa   PPAGE                       ; Get current value of PPAGE register    psha                               ; Push PPAGE register onto current task's stack    inc    OSIntNesting                ; Notify uC/OS-II about ISR    ldab   OSIntNesting                ; if (OSIntNesting == 1) {    cmpb   #$01    bne    SCI1_RxTxISR1    ldy    OSTCBCur                    ;     OSTCBCur->OSTCBStkPtr = Stack Pointer    sts    0,y                         ; }SCI1_RxTxISR1:    call   SCI1_ISR_Handler  ; Call TxRx ISR handler. (See SCI_uCos.c);   cli                               ; Optionally enable interrupts to allow interrupt nesting    call   OSIntExit                  ; Notify uC/OS-II about end of ISR, a context switch may occur from within OSIntExit().    pula                               ; Get value of PPAGE register    staa   PPAGE                       ; Store into CPU's PPAGE register    pula                               ; Get value of RPAGE register    staa   RPAGE                       ; Store into CPU's RPAGE register    pula                               ; Get value of EPAGE register    staa   EPAGE                       ; Store into CPU's EPAGE register    pula                               ; Get value of GPAGE register    staa   GPAGE                       ; Store into CPU's GPAGE register    rti                               ; Return from interrupt to interrupted task.SCI2_RxTxISR:    ldaa   GPAGE                       ; Get current value of GPAGE register    psha                               ; Push GPAGE register onto current task's stack    ldaa   EPAGE                       ; Get current value of EPAGE register    psha                               ; Push EPAGE register onto current task's stack    ldaa   RPAGE                       ; Get current value of RPAGE register    psha                               ; Push RPAGE register onto current task's stack    ldaa   PPAGE                       ; Get current value of PPAGE register    psha                               ; Push PPAGE register onto current task's stack    inc    OSIntNesting                ; Notify uC/OS-II about ISR    ldab   OSIntNesting                ; if (OSIntNesting == 1) {    cmpb   #$01    bne    SCI2_RxTxISR1    ldy    OSTCBCur                    ;     OSTCBCur->OSTCBStkPtr = Stack Pointer    sts    0,y                         ; }SCI2_RxTxISR1:    call   SCI2_ISR_Handler  ; Call TxRx ISR handler. (See SCI_uCos.c);   cli                               ; Optionally enable interrupts to allow interrupt nesting    call   OSIntExit                  ; Notify uC/OS-II about end of ISR, a context switch may occur from within OSIntExit().    pula                               ; Get value of PPAGE register    staa   PPAGE                       ; Store into CPU's PPAGE register    pula                               ; Get value of RPAGE register    staa   RPAGE                       ; Store into CPU's RPAGE register    pula                               ; Get value of EPAGE register    staa   EPAGE                       ; Store into CPU's EPAGE register    pula                               ; Get value of GPAGE register    staa   GPAGE                       ; Store into CPU's GPAGE register    rti                               ; Return from interrupt to interrupted task.SCI3_RxTxISR:    ldaa   GPAGE                       ; Get current value of GPAGE register    psha                               ; Push GPAGE register onto current task's stack    ldaa   EPAGE                       ; Get current value of EPAGE register    psha                               ; Push EPAGE register onto current task's stack    ldaa   RPAGE                       ; Get current value of RPAGE register    psha                               ; Push RPAGE register onto current task's stack    ldaa   PPAGE                       ; Get current value of PPAGE register    psha                               ; Push PPAGE register onto current task's stack    inc    OSIntNesting                ; Notify uC/OS-II about ISR    ldab   OSIntNesting                ; if (OSIntNesting == 1) {    cmpb   #$01    bne    SCI3_RxTxISR1    ldy    OSTCBCur                    ;     OSTCBCur->OSTCBStkPtr = Stack Pointer    sts    0,y                         ; }SCI3_RxTxISR1:    call   SCI3_ISR_Handler  ; Call TxRx ISR handler. (See SCI_uCos.c);   cli                               ; Optionally enable interrupts to allow interrupt nesting    call   OSIntExit                  ; Notify uC/OS-II about end of ISR, a context switch may occur from within OSIntExit().    pula                               ; Get value of PPAGE register    staa   PPAGE                       ; Store into CPU's PPAGE register    pula                               ; Get value of RPAGE register    staa   RPAGE                       ; Store into CPU's RPAGE register    pula                               ; Get value of EPAGE register    staa   EPAGE                       ; Store into CPU's EPAGE register    pula                               ; Get value of GPAGE register    staa   GPAGE                       ; Store into CPU's GPAGE register    rti                               ; Return from interrupt to interrupted task.SCI4_RxTxISR:    ldaa   GPAGE                       ; Get current value of GPAGE register    psha                               ; Push GPAGE register onto current task's stack    ldaa   EPAGE                       ; Get current value of EPAGE register    psha                               ; Push EPAGE register onto current task's stack    ldaa   RPAGE                       ; Get current value of RPAGE register    psha                               ; Push RPAGE register onto current task's stack    ldaa   PPAGE                       ; Get current value of PPAGE register    psha                               ; Push PPAGE register onto current task's stack    inc    OSIntNesting                ; Notify uC/OS-II about ISR    ldab   OSIntNesting                ; if (OSIntNesting == 1) {    cmpb   #$01    bne    SCI4_RxTxISR1    ldy    OSTCBCur                    ;     OSTCBCur->OSTCBStkPtr = Stack Pointer    sts    0,y                         ; }SCI4_RxTxISR1:    call   SCI4_ISR_Handler  ; Call TxRx ISR handler. (See SCI_uCos.c);   cli                               ; Optionally enable interrupts to allow interrupt nesting    call   OSIntExit                  ; Notify uC/OS-II about end of ISR, a context switch may occur from within OSIntExit().    pula                               ; Get value of PPAGE register    staa   PPAGE                       ; Store into CPU's PPAGE register    pula                               ; Get value of RPAGE register    staa   RPAGE                       ; Store into CPU's RPAGE register    pula                               ; Get value of EPAGE register    staa   EPAGE                       ; Store into CPU's EPAGE register    pula                               ; Get value of GPAGE register    staa   GPAGE                       ; Store into CPU's GPAGE register    rti                               ; Return from interrupt to interrupted task.SCI5_RxTxISR:    ldaa   GPAGE                       ; Get current value of GPAGE register    psha                               ; Push GPAGE register onto current task's stack    ldaa   EPAGE                       ; Get current value of EPAGE register    psha                               ; Push EPAGE register onto current task's stack    ldaa   RPAGE                       ; Get current value of RPAGE register    psha                               ; Push RPAGE register onto current task's stack    ldaa   PPAGE                       ; Get current value of PPAGE register    psha                               ; Push PPAGE register onto current task's stack    inc    OSIntNesting                ; Notify uC/OS-II about ISR    ldab   OSIntNesting                ; if (OSIntNesting == 1) {    cmpb   #$01    bne    SCI5_RxTxISR1    ldy    OSTCBCur                    ;     OSTCBCur->OSTCBStkPtr = Stack Pointer    sts    0,y                         ; }SCI5_RxTxISR1:    call   SCI5_ISR_Handler  ; Call TxRx ISR handler. (See SCI_uCos.c);   cli                               ; Optionally enable interrupts to allow interrupt nesting    call   OSIntExit                  ; Notify uC/OS-II about end of ISR, a context switch may occur from within OSIntExit().    pula                               ; Get value of PPAGE register    staa   PPAGE                       ; Store into CPU's PPAGE register    pula                               ; Get value of RPAGE register    staa   RPAGE                       ; Store into CPU's RPAGE register    pula                               ; Get value of EPAGE register    staa   EPAGE                       ; Store into CPU's EPAGE register    pula                               ; Get value of GPAGE register    staa   GPAGE                       ; Store into CPU's GPAGE register    rti                               ; Return from interrupt to interrupted task.SCI6_RxTxISR:    ldaa   GPAGE                       ; Get current value of GPAGE register    psha                               ; Push GPAGE register onto current task's stack    ldaa   EPAGE                       ; Get current value of EPAGE register    psha                               ; Push EPAGE register onto current task's stack    ldaa   RPAGE                       ; Get current value of RPAGE register    psha                               ; Push RPAGE register onto current task's stack    ldaa   PPAGE                       ; Get current value of PPAGE register    psha                               ; Push PPAGE register onto current task's stack    inc    OSIntNesting                ; Notify uC/OS-II about ISR    ldab   OSIntNesting                ; if (OSIntNesting == 1) {    cmpb   #$01    bne    SCI6_RxTxISR1    ldy    OSTCBCur                    ;     OSTCBCur->OSTCBStkPtr = Stack Pointer    sts    0,y                         ; }SCI6_RxTxISR1:    call   SCI6_ISR_Handler  ; Call TxRx ISR handler. (See SCI_uCos.c);   cli                               ; Optionally enable interrupts to allow interrupt nesting    call   OSIntExit                  ; Notify uC/OS-II about end of ISR, a context switch may occur from within OSIntExit().    pula                               ; Get value of PPAGE register    staa   PPAGE                       ; Store into CPU's PPAGE register    pula                               ; Get value of RPAGE register    staa   RPAGE                       ; Store into CPU's RPAGE register    pula                               ; Get value of EPAGE register    staa   EPAGE                       ; Store into CPU's EPAGE register    pula                               ; Get value of GPAGE register    staa   GPAGE                       ; Store into CPU's GPAGE register    rti                               ; Return from interrupt to interrupted task.SCI7_RxTxISR:    ldaa   GPAGE                       ; Get current value of GPAGE register    psha                               ; Push GPAGE register onto current task's stack    ldaa   EPAGE                       ; Get current value of EPAGE register    psha                               ; Push EPAGE register onto current task's stack    ldaa   RPAGE                       ; Get current value of RPAGE register    psha                               ; Push RPAGE register onto current task's stack    ldaa   PPAGE                       ; Get current value of PPAGE register    psha                               ; Push PPAGE register onto current task's stack    inc    OSIntNesting                ; Notify uC/OS-II about ISR    ldab   OSIntNesting                ; if (OSIntNesting == 1) {    cmpb   #$01    bne    SCI7_RxTxISR1    ldy    OSTCBCur                    ;     OSTCBCur->OSTCBStkPtr = Stack Pointer    sts    0,y                         ; }SCI7_RxTxISR1:    call   SCI7_ISR_Handler  ; Call TxRx ISR handler. (See SCI_uCos.c);   cli                               ; Optionally enable interrupts to allow interrupt nesting    call   OSIntExit                  ; Notify uC/OS-II about end of ISR, a context switch may occur from within OSIntExit().    pula                               ; Get value of PPAGE register    staa   PPAGE                       ; Store into CPU's PPAGE register    pula                               ; Get value of RPAGE register    staa   RPAGE                       ; Store into CPU's RPAGE register    pula                               ; Get value of EPAGE register    staa   EPAGE                       ; Store into CPU's EPAGE register    pula                               ; Get value of GPAGE register    staa   GPAGE                       ; Store into CPU's GPAGE register    rti                               ; Return from interrupt to interrupted task.

要记得修改中断向量表把用到的端口的ISR分别指向其中断地址,如SCI0_RxTxISR指向0xFFD6、SCI1_RxTxISR1指向0xFFD4,也就是SCI0和SCI1的中断地址。

然后是.c文件:

/***********************************************************************************************                    SCI(Serial Communication Interface)  Buffered Serial I/O     *                                   Freescale MC9S12XEP100*                           飞思卡尔   MC9S12XEP100  SCI支持包** File : SCI_uCos.c* By   : Lin Shijun(http://blog.csdn.net/lin_strong)* Date:  2017/10/27* version: V2.1* History: 2017/04/24  V1.0   the prototype of SCI_uCOS,only support SCI0 and SCI1*          2017/07/20  V2.0   update the module to support the SCI0 to SCI7*          2017/10/27  V2.1   fix a bug: when disable a port between two active port,the upper one can't work.*                             this is due to the statment: *                                  for(port = 0;port < 8 && isSCIEnable(port);port++)*                             in SCI_BufferInit().*                             the judgment statment port < 8 && isSCIEnable(port) will jump out the init loop *                               the first time meet the first disabled SCI port.* NOTE(s): 1.refer to Li Yuan's  (http://blog.csdn.net/liyuanbhu/article/details/7768914)*             and *            uCOS-II's Code*          2.记得把SCI_uCOS.s中的SCIx_RxTxISR中断服务程序指向对应的中断向量地址*********************************************************************************************//**********************************************************************************************                                   INCLUDES*********************************************************************************************/#include "SCI_def.h"#if(SCI_MODULE_ENABLE == TRUE && SCI_UCOS_MODULE_ENABLE == TRUE)#include <stddef.h>#include <string.h>#include <ucos_ii.h> #include "RingQueue.h"/* **********************************************************************************************                                    DATA TYPES **********************************************************************************************/typedef struct{    INT8U port;                                 /* Hold the port number         */    OS_EVENT  *RingBufRxSem;                    /* Pointer to Rx semaphore      */      RING_QUEUE*  RingBufRx;                     /* Ring buffer character storage (Rx) */      OS_EVENT  *RingBufTxMutex;                  /* Pointer to Tx MUTUAL semaphore     */    OS_EVENT  *RingBufTxSem;                    /* Pointer to Tx semaphore          */      RING_QUEUE*  RingBufTx;                     /* Ring buffer character storage (Tx) */  } SCI_RING_BUF;/******************************************************************************************                                 CONSTANT *****************************************************************************************/// Flag of SCI enable.#define EnableFlag ((SCI0_UCOS_CODE_EN << 0) | (SCI1_UCOS_CODE_EN << 1) | (SCI2_UCOS_CODE_EN << 2) | \                     (SCI3_UCOS_CODE_EN << 3) | (SCI4_UCOS_CODE_EN << 4) | (SCI5_UCOS_CODE_EN << 5) | \                     (SCI6_UCOS_CODE_EN << 6) | (SCI7_UCOS_CODE_EN << 7))#define isSCIEnable(port) ((EnableFlag >> port) & 0x01)static const INT8U SCITxMutexPrios[] = {   SCI0_TX_MUTEX_PRIO,   SCI1_TX_MUTEX_PRIO,   SCI2_TX_MUTEX_PRIO,   SCI3_TX_MUTEX_PRIO,   SCI4_TX_MUTEX_PRIO,   SCI5_TX_MUTEX_PRIO,   SCI6_TX_MUTEX_PRIO,   SCI7_TX_MUTEX_PRIO,};#define SCI_TX_MUTEX_PRIO(port) SCITxMutexPrios[port]// const of RxBuffer Sizes#if(SCI0_RX_BUFFER_SIZE < 256 && SCI1_RX_BUFFER_SIZE < 256 && SCI2_RX_BUFFER_SIZE < 256 && \    SCI3_RX_BUFFER_SIZE < 256 && SCI4_RX_BUFFER_SIZE < 256 && SCI5_RX_BUFFER_SIZE < 256 && \    SCI6_RX_BUFFER_SIZE < 256 && SCI7_RX_BUFFER_SIZE < 256)   #define RxSizeArrType INT8U#else   #define RxSizeArrType INT16U#endifstatic const RxSizeArrType SCIRxBufferSize[]={     SCI0_RX_BUFFER_SIZE,     SCI1_RX_BUFFER_SIZE,     SCI2_RX_BUFFER_SIZE,     SCI3_RX_BUFFER_SIZE,     SCI4_RX_BUFFER_SIZE,     SCI5_RX_BUFFER_SIZE,     SCI6_RX_BUFFER_SIZE,     SCI7_RX_BUFFER_SIZE, };#define SCIRxBufSize(port) SCIRxBufferSize[port]#define isSCIRxEnable(port) (SCIRxBufferSize[port] > 0)// const of TxBuffer Sizes#if(SCI0_TX_BUFFER_SIZE < 256 && SCI1_TX_BUFFER_SIZE < 256 && SCI2_TX_BUFFER_SIZE < 256 && SCI3_TX_BUFFER_SIZE < 256 \ && SCI4_TX_BUFFER_SIZE < 256 && SCI5_TX_BUFFER_SIZE < 256 && SCI6_TX_BUFFER_SIZE < 256 && SCI7_TX_BUFFER_SIZE < 256) #define TxSizeArrType INT8U#else #define TxSizeArrType INT16U#endifstatic const TxSizeArrType SCITxBufferSize[]={     SCI0_TX_BUFFER_SIZE,     SCI1_TX_BUFFER_SIZE,     SCI2_TX_BUFFER_SIZE,     SCI3_TX_BUFFER_SIZE,     SCI4_TX_BUFFER_SIZE,     SCI5_TX_BUFFER_SIZE,     SCI6_TX_BUFFER_SIZE,     SCI7_TX_BUFFER_SIZE, };#define SCITxBufSize(port) SCITxBufferSize[port]#define isSCITxEnable(port) (SCITxBufferSize[port] > 0)#define SCI_RX_BUFFER_SIZE_SUM (SCI0_RX_BUFFER_SIZE + SCI1_RX_BUFFER_SIZE + SCI2_RX_BUFFER_SIZE + SCI3_RX_BUFFER_SIZE \                                + SCI4_RX_BUFFER_SIZE + SCI5_RX_BUFFER_SIZE + SCI6_RX_BUFFER_SIZE + SCI7_RX_BUFFER_SIZE)#define SCI_TX_BUFFER_SIZE_SUM (SCI0_TX_BUFFER_SIZE + SCI1_TX_BUFFER_SIZE + SCI2_TX_BUFFER_SIZE + SCI3_TX_BUFFER_SIZE \                                + SCI4_TX_BUFFER_SIZE + SCI5_TX_BUFFER_SIZE + SCI6_TX_BUFFER_SIZE + SCI7_TX_BUFFER_SIZE)#define SCI_BUFFER_SIZE_SUM (SCI_RX_BUFFER_SIZE_SUM + SCI_TX_BUFFER_SIZE_SUM)#define SCI_RX_BUFFERS_COUNT ((SCI0_RX_BUFFER_SIZE>0) + (SCI1_RX_BUFFER_SIZE>0) + (SCI2_RX_BUFFER_SIZE>0) + \                             (SCI3_RX_BUFFER_SIZE>0) + (SCI4_RX_BUFFER_SIZE>0) + (SCI5_RX_BUFFER_SIZE>0) + \                             (SCI6_RX_BUFFER_SIZE>0) + (SCI7_RX_BUFFER_SIZE>0))#define SCI_TX_BUFFERS_COUNT ((SCI0_TX_BUFFER_SIZE>0) + (SCI1_TX_BUFFER_SIZE>0) + (SCI2_TX_BUFFER_SIZE>0) + \                             (SCI3_TX_BUFFER_SIZE>0) + (SCI4_TX_BUFFER_SIZE>0) + (SCI5_TX_BUFFER_SIZE>0) + \                             (SCI6_TX_BUFFER_SIZE>0)) + (SCI7_TX_BUFFER_SIZE>0)#define SCI_BUFFERS_COUNT (SCI_RX_BUFFERS_COUNT + SCI_TX_BUFFERS_COUNT)#define SCI_RING_QUEUE_COUNT SCI_BUFFERS_COUNT/******************************************************************************************                                 GLOBAL VARIABLES  *****************************************************************************************/#define SCI_RING_BUFS_COUNT SCI0_UCOS_CODE_EN + SCI1_UCOS_CODE_EN + SCI2_UCOS_CODE_EN + SCI3_UCOS_CODE_EN + \                           SCI4_UCOS_CODE_EN + SCI5_UCOS_CODE_EN + SCI6_UCOS_CODE_EN + SCI7_UCOS_CODE_ENSCI_RING_BUF SCIBufs[SCI_RING_BUFS_COUNT];SCI_RING_BUF * const Ptr_SCIBuf[] = {  #if(SCI0_UCOS_CODE_EN == TRUE)     &SCIBufs[0],  #else     NULL,  #endif  #if(SCI1_UCOS_CODE_EN == TRUE)     &SCIBufs[SCI0_UCOS_CODE_EN],  #else     NULL,  #endif  #if(SCI2_UCOS_CODE_EN == TRUE)     &SCIBufs[SCI0_UCOS_CODE_EN + SCI1_UCOS_CODE_EN],  #else     NULL,  #endif  #if(SCI3_UCOS_CODE_EN == TRUE)     &SCIBufs[SCI0_UCOS_CODE_EN + SCI1_UCOS_CODE_EN + SCI2_UCOS_CODE_EN],  #else     NULL,  #endif  #if(SCI4_UCOS_CODE_EN == TRUE)     &SCIBufs[SCI0_UCOS_CODE_EN + SCI1_UCOS_CODE_EN + SCI2_UCOS_CODE_EN + SCI3_UCOS_CODE_EN],  #else     NULL,  #endif  #if(SCI5_UCOS_CODE_EN == TRUE)     &SCIBufs[SCI0_UCOS_CODE_EN + SCI1_UCOS_CODE_EN + SCI2_UCOS_CODE_EN + SCI3_UCOS_CODE_EN + SCI4_UCOS_CODE_EN],  #else     NULL,  #endif  #if(SCI6_UCOS_CODE_EN == TRUE)     &SCIBufs[SCI0_UCOS_CODE_EN + SCI1_UCOS_CODE_EN + SCI2_UCOS_CODE_EN + SCI3_UCOS_CODE_EN + SCI4_UCOS_CODE_EN \      + SCI5_UCOS_CODE_EN],  #else     NULL,  #endif  #if(SCI7_UCOS_CODE_EN == TRUE)     &SCIBufs[SCI0_UCOS_CODE_EN + SCI1_UCOS_CODE_EN + SCI2_UCOS_CODE_EN + SCI3_UCOS_CODE_EN + SCI4_UCOS_CODE_EN \     + SCI5_UCOS_CODE_EN + SCI6_UCOS_CODE_EN],  #else     NULL,  #endif};#define pSCIBuf(port) Ptr_SCIBuf[port]/***********************************************************************************************                                 LOCAL VARIABLES  **********************************************************************************************/static union{    byte FLAG;    struct {    byte Inited   :1;           //Initialized Flag     byte          :1;                                           byte          :1;                                           byte          :1;                                           byte          :1;                                           byte          :1;                                           byte          :1;     byte          :1;                                         } Bits;} flag = {0};// 所有SCI的所有收发缓冲区其实都在同一个大数组中,每个小块分别由不同的环形队列对象管理即可#if (SCI_BUFFER_SIZE_SUM > 0)   static INT8U SCIBuffer[SCI_BUFFER_SIZE_SUM];#else   static INT8U *SCIBuffer = NULL;#endif// 管理SCI的所有环形队列对象都在一个数组中#if (SCI_RING_QUEUE_COUNT > 0)   static RING_QUEUE SCIRingQueues[SCI_BUFFERS_COUNT];#else   static RING_QUEUE* SCIRingQueues = NULL;#endif#define pSCI_RingBufRx(port) (pSCIBuf(port)->RingBufRx)#define pSCI_RingBufTx(port) (pSCIBuf(port)->RingBufTx)#if (APP_TRACE_LEVEL >= TRACE_LEVEL_INFO)   // 调试用变量   INT16U ClearTimes;#endif/********************************************************************************************                              LOCAL FUNCTION DECLARE*******************************************************************************************/#pragma CODE_SEG __NEAR_SEG NON_BANKED static INT8U _SCI_TxPutCharB(SCI_RING_BUF* pbuf, INT8U c, INT16U timeout);static SCI_RING_BUF* _SCI_getRingBuf_chkRx(INT8U port);static SCI_RING_BUF* _SCI_getRingBuf_chkTx(INT8U port);#pragma CODE_SEG DEFAULT/********************************************************************************************                                 SCI_BufferInit()** Description :   To initialize the communications module.                         *                     初始化通信模型.*                 You must call this function before calling any other functions.  *                     必须在调用其他函数前调用它.* Arguments   : *                       * Return:**Note(s):*******************************************************************************************/void  SCI_BufferInit (void)  {      SCI_RING_BUF *pSCIRingBuf;        INT8U err,port;    RING_QUEUE* pRingQueue = SCIRingQueues;    INT8U *pBuf = SCIBuffer;    // 简单的保护    if(flag.Bits.Inited) return;    // Initialize all buffers     for(port = 0;port < 8;port++){       if(!isSCIEnable(port))       // continue when the current port is not enable.           continue;       pSCIRingBuf = pSCIBuf(port);       pSCIRingBuf->port = port;       if(isSCITxEnable(port)) {           pSCIRingBuf->RingBufTxMutex  = OSMutexCreate(SCI_TX_MUTEX_PRIO(port),&err);            pSCIRingBuf->RingBufTxSem = OSSemCreate(SCITxBufSize(port));                 pSCIRingBuf->RingBufTx = RingQueueInit(pRingQueue++,pBuf,SCITxBufSize(port),&err);           pBuf += SCITxBufSize(port);       }       if(isSCIRxEnable(port)) {           pSCIRingBuf->RingBufRxSem = OSSemCreate(0);                 pSCIRingBuf->RingBufRx = RingQueueInit(pRingQueue++,pBuf,SCIRxBufSize(port),&err);           pBuf += SCIRxBufSize(port);       }     }     flag.Bits.Inited = 1;}/********************************************************************************************                                      SCI_GetCharB()** Description : To obtain a character from the communications channel.  *                  从通信信道中获取一个字符** Arguments   : port       port can be SCI0 / SCI1;                  选择端口;*               timeout    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.*                             调用者最久愿意等待一个字符到达的时钟节拍数,为0表示永久等待.*               err        is a pointer to where an error code will be placed: 用于返回故障码:*                               SCI_NO_ERR      if a character has been received          正确收到字符*                               SCI_RX_TIMEOUT  if a timeout occurred                     接收超时*                               SCI_BAD_CH      if you specify an invalid channel number  通道号错误* Return:       The character in the buffer (or NUL if a timeout occurred); 缓冲区内的字符(或者发生了超时);* Note(s):********************************************************************************************/INT8U  SCI_GetCharB (INT8U port, INT16U timeout, INT8U *err)  {#if OS_CRITICAL_METHOD == 3                    /* Allocate storage for CPU status register     */      OS_CPU_SR  cpu_sr = 0u;  #endif      INT8U c;      INT8U oserr;      SCI_RING_BUF *pbuf;    pbuf = _SCI_getRingBuf_chkRx(port);    if(pbuf == NULL){          *err = SCI_BAD_CH;            return (NUL);           }    OSSemPend(pbuf->RingBufRxSem, timeout, &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();          c = RingQueueOut(pbuf->RingBufRx,&oserr);                   /* Get next one from ring queue.*/        OS_EXIT_CRITICAL();          *err = SCI_NO_ERR;        return (c);      }  } /************************************************************************************************                                        SCI_PutCharB_Mutex()** Description : 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.**               equal to call:     *                  SCI_SendBuf_hold (port, timeout, &perr);*                  perr =  SCI_PutCharB(port, INT8U c, INT16U timeout);*                  SCI_SendBuf_release(port);** Arguments   : port      port can be SCI0 / SCI1;                      选择端口;*               c         the character to send;                        要发送的字符;*               timeout   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. *                         在缓冲区满的情况下, 调用者最久愿意等待的时钟节拍数,为0表示永久等待.* Return:      SCI_NO_ERR       if the character was placed in the Tx buffer;  *                                    字符成功放入Tx缓冲区内;*              SCI_TX_TIMEOUT   if the buffer didn't empty or can't access within the specified timeout period;*                                    超时后还是没有清空缓冲区或者还无法访问*              SCI_BAD_CH       if you specify an invalid channel number  通道号错误*Note(s):      ***********************************************************************************************/INT8U SCI_PutCharB_Mutex (INT8U port, INT8U c, INT16U timeout)  {       SCI_RING_BUF *pbuf;      INT8U oserr;      pbuf = _SCI_getRingBuf_chkTx(port);    if(pbuf == NULL)          return (SCI_BAD_CH);      OSMutexPend(pbuf->RingBufTxMutex,timeout,&oserr); /* Wait for the right of use Tx buffer*/    if(oserr == OS_ERR_NONE)                          /* If get the right then */         oserr =  _SCI_TxPutCharB(pbuf,c,timeout);    /*  Put INT8U into Tx buffer*/     OSMutexPost(pbuf->RingBufTxMutex);                /* Release the the right of use Tx buffer*/        if (oserr == OS_TIMEOUT)                          /* If Timeout happen */        return (SCI_TX_TIMEOUT);                      /* Timed out, return error code             */      return (SCI_NO_ERR);  }/***********************************************************************************************                                        SCI_PutCharsB_Mutex()** Description : This function is called by your application to send chars 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. *                        equal to call:     *                            SCI_SendBuf_hold (port, timeout, &perr);*                            perr =  SCI_PutCharsB(port, INT8U c, INT16U timeout);*                            SCI_SendBuf_release(port);** Arguments   : port       port can be SCI0 / SCI1;          选择端口;*               buf        the buffer;                       要发送的字符;*               length     the length of the buffer;        *               timeout    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. *                                  在缓冲区满的情况下, 调用者最久愿意等待的时钟节拍数,为0表示永久等待.* Return:       SCI_NO_ERR      if the character was placed in the Tx buffer;  字符成功放入Tx缓冲区内;*               SCI_TX_TIMEOUT  if the buffer didn't empty or can't access within the specified timeout period;*                                     超时后还是没有清空缓冲区或者还无法访问*               SCI_BAD_CH      if you specify an invalid channel number  通道号错误*Note(s):      ************************************************************************************************/INT8U SCI_PutCharsB_Mutex (INT8U port, const INT8U *buf,INT16U length, INT16U timeout) {    SCI_RING_BUF *pbuf;      INT8U oserr;      pbuf = _SCI_getRingBuf_chkTx(port);    if(pbuf == NULL)       return (SCI_BAD_CH);      OSMutexPend(pbuf->RingBufTxMutex,timeout,&oserr);        /* Wait for the right of use Tx buffer*/    if(oserr == OS_ERR_NONE)        while(length--){          oserr =  _SCI_TxPutCharB(pbuf,*buf++,timeout);     /*  Put INT8U into Tx buffer*/           if (oserr != OS_ERR_NONE)                           /* if any err happen */              break;                                         /* break */          }    OSMutexPost(pbuf->RingBufTxMutex);    if (oserr == OS_TIMEOUT)        return (SCI_TX_TIMEOUT);                           /* Timed out, return error code             */      return (SCI_NO_ERR);  }/**********************************************************************************************                                 SCI_PutStringB_Mutex()** Description : This function is called by your application to send a string,which ends with '\0', 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 *                 ill be enabled. ** Arguments   : port       port can be SCI0 / SCI1;                  选择端口;*               buf        the buffer;                       要发送的字符;*               length     the length of the buffer;        *               timeout    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. *                            在缓冲区满的情况下, 调用者最久愿意等待的时钟节拍数,为0表示永久等待.* Return:      SCI_NO_ERR        if the character was placed in the Tx buffer;  字符成功放入Tx缓冲区内;*              SCI_TX_TIMEOUT    if the buffer didn't empty or can't access within the specified timeout period;*                                    超时后还是没有清空缓冲区或者还无法访问*              SCI_BAD_CH        if you specify an invalid channel number  通道号错误*Note(s):      ***********************************************************************************************///INT8U SCI_PutStringB_Mutex(INT8U port, const INT8U *str, INT16U timeout){  //   return SCI_PutCharsB_Mutex(port,str,strlen(str),timeout);//}/***********************************************************************************************                                        SCI_SendBuf_hold()** Description : This function is called by your application to own the exclusive right of ...*                ...sending INT8U on particular SCI port. your function should look like this:**                    SCI_SendBuf_hold(port,timeout,&err);*                    if (*err == SCI_NO_ERR){*                       .......*                        SCI_PutCharB(port,c,&err);*                       .......*                    }*                    SCI_SendBuf_release(port);** Arguments : port      port can be SCI0/SCI1;                  选择端口;*             timeout   is the timeout (in clock ticks) to wait in case the buffer is occupied.  If you ...*                       ...specify a timeout of 0, the function will wait forever for the buffer to empty. *                             在其他地方占有使用权的情况下, 调用者最久愿意等待的时钟节拍数,为0表示永久等待.*             perr      SCI_NO_ERR       if get the exclusive right of sending INT8U on particular SCI port successfully;  *                                            成功获取对应端口的发送权*                       SCI_TX_TIMEOUT   if can't get the exclusive right of sending INT8U on particular...*                                          ... SCI port within the specified timeout period;*                                            超时后还是没有获得对应端口的发送权*                       SCI_BAD_CH       if you specify an invalid channel number.  通道号错误*                       SCI_ERR_UNKNOWN  unknow err happen.                         发生了未知的错误* Return:*Note(s):     1.Once call this function successfully, you must call SCI_SendBuf_release in the end of your function.  ...*                       ... Otherwise, other caller to SCI_SendBuf_hold or SCI_XXX_Mutex mothod will fail.*********************************************************************************************/void  SCI_SendBuf_hold(INT8U port, INT16U timeout, INT8U *perr){    SCI_RING_BUF *pbuf;      pbuf = _SCI_getRingBuf_chkTx(port);    if(pbuf == NULL){       *perr = SCI_BAD_CH;       return;    }    OSMutexPend(pbuf->RingBufTxMutex,timeout,perr);        /* Wait for the right of use Tx buffer*/    if(*perr == OS_ERR_NONE)        *perr = SCI_NO_ERR;    else if(*perr == OS_TIMEOUT)        *perr = SCI_TX_TIMEOUT;                      /* Timed out, return error code             */      else        *perr = SCI_ERR_UNKNOWN;}/***********************************************************************************************                                        SCI_PutCharB()** Description : This function is called by your application to send INT8U 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. ** Arguments   : port     port can be SCI0 / SCI1;                  选择端口;*               c        the INT8U to send;                       要发送的字符;*               timeout  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. *                           在缓冲区满的情况下, 调用者最久愿意等待的时钟节拍数,为0表示永久等待.** Return:       SCI_NO_ERR        if the character was placed in the Tx buffer;  *                                     字符成功放入Tx缓冲区内;*               SCI_TX_TIMEOUT    if the buffer didn't empty within the specified timeout period;*                                     超时后还是没有清空缓冲区*               SCI_BAD_CH        if you specify an invalid channel number  通道号错误**Note(s):      1.  you should call SCI_SendBuf_hold() first unless you know what you are doing.*                 调用这个函数前你应该先调用SCI_SendBuf_hold(),除非你知道你在干什么**********************************************************************************************/INT8U SCI_PutCharB (INT8U port, INT8U c, INT16U timeout){    SCI_RING_BUF *pbuf;    INT8U oserr;      pbuf = _SCI_getRingBuf_chkTx(port);    if(pbuf == NULL)      return (SCI_BAD_CH);      oserr =  _SCI_TxPutCharB(pbuf,c,timeout);            /*  Put INT8U into Tx buffer*/     if (oserr == OS_TIMEOUT)                             /* If Timeout happen */      return (SCI_TX_TIMEOUT);                           /* Timed out, return error code   */      return (SCI_NO_ERR);  }/***********************************************************************************************                                        SCI_PutCharsB()** Description : This function is called by your application to send INT8U 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. ** Arguments   : port     port can be SCI0 / SCI1;         选择端口;*               buf      the buffer;                      要发送的缓冲区;*               length   the length of the buffer;        缓冲区长度;*               timeout  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. *                         在缓冲区满的情况下, 调用者最久愿意等待的时钟节拍数,为0表示永久等待.** Return:       SCI_NO_ERR      if the character was placed in the Tx buffer;  *                               字符成功放入Tx缓冲区内;*               SCI_TX_TIMEOUT  if the buffer didn't empty within the specified timeout period;*                               超时后还是没有清空缓冲区*               SCI_BAD_CH      if you specify an invalid channel number  通道号错误**Note(s):      1.  you should call SCI_SendBuf_hold() first unless you know what you are doing.***********************************************************************************************/INT8U SCI_PutCharsB(INT8U port, const INT8U *buf,INT16U length, INT16U timeout) {    SCI_RING_BUF *pbuf;      INT8U oserr;      pbuf = _SCI_getRingBuf_chkTx(port);    if(pbuf == NULL)       return (SCI_BAD_CH);      while(length--){       oserr =  _SCI_TxPutCharB(pbuf,*buf++,timeout);       /*  Put INT8U into Tx buffer*/        if (oserr != OS_ERR_NONE)                                        /* if any err happen */          break;                                                                          /* break */      }    if (oserr == OS_TIMEOUT)                                          /* If Timeout happen */        return (SCI_TX_TIMEOUT);                           /* Timed out, return error code             */      return (SCI_NO_ERR);  }/***********************************************************************************************                                   SCI_SendBuf_release()** Description :  This function is called by your application to release the exclusive right...*                 ... of sending INT8U on particular SCI port.** Arguments   : port   port can be SCI0/SCI1;                  选择端口;** Return:**Note(s):        **********************************************************************************************/void  SCI_SendBuf_release(INT8U port){    SCI_RING_BUF *pbuf;      pbuf = _SCI_getRingBuf_chkTx(port);    if(pbuf != NULL)       OSMutexPost(pbuf->RingBufTxMutex);}/************************************************************************************************                                        SCI_RxBufferIsEmpty()** Description : To see if any character is available from the communications channel.  *                 查看是否接收缓冲区为空** Arguments   : 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).*               0xff     if you specify an invalid channel number.*               如果缓冲区内存在字符,则返回FALSE,否则返回TRUE. 0xff 如果通道号无效.*Note(s):      ***********************************************************************************************/#if (SCI_CHECK_EMPTY_EN == TRUE)INT8U  SCI_RxBufferIsEmpty (INT8U port)  {#if OS_CRITICAL_METHOD == 3u                           /* Allocate storage for CPU status register     */      OS_CPU_SR  cpu_sr = 0u;  #endif      INT8U empty;      SCI_RING_BUF *pbuf;      pbuf = _SCI_getRingBuf_chkRx(port);    if(pbuf == NULL)          return (0xff);      OS_ENTER_CRITICAL();      empty =  RingQueueIsEmpty(pbuf->RingBufRx);    OS_EXIT_CRITICAL();      return (empty);}#endif/**********************************************************************************************                                        SCI_TxBufferIsFull()** Description: To see if any more characters can be placed in the Tx buffer.  *                  是否发送缓冲区已满** Arguments  :  port    port can be SCI0 / SCI1;                  选择端口;** Return     : If the buffer is full, the function returns TRUE. Otherwise, the function returns FALSE. *                   0xff                if you specify an invalid channel number.*              如果发送缓冲区满,则返回TRUE,否则返回FALSE. 0xff 如果通道号无效.*Note(s):      **********************************************************************************************/#if(SCI_CHECK_FULL_EN == TRUE)INT8U SCI_TxBufferIsFull (INT8U port)  {  #if OS_CRITICAL_METHOD == 3u                    /* Allocate storage for CPU status register     */      OS_CPU_SR  cpu_sr = 0u;  #endif      INT8U full;      SCI_RING_BUF *pbuf;       pbuf = _SCI_getRingBuf_chkTx(port);    if(pbuf == NULL)          return (0xff);      OS_ENTER_CRITICAL();      full = RingQueueIsFull(pbuf->RingBufTx);    OS_EXIT_CRITICAL();      return (full);  }  #endif/***********************************************************************************************************                                LOCAL FUNCTION**********************************************************************************************************/#pragma CODE_SEG __NEAR_SEG NON_BANKED // 内部用来放字符到发送缓冲区, 返回的是SemPend的错误,默认RingQueueIn是不可能出错的(因为有信号量保证有空间可用)static INT8U _SCI_TxPutCharB(SCI_RING_BUF* pbuf, INT8U c, INT16U timeout){#if OS_CRITICAL_METHOD == 3u                             /* Allocate storage for CPU status register */      OS_CPU_SR  cpu_sr = 0u;  #endif    INT8U err,tmperr;    OSSemPend(pbuf->RingBufTxSem, timeout, &err);        /* Wait for space in Tx buffer              */      OS_ENTER_CRITICAL();      if (RingQueueIn(pbuf->RingBufTx,c,RQ_OPTION_WHEN_FULL_DISCARD_FIRST,&tmperr) == 1)  /* Get next one from ring queue, and see whether...                                                           ... this is the first character       */       SCI_EnableTxInt(pbuf->port);                       /* Yes, Enable Tx interrupts                */      OS_EXIT_CRITICAL();     return err;}// 返回对应端口的SCI_RING_BUF, 如果端口不存在/未启用,或没启用Tx功能,则返回NULLstatic SCI_RING_BUF* _SCI_getRingBuf_chkTx(INT8U port){    if(port < 8 && isSCITxEnable(port))         return pSCIBuf(port);    return NULL;}// 返回对应端口的SCI_RING_BUF, 如果端口不存在/未启用,或没启用Rx功能,则返回NULLstatic SCI_RING_BUF* _SCI_getRingBuf_chkRx(INT8U port){    if(port < 8 && isSCIRxEnable(port))         return pSCIBuf(port);    return NULL;}// This function is called by the Rx ISR to insert a character into the receive ring buffer.  // 这个函数由Rx ISR来插入一个字符到缓冲区内static void  SCIPutRxChar (INT8U port, INT8U c)  {     SCI_RING_BUF *pbuf;     INT8U oserr;     pbuf =  _SCI_getRingBuf_chkRx(port);     //if(pbuf == NULL)     //   return;     RingQueueIn(pbuf->RingBufRx,c,RQ_OPTION_WHEN_FULL_DISCARD_FIRST,&oserr);     if(oserr == RQ_ERR_NONE)        (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.  // 这个函数由Tx ISR调用来从Tx缓冲区内提取下一个字符.如果在提取完字符后缓冲区空了,函数就返回FALSE.//    这是用来通知Tx ISR禁止中断的。static INT8U SCIGetTxChar (INT8U port, INT8U *perr)  {    INT8U c;    SCI_RING_BUF *pbuf;        pbuf =  _SCI_getRingBuf_chkTx(port);    //if(pbuf == NULL){    //    *err = SCI_BAD_CH;      //    return (0);      //}    c = RingQueueOut(pbuf->RingBufTx,perr);                   /* Get next one from ring queue.*/    if(*perr == RQ_ERR_NONE){       OSSemPost(pbuf->RingBufTxSem);       *perr = SCI_NO_ERR;         return c;    }else{       *perr = SCI_TX_EMPTY;         return (NUL);                                      /* Buffer is empty   */      }}#pragma CODE_SEG DEFALUT// 发现如果放到非分页区,则SCISR1的值会被清0,所以只能放在分页区了。static void SCI_ISR_Handler(INT8U port){    INT8U status,err;    volatile INT8U data;     status = SCISR1(port);    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 = SCIDRL(port);           // in case that compiler optimize this assignment,the 'data' must prefix volatile      #if (APP_TRACE_LEVEL >= TRACE_LEVEL_INFO)        ClearTimes++;      #endif     }    else if(status & 0x20) //Receive Data Reg Full Flag      {        data = SCIDRL(port);        SCIPutRxChar(port, data);                    // Insert received character into buffer           }    else if(status & 0x80)      {        data = SCIGetTxChar(port, &err);             // Get next character to send.                         if (err == SCI_TX_EMPTY)           {                                            // Do we have anymore characters to send ?                                                          // No,  Disable Tx interrupts                              SCI_DisableTxInt(port);          }           else           {              SCIDRL(port) = data;        // Yes, Send character                          }                                                 }}void SCI0_ISR_Handler(void)  {#if(SCI0_UCOS_CODE_EN == TRUE)   SCI_ISR_Handler(SCI0);#endif}void SCI1_ISR_Handler (void)  {#if(SCI1_UCOS_CODE_EN == TRUE)   SCI_ISR_Handler(SCI1);#endif}void SCI2_ISR_Handler(void)  {#if(SCI2_UCOS_CODE_EN == TRUE)    SCI_ISR_Handler(SCI2);#endif}void SCI3_ISR_Handler (void)  {  #if(SCI3_UCOS_CODE_EN == TRUE)   SCI_ISR_Handler(SCI3);#endif} void SCI4_ISR_Handler(void)  {  #if(SCI4_UCOS_CODE_EN == TRUE)   SCI_ISR_Handler(SCI4);#endif}void SCI5_ISR_Handler (void)  {  #if(SCI5_UCOS_CODE_EN == TRUE)   SCI_ISR_Handler(SCI5);#endif} void SCI6_ISR_Handler(void)  {  #if(SCI6_UCOS_CODE_EN == TRUE)   SCI_ISR_Handler(SCI6);#endif}void SCI7_ISR_Handler(void){  #if(SCI7_UCOS_CODE_EN == TRUE)   SCI_ISR_Handler(SCI7);#endif} #endif  // of (SCI_MODULE_ENABLE == TRUE && SCI_UCOS_MODULE_ENABLE == TRUE)

头文件就不再发了,在上一章中。

其中使用到了环形缓冲区,具体实现可以到我的另一篇博文中找到。还使用了uCOS-II嵌入式操作系统提供的互斥型信号量以及信号量来保证不同任务对SCI口缓冲区的访问不发生冲突。每个SCI口都会对应一个接收以及一个发送缓冲区,对应的大小可以在.h文件中配置。

这个驱动的主要作用就是为每个SCI口提供缓冲区,一方面,SCI模块会不断的从发送缓冲区内获取字符并发送,另一方面,它会把接收到的字符不断放入接收缓冲区,这样所有经过SCI口的字节流都经过缓冲,有效缓解了处理不及时等现象。提供的函数也是围绕缓冲区的。

首先使用这个模块前一定要先调用SCI_BufferInit函数来进行初始化。
而由于一般来说一个SCI口只会有一个任务来接收SCI口的字节流,没有竞争的问题,所以只提供了SCI_GetCharB函数来监听SCI口(和硬件驱动提供的SCI_GetChar相比多了一个B,即Buffer)。一般来说会专门开个任务阻塞地监听这个信道,类似这样:

static  void  SCI0ListenTask (void *p_arg){    INT8U c,err;    ……    while(true) {        c = SCI_GetCharB(SCI0,RX_MAX_TIME_INTERVAL,&err); //从SCI0获得一个字符,最大等待RX_MAX_TIME_INTERVAL次TICK。        if( err == SCI_RX_TIMEOUT ){          //超时导致的返回            ……          // 超时的处理            continue;        }        // 正常获得字符后的处理        ……    }}

而对于发送,因为有不同任务同时想用一个SCI口发送的问题,所以提供了互斥的方法,即SCI_PutCharB_Mutex和SCI_PutCharsB_Mutex,只要保证所有地方都使用这些互斥的方法发送,就可以保证不同任务间的发送互不干扰。
比如:

任务一发送:abcde\r 任务二发送:12345\r

如果不使用互斥/独占的方法发送的话(比如直接调用硬件驱动提供的函数),由于任务调度的原因,可能最后另外一头收到的就成了:abc12de\r345\r了。
而如果使用互斥的方法的话,另一头就能保证收到的是 abcde\r12345\r
另外,还提供的等价的互斥发送方法:SCI_SendBuf_hold、SCI_PutCharB、SCI_PutCharsB和SCI_SendBuf_release,他们需要成套使用,先用hold获取发送权,然后发送字节,最后释放发送权。这样就能保证在hold和release之间发送的字节的连续性了。

就讲到这里把,有什么建议或意见请留言。


更改历史:

2017/10/29 更新到 V2.1 支持了所有的SCI口。

原创粉丝点击