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