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中断优先级管理,占个坑;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .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 中如何实现缓存的预热?