嵌入式开发之串口通讯

    串口通信(Serial Communication), 是指外设和计算机间,通过数据信号线 、地线、控制线等,按位进行传输数据的一种通讯方式。这种通信方式使用的数据线少,在远距离通信中可以节约通信成本,但其传输速度比并行传输低,是嵌入式开发中的法宝,也是必备技能之一。

知乎大佬这篇文章讲的比较详细,大家可以移步去看看,我部分摘录

详解串口通信UART - 知乎

嵌入式开发之串口通讯_第1张图片

通用异步接受器-发送器(UART)把数据的字节按照比特顺序发送。另一端的UART把比特组装为字节。每个UART包含一个移位寄存器,这是串行和并行形式之间转换的基本方法。通过一根线或其他媒介的串行通信比通过多根线的并行通信具有更低成本。UART 通常不直接产生或接收不同设备之间使用的外部信号。单独的接口设备用于将 UART 的逻辑电平信号与外部信号电平转换,这些信号电平可以是标准化的电压电平、电流电平或其他信号。

通信有3种模式:

  • 单工(仅在一个方向,没有规定接收设备将信息发送回发送设备)
  • 全双工(两个设备同时发送和接收)
  • 半双工(设备轮流发送和接收)

数据帧

UART 串​​行通信中的数据被组织成称为数据包或帧的块。

对于串口通讯的软件编写,一般有两种模式,查询和终端模式,

      查询就是用循环底层对于寄存器的状态值进行判断,如果有接收到数据则读取,但这种方式很占用CPU时间,在等待数据是CPU不能做其他任务。

     所以一般采用中断模式进行数据的接收,发送可以直接发送或者中断方式发送,一般uart会自带一定数量的fifo,可以通过控制寄存器来设置硬件缓冲大小,以及半满全满的缓冲,然后再将数据在中断来临时读出放入软件层面的ring环形缓冲区里面,再配合一定的api供其他应用进行功能调用,做协议解析等。以下就是一个典型的中断接收的串口驱动,基于PIC32,支持ucosii rtos,大家可以从中学习到串口驱动的基本用法,让硬件层和应用层进行分离,实现通用的可移植的代码。欢迎大家一起交流技术。

 

#define COMM_GLOBALS
//#include 
#include "COMMRTOS_LIB.H"
#include "bsp_peripherals.h"
//#define	GetSystemClock() 			(80000000ul)
//#define	GetPeripheralClock()		(GetSystemClock()/(1 << OSCCONbits.PBDIV))

//uart id
//RS232-1                         U1A
//RS232-2                         U1B
//RS485                           U3B
#define UART1                   UART1A
#define UART2                   UART1B
#define UART3                   UART3B
#define CTS_UART1               0
#define CTS_UART2               0
#define CTS_UART3               0
//uart baudrate
#define  UART1_BAUDRATE           (9600)
#define  UART2_BAUDRATE           (9600)
#define  UART3_BAUDRATE           (9600)
//uart int prio level
#define UART1_INT_PRIORITY_LEVEL  INT_PRIORITY_LEVEL_1
#define UART2_INT_PRIORITY_LEVEL  INT_PRIORITY_LEVEL_2
#define UART3_INT_PRIORITY_LEVEL  INT_PRIORITY_LEVEL_3
//uart int sub prio level
#define UART1_INT_SUB_PRIORITY_LEVEL  INT_SUB_PRIORITY_LEVEL_0
#define UART2_INT_SUB_PRIORITY_LEVEL  INT_SUB_PRIORITY_LEVEL_0
#define UART3_INT_SUB_PRIORITY_LEVEL  INT_SUB_PRIORITY_LEVEL_0

#define UART1TXIntEnable(enable)  mU1ATXIntEnable(enable) 
#define UART2TXIntEnable(enable)  mU1BTXIntEnable(enable) 
#define UART3TXIntEnable(enable)  mU3BTXIntEnable(enable) 

//#define PutcUART1(c)  putcUART3
/*$PAGE*/
/*
*********************************************************************************************************
*                                               CONSTANTS
*********************************************************************************************************
*/
    
/*
*********************************************************************************************************
*                                               DATA TYPES
*********************************************************************************************************
*/

typedef struct {
    INT16U     RingBufRxCtr;                /* Number of characters in the Rx ring buffer              */
    OS_EVENT  *RingBufRxSem;                /* Pointer to Rx semaphore                                 */
    INT8U     *RingBufRxInPtr;              /* Pointer to where next character will be inserted        */
    INT8U     *RingBufRxOutPtr;             /* Pointer from where next character will be extracted     */
    INT8U      RingBufRx[COMM_RX_BUF_SIZE]; /* Ring buffer character storage (Rx)                      */

    INT16U     RingBufTxCtr;                /* Number of characters in the Tx ring buffer              */
    OS_EVENT  *RingBufTxSem;                /* Pointer to Tx semaphore                                 */
    INT8U     *RingBufTxInPtr;              /* Pointer to where next character will be inserted        */
    INT8U     *RingBufTxOutPtr;             /* Pointer from where next character will be extracted     */
    INT8U      RingBufTx[COMM_TX_BUF_SIZE]; /* Ring buffer character storage (Tx)                      */

} COMM_RING_BUF;

/*
*********************************************************************************************************
*                                            GLOBAL VARIABLES
*********************************************************************************************************
*/

COMM_RING_BUF  Comm1Buf;
COMM_RING_BUF  Comm2Buf;
COMM_RING_BUF  Comm3Buf;

/*********************************************************************************************************
** 函数名称: CommTxImmdt() 
** 功能描述: 打开发送中断,把发送缓冲区的数据发送出去
**           
** 输 入  : 
             'ch'   串口号,取值范围为COMM1,COMM2 
** 输 出  : 无
** 全局变量: 无
** 调用模块: 无
** 
** 作 者: 
** 日 期: 
**-------------------------------------------------------------------------------------------------------
** 修 改: 
** 日 期: 
**-------------------------------------------------------------------------------------------------------
********************************************************************************************************/
void CommTxImmdt(INT8U ch)
{
    INT8U   err;


    switch (ch) {
        case COMM1:
            //if((U0IER & 0x02) == 0){                            // 如果发送中断是关的
            //    U0IER |= 0x02;                                  // 开发送中断
            //    U0THR = CommGetTxChar(COMM1, &err);             // 往发送寄存器写初始值
            //}
            //UART1TXIntEnable(1);
            INTEnable(INT_SOURCE_UART_RX(UART1), INT_ENABLED);
            UARTSendDataByte(UART1, CommGetTxChar(COMM1, &err));
            break;
        case COMM2:
            //if((U1IER & 0x02) == 0){                            // 如果发送中断是关的
            //    U1IER |= 0x02;                                  // 开发送中断
            //    U1THR = CommGetTxChar(COMM2, &err);             // 往发送寄存器写初始值
           // }
            //UART2TXIntEnable(1);
            INTEnable(INT_SOURCE_UART_RX(UART2), INT_ENABLED);
            UARTSendDataByte(UART2, CommGetTxChar(COMM2, &err));

            break;
        case COMM3:
            //if((U1IER & 0x02) == 0){                            // 如果发送中断是关的
            //    U1IER |= 0x02;                                  // 开发送中断
            //    U1THR = CommGetTxChar(COMM2, &err);             // 往发送寄存器写初始值
           // }
            //UART3TXIntEnable(1);
             INTEnable(INT_SOURCE_UART_RX(UART3), INT_ENABLED);
             UARTSendDataByte(UART3, CommGetTxChar(COMM3, &err));

            break;
        default:
            break;
    }
}

/*$PAGE*/
/*
*********************************************************************************************************
*                                    REMOVE CHARACTER FROM RING BUFFER
*
*
* Description : This function is called by your application to obtain a character from the communications
*               channel.  The function will wait for a character to be received on the serial channel or
*               until the function times out.
* Arguments   : 'ch'    is the COMM port channel number and can either be:
*                           COMM1
*                           COMM2
*               'to'    is the amount of time (in clock ticks) that the calling function is willing to
*                       wait for a character to arrive.  If you specify a timeout of 0, the function will
*                       wait forever for a character to arrive.
*               'err'   is a pointer to where an error code will be placed:
*                           *err is set to COMM_NO_ERR     if a character has been received
*                           *err is set to COMM_RX_TIMEOUT if a timeout occurred
*                           *err is set to COMM_BAD_CH     if you specify an invalid channel number
* Returns     : The character in the buffer (or NUL if a timeout occurred)
*********************************************************************************************************
*/

INT8U  CommGetChar (INT8U ch, INT16U to, INT8U *err)
{
#if CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL
    CPU_SR  cpu_sr;
#endif
    INT8U          c;
    INT8U          oserr;
    COMM_RING_BUF *pbuf;


    switch (ch) {                                          /* Obtain pointer to communications channel */
        case COMM1:
             pbuf = &Comm1Buf;
             break;

        case COMM2:
             pbuf = &Comm2Buf;
             break;
        case COMM3:
             pbuf = &Comm3Buf;
             break;
        default:
             *err = COMM_BAD_CH;
             return (NUL);
    }
    OSSemPend(pbuf->RingBufRxSem, to, &oserr);             /* Wait for character to arrive             */
    if (oserr == OS_TIMEOUT) {                             /* See if characters received within timeout*/
        *err = COMM_RX_TIMEOUT;                            /* No, return error code                    */
        return (NUL);
    } else {
        OS_ENTER_CRITICAL();
        pbuf->RingBufRxCtr--;                              /* Yes, decrement character count           */
        c = *pbuf->RingBufRxOutPtr++;                      /* Get character from buffer                */
        if (pbuf->RingBufRxOutPtr == &pbuf->RingBufRx[COMM_RX_BUF_SIZE]) {     /* Wrap OUT pointer     */
            pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0];
        }
        OS_EXIT_CRITICAL();
        *err = COMM_NO_ERR;
        return (c);
    }
}

/*$PAGE*/
/*
*********************************************************************************************************
*                                  GET TX CHARACTER FROM RING BUFFER
*
*
* Description : This function is called by the Tx ISR to extract the next character from the Tx buffer.
*               The function returns FALSE if the buffer is empty after the character is extracted from
*               the buffer.  This is done to signal the Tx ISR to disable interrupts because this is the
*               last character to send.
* Arguments   : 'ch'    is the COMM port channel number and can either be:
*                           COMM1
*                           COMM2
*               'err'   is a pointer to where an error code will be deposited:
*                           *err is set to COMM_NO_ERR         if at least one character was available
*                                                              from the buffer.
*                           *err is set to COMM_TX_EMPTY       if the Tx buffer is empty.
*                           *err is set to COMM_BAD_CH         if you have specified an incorrect channel
* Returns     : The next character in the Tx buffer or NUL if the buffer is empty.
*********************************************************************************************************
*/

INT8U  CommGetTxChar (INT8U ch, INT8U *err)
{
    INT8U          c;
    COMM_RING_BUF *pbuf;


    switch (ch) {                                          /* Obtain pointer to communications channel */
        case COMM1:
             pbuf = &Comm1Buf;
             break;

        case COMM2:
             pbuf = &Comm2Buf;
             break;
        case COMM3:
             pbuf = &Comm3Buf;
             break;
        default:
             *err = COMM_BAD_CH;
             return (NUL);
    }
    if (pbuf->RingBufTxCtr > 0) {                          /* See if buffer is empty                   */
        pbuf->RingBufTxCtr--;                              /* No, decrement character count            */
        c = *pbuf->RingBufTxOutPtr++;                      /* Get character from buffer                */
        if (pbuf->RingBufTxOutPtr == &pbuf->RingBufTx[COMM_TX_BUF_SIZE]) {     /* Wrap OUT pointer     */
            pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0];
        }
        OSSemPost(pbuf->RingBufTxSem);                     /* Indicate that character will be sent     */
        *err = COMM_NO_ERR;
        return (c);                                        /* Characters are still available           */
    } else {
        *err = COMM_TX_EMPTY;
        return (NUL);                                      /* Buffer is empty                          */
    }
}

/*$PAGE*/
/*
*********************************************************************************************************
*                                  INITIALIZE COMMUNICATIONS MODULE
*
*
* Description : This function is called by your application to initialize the communications module.  You
*               must call this function before calling any other functions.
* Arguments   : none
*********************************************************************************************************
*/

