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

📄 uart0.c

📁 Rabbit 32Bit RTOS源代码
💻 C
字号:
/*********************************************************************
*                   Copyright (c) 2011-2012,李士伟
*                     All rights reserved.
*文 件 名:uart0.c
*描    述:串口0驱动代码源文件
*          该串口实现多个任务先来先服务的策略
*          对于一个正在发送(接受)任务,它占有UART0SendingTCB(UART0ReceingTCB)
*          并设置发送(接收)字符阀值,每当发送(接收)完一个字符阀值递减
*          直到中断函数判断阀值为0时唤醒正在等待发送(接收)完的任务
*          在发送(接收)期间阻塞其它的发送(接收)任务,
*          将被阻塞的任务按加入UART0SendWaitQ(UART0ReceWaitQ),
*          直到其发送(接收)完成,唤醒阻塞的任务
*当前版本:V1.02
*作    者:李士伟
*创建日期:2011.09.24
**********************************************************************/
/*********************************************************************
*版    本:V1.02
*修 改 人:李士伟
*修改日期:2012.01.07
*描    述:以中断工作方式替换原来的查询等待方式
**********************************************************************/
#include <kernel\asm.h>
#include <kernel\kds.h>
#include <kernel\kd.h>
#include <kernel\sched.h>
#include <kernel\chr_buf.h>
#include <kernel\flag.h>
#include <drivers\lpc2103\uart0.h>
#include <drivers\lpc2103\target.h>
#include <drivers\lpc2103\vic.h>
#include <drivers\lpc2103\pinsel.h>

static INT32U      UART0SendValve;    /* 发送完多少个字节唤醒发送任务 */
static INT32U      UART0ReceValve;    /* 接收完多少个字节唤醒接收任务 */

static OS_TCB     *UART0SendingTCB;    /* 正在等待发送完的任务 */
static OS_TCB     *UART0ReceingTCB;    /* 正在等待接收完的任务 */

static OS_TCB     *UART0SendWaitQ;    /* 等待发送队列 */
static OS_TCB     *UART0ReceWaitQ;    /* 等待接收队列 */

static OS_CHR_BCB *UART0SendBcb;      /* 发送缓冲区控制块 */
static OS_CHR_BCB *UART0ReceBcb;      /* 接收缓冲区控制块 */

/*********************************************************************
*函 数 名:UART0_SetBuf
*描    述:设置串口0的发送/接收缓冲区大小
*输入参数:send_buf_size, 发送缓冲区大小
*          rece_buf_size, 接收缓冲区大小
*输出参数:无
*返 回 值:0,设置失败,1,设置成功
*注    意:
**********************************************************************/
INT32U UART0_SetBuf(INT32U send_buf_size, INT32U rece_buf_size)
{
    UART0SendBcb = OS_CreateChrBuf(send_buf_size);
    if (UART0SendBcb == NULL)
    {
        return 0;
    }
    UART0ReceBcb = OS_CreateChrBuf(rece_buf_size);
    if (UART0ReceBcb == NULL)
    {
        OS_FreeChrBuf(UART0SendBcb);
        return 0;
    }
    return 1;
}

/*********************************************************************
*函 数 名:UART0_Init
*描    述:初始化串口0
*输入参数:
*          baud:波特率
*          bits: 字长度,可选5,6,7,8
*          stopbits: 停止位位数,取值1或2
*              stopbits == 2 时 如果字长5位,则停止位1.5位
*          parity: 校验选择
*              parity == 0 奇检验
*              parity == 1 偶校验
*              parity == 2 校验位强制为"1"
*              parity == 3 校验位强制为"0"
*              parity == 4 不校验
*输出参数:无
*返 回 值:无
*注    意:为防止在未设置缓冲区的情况下接收到字符
*          最好是先调用UART0_SetBuf设置完缓冲区在调用该函数初始化UART0
**********************************************************************/
INT32U UART0_Init(INT32U baud, INT32U bits, INT32U stopbits, INT32U parity)
{
    INT8U Reg = 0;
    INT16U Fdiv;

    /* 参数检查 */
    if ((bits < 5) || (bits > 8) 
        || (stopbits < 1) || (stopbits > 2)
        || (parity > 4))
    {
        return 0;
    }
    
    if (PIN_Configure(PIN_TXD0))
    {
        if (PIN_Configure(PIN_RXD0) == 0)
        {
            PIN_Release(PIN_TXD0);
            return 0;
        }
    }
    Reg  = bits-5;  /* 设置字长度 */
    Reg |= ((stopbits - 1) << 2);  /* 设置停止位数 */
    if (parity < 4)
    {
        Reg |= (parity << 4) + 8;   /* 设置校验 */
    }
    
    Reg |= 0x80;   /* DLAB = 1 */

    U0LCR = 0;
    U0LCR = Reg;  /* U0LCR */
    
    /* 设置波特率 */
    Fdiv = (Fpclk / 16) / baud;
    U0DLM = Fdiv >> 8;
    U0DLL = Fdiv & 0xff;
    U0LCR &= 0x7f;

    U0IER = 3;  /* 开发送和接收中断 */
    U0TER = 0x80; /* 发送使能 */

    UART0SendValve = 0;
    UART0ReceValve = 0;
    UART0SendWaitQ = NULL;
    UART0ReceWaitQ = NULL;
    UART0SendingTCB = NULL;
    UART0ReceingTCB = NULL;
    /* 注册UART0中断例程 */
    VIC_RegisterIRQ(UART0_Handler, UART0_INTR_NUM, UART0_INTR_PRIO);
    return 1;
}

/*********************************************************************
*函 数 名:UART0_ISR
*描    述:UART0中断服务例程
*输入参数:无
*输出参数:无
*返 回 值:无
*注    意:该例程根据读取U0IIR(读取时自动消除中断标志)
*          判断UART0产生什么中断,执行相应的操作
**********************************************************************/
void UART0_ISR(void)
{
    INT8U ch, IIR;

    IIR = U0IIR;

    if (IIR & 0x2)  /* THRE 中断 */
    {
        if (UART0SendingTCB == NULL) /* 防止没有任务在等待发送完 */
        {
            goto __end_uart0_send_isr;
        }
        UART0SendValve--;
        if (OS_GetChrBufByte(UART0SendBcb, &ch)) /* 缓冲区还有未发送的数据 */
        {
            U0THR = ch;
        }
        if (UART0SendValve == 0)   /* 阀值为0,唤醒等待发送完的任务 */
        {
            OS_EnterRunQ(UART0SendingTCB);
        }
    }
__end_uart0_send_isr:

    if (IIR & 0x4)  /* 接收到字符 */
    {
        ch = U0RBR;
        if (UART0ReceingTCB == NULL) /* 防止没有任务在等待接收完 */
        {
            goto __end_uart0_rece_isr;
        }
        UART0ReceValve--;
        OS_PutChrBufByte(UART0ReceBcb, ch);  /* 将接收的字符输入到接收缓冲区 */ 
        if (UART0ReceValve == 0)  /* 阀值为0,唤醒等待接收完的任务 */
        {
            OS_EnterRunQ(UART0ReceingTCB);
        }
    }
__end_uart0_rece_isr:
    VICVectAddr = 0x00;  /* 通知VIC中断处理完 */
}

/*********************************************************************
*函 数 名:UART0_SendByte
*描    述:发送一个字节
*输入参数:b:字节
*输出参数:无
*返 回 值:无
*注    意:该函数在将数据送入到U0THR,阻塞任务并调度,
*          直到发送完,才唤醒任务,
*          任务被唤醒时唤醒一个其它等待发送的任务
**********************************************************************/
void UART0_SendByte(INT8U b)
{
    OS_ENTER_CRITICAL();
    for ( ; ; )
    {
        if (UART0SendingTCB != NULL) /* 判断是否有任务正在发送数据 */
        {
            /* 有任务在发送数据,进入等待发送队列 */
            OS_EnterWaitQTail(&UART0SendWaitQ, OSTCBCur); 
            OS_Sched();
            continue ;
        }
        break ;
    }
    UART0SendValve = 1; /* 设置阀值1,发送完一个字节就唤醒任务 */
    OS_EnterWaitQTail(&UART0SendingTCB, OSTCBCur); /* 进入到等待发送完队列 */
    U0THR = b; /* 发送数据 */
    OS_EXIT_CRITICAL();
    OS_Sched();
    if (UART0SendWaitQ != NULL)
    {
        OS_EnterRunQ(UART0SendWaitQ); /* 唤醒其它任务发送数据 */
    }
    OS_Sched();
    return ;
}

/*********************************************************************
*函 数 名:UART0_SendNBytes
*描    述:发送N个字节
*输入参数:pbyte_arr: 字节数组指针
*          n:发送字节数
*输出参数:无
*返 回 值:无
*注    意:该函数区别于UART0_SendByte的地方是它将数据送入缓冲区,
*          并从缓冲区获取第一个字节送入发送寄存器
**********************************************************************/
void UART0_SendNBytes(INT8U *pbyte_arr, INT32U n)
{
    INT8U tx;
    /* 错误参数检查 */
    if (pbyte_arr == NULL || n == 0)
    {
        return ;
    }
    
    OS_ENTER_CRITICAL();
    for ( ; ; )
    {
        if (UART0SendingTCB != NULL) /* 判断是否有任务正在发送数据 */
        {
            /* 有任务在发送数据,进入等待发送队列 */
            OS_EnterWaitQTail(&UART0SendWaitQ, OSTCBCur);
            OS_Sched();
            continue ;
        }
        break ;
    }
    UART0SendValve = n;  /* 设置阀值,发送完n个字节唤醒任务 */
    OS_EnterWaitQTail(&UART0SendingTCB, OSTCBCur); 
    OS_PutChrBufNBytes(UART0SendBcb, pbyte_arr, n); /* 将数据送入发送缓冲区 */
    OS_GetChrBufByte(UART0SendBcb, &tx);  /* 从缓冲区获取一个字节发送 */
    U0THR = tx; /* 发送,发送完触发中断 */
    OS_EXIT_CRITICAL();
    OS_Sched();
    if (UART0SendWaitQ != NULL)
    {
        OS_EnterRunQ(UART0SendWaitQ); /* 唤醒其它任务发送数据 */
    }
    OS_Sched();
    return ;
}

/*********************************************************************
*函 数 名:UART0_ReceByte
*描    述:接收一个字节
*输入参数:无
*输出参数:无
*返 回 值:返回字节
*注    意:
**********************************************************************/
INT8U UART0_ReceByte(void)
{
    INT8U ch;
    OS_ENTER_CRITICAL();
    for ( ; ; )
    {
        if (UART0ReceingTCB != NULL)
        {
            OS_EnterWaitQTail(&UART0ReceWaitQ, OSTCBCur);
            OS_Sched();
            continue ;
        }
        break ;
    }
    UART0ReceValve = 1;
    OS_EnterWaitQTail(&UART0ReceingTCB,OSTCBCur);
    OS_Sched();
    OS_GetChrBufByte(UART0ReceBcb, &ch);
    OS_EXIT_CRITICAL();
    if (UART0ReceWaitQ != NULL)
    {
        OS_EnterRunQ(UART0ReceWaitQ); /* 唤醒其它任务发送数据 */
    }
    OS_Sched();
    return ch;
}

/*********************************************************************
*函 数 名:UART0_ReceNBytes
*描    述:接收N个字节
*输入参数:n:接收字节数
*输出参数:pbyte_arr: 字节串接收容器
*返 回 值:无
*注    意:
**********************************************************************/
void UART0_ReceNBytes(INT8U *pbyte_arr, INT32U n)
{
    if (pbyte_arr == NULL || n == 0)
    {
        return ;
    }
    OS_ENTER_CRITICAL();
    for ( ; ; )
    {
        if (UART0ReceingTCB != NULL)
        {
            OS_EnterWaitQTail(&UART0ReceWaitQ, OSTCBCur);
            OS_Sched();
            continue ;
        }
        break;
    }
    UART0ReceValve = n;
    OS_EnterWaitQTail(&UART0ReceingTCB,OSTCBCur);
    OS_Sched();
    OS_GetChrBufNBytes(UART0ReceBcb, pbyte_arr, n);
    OS_EXIT_CRITICAL();
    if (UART0ReceWaitQ != NULL)
    {
        OS_EnterRunQ(UART0ReceWaitQ); /* 唤醒其它任务发送数据 */
    }
    OS_Sched();
}

/*********************************************************************
*函 数 名:UART0_putc
*描    述:发送一个字符
*输入参数:ch:字符
*输出参数:无
*返 回 值:无
*注    意:
**********************************************************************/
void UART0_putc(char ch)
{
    UART0_SendByte((INT8U) ch);
}

/*********************************************************************
*函 数 名:UART0_puts
*描    述:发送一个字符串
*输入参数:str:字符串指针
*输出参数:无
*返 回 值:无
*注    意:
**********************************************************************/
void UART0_puts(char *str)
{
    INT32U i = 0;
    while (*(str + i++) != '\0')
        ;
    if (i == 1)
    {
        return ;
    }
    UART0_SendNBytes((INT8U*)str, --i);
}

/*********************************************************************
*函 数 名:UART0_getc
*描    述:接收一个字符
*输入参数:无
*输出参数:无
*返 回 值:接收到的字符
*注    意:
**********************************************************************/
char UART0_getc(void)
{
    return (char)UART0_ReceByte();
}

/*********************************************************************
*函 数 名:UART0_gets
*描    述:接收一个字符串
*输入参数:无
*输出参数:s: 接收字符串容器指针
*返 回 值:无
*注    意:回车,换行自动转化字符串结束标志
**********************************************************************/
void UART0_gets(char *s)
{
    for ( ; ; )
    {
        *s=(char)UART0_ReceByte();
        /* 回车,换行自动转化字符串结束标志 */
        if (*s == 13 || *s == 10)
        {
            *s = '\0';
             return ;
        }
        s++;
    }
}

⌨️ 快捷键说明

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