📄 a0acd09115c5001d1a38f54921afee39
字号:
/*****************************************************************************
* uart.c: UART API file for NXP LPC23xx/24xx Family Microprocessors
*
* Copyright(C) 2006, NXP Semiconductor
* All rights reserved.
*
* History
* 2006.07.12 ver 1.00 Prelimnary version, first Release
*
******************************************************************************/
// modified by Martin Thomas
// - const BYTE in send
#include "FreeRTOS.h"
#include "queue.h"
#include "task.h"
#include "LPC23xx.h" /* LPC23xx/24xx definitions */
#include "type.h"
#include "target.h"
#include "irq.h"
#include "uart.h"
#include "string.h"
//#include "portmacro.h"
#define UART_RATE_BASE ( ( portTickType ) 20 ) // UART's base tick is 20ms
#define UART_STACK_SIZE configMINIMAL_STACK_SIZE
/* UART0 interrupt service routine handler. */
void vUART_ISR_Handler( void );
/* Queues used to hold received characters, and characters waiting to be
transmitted. */
static xQueueHandle xRxedChars;
static xQueueHandle xCharsForTx;
static volatile portLONG lTHREEmpty;
void PushACharIntoRcvBuffer(unsigned char rChr);
/*-----------------------------------------------------------*/
#define BUFSIZE UART_BUFSIZE
volatile DWORD UART0Status, UART1Status;
volatile BYTE UART0TxEmpty = 1, UART1TxEmpty = 1;
volatile BYTE UART0Buffer[BUFSIZE], UARTTxBuffer[BUFSIZE];
volatile DWORD UART0Count = 0, UARTTxCount = 0,UARTTxOffset=0;
/*
* The queues are created in serialISR.c as they are used from the ISR.
* Obtain references to the queues and THRE Empty flag.
*/
void vSerialISRCreateQueues( unsigned portBASE_TYPE uxQueueLength, xQueueHandle *pxRxedChars, xQueueHandle *pxCharsForTx, portLONG volatile **pplTHREEmptyFlag );
extern void IntDisable(void) ;
extern void IntEnable(void) ;
extern void myuart_irq(void);
void UART0Handler (void) __irq //__attribute__((naked))
{
IntDisable();
//portSAVE_CONTEXT();
UART0_Handler();
//portRESTORE_CONTEXT();
IntEnable();
}
/*-----------------------------------------------------------*/
void vSerialISRCreateQueues( unsigned portBASE_TYPE uxQueueLength, xQueueHandle *pxRxedChars,
xQueueHandle *pxCharsForTx, portLONG volatile **pplTHREEmptyFlag )
{
/* Create the queues used to hold Rx and Tx characters. */
xRxedChars = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( signed portCHAR ) );
xCharsForTx = xQueueCreate( uxQueueLength + 1, ( unsigned portBASE_TYPE ) sizeof( signed portCHAR ) );
/* Pass back a reference to the queues so the serial API file can
post/receive characters. */
*pxRxedChars = xRxedChars;
*pxCharsForTx = xCharsForTx;
/* Initialise the THRE empty flag - and pass back a reference. */
lTHREEmpty = ( portLONG ) pdTRUE;
*pplTHREEmptyFlag = &lTHREEmpty;
}
/*---------------------------------------------------- */
#define recv_ok 0x05
#define err_bcc 0x01
#define err_busy 0x02
#define err_cmd 0x03
#define err_flag 0x04
/*---------------------------------------------------- */
#define ERROR_INIT 0x05 //初始值
#define ERROR_ID 0x03 //错误ID
#define ERROR_CMD 0x03 //无此命令
#define ERROR_TOO_LONG 0x03 //数据太长
#define ERROR_ETX 0x03 //标志位错
#define ERROR_BCC 0x01 //校验码错
#define EEROR_OVER_TIME 0x04 // 超时
#define ERROR_SUCCESS 0x00 //接收成功
#define MKD_ID 0x2c
#define RCV_STX 0x01
#define RCV_ID 0x02
#define RCV_LENGTH 0x03
#define RCV_CMD_CODE 0x04
#define RCV_ETX 0x05
#define RCV_BCC 0x06
#define RCV_IDLE 0x00
#define FINISH 0x01
#define WAITTINGDATA 0x00
#define STX 0X02
#define ETX 0X03
/*---------------------------------------------------- */
struct CmdRcv CmdRcvIrq;
/*---------------------------------------------------- */
void PushACharIntoRcvBuffer(unsigned char rChr)
{
switch(CmdRcvIrq.rcvflg)
{
case RCV_STX:
if(rChr==STX)
{
CmdRcvIrq.rcvflg=RCV_ID;
CmdRcvIrq.bcc=CmdRcvIrq.bcc^rChr;
CmdRcvIrq.time_flag=1;
}
break;
case RCV_ID:
if(rChr!=MKD_ID) //如果ID错误,放弃接收后面字节,返回ERROR_ID
{
CmdRcvIrq.errcode=ERROR_ID;
CmdRcvIrq.cResult=FINISH;
CmdRcvIrq.rcvflg=RCV_IDLE;
}else
{
CmdRcvIrq.bcc=CmdRcvIrq.bcc^rChr;
CmdRcvIrq.rcvflg=RCV_LENGTH;
}
CmdRcvIrq.time_flag=1;
break;
case RCV_LENGTH:
CmdRcvIrq.len=rChr;
if(CmdRcvIrq.len>MAX_RCV_LENGTH_CMD_MKD) //数据长度超出范围
{
CmdRcvIrq.errcode=ERROR_TOO_LONG; //接收结果为真,返回ERROR_TOO_LONG
CmdRcvIrq.cResult=FINISH;
CmdRcvIrq.rcvflg=RCV_IDLE;
}else
{
CmdRcvIrq.bcc=CmdRcvIrq.bcc^rChr;
CmdRcvIrq.offset=0;
CmdRcvIrq.rcvflg=RCV_CMD_CODE;
}
CmdRcvIrq.time_flag=1;
break;
case RCV_CMD_CODE:
CmdRcvIrq.buffer[CmdRcvIrq.offset]=rChr;
CmdRcvIrq.bcc=CmdRcvIrq.bcc^rChr;
CmdRcvIrq.offset++;
if(CmdRcvIrq.offset==CmdRcvIrq.len)
{
CmdRcvIrq.rcvflg=RCV_ETX;
}
CmdRcvIrq.time_flag=1;
break;
case RCV_ETX:
if(rChr!=ETX)
{
CmdRcvIrq.errcode=ERROR_ETX;
CmdRcvIrq.rcvflg=RCV_IDLE;
}else
{
CmdRcvIrq.bcc=CmdRcvIrq.bcc^rChr;
CmdRcvIrq.rcvflg=RCV_BCC;
}
CmdRcvIrq.time_flag=1;
break;
case RCV_BCC:
CmdRcvIrq.cResult=FINISH; //接收完一次,需要回复消息
CmdRcvIrq.rcvflg=RCV_IDLE;
CmdRcvIrq.time_flag=0;
//if((CmdRcvIrq.bcc==rChr)&&(CmdRcvIrq.errcode==0x00))
{
CmdRcvIrq.errcode=ERROR_SUCCESS;
}
//else if(CmdRcvIrq.bcc!=rChr)
{
//CmdRcvIrq.errcode=ERROR_BCC;
}
break;
case RCV_IDLE:
default:
break;
}
}
/*****************************************************************************
** Function name: UART0Handler
**
** Descriptions: UART0 interrupt handler
**
** parameters: None
** Returned value: None
**
*****************************************************************************/
void UART0_Handler (void)
{
BYTE IIRValue, LSRValue;
volatile BYTE Dummy = Dummy;
signed portCHAR cChar;
//portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
//portENTER_CRITICAL();
IIRValue = U0IIR;
IIRValue >>= 1; /* skip pending bit in IIR */
IIRValue &= 0x07; /* check bit 1~3, interrupt identification */
if ( IIRValue == IIR_RLS ) /* Receive Line Status */
{
LSRValue = U0LSR;
/* Receive Line Status */
if ( LSRValue & (LSR_OE|LSR_PE|LSR_FE|LSR_RXFE|LSR_BI) )
{
/* There are errors or break interrupt */
/* Read LSR will clear the interrupt */
UART0Status = LSRValue;
Dummy = U0RBR; /* Dummy read on RX to clear
interrupt, then bail out */
//IDISABLE;
VICVectAddr = 0; /* Acknowledge Interrupt */
return;
}
if ( LSRValue & LSR_RDR ) /* Receive Data Ready */
{
/* If no error on RLS, normal ready, save into the data buffer. */
/* Note: read RBR will clear the interrupt */
cChar = UART0_RBR;
PushACharIntoRcvBuffer(cChar);
//xQueueSendFromISR( xRxedChars, &cChar, &xHigherPriorityTaskWoken );
}
}
else if ( IIRValue == IIR_RDA ) /* Receive Data Available */
{
/* Receive Data Available */
cChar = UART0_RBR;
PushACharIntoRcvBuffer(cChar);
//xQueueSendFromISR( xRxedChars, &cChar, &xHigherPriorityTaskWoken );
}
else if ( IIRValue == IIR_CTI ) /* Character timeout indicator */
{
/* Character Time-out indicator */
UART0Status |= 0x100; /* Bit 9 as the CTI error */
}
else if ( IIRValue == IIR_THRE ) /* THRE, transmit holding register empty */
{
/* THRE interrupt */
LSRValue = U0LSR; /* Check status in the LSR to see if
valid data in U0THR or not */
//UARTTxCount=0;
if ( LSRValue & LSR_THRE )
{
UART0TxEmpty = 1;
if(UARTTxOffset <UARTTxCount)
{
U0THR=UARTTxBuffer[UARTTxOffset];
UARTTxOffset++;
}else
{
UARTTxOffset=0;
UARTTxCount=0;
}
}
else
{
UART0TxEmpty = 0;
}
}
VICVectAddr = 0; /* Acknowledge Interrupt */
// portEXIT_CRITICAL();
}
/*****************************************************************************
** Function name: UARTInit
**
** Descriptions: Initialize UART0 port, setup pin select,
** clock, parity, stop bits, FIFO, etc.
**
** parameters: portNum(0 or 1) and UART baudrate
** Returned value: true or false, return false only if the
** interrupt handler can't be installed to the
** VIC table
**
*****************************************************************************/
DWORD UARTInit( DWORD PortNum, DWORD baudrate )
{
DWORD Fdiv;
memset(&CmdRcvIrq,0x0,sizeof(CmdRcvIrq)); /* clear the struct of receive irq */
if ( PortNum == 0 )
{
PINSEL0 = 0x00000050; /* RxD0 and TxD0 */
U0LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */
Fdiv = ( Fpclk / 16 ) / baudrate ; /*baud rate */
U0DLM = Fdiv / 256;
U0DLL = Fdiv % 256;
U0LCR = 0x03; /* DLAB = 0 */
U0FCR = 0x07; /* Enable and reset TX and RX FIFO. */
if ( install_irq( UART0_INT, (void *)myuart_irq, 1 ) == FALSE )
{
return (FALSE);
}
U0IER = IER_RBR | IER_THRE | IER_RLS; /* Enable UART0 interrupt */
return (TRUE);
}
return( FALSE );
}
/*****************************************************************************
** Function name: UARTSend
**
** Descriptions: Send a block of data to the UART 0 port based
** on the data length
**
** parameters: portNum, buffer pointer, and data length
** Returned value: None
**
*****************************************************************************/
void xUARTSend( const uint8 *BufferPtr, uint8 Length )
{
/*
while ( Length != 0)
{
//THRE status, contain valid data
while ( !(UART0TxEmpty & 0x01) );
U0THR = *BufferPtr;
UART0TxEmpty = 0; //not empty in the THR until it shifts out
BufferPtr++;
Length--;
}*/
while ( !(UART0TxEmpty & 0x01) );
memcpy(UARTTxBuffer,BufferPtr,Length);
UARTTxCount=Length;
UARTTxOffset=1;
U0THR = *BufferPtr;
return;
}
/*****************************************************************************
** Function name: UARTReceive
**
** Descriptions:
**
** parameters:
** Returned value:
**
*****************************************************************************/
int xUARTRead( const BYTE *BufferPtr, DWORD *Length )
{
int retcode;
if(CmdRcvIrq.cResult!=FINISH) return 0x0f; //是否接收完一个有用的数据包
portENTER_CRITICAL();
if(CmdRcvIrq.errcode==ERROR_SUCCESS) //如果接收正确
{
memcpy(BufferPtr,CmdRcvIrq.buffer,CmdRcvIrq.len);
*Length=(DWORD)CmdRcvIrq.len;
}
retcode=CmdRcvIrq.errcode;
xUARTStartReceive();
portEXIT_CRITICAL();
return retcode;
}
/*-----------------------------------------------------------------------------------
* **********************************************************************************
* UART Restart.Initialize UART receive status.
* CmdRcvIrq 是接收状态字。它表明了串口接收的状态。
*
* **********************************************************************************
* --------------------------------------------------------------------------------- */
void xUARTStartReceive(void)
{
portENTER_CRITICAL();
CmdRcvIrq.errcode=ERROR_INIT;
CmdRcvIrq.cResult=WAITTINGDATA;
CmdRcvIrq.rcvflg=RCV_STX;
CmdRcvIrq.time_flag=0x00;
portEXIT_CRITICAL();
}
/*----------------------------------------------------------------------------------
* function : xStartU0CHECKTasks
* specification: 检测2个接收字节之间是否超时 , CmdRcvIrq.time_flag>2表示超时。
*
* parameter : 每隔20ms检测一次
*
* ---------------------------------------------------------------------------------*/
static portTASK_FUNCTION_PROTO( vU0CHECKTask, pvParameters );
void vStartU0CHECKTasks( unsigned portBASE_TYPE uxPriority )
{
/* Create the task. */
xTaskCreate(vU0CHECKTask,( signed portCHAR * )"U0CHECK", UART_STACK_SIZE, NULL, uxPriority, ( xTaskHandle * ) NULL );
}
static portTASK_FUNCTION(vU0CHECKTask, pvParameters)
{
portTickType xUartRate, xLastUartTime;
/* The parameters are not used. */
( void ) pvParameters;
xUartRate = UART_RATE_BASE ;
xUartRate /= portTICK_RATE_MS;
/* We need to initialise xLastkbdTime prior to the first call to vTaskDelayUntil(). */
xLastUartTime = xTaskGetTickCount();
for(;;)
{
/* Delay for half the flash period then turn the LED on. */
vTaskDelayUntil( &xLastUartTime, xUartRate );
if(CmdRcvIrq.time_flag>2)
{
xUARTStartReceive(); //restart the received status
}
}
}
/*-----------------------------------------------------------------------
*
*
* Send a byte to the upper
*
*
* ----------------------------------------------------------------------*/
void SendByte(BYTE chr)
{
//while ( !(UART0TxEmpty & 0x01) );
U0THR=chr;
while( (U0LSR&0x20)==0 ); // 等待数据发送
//sDelayNS(2);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -