打印

分享一个STM32下的UART万能驱动,希望可以移植到GD32上

[复制链接]
4044|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
罗菜鸟|  楼主 | 2013-6-28 17:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
该驱动采用中断方式,未来会加入DMA方式。中断方式采用FIFO的方式。用户程序直接用UartRead和UartWrite操作读写。
无论采用中断还是DMA,都会支持一个中断回调函数。该中断回调函数处理由用户自己定义,触发条件为——接收缓冲超时(1Byte的时间),接收缓冲过半,接收缓冲满,发送缓冲空,以应对UART在某些场合对实时性的需求。
该驱动采用中断方式,未来会加入DMA方式。中断方式采用FIFO的方式。用户程序直接用UartRead和UartWrite操作读写。
无论采用中断还是DMA,都会支持一个中断回调函数。该中断回调函数处理由用户自己定义,触发条件为——接收缓冲超时(1Byte的时间),接收缓冲过半,接收缓冲满,发送缓冲空,以应对UART在某些场合对实时性的需求。
同时为了支持多种OS环境(本人移植过UCOS和RTX两种OS),也可以裸奔,UART驱动中不会有任何和特定OS相关的操作,所以中断回调函数中可以向任务中发送信号量,消息邮箱等。同时任务在初始化UART时,可以分配一个缓冲供中断回调函数操作。比如中断回调函数向任务中发送一个消息邮箱,消息邮箱的缓冲可以建立在任务中,初始化串口的时候分配给串口驱动,当串口中断发生时直接把该缓冲区的指针发给任务,如果中断发送给任务的消息邮箱,指针位于中断函数的局部变量,当中断函数结束时,任务还没有收到消息邮箱,邮箱里面的“邮件”就变成了“空白”。


UART.h

/******************** (C) COPYRIGHT 2008 boost ********************
* File Name          : usart.h
* Author             : Luo Yiming
* Version            : V1.1.0
* Date               : 2013年3月19日
* Description        : Header for usart.c module
********************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"

/* Define to prevent recursive inclusion ------------------------------------ */
#ifndef __USART_H
#define __USART_H

#define UART_RX_IDLE  0x01           // Uart Rx Buffer is less than half when idle
#define UART_RX_OVF   0x02           // Uart Rx Buffer is more than half
#define UART_RX_FULL  0x04           // Uart Rx Buffer is full
#define UART_TX_DONE  0x08           // Uart Tx Buffer is empty

#define  UART_PORT_MAX            5

#define  UART_PORT_1              0
#define  UART_PORT_2              1
#define  UART_PORT_3              2
#define  UART_PORT_4              3
#define  UART_PORT_5              4

#define  UART_FLOW_EN             0x80
#define  UART_2STOP_EN            0x40
#define  UART_EVEN_EN             0x20
#define  UART_ODD_EN              0x10

typedef struct{
        u16 rxSize;
        u16 txSize;       
        u8* rxBuf;
        u8* txBuf;
        void (*isr)(uint8_t port,uint8_t event,void* msg);
        void *msg;
        USART_InitTypeDef init;
        u8  rxdma;
        u8  txdma;
}uart_seting_t;

/* Exported functions ------------------------------------------------------- */
extern void UartNvicSet(uint8_t port,uint8_t preprio,uint8_t subprio);
extern void USART_ISR(uint8_t port);
extern void UartSeting(uint8_t port,uart_seting_t seting);
extern uint16_t UartRead(uint8_t port,uint8_t *data,uint16_t len);
extern uint16_t UartWrite(uint8_t port,uint8_t *data,uint16_t len);
extern uint16_t UartRxCnt(uint8_t port);
extern uint16_t UartTxCnt(uint8_t port);
extern void UartSetIsrMsg(uint8_t port,void* msg);
#endif /* __USART_H */

/******************* (C) COPYRIGHT 2008 boost *****END OF FILE****/




UART.c

/******************** (C) COPYRIGHT 2008 litt ********************
* File Name          : usart.c
* Author             : luo yi ming
* Version            : V1.1.0
* Date               : 2013年3月19日
* Description        : This file provides a set of functions needed to manage the
*                      communication between usart peripheral and RS485/HW/PLC.
********************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "usart.h"



/* Private typedef -----------------------------------------------------------*/
struct _uart_fifo_t{
        //rx 12byte
        u8*   rxBuf;             //4
        u16   rxSize;            //2
        vu16  rxPush;   //2
        vu16  rxPop;    //2
        vu16  rxCnt;    //2
        //tx 12byte
        u8*   txBuf;             //4
        u16   txSize;            //2
        vu16  txPush;   //2
        vu16  txPop;    //2
        vu16  txCnt;    //2
        //Isr 4byte
        void (*isr)(uint8_t port,uint8_t event,void* msg);
        //task msg to isr
        void* msg;
};//28


struct _uart_device_t{
        struct _uart_fifo_t  fifo;
        USART_TypeDef*   uart;
        DMA_Channel_TypeDef*     rxdma;
        DMA_Channel_TypeDef*     txdma;
};


typedef   USART_TypeDef*        pUSART_TypeDef;
typedef   DMA_Channel_TypeDef*  pDMA_Channel_TypeDef;
/* Private define ------------------------------------------------------------*/
//#define  UART_OVF_LINE     16
//#define  UART_MIN_FIFO     16
//#define  UART_MAX_FIFO     2048

#define  UART1_DMA_RX  DMA1_Channel5
#define  UART1_DMA_TX  DMA1_Channel4

#define  UART2_DMA_RX  DMA1_Channel6
#define  UART2_DMA_TX  DMA1_Channel7

#define  UART3_DMA_RX  DMA1_Channel3
#define  UART3_DMA_TX  DMA1_Channel2

#define  UART_REG_1 {USART1,UART1_DMA_RX,UART1_DMA_TX}
#define  UART_REG_2 {USART2,UART2_DMA_RX,UART2_DMA_TX}
#define  UART_REG_3 {USART3,UART3_DMA_RX,UART3_DMA_TX}
#define  UART_REG_4 {UART4,NULL,NULL}
#define  UART_REG_5 {UART5,NULL,NULL}

/* Private macro -------------------------------------------------------------*/


/* Private variables ---------------------------------------------------------*/
const  pUSART_TypeDef         USART_TABLE[UART_PORT_MAX] = {USART1,USART2,USART3,UART4,UART5};
const  pDMA_Channel_TypeDef          UART_DMA_RX_TABLE[UART_PORT_MAX] = {UART1_DMA_RX,UART2_DMA_RX,UART3_DMA_RX,NULL,NULL};
const  pDMA_Channel_TypeDef          UART_DMA_TX_TABLE[UART_PORT_MAX] = {UART1_DMA_TX,UART2_DMA_TX,UART3_DMA_TX,NULL,NULL};
static struct _uart_device_t  UartDevice[UART_PORT_MAX];


/* Function -------------------------------------------------------------------*/

/*************************************************************************************************
* Name       : _uart_isr
* Describe   : 串口中断服务程序
* param      : pfifo,uart
* Return     : 无
* Create by  : 罗一鸣 2012-12-03
* Moid   by  :
*************************************************************************************************/
static __inline void _uart_isr(uint8_t port,struct _uart_fifo_t *pfifo,USART_TypeDef *uart)
{
        uint32_t ie,iflag;
        uint8_t c,event = 0;
        ie = __get_PRIMASK();
        __set_PRIMASK(1);
        iflag = (uart->CR1 & (USART_FLAG_TXE|USART_FLAG_TC|USART_FLAG_RXNE|USART_FLAG_IDLE) & uart->SR);
        __set_PRIMASK(ie);
        //IDLE IRQ
        if(iflag & USART_FLAG_IDLE)
        {
                c = uart->DR;
                if(pfifo->rxCnt <= (pfifo->rxSize>>1)) //rx buffer is not full when rx idle happen
                {
                        event |=  UART_RX_IDLE;
                }
        }
        //RX IRQ
        if(iflag & USART_FLAG_RXNE)
        {
                c = uart->DR;
                if(pfifo->rxCnt < pfifo->rxSize)
                {
                        pfifo->rxBuf[pfifo->rxPush] = c;
                        pfifo->rxPush += 1;
                        if(pfifo->rxPush >= pfifo->rxSize)
                        {
                                pfifo->rxPush = 0;
                        }
                        pfifo->rxCnt += 1;
                        if(pfifo->rxCnt == pfifo->rxSize)  //rx buffer is full
                        {
                                event |= UART_RX_FULL;
                        }
                        else if(pfifo->rxCnt > (pfifo->rxSize>>1))//rx byte is more than half of rx buffer  
                        {
                                event |= UART_RX_OVF;
                        }
                }
        }
        //TXE IRQ
        if(iflag & USART_FLAG_TXE)
        {
                uart->CR1 &= (uint16_t)~0x0080; //off TX
                if(pfifo->txCnt)
                {
                        c = pfifo->txBuf[pfifo->txPop];
                        uart->DR = c;
                        uart->CR1 |= (uint16_t)0x0080;
                        pfifo->txPop += 1;
                        if(pfifo->txPop >= pfifo->txSize)
                        {
                                pfifo->txPop = 0;
                        }
                        pfifo->txCnt -= 1;
                        if(pfifo->txCnt == 0)
                        {
                                event |=  UART_TX_DONE;
                        }
                }
        }
        //run isr function
        if(NULL != pfifo->isr)
        {
                pfifo->isr(port,event,pfifo->msg);
        }
}


/*************************************************************************************************
* Name       : _uart_read_isr
* Describe   : 串口读取函数中断模式
* param      :
* Return     :
* Create by  :
* Moid   by  :
*************************************************************************************************/
static uint16_t _uart_read_isr(struct _uart_fifo_t *pfifo,USART_TypeDef *uart,uint8_t *data,uint16_t len)
{
        uint32_t ie;
        uint16_t n;
        if(len == 0)
        {
                return 0;
        }
        for(n=0;n<len;n++)
        {
                if(n < pfifo->rxCnt)
                {
                        *data++ = pfifo->rxBuf[pfifo->rxPop];
                        pfifo->rxPop += 1;
                        if(pfifo->rxPop>=pfifo->rxSize)
                        {
                                pfifo->rxPop = 0;
                        }
                }
                else
                {
                        break;
                }
        }
        ie = __get_PRIMASK();
        __set_PRIMASK(1);
        pfifo->rxCnt -= n;
        __set_PRIMASK(ie);
        return n;
}


/*************************************************************************************************
* Name       : _uart_write_isr
* Describe   : 串口写入函数中断模式
* param      :
* Return     :
* Create by  :
* Moid   by  :
*************************************************************************************************/
static uint16_t _uart_write_isr(struct _uart_fifo_t *pfifo,USART_TypeDef *uart,uint8_t *data,uint16_t len)
{
        uint32_t ie;
        uint16_t n;
        if(len == 0)
        {
                return 0;
        }
        for(n=0;n<len;n++)
        {
                if((pfifo->txSize-n) > pfifo->txCnt)
                {
                        pfifo->txBuf[pfifo->txPush] = *data++;
                        pfifo->txPush += 1;
                        if(pfifo->txPush >= pfifo->txSize)
                        {
                                pfifo->txPush = 0;
                        }
                }
                else
                {
                        break;
                }
        }
        ie = __get_PRIMASK();
        __set_PRIMASK(1);
        pfifo->txCnt += n;
        __set_PRIMASK(ie);
        return n;
}



/*************************************************************************************************
* Name       : UART_ISR
* Describe   : 串口中断服务
* param      :
* Return     :
* Create by  :
* Moid   by  :
*************************************************************************************************/
void USART_ISR(uint8_t port)
{
        _uart_isr(port,&UartDevice[port].fif**ice[port].uart);
}


/*************************************************************************************************
* Name       : UART_DMA_ISR
* Describe   : 串口中断服务
* param      :
* Return     :
* Create by  :
* Moid   by  :
*************************************************************************************************/
void UART_DMA_ISR(uint8_t port)
{

}

/*
__inline void UartDmaIsr(uint8_t port,struct UartFifo *pfifo,USART_TypeDef *uart)
{
       
       
}
*/



/*************************************************************************************************
* Name       : UartSeting
* Describe   :  
* param      :  
* Return     :  
* Create by  : 罗一鸣    Date: 2013-06-18
* Moid   by  :
*************************************************************************************************/
void UartSeting(uint8_t port,uart_seting_t seting)
{
        UartDevice[port].uart  = USART_TABLE[port];
        UartDevice[port].rxdma = NULL;
        UartDevice[port].txdma = NULL;
        UartDevice[port].fifo.rxCnt  = UartDevice[port].fifo.txCnt  = 0;
        UartDevice[port].fifo.rxPush = UartDevice[port].fifo.rxPop  = 0;       
        UartDevice[port].fifo.txPush = UartDevice[port].fifo.txPop  = 0;
        UartDevice[port].fifo.rxSize = seting.rxSize;
        UartDevice[port].fifo.rxBuf  = seting.rxBuf;
        UartDevice[port].fifo.txSize = seting.txSize;
        UartDevice[port].fifo.txBuf  = seting.txBuf;
        UartDevice[port].fifo.isr    = seting.isr;
        UartDevice[port].fifo.msg         = seting.msg;
        if(seting.rxdma)
        {
                UartDevice[port].rxdma = UART_DMA_RX_TABLE[port];
        }
        if(seting.txdma)
        {
                UartDevice[port].txdma = UART_DMA_TX_TABLE[port];
        }
        USART_Init(UartDevice[port].uart, &seting.init);
}


/*************************************************************************************************
* Name       : UartRead
* Describe   :  
* param      :  
* Return     :  
* Create by  : 罗一鸣    Date: 2012-12-03
* Moid   by  :
*************************************************************************************************/
uint16_t UartRead(uint8_t port,uint8_t *data,uint16_t len)
{
        if(UART_PORT_MAX <= port)
        {
                return 0;
        }
        if((NULL != UartDevice[port].rxdma))
        {
                return 0;
        }
        else
        {
                return _uart_read_isr(&UartDevice[port].fif**ice[port].uart,data,len);
        }
}