void  CommInit (void)
{
    COMM_RING_BUF *pbuf;


    pbuf                  = &Comm1Buf;                     /* Initialize the ring buffer for COMM1     */
    pbuf->RingBufRxCtr    = 0;
    pbuf->RingBufRxInPtr  = &pbuf->RingBufRx[0];
    pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0];
    pbuf->RingBufRxSem    = OSSemCreate(0);

    pbuf->RingBufTxCtr    = 0;
    pbuf->RingBufTxInPtr  = &pbuf->RingBufTx[0];
    pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0];
    pbuf->RingBufTxSem    = OSSemCreate(COMM_TX_BUF_SIZE);



    pbuf                  = &Comm2Buf;                     /* Initialize the ring buffer for COMM2     */
    pbuf->RingBufRxCtr    = 0;
    pbuf->RingBufRxInPtr  = &pbuf->RingBufRx[0];
    pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0];
    pbuf->RingBufRxSem    = OSSemCreate(0);

    pbuf->RingBufTxCtr    = 0;
    pbuf->RingBufTxInPtr  = &pbuf->RingBufTx[0];
    pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0];
    pbuf->RingBufTxSem    = OSSemCreate(COMM_TX_BUF_SIZE);

    pbuf                  = &Comm3Buf;                     /* Initialize the ring buffer for COMM3     */
    pbuf->RingBufRxCtr    = 0;
    pbuf->RingBufRxInPtr  = &pbuf->RingBufRx[0];
    pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0];
    pbuf->RingBufRxSem    = OSSemCreate(0);

    pbuf->RingBufTxCtr    = 0;
    pbuf->RingBufTxInPtr  = &pbuf->RingBufTx[0];
    pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0];
    pbuf->RingBufTxSem    = OSSemCreate(COMM_TX_BUF_SIZE);

    UART_INIT();
}
void CommTxIntEn(INT8U ch)
{
    INT8U   err;

    switch (ch) {
        case COMM1:
            INTEnable(INT_SOURCE_UART_TX(UART1), INT_ENABLED);
            break;
        case COMM2:
            INTEnable(INT_SOURCE_UART_TX(UART2), INT_ENABLED);
            break;
        case COMM3:
             INTEnable(INT_SOURCE_UART_TX(UART3), INT_ENABLED);
            break;
        default:
            break;
    }
}

/*$PAGE*/
/*
*********************************************************************************************************
*                                   SEE IF RX CHARACTER BUFFER IS EMPTY
*
*
* Description : This function is called by your application to see if any character is available from the
*               communications channel.  If at least one character is available, the function returns
*               FALSE otherwise, the function returns TRUE.
* Arguments   : 'ch'    is the COMM port channel number and can either be:
*                           COMM1
*                           COMM2
* Returns     : TRUE    if the buffer IS empty.
*               FALSE   if the buffer IS NOT empty or you have specified an incorrect channel.
*********************************************************************************************************
*/

BOOLEAN  CommIsEmpty (INT8U ch)
{
#if CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL
    CPU_SR  cpu_sr;
#endif
    BOOLEAN        empty;
    COMM_RING_BUF *pbuf;


    switch (ch) {                                          /* Obtain pointer to communications channel */
        case COMM1:
             pbuf = &Comm1Buf;
             break;

        case COMM2:
             pbuf = &Comm2Buf;
             break;
        case COMM3:
             pbuf = &Comm3Buf;
             break;
        default:
             return (TRUE);
    }
    OS_ENTER_CRITICAL();
    if (pbuf->RingBufRxCtr > 0) {                          /* See if buffer is empty                   */
        empty = FALSE;                                     /* Buffer is NOT empty                      */
    } else {
        empty = TRUE;                                      /* Buffer is empty                          */
    }
    OS_EXIT_CRITICAL();
    return (empty);
}

/*$PAGE*/
/*
*********************************************************************************************************
*                                   SEE IF TX CHARACTER BUFFER IS FULL
*
*
* Description : This function is called by your application to see if any more characters can be placed
*               in the Tx buffer.  In other words, this function check to see if the Tx buffer is full.
*               If the buffer is full, the function returns TRUE otherwise, the function returns FALSE.
* Arguments   : 'ch'    is the COMM port channel number and can either be:
*                           COMM1
*                           COMM2
* Returns     : TRUE    if the buffer IS full.
*               FALSE   if the buffer IS NOT full or you have specified an incorrect channel.
*********************************************************************************************************
*/

BOOLEAN  CommIsFull (INT8U ch)
{
#if CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL
    CPU_SR  cpu_sr;
#endif
    BOOLEAN        full;
    COMM_RING_BUF *pbuf;


    switch (ch) {                                          /* Obtain pointer to communications channel */
        case COMM1:
             pbuf = &Comm1Buf;
             break;

        case COMM2:
             pbuf = &Comm2Buf;
             break;

        case COMM3:
             pbuf = &Comm3Buf;
             break;
        default:
             return (TRUE);
    }
    OS_ENTER_CRITICAL();
    if (pbuf->RingBufTxCtr < COMM_TX_BUF_SIZE) {           /* See if buffer is full                    */
        full = FALSE;                                      /* Buffer is NOT full                       */
    } else {
        full = TRUE;                                       /* Buffer is full                           */
    }
    OS_EXIT_CRITICAL();
    return (full);
}

/********************************************************************************************************
*                                            OUTPUT CHARACTER
*
*
* Description : This function is called by your application to send a character on the communications
*               channel.  The function will wait for the buffer to empty out if the buffer is full.
*               The function returns to your application if the buffer doesn't empty within the specified
*               timeout.  A timeout value of 0 means that the calling function will wait forever for the
*               buffer to empty out.  The character to send is first inserted into the Tx buffer and will
*               be sent by the Tx ISR.  If this is the first character placed into the buffer, the Tx ISR
*               will be enabled.
* Arguments   : 'ch'    is the COMM port channel number and can either be:
*                           COMM1
*                           COMM2
*               'c'     is the character to send.
*               'to'    is the timeout (in clock ticks) to wait in case the buffer is full.  If you
*                       specify a timeout of 0, the function will wait forever for the buffer to empty.
* Returns     : COMM_NO_ERR      if the character was placed in the Tx buffer
*               COMM_TX_TIMEOUT  if the buffer didn't empty within the specified timeout period
*               COMM_BAD_CH      if you specify an invalid channel number
********************************************************************************************************/
INT8U  CommPutChar (INT8U ch, INT8U c, INT16U to)
{
#if CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL
    CPU_SR  cpu_sr;
#endif   
 INT8U          oserr;
    COMM_RING_BUF *pbuf;


    switch (ch) {                                          /* Obtain pointer to communications channel */
        case COMM1:
             pbuf = &Comm1Buf;
             break;

        case COMM2:
             pbuf = &Comm2Buf;
             break;
        case COMM3:
             pbuf = &Comm3Buf;
             break;
        default:
             return (COMM_BAD_CH);
    }

    OSSemPend(pbuf->RingBufTxSem, to, &oserr);             /* Wait for space in Tx buffer              */
    if (oserr == OS_TIMEOUT) {
        return (COMM_TX_TIMEOUT);                          /* Timed out, return error code             */
    }
    OS_ENTER_CRITICAL();
    pbuf->RingBufTxCtr++;                                  /* No, increment character count            */
    *pbuf->RingBufTxInPtr++ = c;                           /* Put character into buffer                */
    if (pbuf->RingBufTxInPtr == &pbuf->RingBufTx[COMM_TX_BUF_SIZE]) {     /* Wrap IN pointer           */
        pbuf->RingBufTxInPtr = &pbuf->RingBufTx[0];
    }
    if (pbuf->RingBufTxCtr == 1) {                         // See if this is the first character       
        CommTxIntEn(ch);                                   // Yes, Enable Tx interrupts                
    }
    OS_EXIT_CRITICAL();
    return (COMM_NO_ERR);
}

