📄 commrtos.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 + -