⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 commrtos.c

📁 一个简单易用的可裁减的小型实时操作系统 移植非常简单
💻 C
字号:
/*
 *******************************************************************************
 *
 * MicroROS
 *
 * Copyright (C) 2007 <amwox@163.com>			
 *
 * Description	: 异步串口通信
 *				参考Jean J. Labrosse的<<Embedded Systems Building Blocks>>
 * File			: commrtos.c
 * Author		: amwox
 * Edition		: V0.01
 * History		: 2008-01-29  created 
 *******************************************************************************
 */
#include "..\include\MicroROS.h"
#include "..\include\os_cpu.h" 

typedef struct {
    BYTE		RingBufRxCtr;					/* 环形队列接收计数器				*/
    SEM			RingBufRxSem;					/* 接收信号量                       */
    BYTE*		RingBufRxInPtr;					/* 接收队列入队指针					*/
    BYTE*		RingBufRxOutPtr;				/* 接收队列出队指针					*/
    BYTE		RingBufRx[COMM_RX_BUFF_SIZE];	/* 接收环形队列                     */
    BYTE		RingBufTxCtr;					/* 环形队列发送计数器               */
    SEM			RingBufTxSem;					/* 发送信号量                       */
    BYTE*		RingBufTxInPtr;					/* 发送队列入队指针					*/
    BYTE*		RingBufTxOutPtr;				/* 发送队列出队指针					*/
    BYTE		RingBufTx[COMM_TX_BUFF_SIZE];	/* 发送环形队列                     */
} COMM_RING_BUF;

COMM_RING_BUF  Comm1Buf;
COMM_RING_BUF  Comm2Buf;	

/* 
 * Description	: 在指定通道ch的时间time内读取一个字符
 * Arguments	: ch		通信通道:COMM0,COMM1
 *				  time		等待一个字符的时间,LIMITLESS(0xFFFF)为不限时
 *				  err		错误代码指针
 * Returns		: 返回接收到的字符
 */
BYTE CommGetChar(BYTE ch, WORD time, BYTE *err)
{
	BYTE          c;
    BYTE          oserr;
    COMM_RING_BUF *pbuf;


    switch (ch) {                                     
        case COMM0:
             pbuf = &Comm1Buf;
             break;

        case COMM1:
             pbuf = &Comm2Buf;
             break;

        default:
             *err = COMM_BAD_CH;
             return (NULL);
    }
    oserr = OS_SemaphorePend(&(pbuf->RingBufRxSem), 1,time);             
    if (oserr == TIME_OUT) {                            
        *err = COMM_RX_TIMEOUT;                         
        return (NULL);
    } else {
        OS_ENTER_CRITICAL();
        pbuf->RingBufRxCtr--;                     
        c = *pbuf->RingBufRxOutPtr++;                  
        if (pbuf->RingBufRxOutPtr == &pbuf->RingBufRx[COMM_RX_BUFF_SIZE]) {     
            pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0];
        }
        OS_EXIT_CRITICAL();
        *err = COMM_NO_ERR;
        return (c);
    }
}

/* 
 * Description	: 在中断服务程序中从发送环形队列中读取一个字符
 * Arguments	: ch		通信通道
 *				  err		错误代码指针
 * Returns		: 读取到的字符
 */
BYTE CommGetTxChar(BYTE ch, BYTE *err)
{
	BYTE          c;
    COMM_RING_BUF *pbuf;


    switch (ch) {                                        
        case COMM0:
             pbuf = &Comm1Buf;
             break;

        case COMM1:
             pbuf = &Comm2Buf;
             break;

        default:
             *err = COMM_BAD_CH;
             return (NULL);
    }
    if (pbuf->RingBufTxCtr > 0) {                         
        pbuf->RingBufTxCtr--;                           
        c = *pbuf->RingBufTxOutPtr++;                    
        if (pbuf->RingBufTxOutPtr == &pbuf->RingBufTx[COMM_TX_BUFF_SIZE]) {    
            pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0];
        }
        OS_SemaphorePost(&(pbuf->RingBufTxSem));                   
        *err = COMM_NO_ERR;
        return (c);                                    
    } else {
        *err = COMM_TX_EMPTY;
        return (NULL);                                  
    }
}

/* 
 * Description	:初始化通信端口
 * Arguments	: 
 * Returns		: 
 */
void CommInit(void)
{
	COMM_RING_BUF *pbuf;


    pbuf                  = &Comm1Buf;                    
    pbuf->RingBufRxCtr    = 0;
    pbuf->RingBufRxInPtr  = &pbuf->RingBufRx[0];
    pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0];
    OS_SemaphoreCreate(&(pbuf->RingBufRxSem),0);
    pbuf->RingBufTxCtr    = 0;
    pbuf->RingBufTxInPtr  = &pbuf->RingBufTx[0];
    pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0];
    OS_SemaphoreCreate(&(pbuf->RingBufTxSem),0);

    pbuf                  = &Comm2Buf;                     
	pbuf->RingBufRxCtr    = 0;
    pbuf->RingBufRxInPtr  = &pbuf->RingBufRx[0];
    pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0];
    OS_SemaphoreCreate(&(pbuf->RingBufRxSem),0);
    pbuf->RingBufTxCtr    = 0;
    pbuf->RingBufTxInPtr  = &pbuf->RingBufTx[0];
    pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0];
    OS_SemaphoreCreate(pbuf->RingBufTxSem,0);
}

/* 
 * Description	: 查询缓冲区是否为空
 * Arguments	: ch		通信通道
 * Returns		: 
 */
BOOL CommIsEmpty(BYTE ch)
{
	BOOL        	empty;
	COMM_RING_BUF*	pbuf;
	
    switch (ch) {                                          
        case COMM0:
             pbuf = &Comm1Buf;
             break;

        case COMM1:
             pbuf = &Comm2Buf;
             break;

        default:
             return (TRUE);
    }
    OS_ENTER_CRITICAL();
    if (pbuf->RingBufRxCtr > 0) {                          
        empty = FALSE;                                   
    } else {
        empty = TRUE;                                   
    }
    OS_EXIT_CRITICAL();
    return (empty);
}

/* 
 * Description	: 查询缓冲区是否满
 * Arguments	: ch		通信通道
 * Returns		: 
 */
BOOL CommIsFull(BYTE ch)
{
	BOOL			full;
	COMM_RING_BUF *	pbuf;


    switch (ch) {                                          
        case COMM0:
             pbuf = &Comm1Buf;
             break;

        case COMM1:
             pbuf = &Comm2Buf;
             break;

        default:
             return (TRUE);
    }
    OS_ENTER_CRITICAL();
    if (pbuf->RingBufTxCtr < COMM_TX_BUFF_SIZE) {          
        full = FALSE;                                      
    } else {
        full = TRUE;                                       
    }
    OS_EXIT_CRITICAL();
    return (full);
}

/* 
 * Description	: 将字符c放入通道ch的环形队列
 * Arguments	: ch		通信通道
 *				  c			字符
 *				  time		超时时间:LIMITLESS(0xFFFF)为不限时
 * Returns		: 返回错误代码
 */
BYTE CommPutChar(BYTE ch, BYTE c, WORD time)
{
	BYTE          oserr;
    COMM_RING_BUF *pbuf;


    switch (ch) {                                        
        case COMM0:
             pbuf = &Comm1Buf;
             break;

        case COMM1:
             pbuf = &Comm2Buf;
             break;

        default:
             return (COMM_BAD_CH);
    }
    OS_SemaphorePend(pbuf->RingBufTxSem, to, &oserr);         
    if (oserr == TIME_OUT) {
        return (COMM_TX_TIMEOUT);                        
    }
    OS_ENTER_CRITICAL();
    pbuf->RingBufTxCtr++;                                
    *pbuf->RingBufTxInPtr++ = c;                          
    if (pbuf->RingBufTxInPtr == &pbuf->RingBufTx[COMM_TX_BUFF_SIZE]) {    
        pbuf->RingBufTxInPtr = &pbuf->RingBufTx[0];
    }
    if (pbuf->RingBufTxCtr == 1) {                        
        CommTxIntEn(ch);                                  
    }
    OS_EXIT_CRITICAL();
    return (COMM_NO_ERR);
}

/* 
 * Description	: 在中断服务程序中向发送环形队列中写一个字符
 * Arguments	: ch		通信通道
 *				  c			字符
 * Returns		: 
 */
void CommPutRxChar(BYTE ch, BYTE c)
{
	COMM_RING_BUF *pbuf;


    switch (ch) {                                         
        case COMM0:
             pbuf = &Comm1Buf;
             break;

        case COMM1:
             pbuf = &Comm2Buf;
             break;

        default:
             return;
    }
    if (pbuf->RingBufRxCtr < COMM_RX_BUFF_SIZE) {          
        pbuf->RingBufRxCtr++;                             
        *pbuf->RingBufRxInPtr++ = c;                      
        if (pbuf->RingBufRxInPtr == &pbuf->RingBufRx[COMM_RX_BUFF_SIZE]) { 
            pbuf->RingBufRxInPtr = &pbuf->RingBufRx[0];
        }
        OS_SemaphorePost(&(pbuf->RingBufRxSem));                  
    }
}

