📄 serial.c
字号:
#include "includes.h"
#include "serial.h"
#include "interrupt.h"
//#include <string.h>
//#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
/*******************************************************************************
* Uart的PDC,如果(PDC_RPR,PDC_RCR),(PDC_TNPR,PDC_TNCR)都设置了,那么当Uart接收
* 一个字符PDC_RCR减1,当减到0时,会产生相应的中断,并由硬件自动完成PDC_RPR =
* PDC_TNPR,PDC_RCR = PDC_TNCR的装载,因此产生相应中断后,我们只重新设置PDC_TNPR
* 和PDC_TNCR即可,不需要设置当前使用的缓冲PDC_RPR,PDC_RCR
*******************************************************************************/
AT91_CHAN UART_CHAN[UART_CNT] =
{
{AT91C_ID_SYS,FALSE,{0,},(AT91PS_USART)AT91C_BASE_DBGU,
NULL,NULL,{{0,},},{0,},NULL,NULL,{0,}},
{AT91C_ID_US0,FALSE,{0,},AT91C_BASE_US0,
NULL,NULL,{{0,},},{0,},NULL,NULL,{0,}},
{AT91C_ID_US1,FALSE,{0,},AT91C_BASE_US1,
NULL,NULL,{{0,},},{0,},NULL,NULL,{0,}},
{AT91C_ID_US2,FALSE,{0,},AT91C_BASE_US2,
NULL,NULL,{{0,},},{0,},NULL,NULL,{0,}},
{AT91C_ID_US3,FALSE,{0},AT91C_BASE_US3,
NULL,NULL,{{0,},},{0,},NULL,NULL,{0,}}
};
/*******************************************************************************
* 名称:SetUartIO()
* 功能:配置串口设备的IO及控制电源
* 入口参数:pUart 串口设备的属性参数
* ID--//该设备的ID,目前用该外设的中断号
*
* 出口参数:无
* 说明:根据设备ID设置设备的IO及时钟
*******************************************************************************/
void SetUartIO(AT91_CHAN *pUart)
{
switch(pUart->Id)
{
case AT91C_ID_SYS:
AT91F_DBGU_CfgPMC();
AT91F_DBGU_CfgPIO();
break;
case AT91C_ID_US0:
AT91F_US0_CfgPMC();
AT91F_US0_CfgPIO();
break;
case AT91C_ID_US1:
AT91F_US1_CfgPMC();
AT91F_US1_CfgPIO();
break;
case AT91C_ID_US2:
AT91F_US2_CfgPMC();
AT91F_US2_CfgPIO();
break;
case AT91C_ID_US3:
AT91F_US3_CfgPMC();
AT91F_US3_CfgPIO();
break;
default:
break;
}
}
/*******************************************************************************
* 名称:SetUartMode()
* 功能:配置串口设备的IO及控制电源
* 入口参数:pUart 串口设备的属性参数
* data--数据位,校验位,停止位,波特率
*
* 出口参数:无
* 说明:根据pUart->data的设置该设备的通讯属性
*
*******************************************************************************/
void SetUartMode(AT91_CHAN *pUart)
{
int mode;
mode = AT91C_US_USMODE_NORMAL + AT91C_US_CLKS_CLOCK;
switch(pUart->data.stop)
{
case 1:
mode += AT91C_US_NBSTOP_1_BIT;
break;
case 2:
mode += AT91C_US_NBSTOP_2_BIT;
break;
case 15:
mode += AT91C_US_NBSTOP_15_BIT;
break;
default:
return;
}
switch(pUart->data.parity)
{
case 0:
mode += AT91C_US_PAR_EVEN;
break;
case 1:
mode += AT91C_US_PAR_ODD;
break;
case 2:
mode += AT91C_US_PAR_SPACE;
break;
case 3:
mode += AT91C_US_PAR_MARK;
break;
case 4:
mode += AT91C_US_PAR_NONE;
break;
case 6:
mode +=AT91C_US_PAR_MULTI_DROP;
break;
default:
return;
}
switch(pUart->data.len)
{
case 5:
mode += AT91C_US_CHRL_5_BITS;
break;
case 6:
mode += AT91C_US_CHRL_6_BITS;
break;
case 7:
mode += AT91C_US_CHRL_7_BITS;
break;
case 8:
mode += AT91C_US_CHRL_8_BITS;
break;
default:
return;
}
AT91F_US_Configure (
pUart->pUart, // Uart base address
MASTER_CLK, // 60 MHz
mode, // mode Register to be programmed
pUart->data.baud, // baudrate to be programmed
0); // timeguard to be programmed
}
/*******************************************************************************
* 名称:SetUartPDC()
* 功能:设置Uart的PDC的环行缓冲
* 入口参数:pUart 串口设备的属性参数
* Cbuf--接收数据环行缓冲
*
* 出口参数:无
* 说明:把PDC的两个指针分别指向pUart->Cbuf[i].buf的地址,长度分别是
* pUart->Cbuf[i].len的值
*******************************************************************************/
void SetUartPDC(AT91_CHAN *pUart)
{
AT91PS_PDC pPDC = (AT91PS_PDC) &(pUart->pUart->US_RPR);
while((!AT91F_PDC_IsRxEmpty(pPDC)) || (!AT91F_PDC_IsNextRxEmpty(pPDC)))
;
AT91F_PDC_SetRx(pPDC,
pUart->Cbuf[0].buf,
pUart->Cbuf[0].len);
AT91F_PDC_SetNextRx(pPDC,
pUart->Cbuf[1].buf,
pUart->Cbuf[1].len);
AT91F_PDC_EnableRx(pPDC);
}
/*******************************************************************************
* 名称:SetUartMutexSem()
* 功能:创建该设备的发送缓冲竞争信号量
* 入口参数:pUart 串口设备的属性参数
* MutexSem--发送缓冲区的竞争信号量
*
* 出口参数:无
* 说明:
*******************************************************************************/
void SetUartMutexSem(AT91_CHAN *pUart)
{
//发送互斥信号量
pUart->pMutexSem = OSSemCreate(1);
}
/*******************************************************************************
* 名称:SerialInit()
* 功能:串口设备初始化函数
* 入口参数:Uart 串口设备的属性参数
* ID--该设备的ID,目前用该外设的中断号
* data--数据位,校验位,停止位,波特率,超时时间
* GetChar--接收数据的处理函数
* 出口参数:无
* 说明:设置对应串口设备的通讯属性及针对该串口的接收处理函数,打开该设备自己的
* 中断使能位,同时把设备加入中断处理程序列表,打开中断控制器的对应中断使
* 能位
*******************************************************************************/
void SerialInit(AT91_CHAN Uart)
{
#if OS_CRITICAL_METHOD == 3
int cpu_sr;
#endif
int idx;
AT91_CHAN *pUart;
OS_ENTER_CRITICAL();
//根据中断号从同类设备的索引表中找出对应的序号
idx = Index_table[Uart.Id];
pUart = &UART_CHAN[idx];
pUart->data = Uart.data;
pUart->GetChar = UartGetChar;//Uart.GetChar;
pUart->PutChar = UartPutChar;//Uart.PutChar;
//设置环行缓冲区的初始值
pUart->pHead = pUart->Cbuf;
pUart->Cbuf[0].len = RECV_BUF_LEN;
pUart->Cbuf[1].len = RECV_BUF_LEN;
pUart->Cbuf[0].pNext = &pUart->Cbuf[1];
pUart->Cbuf[1].pNext = &pUart->Cbuf[0];
//设置串口的IO,PMC
SetUartIO(&Uart);
SetUartMutexSem(pUart);
SetUartMode(pUart);
SetUartPDC(pUart);
// Reset Status Bits (PARE, FRAME, OVRE and RXBRK)
pUart->pUart->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX;
pUart->pUart->US_CR = AT91C_US_RSTSTA;
//设置接收超时时间
if(pUart->data.timeout > 0xffff)
pUart->pUart->US_RTOR = 0xffff;
else
pUart->pUart->US_RTOR = pUart->data.timeout;
pUart->pUart->US_CR = AT91C_US_STTTO;
// Enable Transmitter
AT91F_US_EnableTx(pUart->pUart);
AT91F_US_EnableRx(pUart->pUart);
AT91F_US_EnableIt(pUart->pUart,AT91C_US_RXBUFF|AT91C_US_TIMEOUT|AT91C_US_ENDRX);
//填充中断处理函数列表,供OS_CPU_IRQ_ISR_Handler查询使用
intConnect(pUart->Id,(AT91_REG)pUart->pUart,SerialIntHandling);
//设置该外设对应的中断控制器使能位
intEnable(pUart->Id);
//置该设备可用标志
pUart->flag = TRUE;
OS_EXIT_CRITICAL();
}
/***********************************************
***AT91C_BASE_DBGU没有TIME_OUT功能,应该特殊
***处理,现没做特殊处理
************************************************/
/*******************************************************************************
* 名称:SerialIntHandling()
* 功能:串口中断处理函数
* 入口参数:uart_base 对应串口外设的基地址
* uart_vector 对应的外设中断号
* 出口参数:无
* 说明:该函数是所有串口外设的中断函数入口(与OS_CPU_IRQ_ISR_Handler的接口),在
* 该函数中判断具体的外设并把接收的数据放入Buf_bake,以该数据为参数调用相
* 应GetChar接收处理函数处理接收的数据
*******************************************************************************/
void SerialIntHandling(int uart_base,int uart_vector)
{
int state,idx;
int len;
AT91PS_USART pUart = (AT91PS_USART)uart_base;
AT91_CHAN *pChan;
state = pUart->US_CSR;
//根据中断号从同类设备的索引表中找出对应的序号
idx = Index_table[uart_vector];
pChan = UART_CHAN + idx;
//接收到预期长度的数据
if ((state & AT91C_US_ENDRX) || (state & AT91C_US_RXBUFF))
{
//把接收的数据放到Buf_bake
memcpy(pChan->Buf_bake,pChan->pHead->buf,pChan->pHead->len);
//把当前使用的缓冲区设置到备用缓冲序列
AT91F_PDC_SetNextRx(
(AT91PS_PDC) &(pUart->US_RPR),
pChan->pHead->buf,
pChan->pHead->len);
//把pHead当前缓冲头指向原备用缓冲区(是目前的使用缓冲区,由PDC
//自动切换)
pChan->pHead = pChan->pHead->pNext;
//执行接收处理函数
if(pChan->GetChar)
pChan->GetChar(pChan,len);
}
else//没接收到预期的数据而超时
if(state & AT91C_US_TIMEOUT)
{
//先取出当前还要接收的数据数
len = pUart->US_RCR;
//把备用的缓冲区设置为当前使用的缓冲区
AT91F_PDC_SetRx(
(AT91PS_PDC) &(pUart->US_RPR),
pChan->pHead->pNext->buf,
pChan->pHead->pNext->len
);
//把当前使用的缓冲区设置为备用缓冲区
AT91F_PDC_SetNextRx(
(AT91PS_PDC) &(pUart->US_RPR),
pChan->pHead->buf,
pChan->pHead->len);
//从当前缓冲区中取出已经接收的数据到Buf_bake
len = pChan->pHead->len - len;
memcpy(pChan->Buf_bake,pChan->pHead->buf,len);
//把pHead当前缓冲头指向原备用缓冲区
pChan->pHead = pChan->pHead->pNext;
//执行接收处理函数
if(pChan->GetChar)
pChan->GetChar(pChan,len);
}
else//别的错误情况
{
//执行接收处理函数
if(pChan->GetChar)
pChan->GetChar(pChan,0);
}
//重新设置超时,有新数据到达时重载
if(pChan->data.timeout > 0xffff)
pUart->US_RTOR = 0xffff;
else
pUart->US_RTOR = pChan->data.timeout;
pUart->US_CR = AT91C_US_STTTO;
}
/*******************************************************************************
* 名称:UartPrintf()
* 功能:串口输出处理函数
* 入口参数:id--串口号0-4对应串口列表的下标
* format--要输出的数据
* 出口参数:无
* 说明:
*******************************************************************************/
void UartPrintf(int id,const char *format,...)
{
AT91_CHAN *pUart;
INT8U err;
int len = 0;
va_list args;
if((id < 0) || (id >= UART_CNT))
return;
pUart = UART_CHAN + id;
//该设备不可用--没出初始化
if(!pUart->flag)
return;
//该设备是否被站用
OSSemPend(pUart->pMutexSem,0,&err);
//数据处理
va_start(args,format);
//len = vsprintf(pUart->Sbuf,format,args);//不能打印浮点型数据
len = vsnprintf(pUart->Sbuf,SEND_BUF_LEN,format,args);
va_end(args);
//数据输出
if(pUart->PutChar)
pUart->PutChar(pUart,len);
//释放该设备
OSSemPost(pUart->pMutexSem);
}
extern OS_EVENT *pQMsg;
extern void *QMsgTbl[MSG_QUEUE_SIZE];
extern TMessage Msg;
/*******************************************************************************
* 名称:UartGetChar()
* 功能:串口接收处理函数
* 入口参数:pUart--串口设备
* len--Sbuf中的数据长度
* 出口参数:无
* 说明:该函数由SerialIntHandling调用,可根据不同情况写不同的处理代码
*******************************************************************************/
void UartGetChar(AT91_CHAN *pUart,int len)
{
switch(len)
{
case RECV_ERR_LEN:
Msg.Type = FRAME_ERROR;
break;
case RECV_BUF_LEN:
Msg.Type = FRAME_FULL;
break;
default:
Msg.Type = FRAME_TIMEOUT;
break;
}
Msg.Body = pUart->Buf_bake;
Msg.Extra = len;
OSQPost(pQMsg,&Msg);//发送消息
}
/*******************************************************************************
* 名称:UartPutChar()
* 功能:串口发送函数
* 入口参数:pUart--串口设备
* len--Buf_bake中的数据长度
* 出口参数:无
* 说明:该函数由UartPrintf调用,向对应的串口设备发送数据
*******************************************************************************/
void UartPutChar(AT91_CHAN *pUart,int len)
{
int i;
if(len > SEND_BUF_LEN)
return;
for(i = 0; i < len; i ++)
{
while(!AT91F_US_TxReady(pUart->pUart));
AT91F_US_PutChar(pUart->pUart,pUart->Sbuf[i]);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -