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 @   rls_v  阅读(4713)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示