STM32:USART

1 前言

  串口,即数据按位串行发送的通信接口协议,比如usart串行通讯协议;

  usart全称universal synchronous asynchronous receiver transmitter通用同步异步接收发送器;

  usart接口通过RX,TX,GND同其他设备相连;速率最高约4.5Mbps,波特率最高460800baud;

  1.1 通讯名词

    同步通讯:收发双方使用相同的时钟信号线进行通讯,数据传输效率高;

    异步通讯:收发双方使用各自的时钟信号线进行通讯,通过起始位和停止位来确定收发数据,数据传输效率低;

         异步指使用的是各自的时钟信号发生器;发送方发送的时候接收方没收到,数据就丢失了;处理信息还是要同时处理;

    单工通讯:单向通讯,器件要么只发送数据,要么只接收数据;一条数据线工作,数据线不能分时复用收发;

    双工通讯:双向通讯,器件可以发送数据,也可以接收数据;两条数据线工作;

    半双工通讯:接口协议在同一时刻,只能发送数据或者接收数据;一条数据线工作,数据线分时复用收发;

    全双工通讯:接口协议在同一时刻,发送数据的同时也可以接收数据;两条数据线工作;

  1.3 波特率和比特率

    波特率:每秒内传输的信号可变化次数,单位baud;顾名思义理解为每秒内信号可波动的次数;

    比特率:每秒内传输的数据bit位数,单位bps;如果一个电平变化有6种状态,那么变化一次传输的是3bit数据;

        对于单片机而言,每次传输数据不是0就是1,所以波动一次表示1bit数据,二进制传输的波特率等于比特率;

2 USART的帧格式

  

  目前遇到过的串口协议都是1bit起始位,8bit数据位,1bit停止位,无校验位;

3 USART的寄存器

  每个usart都有7个自己的寄存器,功能简略概括如下;搭配中文参考手册25.3小节的图248-usart功能框图理解;

  

  其中,与串行通信协议相关的部分寄存器如下列出,也是常见usart协议使用到的寄存器部分;

  

  3.1 DR数据寄存器工作框图

    

   TXE置1表示TDR可写,也可理解为TDR未写入新数据;

    RXNE置1表示RDR可读,也可理解为RDR未读出新数据;

    TC置1表示TDR没有新的数据,且移位寄存器发送完毕,即全部数据帧发送完毕;

4 USART的代码

  4.1 标准库封装

USART_TypeDef
/***lie in stm32f10x.h ***/
typedef struct
{
  __IO uint16_t SR;
  uint16_t  RESERVED0;
  __IO uint16_t DR;
  uint16_t  RESERVED1;
  __IO uint16_t BRR;
  uint16_t  RESERVED2;
  __IO uint16_t CR1;
  uint16_t  RESERVED3;
  __IO uint16_t CR2;
  uint16_t  RESERVED4;
  __IO uint16_t CR3;
  uint16_t  RESERVED5;
  __IO uint16_t GTPR;
  uint16_t  RESERVED6;
} USART_TypeDef;

#define PERIPH_BASE           ((uint32_t)0x40000000)
#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)
#define USART1_BASE           (APB2PERIPH_BASE + 0x3800)
#define USART1              ((USART_TypeDef *) USART1_BASE)
USART_InitTypeDef
/***stm32f10x_usart.h***/
typedef struct
{
  uint32_t USART_BaudRate;          
  uint16_t USART_WordLength;          
  uint16_t USART_StopBits;           
  uint16_t USART_Parity;             
  uint16_t USART_Mode;              
  uint16_t USART_HardwareFlowControl;                                                                                  
} USART_InitTypeDef;

#define IS_USART_BAUDRATE(BAUDRATE) (((BAUDRATE) > 0) && ((BAUDRATE) < 0x0044AA21))

#define USART_WordLength_8b                  ((uint16_t)0x0000)
#define USART_WordLength_9b                  ((uint16_t)0x1000)

#define USART_StopBits_1                     ((uint16_t)0x0000)
#define USART_StopBits_0_5                   ((uint16_t)0x1000)
#define USART_StopBits_2                     ((uint16_t)0x2000)
#define USART_StopBits_1_5                   ((uint16_t)0x3000)

#define USART_Parity_No                      ((uint16_t)0x0000)
#define USART_Parity_Even                    ((uint16_t)0x0400)
#define USART_Parity_Odd                     ((uint16_t)0x0600) 

#define USART_Mode_Rx                        ((uint16_t)0x0004)
#define USART_Mode_Tx                        ((uint16_t)0x0008)
/***这是CR1中的TE、RE位,收发器使能位;放在这里配置的;***/

#define USART_HardwareFlowControl_None       ((uint16_t)0x0000)
#define USART_HardwareFlowControl_RTS        ((uint16_t)0x0100)
#define USART_HardwareFlowControl_CTS        ((uint16_t)0x0200)
#define USART_HardwareFlowControl_RTS_CTS    ((uint16_t)0x0300)

  4.2 USART的库代码

USART_DeInit()
 void USART_DeInit(USART_TypeDef* USARTx)
{
  /* Check the parameters */
  assert_param(IS_USART_ALL_PERIPH(USARTx));

  if (USARTx == USART1)
  {
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1, ENABLE);
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1, DISABLE);
  }
  else if (USARTx == USART2)
  {
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2, ENABLE);
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2, DISABLE);
  }
  else if (USARTx == USART3)
  {
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART3, ENABLE);
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART3, DISABLE);
  }    
  else if (USARTx == UART4)
  {
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_UART4, ENABLE);
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_UART4, DISABLE);
  }    
  else
  {
    if (USARTx == UART5)
    { 
      RCC_APB1PeriphResetCmd(RCC_APB1Periph_UART5, ENABLE);
      RCC_APB1PeriphResetCmd(RCC_APB1Periph_UART5, DISABLE);
    }
  }
}
USART_Init()
#define CR2_STOP_CLEAR_Mask       ((uint16_t)0xCFFF)  /*!< USART CR2 STOP Bits Mask */
#define CR1_CLEAR_Mask            ((uint16_t)0xE9F3)  /*!< USART CR1 Mask */
/***其中波特率代码的计算公式不知道为什么这么计算的,有空再补充;***/

void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct)
{
  uint32_t tmpreg = 0x00, apbclock = 0x00;
  uint32_t integerdivider = 0x00;
  uint32_t fractionaldivider = 0x00;
  uint32_t usartxbase = 0;
  RCC_ClocksTypeDef RCC_ClocksStatus;
  /* Check the parameters */
  assert_param(IS_USART_ALL_PERIPH(USARTx));
  assert_param(IS_USART_BAUDRATE(USART_InitStruct->USART_BaudRate));  
  assert_param(IS_USART_WORD_LENGTH(USART_InitStruct->USART_WordLength));
  assert_param(IS_USART_STOPBITS(USART_InitStruct->USART_StopBits));
  assert_param(IS_USART_PARITY(USART_InitStruct->USART_Parity));
  assert_param(IS_USART_MODE(USART_InitStruct->USART_Mode));
  assert_param(IS_USART_HARDWARE_FLOW_CONTROL(USART_InitStruct->USART_HardwareFlowControl));
  /* The hardware flow control is available only for USART1, USART2 and USART3 */
  if (USART_InitStruct->USART_HardwareFlowControl != USART_HardwareFlowControl_None)
  {
    assert_param(IS_USART_123_PERIPH(USARTx));
  }

  usartxbase = (uint32_t)USARTx;

/*---------------------------- USART CR2 Configuration -----------------------*/
  tmpreg = USARTx->CR2;
  tmpreg &= CR2_STOP_CLEAR_Mask;
    /***0xCFFF:1100 1111 1111 1111b,清0bit[13:12] CR2的停止位***/
  tmpreg |= (uint32_t)USART_InitStruct->USART_StopBits;
  
  /* Write to USART CR2 */
  USARTx->CR2 = (uint16_t)tmpreg;

/*---------------------------- USART CR1 Configuration -----------------------*/
  tmpreg = USARTx->CR1;
  tmpreg &= CR1_CLEAR_Mask;
    /***0xE9F3:1110 1001 1111 0011b,掩码作用是清0 CR1的bit[12,10,9,3,2],
    ***[12]M字长位,[10]PCE (Parity control enable)校验控制使能, [9]PS (Parity selection)奇偶校验选择
    ***[3]TE发送器使能位,[2]RE接收器使能位;
    ***然后下面代码就配置上面的参数***/ 
  tmpreg |= (uint32_t)USART_InitStruct->USART_WordLength | USART_InitStruct->USART_Parity |
            USART_InitStruct->USART_Mode;
    
  USARTx->CR1 = (uint16_t)tmpreg;

/*---------------------------- USART CR3 Configuration -----------------------*/  
  tmpreg = USARTx->CR3;
  /* Clear CTSE and RTSE bits */
  tmpreg &= CR3_CLEAR_Mask;
  /* Configure the USART HFC -------------------------------------------------*/
  /* Set CTSE and RTSE bits according to USART_HardwareFlowControl value */
  tmpreg |= USART_InitStruct->USART_HardwareFlowControl;
  /* Write to USART CR3 */
  USARTx->CR3 = (uint16_t)tmpreg;

/*---------------------------- USART BRR Configuration -----------------------*/
  /* Configure the USART Baud Rate -------------------------------------------*/
  RCC_GetClocksFreq(&RCC_ClocksStatus);
  if (usartxbase == USART1_BASE)
  {
    apbclock = RCC_ClocksStatus.PCLK2_Frequency;
  }
  else
  {
    apbclock = RCC_ClocksStatus.PCLK1_Frequency;
  }
  
  /* Determine the integer part */
  if ((USARTx->CR1 & CR1_OVER8_Set) != 0)
  {
    /* Integer part computing in case Oversampling mode is 8 Samples */
    integerdivider = ((25 * apbclock) / (2 * (USART_InitStruct->USART_BaudRate)));    
  }
  else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */
  {
    /* Integer part computing in case Oversampling mode is 16 Samples */
    integerdivider = ((25 * apbclock) / (4 * (USART_InitStruct->USART_BaudRate)));    
  }
  tmpreg = (integerdivider / 100) << 4;

  /* Determine the fractional part */
  fractionaldivider = integerdivider - (100 * (tmpreg >> 4));

  /* Implement the fractional part in the register */
  if ((USARTx->CR1 & CR1_OVER8_Set) != 0)
  {
    tmpreg |= ((((fractionaldivider * 8) + 50) / 100)) & ((uint8_t)0x07);
  }
  else /* if ((USARTx->CR1 & CR1_OVER8_Set) == 0) */
  {
    tmpreg |= ((((fractionaldivider * 16) + 50) / 100)) & ((uint8_t)0x0F);
  }
  
  /* Write to USART BRR */
  USARTx->BRR = (uint16_t)tmpreg;
}
USART_StructInit()
 /***stm32f10x_usart.c  标准库提供的默认配置代码;***/
void USART_StructInit(USART_InitTypeDef* USART_InitStruct)
{
  /* USART_InitStruct members default value */
  USART_InitStruct->USART_BaudRate = 9600;
  USART_InitStruct->USART_WordLength = USART_WordLength_8b;
  USART_InitStruct->USART_StopBits = USART_StopBits_1;
  USART_InitStruct->USART_Parity = USART_Parity_No ;
  USART_InitStruct->USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_InitStruct->USART_HardwareFlowControl = USART_HardwareFlowControl_None;  
}
USART_Cmd()
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_USART_ALL_PERIPH(USARTx));
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  
  if (NewState != DISABLE)
  {
    /* Enable the selected USART by setting the UE bit in the CR1 register */
    USARTx->CR1 |= CR1_UE_Set;
  }
  else
  {
    /* Disable the selected USART by clearing the UE bit in the CR1 register */
    USARTx->CR1 &= CR1_UE_Reset;
  }
}
USART_ITConfig()
 /***stm32f10x_usart.c  ***/ 
                                                                   /***usartreg[7:5],itpos[4:0]***/ 
#define USART_IT_PE                          ((uint16_t)0x0028)    /***0000 0000 0010 1000b***/ 
#define USART_IT_TXE                         ((uint16_t)0x0727)    /***0000 0111 0010 0111b***/ 
#define USART_IT_TC                          ((uint16_t)0x0626)    /***0000 0110 0010 0110b***/ 
#define USART_IT_RXNE                        ((uint16_t)0x0525)    /***0000 0101 0010 0101b***/ 
#define USART_IT_IDLE                        ((uint16_t)0x0424)    /***0000 0100 0010 0100***/ 
#define USART_IT_LBD                         ((uint16_t)0x0846)    /***0000 1000 0100 0110b***/ 
#define USART_IT_CTS                         ((uint16_t)0x096A)    /***0000 1001 0110 1010b***/ 
#define USART_IT_ERR                         ((uint16_t)0x0060)    /***0000 0000 0110 0000b***/
#define USART_IT_ORE                         ((uint16_t)0x0360)    /***0000 0011 0110 0000b***/
#define USART_IT_NE                          ((uint16_t)0x0260)    /***0000 0010 0110 0000b***/
#define USART_IT_FE                          ((uint16_t)0x0160)    /***0000 0001 0110 0000b***/
#define IS_USART_CONFIG_IT(IT) (((IT) == USART_IT_PE) || ((IT) == USART_IT_TXE) || \
                               ((IT) == USART_IT_TC) || ((IT) == USART_IT_RXNE) || \
                               ((IT) == USART_IT_IDLE) || ((IT) == USART_IT_LBD) || \
                               ((IT) == USART_IT_CTS) || ((IT) == USART_IT_ERR))

void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)
{
  uint32_t usartreg = 0x00, itpos = 0x00, itmask = 0x00;
  uint32_t usartxbase = 0x00;
  /* Check the parameters */
  assert_param(IS_USART_ALL_PERIPH(USARTx));
  assert_param(IS_USART_CONFIG_IT(USART_IT));
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  /* The CTS interrupt is not available for UART4 and UART5 */
  if (USART_IT == USART_IT_CTS)
  {
    assert_param(IS_USART_123_PERIPH(USARTx));
  }   
  
  usartxbase = (uint32_t)USARTx;

  /* Get the USART register index */
  usartreg = (((uint8_t)USART_IT) >> 0x05);

  /* Get the interrupt position */
  itpos = USART_IT & IT_Mask;
  itmask = (((uint32_t)0x01) << itpos);
    
  if (usartreg == 0x01) /* The IT is in CR1 register */
  {
    usartxbase += 0x0C;
  }
  else if (usartreg == 0x02) /* The IT is in CR2 register */
  {
    usartxbase += 0x10;
  }
  else /* The IT is in CR3 register */
  {
    usartxbase += 0x14; 
  }
  if (NewState != DISABLE)
  {
    *(__IO uint32_t*)usartxbase  |= itmask;
  }
  else
  {
    *(__IO uint32_t*)usartxbase &= ~itmask;
  }
}
USART_SendData()
 void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
{
  /* Check the parameters */
  assert_param(IS_USART_ALL_PERIPH(USARTx));
  assert_param(IS_USART_DATA(Data)); 
    
  /* Transmit Data */
  USARTx->DR = (Data & (uint16_t)0x01FF);
}
USART_ReceiveData()
 uint16_t USART_ReceiveData(USART_TypeDef* USARTx)
{
  /* Check the parameters */
  assert_param(IS_USART_ALL_PERIPH(USARTx));
  
  /* Receive Data */
  return (uint16_t)(USARTx->DR & (uint16_t)0x01FF);
}
USART_GetFlagStatus()
#define USART_FLAG_CTS                       ((uint16_t)0x0200)
#define USART_FLAG_LBD                       ((uint16_t)0x0100)
#define USART_FLAG_TXE                       ((uint16_t)0x0080)
#define USART_FLAG_TC                        ((uint16_t)0x0040)
#define USART_FLAG_RXNE                      ((uint16_t)0x0020)
#define USART_FLAG_IDLE                      ((uint16_t)0x0010)
#define USART_FLAG_ORE                       ((uint16_t)0x0008)
#define USART_FLAG_NE                        ((uint16_t)0x0004)
#define USART_FLAG_FE                        ((uint16_t)0x0002)
#define USART_FLAG_PE                        ((uint16_t)0x0001)
#define IS_USART_FLAG(FLAG) (((FLAG) == USART_FLAG_PE) || ((FLAG) == USART_FLAG_TXE) || \
                             ((FLAG) == USART_FLAG_TC) || ((FLAG) == USART_FLAG_RXNE) || \
                             ((FLAG) == USART_FLAG_IDLE) || ((FLAG) == USART_FLAG_LBD) || \
                             ((FLAG) == USART_FLAG_CTS) || ((FLAG) == USART_FLAG_ORE) || \
                             ((FLAG) == USART_FLAG_NE) || ((FLAG) == USART_FLAG_FE))

FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)
{
  FlagStatus bitstatus = RESET;
  /* Check the parameters */
  assert_param(IS_USART_ALL_PERIPH(USARTx));
  assert_param(IS_USART_FLAG(USART_FLAG));
  /* The CTS flag is not available for UART4 and UART5 */
  if (USART_FLAG == USART_FLAG_CTS)
  {
    assert_param(IS_USART_123_PERIPH(USARTx));
  }  
  
  if ((USARTx->SR & USART_FLAG) != (uint16_t)RESET)
  {
    bitstatus = SET;
  }
  else
  {
    bitstatus = RESET;
  }
  return bitstatus;
}
USART_ClearFlag()
#define IS_USART_CLEAR_FLAG(FLAG) ((((FLAG) & (uint16_t)0xFC9F) == 0x00) && ((FLAG) != (uint16_t)0x00))
/***0xFC9F:1111 1100 1001 1111b;  FLAG:bit[9,8,6,5];***/
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG)
{
  /* Check the parameters */
  assert_param(IS_USART_ALL_PERIPH(USARTx));
  assert_param(IS_USART_CLEAR_FLAG(USART_FLAG));
  /* The CTS flag is not available for UART4 and UART5 */
  if ((USART_FLAG & USART_FLAG_CTS) == USART_FLAG_CTS)
  {
    assert_param(IS_USART_123_PERIPH(USARTx));
  } 
   
  USARTx->SR = (uint16_t)~USART_FLAG;
}
USART_GetITStatus()
 ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)
{
  uint32_t bitpos = 0x00, itmask = 0x00, usartreg = 0x00;
  ITStatus bitstatus = RESET;
  /* Check the parameters */
  assert_param(IS_USART_ALL_PERIPH(USARTx));
  assert_param(IS_USART_GET_IT(USART_IT));
  /* The CTS interrupt is not available for UART4 and UART5 */ 
  if (USART_IT == USART_IT_CTS)
  {
    assert_param(IS_USART_123_PERIPH(USARTx));
  }   
  
  /* Get the USART register index */
  usartreg = (((uint8_t)USART_IT) >> 0x05);
  /* Get the interrupt position */
  itmask = USART_IT & IT_Mask;
  itmask = (uint32_t)0x01 << itmask;
  
  if (usartreg == 0x01) /* The IT  is in CR1 register */
  {
    itmask &= USARTx->CR1;
  }
  else if (usartreg == 0x02) /* The IT  is in CR2 register */
  {
    itmask &= USARTx->CR2;
  }
  else /* The IT  is in CR3 register */
  {
    itmask &= USARTx->CR3;
  }
  
  bitpos = USART_IT >> 0x08;
  bitpos = (uint32_t)0x01 << bitpos;
  bitpos &= USARTx->SR;
  if ((itmask != (uint16_t)RESET)&&(bitpos != (uint16_t)RESET))
  {
    bitstatus = SET;
  }
  else
  {
    bitstatus = RESET;
  }
  
  return bitstatus;  
}
USART_DMACmd()
 /***配置CR3中的dma传输位,配合DMA_Init()使用;***/
#define USART_DMAReq_Tx                      ((uint16_t)0x0080)
#define USART_DMAReq_Rx                      ((uint16_t)0x0040)
#define IS_USART_DMAREQ(DMAREQ) ((((DMAREQ) & (uint16_t)0xFF3F) == 0x00) && ((DMAREQ) != (uint16_t)0x00))
void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_USART_ALL_PERIPH(USARTx));
  assert_param(IS_USART_DMAREQ(USART_DMAReq));  
  assert_param(IS_FUNCTIONAL_STATE(NewState)); 
  if (NewState != DISABLE)
  {
    /* Enable the DMA transfer for selected requests by setting the DMAT and/or
       DMAR bits in the USART CR3 register */
    USARTx->CR3 |= USART_DMAReq;
  }
  else
  {
    /* Disable the DMA transfer for selected requests by clearing the DMAT and/or
       DMAR bits in the USART CR3 register */
    USARTx->CR3 &= (uint16_t)~USART_DMAReq;
  }
}

  4.2 USART1使用代码

usart.c
#include "usart.h"  

u8 USART1_REV_BUF[256];	//接收缓存
u8 USART1_REV_CNT = 0;	//接收字节计数
u8 USART1_REV_FLAG = 0;	//收到\r\n

u8 USART2_REV_BUF[256];
u8 USART2_REV_CNT = 0;
u8 USART2_REV_FLAG = 0; 

//usart1初始化之后,便可以通过串口读写了;
void usart1_init(u32 bound)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE);
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);    

    //USART1外设中断配置
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;	
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;			
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				
    NVIC_Init(&NVIC_InitStructure);  
	
    //GPIO初始化 USART1_TX	PA9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;		
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    //GPIO初始化    USART1_RX	PA10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);

   //USART1初始化
    USART_InitStructure.USART_BaudRate = bound;
    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;   //CR1中的TE,RE  
    USART_Init(USART1, &USART_InitStructure); 
    
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//CR1中的RXNEIE中断
    USART_Cmd(USART1, ENABLE);                    //CR1中的UE使能
}

#if 1

//将想要通过串口发送的buff和buff长度传入即可,不用配置其他参数,函数执行完即发送完成;
void USART1_sendbuff(u8 *buf,u16 len)
{
    u16 t;
    for(t=0;t<len;t++)        
    {
        USART_SendData(USART1,buf[t]);
		while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET); 
		//等待TC硬件置1,则发送完毕,继续发送;;
    }	
}

#else
void USART1_sendbuff(u8 *buf,u16 len)
{
	u16 t=0;
	for(t=0;t<len;t++)
	{
		USART_SendData(USART1,buf[t]);
		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET)
			;
	}
}

#endif


void USART1_IRQHandler(void)                    
{
    if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
     	USART1_REV_BUF[USART1_REV_CNT] =USART_ReceiveData(USART1);
        USART1_REV_CNT++; 
		
        if( (USART1_REV_BUF[USART1_REV_CNT-2]==0x0d) && (USART1_REV_BUF[USART1_REV_CNT-1]==0x0a) )
		{
			USART1_REV_FLAG = 1;
        	printf(" IRQ USART1_REV_FLAG    \r\n");
		}
	}
	
	//详见<中文参考手册>25.3.3 字符接收小节
    if(USART_GetFlagStatus(USART1,USART_FLAG_ORE) == SET)
    {
    	printf("USART_FLAG_ORE  \r\n");
        USART_ReceiveData(USART1);
        //USART_ClearFlag(USART1,USART_FLAG_ORE);
        //先读SR,后读DR,可以复位ORE位;但是前面有个bug可能是卡在这里了,注释掉等下次出现再看看;
        
    }
}


/***等待上位机发送/r/n后,USART1_REV_FLAG置1,然后回发数据;***/
void usart1_receive_test(int bound)
{
    usart1_init(bound); 
	while(1)
	{
		if(USART1_REV_FLAG)
		{
			USART1_REV_FLAG = 0;
			
			printf( "USART1_REV_FLAG 1  \r\n");
			USART1_sendbuff(USART1_REV_BUF,USART1_REV_CNT);
			
			USART1_REV_CNT = 0;
			
	   }
	}

}
main.c
 #include "main.h"

int main(void)
{
	usart1_receive_test(115200);
}

    4.2.1 不使用RXNEIE中断的串口收发

/***不使能RXNEIE,使能CR1中的UE、TE和RE之后,usart也可以正常工作了,直接通过对SR状态寄存器的读取来收发也是可以的
***因为没有使用中断,所以不配置NVIC,串口也可以使用***/
main.c
 #include "main.h"


int main(void)
{
	 GPIO_InitTypeDef GPIO_InitStructure;
	 USART_InitTypeDef USART_InitStructure;
	 //NVIC_InitTypeDef NVIC_InitStructure;
	
	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE);
	 //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	
	
	 //USART1外设中断配置
	 //NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	 //NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;	 
	 //NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; 		 
	 //NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			 
	 //NVIC_Init(&NVIC_InitStructure);  
	 
	 //GPIO初始化 USART1_TX	 PA9
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 
	 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	 
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	 
	 GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	 //GPIO初始化	USART1_RX	 PA10
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	 GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//USART1初始化
	 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;   //CR1中的TE,RE  
	 USART_Init(USART1, &USART_InitStructure); 
	 
	 //USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//CR1中的RXNEIE中断
	 USART_Cmd(USART1, ENABLE); 				   //CR1中的UE使能


	while(1)
	{
		 if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)
		{
		 	USART1_REV_BUF[USART1_REV_CNT] =USART_ReceiveData(USART1);
		    USART1_REV_CNT++; 
			
		    if( (USART1_REV_BUF[USART1_REV_CNT-2]==0x0d) && (USART1_REV_BUF[USART1_REV_CNT-1]==0x0a) )
			{
				USART1_REV_FLAG = 1;
		    	printf(" IRQ USART1_REV_FLAG \r\n";
			}
		}

		if(USART1_REV_FLAG)
		{
			u16 t;
			for(t=0;t<USART1_REV_CNT;t++)	  
			{
				USART_SendData(USART1,USART1_REV_BUF[t]);
				while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET)
					; 
					//等待TXE硬件置1;

			}
			
			USART1_REV_FLAG = 0;
			USART1_REV_CNT = 0;
		
		}

	}

}

5 重定向printf()

fputc()
#if 1
/***
***半主机模式就是半独立的主机模式,是单片机的一种功能;为什么是半独立的呢?
***因为它没有自己配套的输入输出设备,需要和其他主机通信,借用其他主机配套的输入输出设备显示;
***那该怎么使用半主机模式呢?通过仿真器连接其他主机,代码中应该就可以直接使用printf和scanf了;
***
***printf和scanf属于"stdio.h"库函数;stdio.h库属于microLIB库;
***#pragma import(__use_no_semihosting)禁用半主机模式,你都禁用了还怎么调用fputc和fgetc呢?
***
***/
/***使用举例:
	printf("enter byte:\r\n");
	scanf("%d",&scan_num);
	printf("%d",scan_num);***/

//#pragma import(__use_no_semihosting)   
//上面这个定义和microLIB冲突,所以“勾选microLIB、#pregma”二选一;我选勾microLIB;
//Error: L6915E: Library reports error: __use_no_semihosting was requested, but a semihosting fgetc was linked in

//下面这些函数都是不使用mircoLIB时需要配置的函数,我使用microLIB注释掉好像也没什么问题;               
//struct __FILE 
//{ 
//	int handle; 
//}; 
//FILE __stdout; 
//FILE __stdint;

//调用了库函数之后都会通过_sys_exit()退出库;  
//void _sys_exit(int x) 
//{ 
//	x = x; 
//} 

int fputc(int ch, FILE *f)
{
    while( !(USART1->SR&USART_FLAG_TXE) )
        ;
    USART1->DR = (u8) ch;      
    return ch;
}

//编译没有问题,等待扫描的样子也有,但是数据不对,这个get函数跑不对有点离谱,先放着吧;
//所以这个代码scanf不能用,printf能用;
int fgetc(FILE *f)
{
	while( !(USART1->SR&USART_FLAG_RXNE) )
		;
	return (u8)USART1->DR;
}

#endif

6 RS232、RS485

  usart使用TTL电平标准,抗干扰能力弱通常用于板间通信;所以又陆续制定了RS232、RS485电平标准的usart通讯;

  RS232通讯、RS485通讯本质依旧是usart通讯,外加了电平转换芯片,然后换了数据线而已;

    RS232协议:将usart的RX、TX、GND通过232电平转换芯片转换成232电平,实现板与板的板外通讯;

    RS485协议:将usart的RX、TX、GND通过485电平转换芯片转换成485电平,实现板与板的板外通讯;

  

  这个差分信号如何差分,起始电平是多少呢?是TX-RX呢,还是RX-TX呢?不管了,先放着吧;

7 总结

  USART的功能没想到还挺多的,寄存器看起来就有些费时了,很多概念都是新的,不好理解,直接拉低了效率;

  于是觉得这样不行,应该用什么看什么,用到再看,学海无涯,精力有限;

  另外人家费心费力写好标准库不就是为了帮开发人员省时间吗?了解一下即可,以后没必要深入;

  2023-03-14如果不看寄存器就不会知道底层代码什么意思,虽然代码能跑但是不知道代码为什么能跑,少了点踏实感,至于效率拉低就拉低把;

  本来是尝试直接在接收函数里将接收到的函数发送回去的;大概因为都是寄存器的操作,并且又是在中断函数里容易被中断打断;

  所以不稳定,容易出现寄存器操作到一半被中断打断;读写序列打乱,导致程序丢帧或不能正常运行;

  2023-03-14这个问题大概率是ORE的溢出错误,没有判断是否溢出,不过不容易重现;

  关于NVIC中断优先级管理,占个坑;

posted @ 2020-06-11 20:15  caesura_k  阅读(4595)  评论(0编辑  收藏  举报