/*$PAGE*/
/*
*********************************************************************************************************
*                                    INSERT CHARACTER INTO RING BUFFER
*
*
* Description : This function is called by the Rx ISR to insert a character into the receive ring buffer.
* Arguments   : 'ch'    is the COMM port channel number and can either be:
*                           COMM1
*                           COMM2
*               'c'     is the character to insert into the ring buffer.  If the buffer is full, the
*                       character will not be inserted, it will be lost.
*********************************************************************************************************
*/

void  CommPutRxChar (INT8U ch, INT8U c)
{
    COMM_RING_BUF *pbuf;


    switch (ch) {                                          /* Obtain pointer to communications channel */
        case COMM1:
             pbuf = &Comm1Buf;
             break;

        case COMM2:
             pbuf = &Comm2Buf;
             break;
        case COMM3:
             pbuf = &Comm3Buf;
             break;
        default:
             return;
    }

    if (pbuf->RingBufRxCtr < COMM_RX_BUF_SIZE) {           /* See if buffer is full                    */
        pbuf->RingBufRxCtr++;                              /* No, increment character count            */
        *pbuf->RingBufRxInPtr++ = c;                       /* Put character into buffer                */
        if (pbuf->RingBufRxInPtr == &pbuf->RingBufRx[COMM_RX_BUF_SIZE]) { /* Wrap IN pointer           */
            pbuf->RingBufRxInPtr = &pbuf->RingBufRx[0];
        }
        OSSemPost(pbuf->RingBufRxSem);                     /* Indicate that character was received     */
    }
}

/*
*********************************************************************************************************
*                                    UART1_UARTHandler()
*
* Description: This function handles interrupts from the UART1.
*
* Arguments  : None
*
* Returns    : None
*********************************************************************************************************
*/

void UART1_UARTHandler(void)
{
    INT8U c;
    INT8U err;	
// Is this an RX interrupt?
	if(INTGetFlag(INT_SOURCE_UART_RX(UART1)))
	{
		// Clear the RX interrupt Flag
	    INTClearFlag(INT_SOURCE_UART_RX(UART1));
        c=UARTGetDataByte(UART1);
        CommPutRxChar(COMM1,c);
		// Toggle LED to indicate UART activity
		//mPORTAToggleBits(BIT_7);

	}

	// We don't care about TX interrupt
	if ( INTGetFlag(INT_SOURCE_UART_TX(UART1)) )
	{
		INTClearFlag(INT_SOURCE_UART_TX(UART1));
	    c = CommGetTxChar(COMM1, &err);  
        if(err==COMM_NO_ERR)
           UARTSendDataByte(UART1, c);
        else if(err==COMM_TX_EMPTY)
           INTEnable(INT_SOURCE_UART_TX(UART1), INT_DISABLED);
	}
}

void UART2_UARTHandler(void)
{
    INT8U c;
    INT8U err;	
// Is this an RX interrupt?
	if(INTGetFlag(INT_SOURCE_UART_RX(UART2)))
	{
		// Clear the RX interrupt Flag
	    INTClearFlag(INT_SOURCE_UART_RX(UART2));
        c=UARTGetDataByte(UART2);
        CommPutRxChar(COMM2,c);
		// Toggle LED to indicate UART activity
		//mPORTAToggleBits(BIT_7);

	}

	// We don't care about TX interrupt
	if ( INTGetFlag(INT_SOURCE_UART_TX(UART2)) )
	{
		INTClearFlag(INT_SOURCE_UART_TX(UART2));
	    c = CommGetTxChar(COMM2, &err);   
        if(err==COMM_NO_ERR)
           UARTSendDataByte(UART2, c);
        else if(err==COMM_TX_EMPTY)
           INTEnable(INT_SOURCE_UART_TX(UART2), INT_DISABLED);
	}
}

