STM32
直播中

zhongnian

8年用户 1260经验值
擅长:MEMS/传感技术
私信 关注
[问答]

如何对STM32F10x的UART1/UART2/UART3的IO进行配置呢

USART和UART的区别在哪呢?
如何对UART1/UART2/UART3的IO进行配置呢?

回帖(2)

乔占宽

2021-12-10 10:38:41
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;
}
举报

李刚

2021-12-10 10:38:48
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;
}
举报

更多回帖

发帖
×
20
完善资料,
赚取积分