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

📄 serial.c

📁 AT91RM9200-UC/OS-II,clock,irq,usart,pio等驱动
💻 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 + -