/*************************************************************************************************
* Name       : UartWrite
* Describe   :  
* param      :  
* Return     :  
* Create by  : 罗一鸣    Date: 2012-12-03
* Moid   by  :
*************************************************************************************************/
uint16_t UartWrite(uint8_t port,uint8_t *data,uint16_t len)
{
        if(UART_PORT_MAX <= port)
        {
                return 0;
        }
        if((NULL != UartDevice[port].txdma))
        {
                return 0;
        }
        else
        {
                return _uart_write_isr(&UartDevice[port].fif**ice[port].uart,data,len);
        }
}


/*************************************************************************************************
* Name       : UartRxCnt
* Describe   :
* param      :
* Return     :
* Create by  :
* Moid   by  :
*************************************************************************************************/
uint16_t UartRxCnt(uint8_t port)
{
        return UartDevice[port].fifo.rxCnt;
}

/*************************************************************************************************
* Name       : UartTxCnt
* Describe   :
* param      :
* Return     :
* Create by  :
* Moid   by  :
*************************************************************************************************/
uint16_t UartTxCnt(uint8_t port)
{
        return UartDevice[port].fifo.txCnt;
}

/*************************************************************************************************
* Name       : UartSetIsrMsg
* Describe   : send msg to Isr
* param      :  
* Return     :  
* Create by  : 罗一鸣    Date: 2013-06-18
* Moid   by  :
*************************************************************************************************/
void UartSetIsrMsg(uint8_t port,void* msg)
{
        UartDevice[port].fifo.msg = msg;
}


/*************************************************************************************************
* Name       : UartInit
* Describe   :  
* param      :  
* Return     :  
* Create by  : 罗一鸣    Date: 2012-12-03
* Moid   by  :
*************************************************************************************************/
void UartInit(uint8_t port,uint8_t preprio,uint8_t subprio)
{
        NVIC_InitTypeDef NVIC_InitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;
        if(UART_PORT_1 == port)
        {               
                // config USART1 clock
                RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
                // Configure USART1 Tx (PA.09) as alternate function push-pull
                GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
                GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
                GPIO_Init(GPIOA, &GPIO_InitStructure);
                // Configure USART1 Rx (PA.10) as input floating
                GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
                GPIO_Init(GPIOA, &GPIO_InitStructure);
                // Set Interrupt Priority
            NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
            NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = preprio;
            NVIC_InitStructure.NVIC_IRQChannelSubPriority = subprio;
            NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
                //CLI();
                NVIC_Init(&NVIC_InitStructure);
                //SEI();
        }
        else if(UART_PORT_2 == port)
        {
                // config USART2 clock
                RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
                RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
                // Configure USART2 Tx (PA.02) as alternate function push-pull
                GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
                GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
                GPIO_Init(GPIOA, &GPIO_InitStructure);
                // Configure USART2 Rx (PA.03) as input floating
                GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
                GPIO_Init(GPIOA, &GPIO_InitStructure);               
                // Set Interrupt Priority
            NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
            NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = preprio;
            NVIC_InitStructure.NVIC_IRQChannelSubPriority = subprio;
            NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
                //CLI();
                NVIC_Init(&NVIC_InitStructure);
                //SEI();
        }
        else if(UART_PORT_3 == port)
        {
                // config USART3 clock
                RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
                RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
                // Configure USART2 Tx (PB.10) as alternate function push-pull
                GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
                GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
                GPIO_Init(GPIOB, &GPIO_InitStructure);
                // Configure USART2 Rx (PB.11) as input floating
                GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
                GPIO_Init(GPIOB, &GPIO_InitStructure);
                // Set Interrupt Priority
            NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
            NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = preprio;
            NVIC_InitStructure.NVIC_IRQChannelSubPriority = subprio;
            NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
                //CLI();
                NVIC_Init(&NVIC_InitStructure);
                //SEI();
        }
}



/****************************************************************************
*************************** End of File *************************************
****************************************************************************/

沙发
ZRJ8951| | 2013-7-23 15:39 | 只看该作者
收藏。方便查找。

使用特权

评论回复
板凳
jack888518| | 2013-7-23 15:58 | 只看该作者
有GD开发板的朋友可以试一下是否能直接使用。

使用特权

评论回复
地板
4310| | 2013-7-23 17:21 | 只看该作者
呵,lz和锐鑫同创申请开发板吧,必须通过啊

使用特权

评论回复
5
hunter0773| | 2014-11-25 00:11 | 只看该作者
看看如何,谢谢分享

使用特权

评论回复
6
orangerHero| | 2020-6-6 14:16 | 只看该作者
MARK!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

132

主题

522

帖子

8

粉丝