BYTE  CommCfgPort (BYTE ch, WORD baud, BYTE bits, BYTE parity, BYTE stops)
{
    WORD  div;                                      /* Baud rate divisor                             */
    BYTE   divlo;
    BYTE   divhi;
    BYTE   lcr;                                      /* Line Control Register                         */
    WORD  base;                                     /* COMM port base address                        */


    switch (ch) {                                     /* Obtain base address of COMM port              */
        case COMM0:
             base = COMM1_BASE;
             break;

        case COMM1:
             base = COMM1_BASE;
             break;

        default:
             return (COMM_BAD_CH);
    }
    div   = (WORD)(115200L / (INT32U)baud);         /* Compute divisor for desired baud rate         */
    divlo =  div & 0x00FF;                            /* Split divisor into LOW and HIGH bytes         */
    divhi = (div >> 8) & 0x00FF;
    lcr   = ((stops - 1) << 2) + (bits - 5);
    switch (parity) {
        case COMM_PARITY_ODD: 
             lcr |= 0x08;                             /* Odd  parity                                   */
             break;

        case COMM_PARITY_EVEN: 
             lcr |= 0x18;                             /* Even parity                                   */
             break;
    }
    OS_ENTER_CRITICAL();
    outp(base + COMM_UART_LCR, BIT7);                 /* Set divisor access bit                        */
    outp(base + COMM_UART_DIV_LO, divlo);             /* Load divisor                                  */
    outp(base + COMM_UART_DIV_HI, divhi);
    outp(base + COMM_UART_LCR, lcr);                  /* Set line control register (Bit 8 is 0)        */
    outp(base + COMM_UART_MCR, BIT3 | BIT1 | BIT0);   /* Assert DTR and RTS and, allow interrupts      */
    outp(base + COMM_UART_IER, 0x00);                 /* Disable both Rx and Tx interrupts             */
    OS_EXIT_CRITICAL();
    CommRxFlush(ch);                                  /* Flush the Rx input                            */
    return (COMM_NO_ERR);
}

void  CommISRHandler (BYTE ch)
{
    BYTE   c;
    BYTE   iir;                                          /* Interrupt Identification Register (IIR)   */
    BYTE   stat;
    WORD  base;                                         /* COMM port base address                    */
    BYTE   err;
    BYTE   max;                                          /* Max. number of interrupts serviced        */


    switch (ch) {                                         /* Obtain pointer to communications channel  */
        case COMM0:
             base = COMM0_BASE;
             break;

        case COMM1:
             base = COMM1_BASE;
             break;

        default:
             return;
    }
    max = COMM_MAX_RX;
    iir = (BYTE)inp(base + COMM_UART_IIR) & 0x07;        /* Get contents of IIR                       */
    while (iir != 1 && max > 0) {                         /* Process ALL interrupts                    */
        switch (iir) {
            case 0:                                       /* See if we have a Modem Status interrupt   */
                 c = (BYTE)inp(base + COMM_UART_MSR);    /* Clear interrupt (do nothing about it!)    */
                 break;

            case 2:                                       /* See if we have a Tx interrupt             */
                 c = CommGetTxChar(ch, &err);             /* Get next character to send.               */
                 if (err == COMM_TX_EMPTY) {              /* Do we have anymore characters to send ?   */
                                                          /* No,  Disable Tx interrupts                */
                     stat = (BYTE)inp(base + COMM_UART_IER) & ~BIT1; 
                     outp(base + COMM_UART_IER, stat);
                 } else {
                     outp(base + COMM_UART_THR, c);       /* Yes, Send character                       */
                 }
                 break;

            case 4:                                       /* See if we have an Rx interrupt            */
                 c  = (BYTE)inp(base + COMM_UART_RBR);   /* Process received character                */
                 CommPutRxChar(ch, c);                    /* Insert received character into buffer     */
                 break;

            case 6:                                       /* See if we have a Line Status interrupt    */
                 c   = (BYTE)inp(base + COMM_UART_LSR);  /* Clear interrupt (do nothing about it!)    */
                 break;
        }
        iir = (BYTE)inp(base + COMM_UART_IIR) & 0x07;    /* Get contents of IIR                       */
        max--;
    }
    switch (ch) {
        case COMM0:
        case COMM1:
             outp(PIC_INT_REG_PORT, 0x20);                /* Reset interrupt controller                */
             break;

        default:
             outp(PIC_INT_REG_PORT, 0x20);
             break;
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -