UART

STMF4之UART使用

一、串口简介

串口通讯基本是所有MCU的标配,在实际的项目中也经常使用,在项目中常常使用串口打印调试信息以及使用RS485、RS232和外部设备的通讯。

二、什么是重定向?

所谓重定向就是复写标准库函数,在使用printf时,printf最终会调用fputc函数将信息输出,所以需要重写fputc函数,在该函数中实现串口的输出,该函数重写后不需要声明。

三、串口发送和接收的几种方式

1、轮询方式:在主函数中轮询串口接收或者发送标准位,该种发送占用资源较多,使用较少。

2、中断方式:使能串口的中断后,当串口发送或者接收完成后会产生中断,该种方式消耗较少的资源,最为常用。

3、DMA发送:该种方式需要有芯片有DMA支持才可以,消耗资源最少,不是本篇讨论重点。

四、代码解析

1、初始化串口

/* 库版本: V1.8.0
 * 串口1初始化
 * 使用PA9和PA10
 */
static void UART1Init(void)     
{
    USART_DeInit(USART1);
    /* 1.使能PA口时钟 */
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

    /* 2.使能串口1时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

    /* 3.管脚映射 */
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);  /* GPIOA9复用为USART1 */  
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); /* GPIOA10复用为USART1 */ 

    /* 4.配置串口1的PA9和PA10管脚 */
    GPIO_InitTypeDef    GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9;         
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;       
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;       
    GPIO_Init(GPIOA, &GPIO_InitStructure);  /* TXIO */  

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_10;                
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;       
    GPIO_Init(GPIOA, &GPIO_InitStructure);  /* RXIO */

    /* 5.配置串口工作模式 */
    USART_InitTypeDef   USART_InitStructure;
    USART_InitStructure.USART_BaudRate            = 115200;                             
    USART_InitStructure.USART_WordLength          = USART_WordLength_8b;                    
    USART_InitStructure.USART_StopBits            = USART_StopBits_1;                           
    USART_InitStructure.USART_Parity              = USART_Parity_No ;                       
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 
    USART_InitStructure.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx; 
    USART_Init(USART1, &USART_InitStructure);

    /* 6.设置中断 */
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel                   = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;      
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;       
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    /* 7.使能串口中断 */

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
#ifdef USE_TC_SEND_DATA
    USART_ITConfig(USART1, USART_IT_TC, ENABLE);
#else
    USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
#endif
    USART_Cmd(USART1, ENABLE);

}

2、重定向

int fputc(int ch, FILE *f)
{
    USART_SendData(USART1, (uint8_t) ch);

    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);

    return (ch);
}

3、中断函数

/* 串口收发中断处理函数 */
void UART1RxOverInterrupt(void)
{
#ifdef USE_TC_SEND_DATA
    /* TX */
    if(USART_GetITStatus(USART1, USART_IT_TC) == SET)  
    { 
        /* 清零标志 */
        USART_ClearITPendingBit(USART1, USART_IT_TC);
        TX1BusyFlag = 0;
    }
#else
    /* TX */
    if( USART_GetITStatus(USART1, USART_IT_TXE) == SET)
    {
        if(UART1RxdWriteCnt == UART1RxdReadCnt)   
            USART_ITConfig(USART1, USART_IT_TXE, DISABLE);/* 发送完数据必须关掉中断 */
        else
        {
            USART_SendData(USART1, UART1RxdBuf[UART1RxdReadCnt++]);
            if(UART1RxdReadCnt == MAXBUFLENG)
            {
                UART1RxdReadCnt = 0;
            }
        }
    }
#endif

    /* RX */
    if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET) 
    {   
        UART1RxdBuf[UART1RxdWriteCnt++] = (u8)USART_ReceiveData(USART1);
        if(UART1RxdWriteCnt == MAXBUFLENG)
        {
            UART1RxdWriteCnt = 0;
        }
    }

}

五、额外提示:

1、发送标识USART_IT_TCUSART_IT_TXE区别

USART_IT_TC:串口8051方式,在发送完一个字节后产生中断,在中断中清除标准位。
USART_IT_TXE:发送寄存器空中断,即发送寄存器没有数据时,会产生中断,因此在没有数据发送时需要关闭中断,不然会一直进入中断,在需要发送数据时打开中断。

2、printf打印问题

在所有函数都正确设置后,任然没有打印信息,可以是由于编译器设置不对,不同的编译器有不同的设置方法,如MDK需要勾选Use MicroLIB

3、在使用串口时,所有串口配置都正确,但是数据输出不正确

可能是由于使用的晶振和代码中设置的晶振频率不一致导致,在stm32f4xx.h中默认外部晶振频率为25MHz

 #if !defined  (HSE_VALUE) 
  #define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
 #endif /* HSE_VALUE */

需要根据所使用的外部晶振定义重新定义 HSE_VALUE,由于stm32f4xx.h是库文件最后不要改动,可在stm32f4xx_conf.h中添加如下代码:

#if defined(HSE_VALUE)
#undef HSE_VALUE
#define HSE_VALUE   ((uint32_t)8000000)
#endif

4、串口中断标识有多种,不同的标识有不同的清零方式

具体参考《STM32F4xx中文参考手册.pdf》中关系USART_SR寄存器的详细介绍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值