STM32F10x之USART(库方式)

目录

1. USART和UART的区别

2. UART1/UART2/UART3的IO配置

3. 全局变量

4. UART初始化

4.1 使能USART的RCC并DeInit USART

4.2 中断初始化

4.3  配置USART

5. 中断处理程序

6. 写数据

6. 读数据

6.1 获取接收缓冲有效数据个数

6.2 读取缓冲数据

7. DMA方式

7.1 全局变量

7.2 初始化

7.3 配置DMA

7.4 发送

7.5 接收


STM32F10x的USART有不少功能(例如LIN、irDA等),这里只用作普通串口。

STM32F10x最多有3组USART和2组UART。

1. USART和UART的区别

UART:Universal Asynchronous Receiver and Transmitter通用异步收发器。信号: RXD, TXD。

USART:Universal Synchronous Asynchronous Receiver and Transmitter通用同步异步收发器。信号:RXD,TXD,CK,其中CK为同步时钟信号。

这里只考虑UART的情况。

2. UART1/UART2/UART3的IO配置

IO采用默认的复用脚。这里只列举了3个USART的IO配置

RCC->APB2ENR |= RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB;

//A9: TX1, A10: RX1
GPIOA->CRH &= ~(0x000000FF << ((9 % 8) * 4));
GPIOA->CRH |= (0x0000008B << ((9 % 8) * 4));
GPIOA->BSRR = ((uint32_t)1 << 10);

//A2: TX2, A3: RX2
GPIOA->CRL &= ~(0x000000FF << ((2 % 8) * 4));
GPIOA->CRL |= (0x0000008B << ((2 % 8) * 4));
GPIOA->BSRR = ((uint32_t)1 << 3);

//B10: TX3, B11: RX3
GPIOB->CRH &= ~(0x000000FF << ((10 % 8) * 4));
GPIOB->CRH |= (0x0000008B << ((10 % 8) * 4));
GPIOB->BSRR = ((uint32_t)1 << 11);

3. 全局变量

首先定义需要用到的全局变量:

USART_TypeDef* const USARTxGroup[] = {USART1, USART2, USART3};

 用于对应STM32的USART寄存器结构。

 

EXTERN volatile uint8_t gUart0RecvBuf[UART0_RECV_BUFSIZE];
EXTERN volatile uint8_t gUart1RecvBuf[UART1_RECV_BUFSIZE];
EXTERN volatile uint8_t gUart2RecvBuf[UART2_RECV_BUFSIZE];

各个USART接收缓冲,如果不使用则设置大小为0。

 

static volatile uint16_t gUartRecvIn[] = {0, 0, 0};
static volatile uint16_t gUartRecvRd[] = {0, 0, 0};

 USART读写接收缓冲的位置,gUartRecvIn表示写入位置,gUartRecvRd表示读出位置。

4. UART初始化

程序采用数字来表示不同的Uart,port 0表示USART1,port 1表示USART2,以此类推。

UART初始化的API函数原型如下:

void uartInit(uint8_t port, uint32_t baudrate, 
    uartparity_e parity, uartStop_e stopBit, uint8_t datBit)

参数说明:

port - UART端口号,有效值0 – n,具体根据MCU和应用设计对应的端口定义。这里有效值是0到2.

baudrate - UART的波特率。

parity - UART的奇偶校验位设置。定义其枚举类型如下:

typedef enum eUartParity

{

       UART_PARITY_NONE = 0,

       UART_PARITY_EVEN,

       UART_PARITY_ODD,

}uartparity_e;

stopBit - UART的停止位设置。定义其枚举类型如下:

typedef enum eUartStop
{
    UART_STOP_1 = 0,
    UART_STOP_0_5,
    UART_STOP_1_5,
    UART_STOP_2,
}uartStop_e;

4.1 使能USART的RCC并DeInit USART

switch(port)
{
    case HW_UART0:
        RCC->APB2ENR |= RCC_APB2Periph_USART1;
        RCC->APB2RSTR |= RCC_APB2Periph_USART1; //DeInit
        RCC->APB2RSTR &= ~RCC_APB2Periph_USART1;
        break;
    case HW_UART1:
        RCC->APB1ENR |= RCC_APB1Periph_USART2;
        RCC->APB1RSTR |= RCC_APB1Periph_USART2; //DeInit
        RCC->APB1RSTR &= ~RCC_APB1Periph_USART2;
        break;
    case HW_UART2:
        RCC->APB1ENR |= RCC_APB1Periph_USART3;
        RCC->APB1RSTR |= RCC_APB1Periph_USART3; //DeInit
        RCC->APB1RSTR &= ~RCC_APB1Periph_USART3;
        break;
    default:
        return;
}

4.2 中断初始化

void uartNVICInit(USART_TypeDef *USARTx, uint8_t priority)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    if(USARTx == USART1)
        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    else if(USARTx == USART2)
        NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    else if(USARTx == USART3)
        NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = priority;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE);
}

使能RXNE中断。 

优先级为0:

USART_TypeDef *USARTx;
USARTx = USARTxGroup[port];
uartNVICInit(USARTx, 0);

4.3  配置USART

USART_InitStructure.USART_BaudRate = baudrate;
switch(datBit)
{
    case 8:
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;
        break;
    case 9:
        USART_InitStructure.USART_WordLength = USART_WordLength_9b;
        break;
    default:
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;
        break;
}
switch(stopBit)
{
    case UART_STOP_1:
        USART_InitStructure.USART_StopBits = USART_StopBits_1;
        break;
    case UART_STOP_0_5:
        USART_InitStructure.USART_StopBits = USART_StopBits_0_5;
        break;
    case UART_STOP_1_5:
        USART_InitStructure.USART_StopBits = USART_StopBits_1_5;
        break;
    case UART_STOP_2:
        USART_InitStructure.USART_StopBits = USART_StopBits_2;
        break;
    default:
        USART_InitStructure.USART_StopBits = USART_StopBits_1;
        break;
}
switch(parity)
{
    case UART_PARITY_NONE:
    default:
        USART_InitStructure.USART_Parity = USART_Parity_No;
        break;
    case UART_PARITY_EVEN:
        USART_InitStructure.USART_Parity = USART_Parity_Even;
        break;
    case UART_PARITY_ODD:
        USART_InitStructure.USART_Parity = USART_Parity_Odd;
        break;
}
    
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
/* Configure USART1 */
USART_Init(USARTx, &USART_InitStructure);

5. 中断处理程序

void USART1_IRQHandler(void)
{
    USART_IRQHandler(0);
}

void USART2_IRQHandler(void)
{
    USART_IRQHandler(1);
}

void USART3_IRQHandler(void)
{
    USART_IRQHandler(2);
}

void USART_IRQHandler(uint8_t port)
{
    USART_TypeDef *USARTx = USARTxGroup[port];
    volatile uint8_t *pUartRecvBuf[] = {gUart0RecvBuf, gUart1RecvBuf, gUart2RecvBuf};
    uint16_t bufSize;
    switch(port)
    {
        case HW_UART0:
            bufSize = sizeof(gUart0RecvBuf);
            break;
        case HW_UART1:
            bufSize = sizeof(gUart1RecvBuf);
            break;
        case HW_UART2:
            bufSize = sizeof(gUart2RecvBuf);
            break;
    }
    if (USART_GetFlagStatus(USARTx, USART_FLAG_ORE) != RESET)
    {
        pUartRecvBuf[port][gUartRecvIn[port]] = (uint8_t)(USART_ReceiveData(USARTx) & 0xff);
        gUartRecvIn[port] %= bufSize;
        USART_ClearITPendingBit(USARTx,  USART_FLAG_ORE);
    }
    else if (USART_GetITStatus(USARTx, USART_IT_RXNE) != RESET)
    {
        pUartRecvBuf[port][gUartRecvIn[port]++] = (uint8_t)(USART_ReceiveData(USARTx) & 0xff);
        gUartRecvIn[port] %= bufSize;
        USART_ClearITPendingBit(USARTx,  USART_IT_RXNE);
    }
}

接收到的数据只保存在接收缓冲中,Circle的方式,数据如果没有被及时取走会被覆盖。 

6. 写数据

void uartSendByte(USART_TypeDef *USARTx, uint8_t dat)
{
    while(USART_GetFlagStatus(USARTx, USART_FLAG_TC)==RESET)
    {
    }
    USART_SendData(USARTx, dat);
}

bool_t uartWriteBytes(uint8_t port, uint8_t *buf, uint16_t len)
{
    if(port >= HW_UART_MAX)
        return FALSE;
    while(len)
    {
        uartSendByte(USARTxGroup[port], *buf);
        buf++;
        len--;
    }
    return TRUE;
}

6. 读数据

6.1 获取接收缓冲有效数据个数

uint16_t uartGetQueueStatus(uint8_t port)
{
    uint16_t datLen = 0;
    uint16_t bufSize;
    uint16_t recvIn = gUartRecvIn[port];
    switch(port)
    {
        case HW_UART0:
            bufSize = sizeof(gUart0RecvBuf);
            break;
        case HW_UART1:
            bufSize = sizeof(gUart1RecvBuf);
            break;
        case HW_UART2:
            bufSize = sizeof(gUart2RecvBuf);
            break;
        default:
            return 0;
    }
    datLen = (bufSize + recvIn - gUartRecvRd[port]) % bufSize;
    return datLen;
}

6.2 读取缓冲数据

bool_t uartReadBytes(uint8_t port, uint8_t *buf, uint16_t len)
{
    volatile uint8_t *pUartRecvBuf[] = {gUart0RecvBuf, gUart1RecvBuf};
    uint16_t bufSize;
    switch(port)
    {
        case HW_UART0:
            bufSize = sizeof(gUart0RecvBuf);
            break;
        case HW_UART1:
            bufSize = sizeof(gUart1RecvBuf);
            break;
        case HW_UART2:
            bufSize = sizeof(gUart2RecvBuf);
            break;
        default:
            return FALSE;
    }

    if(len > uartGetQueueStatus(port))
        return FALSE;

    while(len)
    {
        *buf = pUartRecvBuf[port][gUartRecvRd[port]++];
        len--;
        buf++;
        gUartRecvRd[port] %= bufSize;
    }
    return TRUE;
}

7. DMA方式

7.1 全局变量

DMA_Channel_TypeDef* const USARTxDmaCH[] = {DMA1_Channel4, DMA1_Channel7, DMA1_Channel2};
DMA_Channel_TypeDef* const USARRxDmaCH[] = {DMA1_Channel5, DMA1_Channel6, DMA1_Channel3};

定义DMA收发对应的Channel以方便port去对应的Channel。

 注意:USART使用的DMA Channel可能会和其他外设的DMA Channel重合,比如SPI,这样就不能2个外设都用DMA的方式。

7.2 初始化

void uartDmaInit(USART_TypeDef *USARTx)
{ 
    RCC->AHBENR |= RCC_AHBENR_DMA1EN;
    USARTx->CR3 |= USART_DMAReq_Tx | USART_DMAReq_Rx;
}

7.3 配置DMA

void uartDmaCfg(uint8_t port)
{
    DMA_Channel_TypeDef *dmaCH;
    //TX Channel
    dmaCH = USARTxDmaCH[port];
    dmaCH->CCR = ((uint32_t)0 << 14) |    //Peripheral to Mem
        ((uint32_t)0x03 << 12) |            //Priority Very High
        ((uint32_t)0x00 << 10) |            //Mem Size is 8bit
        ((uint32_t)0x00 << 8) |             //Periph Size is 8bit
        ((uint32_t)0x01 << 7) |             //Mem Increase
        ((uint32_t)0x00 << 6) |             //Periph Increase Disable
        ((uint32_t)0x00 << 5) |             //Circle mode Disable
        ((uint32_t)0x01 << 4) |             //Mem to Periph
        ((uint32_t)0x00 << 3) |             //Error Transfer Int Disable
        ((uint32_t)0x00 << 2) |             //Half Transfer Int Disable
        ((uint32_t)0x00 << 1) |             //Transfer Finish Int Disable
        ((uint32_t)0x00 << 0);              //Channel enable
    dmaCH->CNDTR = 0;
    dmaCH->CPAR = (uint32_t)(&USARTxGroup[port]->DR);
    dmaCH->CMAR = 0;
    
    //RX Channel
    dmaCH = USARRxDmaCH[port];
    dmaCH->CCR = ((uint32_t)0 << 14) |    //Mem to Peripheral
        ((uint32_t)0x03 << 12) |            //Priority Very High
        ((uint32_t)0x00 << 10) |            //Mem Size is 8bit
        ((uint32_t)0x00 << 8) |             //Periph Size is 8bit
        ((uint32_t)0x01 << 7) |             //Mem Increase
        ((uint32_t)0x00 << 6) |             //Periph Increase Disable
        ((uint32_t)0x01 << 5) |             //Circle mode Enable
        ((uint32_t)0x00 << 4) |             //Periph to Mem
        ((uint32_t)0x00 << 3) |             //Error Transfer Int Disable
        ((uint32_t)0x00 << 2) |             //Half Transfer Int Enable
        ((uint32_t)0x00 << 1) |             //Transfer Finish Int Disable
        ((uint32_t)0x00 << 0);              //Channel enable
    
    dmaCH->CPAR = (uint32_t)(&USARTxGroup[port]->DR);
    switch(port)
    {
        case HW_UART0:
            dmaCH->CNDTR = sizeof(gUart0RecvBuf);
            dmaCH->CMAR = (uint32_t)gUart0RecvBuf;
            break;
        case HW_UART1:
            dmaCH->CNDTR = sizeof(gUart1RecvBuf);
            dmaCH->CMAR = (uint32_t)gUart1RecvBuf;
            break;
        case HW_UART2:
            dmaCH->CNDTR = sizeof(gUart2RecvBuf);
            dmaCH->CMAR = (uint32_t)gUart2RecvBuf;
            break;
        default:
            break;
    }
    dmaCH->CCR |= (uint32_t)((uint32_t)0x01 << 0); //Channel Enable
}

 发送DMA在配置好参数后不会启动,等实际发送数据时再更新对应的寄存器设置。

而接受DMA配置好就启动,接受到的数据会不停的更新到接受缓冲中,满了自动覆盖前面的数据。这样程序并不需要有接收中断了,需要把中断初始化去掉。

#ifndef UART_DMA
uartNVICInit(USARTx, 0);
#endif

而DMA初始化和配置要放在USART使能之后

USART_Cmd(USARTx, ENABLE);
#ifdef UART_DMA
uartDmaInit(USARTx);
uartDmaCfg(port);
#endif

7.4 发送

bool_t uartWriteBytes(uint8_t port, uint8_t *buf, uint16_t len)
{
    if(port >= HW_UART_MAX)
        return FALSE;

    #ifdef UART_DMA
    {
        DMA_Channel_TypeDef *dmaCHTx;
        dmaCHTx = USARTxDmaCH[port];
        dmaCHTx->CCR &= ~((uint32_t)0x01 << 0); //Channel Disable
        dmaCHTx->CMAR = (uint32_t)buf;
        dmaCHTx->CNDTR = len;
        dmaCHTx->CCR |= (uint32_t)((uint32_t)0x01 << 0); //Channel Enable
        while(dmaCHTx->CNDTR > 0)
        {
            delayus(2);
        }
    }
    #else
    while(len)
    {
        uartSendByte(USARTxGroup[port], *buf);
        buf++;
        len--;
    }
    #endif
    return TRUE;
}

以CNDTR为0表示发送结束。 

7.5 接收

只需要修改uartGetQueueStatus,通过CNDTR获取接收缓冲中的数据个数。

switch(port)
{
    case HW_UART0:
        bufSize = sizeof(gUart0RecvBuf);
        #ifdef UART_DMA
        gUartRecvIn[0] = (bufSize - DMA1_Channel5->CNDTR) % bufSize; 
        #endif
        break;
    case HW_UART1:
        bufSize = sizeof(gUart1RecvBuf);
        #ifdef UART_DMA
        gUartRecvIn[1] = (bufSize - DMA1_Channel6->CNDTR) % bufSize; 
        #endif
        break;
    case HW_UART2:
        bufSize = sizeof(gUart2RecvBuf);
        #ifdef UART_DMA
        gUartRecvIn[2] = (bufSize - DMA1_Channel3->CNDTR) % bufSize; 
        #endif
        break;
    default:
        return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值