void UART3_UARTHandler(void)
{
    INT8U c;
    INT8U err;	
// Is this an RX interrupt?
	if(INTGetFlag(INT_SOURCE_UART_RX(UART3)))
	{
		// Clear the RX interrupt Flag
	    INTClearFlag(INT_SOURCE_UART_RX(UART3));
        c=UARTGetDataByte(UART3);
        CommPutRxChar(COMM3,c);
		// Toggle LED to indicate UART activity
		//mPORTAToggleBits(BIT_7);

	}

	// We don't care about TX interrupt
	if ( INTGetFlag(INT_SOURCE_UART_TX(UART3)) )
	{
		INTClearFlag(INT_SOURCE_UART_TX(UART3));
	    c = CommGetTxChar(COMM3, &err);    
        if(err==COMM_NO_ERR)
           UARTSendDataByte(UART3, c);
        else if(err==COMM_TX_EMPTY)
           INTEnable(INT_SOURCE_UART_TX(UART3), INT_DISABLED);
	}
}
/*
*********************************************************************************************************
*                                      UART_Init()
*
* Description: This function performs all necessary initializations on the UART.
*
* Arguments  : baud_rate    The desired baud rate for the UART
*
* Returns    : None
*********************************************************************************************************
*/

void  UART_INIT (void)
{
     int    pbClk;
     pbClk=GetPeripheralClock();
    // OpenUART1(UART_EN, UART_RX_ENABLE | UART_TX_ENABLE, pbClk/16/UART1_BAUDRATE-1);    // calculate actual BAUD generate value.



//    INT_EN_DIS  INT_Value=INT_ENABLED;
    //uart1
    UARTConfigure(UART1, UART_ENABLE_PINS_TX_RX_ONLY);
    UARTSetFifoMode(UART1, UART_INTERRUPT_ON_TX_NOT_FULL | UART_INTERRUPT_ON_RX_NOT_EMPTY);
    UARTSetLineControl(UART1, UART_DATA_SIZE_8_BITS | UART_PARITY_NONE | UART_STOP_BITS_1);
    UARTSetDataRate(UART1, pbClk, UART1_BAUDRATE);
    UARTEnable(UART1, UART_ENABLE_FLAGS(UART_PERIPHERAL | UART_RX | UART_TX));

    INTSetVectorPriority(INT_VECTOR_UART(UART1), UART1_INT_PRIORITY_LEVEL);
    INTSetVectorSubPriority(INT_VECTOR_UART(UART1), UART1_INT_SUB_PRIORITY_LEVEL);
	// Configure UART1 RX Interrupt
	INTEnable(INT_SOURCE_UART_RX(UART1),INT_ENABLED);
	// Configure UART1 TX Interrupt
	//enable as tx data in 
    //INTEnable(INT_SOURCE_UART_TX(UART1),INT_ENABLED);

    //uart2
    UARTConfigure(UART2, UART_ENABLE_PINS_TX_RX_ONLY);
    UARTSetFifoMode(UART2, UART_INTERRUPT_ON_TX_NOT_FULL | UART_INTERRUPT_ON_RX_NOT_EMPTY);
    UARTSetLineControl(UART2, UART_DATA_SIZE_8_BITS | UART_PARITY_NONE | UART_STOP_BITS_1);
    UARTSetDataRate(UART2, pbClk, UART2_BAUDRATE);
    
    UARTEnable(UART2, UART_ENABLE_FLAGS(UART_PERIPHERAL | UART_RX | UART_TX));

	// Configure UART1 TX Interrupt
	//INTEnable(INT_SOURCE_UART_TX(UART2), INT_ENABLED);
    INTSetVectorPriority(INT_VECTOR_UART(UART2), UART2_INT_PRIORITY_LEVEL);
    INTSetVectorSubPriority(INT_VECTOR_UART(UART2), UART2_INT_SUB_PRIORITY_LEVEL);
	// Configure UART1 RX Interrupt
	INTEnable(INT_SOURCE_UART_RX(UART2), INT_ENABLED);

    //uart3
    UARTConfigure(UART3, UART_ENABLE_PINS_TX_RX_ONLY);
    UARTSetFifoMode(UART3, UART_INTERRUPT_ON_TX_NOT_FULL | UART_INTERRUPT_ON_RX_NOT_EMPTY);
    UARTSetLineControl(UART3, UART_DATA_SIZE_8_BITS | UART_PARITY_NONE | UART_STOP_BITS_1);
    UARTSetDataRate(UART3, pbClk, UART3_BAUDRATE);
    UARTEnable(UART3, UART_ENABLE_FLAGS(UART_PERIPHERAL | UART_RX | UART_TX));

	// Configure UART1 TX Interrupt
	//INTEnable(INT_SOURCE_UART_TX(UART3), INT_ENABLED);
    INTSetVectorPriority(INT_VECTOR_UART(UART3), UART3_INT_PRIORITY_LEVEL);//INT_PRIORITY_LEVEL_2);
    INTSetVectorSubPriority(INT_VECTOR_UART(UART3), UART3_INT_SUB_PRIORITY_LEVEL);
	// Configure UART1 RX Interrupt
	INTEnable(INT_SOURCE_UART_RX(UART3), INT_ENABLED);

    // configure for multi-vectored mode
    //INTConfigureSystem(INT_SYSTEM_CONFIG_MULT_VECTOR);

    // enable interrupts
    //INTEnableInterrupts();


   //WriteString("*** UART Interrupt-driven Application Example ***\r\n");
   //WriteString("*** Type some characters and observe echo and RA7 LED toggle ***\r\n");


	// Let interrupt handler do the work
	//while (1);

//	return 0;

}
void PutString(const char *string,INT8U CommPort)
{
    while(*string != '\0')
    {
       CommPutChar(CommPort,*string,100);
       string++;
    }
}
// helper functions
void WriteString(const char *string,INT8U CommPort)
{
    switch(CommPort)
   {
     case COMM1:
    while(*string != '\0')
    {
       while ( CTS_UART1);		        // wait for !CTS, clear to send
       while ( U1ASTAbits.UTXBF);   // wait while Tx buffer full
       U1ATXREG = *string++;
    }


       //uart=UART1;
       break;
     case COMM2:
    while(*string != '\0')
    {
       while ( CTS_UART1);		        // wait for !CTS, clear to send
       while ( U1BSTAbits.UTXBF);       // wait while Tx buffer full
       U1BTXREG = *string++;
    }
       break;
     case COMM3:
    while(*string != '\0')
    {
       while ( CTS_UART1);		        // wait for !CTS, clear to send
       while ( U3BSTAbits.UTXBF);   // wait while Tx buffer full
       U3BTXREG = *string++;
    }
       break;
     default:
       return;
   }

}
void PutCharacter(const char character,INT8U CommPort)
{

    INT8U uart=UART1;
    switch(CommPort)
   {
     case COMM1:
       while ( CTS_UART1);		        // wait for !CTS, clear to send
       while ( U1ASTAbits.UTXBF);   // wait while Tx buffer full
       U1ATXREG = character;

       //uart=UART1;
       break;
     case COMM2:
       while ( CTS_UART2);		        // wait for !CTS, clear to send
       while ( U1BSTAbits.UTXBF);   // wait while Tx buffer full
       U1BTXREG = character;

       //uart=UART2;
       break;
     case COMM3:
       while ( CTS_UART3);		        // wait for !CTS, clear to send
       while ( U3BSTAbits.UTXBF);   // wait while Tx buffer full
       U3BTXREG = character;

       //uart=UART3;
       break;
     default:
       return;
   }
}


/*
// initialize the UART2 serial port
void initU2( void)
{
    U2BRG 	= BRATE;    
    U2MODE 	= U_ENABLE;
    U2STA 	= U_TX;
    TRTS    = 0;        // make RTS output
    RTS     = 1;        // set RTS default status
} // initU2


// send a character to the UART2 serial port
int putU2( int c)
{
    while ( CTS);		        // wait for !CTS, clear to send
    while ( U2STAbits.UTXBF);   // wait while Tx buffer full
    U2TXREG = c;
    return c;
} // putU2


// wait for a new character to arrive to the UART2 serial port
char getU2( void)
{
    RTS = 0;            // assert Request To Send !RTS
    while ( !U2STAbits.URXDA);	// wait for a new character to arrive
    RTS = 1;
    return U2RXREG;		// read the character from the receive buffer
}// getU2


*/
static char uart_string[600];
/
void Uart_Printf(char *fmt,...)
{
    int i=0;
    va_list ap;

    va_start(ap,fmt);
    vsprintf(uart_string,fmt,ap);
    WriteString(uart_string,UART1);
    va_end(ap);
    for(i=0;i<1000;i++);
}

你可能感兴趣的:(单片机,stm32,mcu,物联网,嵌入式硬件,iot)