完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
在USART的发送端有2个寄存器,一个是程序可以看到的USART_DR寄存器,另一个是程序看不到的移位寄存器,对应USART数据发送有两个标志,一个是TXE=发送数据寄存器空(单字节),另一个是TC=发送结束(多字节)。
当USART_DR中的1字节数据传送到移位寄存器后,TXE被置位,此时移位寄存器开始向TX信号线按位传输数据,但因为TDR已经变空,程序可以把下一个要发送的1字节数据(操作USART_DR)写入TDR中,而不必等到移位寄存器中所有位(共8位)发送结束,所有多个字节均发送结束时(最后1字节中送出停止位后)硬件会将TC标志置位。 另一方面,在刚刚初始化好USART还没有发送任何数据时,也会有TXE标志,因为这时发送数据寄存器是空的(故通常程序串口初始化时不打开此中断,否则频繁进入TXE中断)。而发送完成TCIE和IDLEIE则必须等发送1次数据后,才会有此中断产生,故一开始打开TCIE和IDLEIE中断没有关系。当然一开始必须要打开RXNEIE中断(接收数据),TXEIE和TCIE的意义很简单,TXEIE允许在TXE标志为'1'时产生中断,而TCIE允许在TC标志为'1'时产生中断。 至于什么时候使用哪个标志,需要根据你的需要自己决定。但我认为TXE允许程序有更充裕的时间填写TDR寄存器,保证发送的数据流不间断。TC可以让程序知道发送结束的确切时间,有利于程序控制外部数据流的时序。 TXE--写寄存器DR清零 RXNE--读寄存器DR清零,也可软件手动清零 TC-- 读/写寄存器DR清零,也可软件手动清零 IDLE--需要软件清除,__HAL_UART_CLEAR_IDLEFLAG[HAL] 串口收发数据都是以1个字节为单位,如果是阻塞轮询模式,是while多少字节数,如果是中断,则每收发1个字节,则进入1次中断; HAL库代码分析: HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout) {//阻塞串口发送函数 uint16_t* tmp; uint32_t tickstart = 0U; /* Check that a Tx process is not already ongoing */ if(huart->gState == HAL_UART_STATE_READY) { if((pData == NULL) || (Size == 0U)) { return HAL_ERROR; } /* Process Locked */ __HAL_LOCK(huart); huart->ErrorCode = HAL_UART_ERROR_NONE; huart->gState = HAL_UART_STATE_BUSY_TX; /* Init tickstart for timeout managment */ tickstart = HAL_GetTick(); huart->TxXferSize = Size;//发送的数据量(多少字节) huart->TxXferCount = Size;//还剩余的要发送的数据量 while(huart->TxXferCount > 0U)//阻塞模式,while循环 { huart->TxXferCount--;//每发完1个字节,剩余要发送数据量减1 if(huart->Init.WordLength == UART_WORDLENGTH_9B) {//带有校验 if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK) { return HAL_TIMEOUT; } tmp = (uint16_t*) pData; huart->Instance->DR = (*tmp & (uint16_t)0x01FF); if(huart->Init.Parity == UART_PARITY_NONE) {//校验正确 pData +=2U; } else { pData +=1U; } } else {//不带校验 if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK) {//上面函数作用是保证发送寄存器里的数据为空(UART_FLAG_TXE置位) return HAL_TIMEOUT; } huart->Instance->DR = (*pData++ & (uint8_t)0xFF);//发送寄存器写入数据,UART_FLAG_TXE复位【待数据全部移到发送移位寄存器时,UART_FLAG_TXE置位,故前面超时等待】 } } if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK) {//上面函数作用是保证全部传输完成,UART_FLAG_TC置1,否则也认为传输失败,双重保证! return HAL_TIMEOUT; } /* At end of Tx process, restore huart->gState to Ready */ huart->gState = HAL_UART_STATE_READY; /* Process Unlocked */ __HAL_UNLOCK(huart); return HAL_OK; } else { return HAL_BUSY; } } HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) {//串口中断方式发送数据 /* Check that a Tx process is not already ongoing */ if(huart->gState == HAL_UART_STATE_READY) { if((pData == NULL) || (Size == 0U)) { return HAL_ERROR; } /* Process Locked */ __HAL_LOCK(huart); huart->pTxBuffPtr = pData;//指向待发送缓冲区首地址 huart->TxXferSize = Size;//发送的数据量(多少字节) huart->TxXferCount = Size;//还剩余的要发送的数据量 huart->ErrorCode = HAL_UART_ERROR_NONE; huart->gState = HAL_UART_STATE_BUSY_TX; /* Process Unlocked */ __HAL_UNLOCK(huart); /* Enable the UART Transmit data register empty Interrupt */ __HAL_UART_ENABLE_IT(huart, UART_IT_TXE);//此处仅仅打开TXE中断,【此时还未开始发送数据,发送缓冲区TDR为空,将进入到串口中断函数-stm32f1xx_it.c的void USARTx_IRQHandler(void) x=1,2,3...】 return HAL_OK; } else { return HAL_BUSY; } } void HAL_UART_IRQHandler(UART_HandleTypeDef *huart) {//串口中断函数回调函数 uint32_t isrflags = READ_REG(huart->Instance->SR); uint32_t cr1its = READ_REG(huart->Instance->CR1); uint32_t cr3its = READ_REG(huart->Instance->CR3); uint32_t errorflags = 0x00U; uint32_t dmarequest = 0x00U; /* If no error occurs */ errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE)); if(errorflags == RESET) {//无任何串口错误时 /* UART in mode Receiver -------------------------------------------------*/ if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET)) {//接收中断标志置位且中断使能 UART_Receive_IT(huart);//串口中断接收处理函数 return; } } /* If some errors occur */ if((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET))) { /* UART parity error interrupt occurred ----------------------------------*/ if(((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET)) {//校验出错且校验中断使能 huart->ErrorCode |= HAL_UART_ERROR_PE; } /* UART noise error interrupt occurred -----------------------------------*/ if(((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET)) { huart->ErrorCode |= HAL_UART_ERROR_NE; } /* UART frame error interrupt occurred -----------------------------------*/ if(((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET)) { huart->ErrorCode |= HAL_UART_ERROR_FE; } /* UART Over-Run interrupt occurred --------------------------------------*/ if(((isrflags & USART_SR_ORE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET)) { huart->ErrorCode |= HAL_UART_ERROR_ORE; } /* Call UART Error Call back function if need be --------------------------*/ if(huart->ErrorCode != HAL_UART_ERROR_NONE) { /* UART in mode Receiver -----------------------------------------------*/ if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET)) { UART_Receive_IT(huart); } /* If Overrun error occurs, or if any error occurs in DMA mode reception, consider error as blocking */ dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR); if(((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest) { /* Blocking error : transfer is aborted Set the UART state ready to be able to start again the process, Disable Rx Interrupts, and disable Rx DMA request, if ongoing */ UART_EndRxTransfer(huart); /* Disable the UART DMA Rx request if enabled */ if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)) { CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR); /* Abort the UART DMA Rx channel */ if(huart->hdmarx != NULL) { /* Set the UART DMA Abort callback : will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */ huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError; if(HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK) { /* Call Directly XferAbortCallback function in case of error */ huart->hdmarx->XferAbortCallback(huart->hdmarx); } } else { /* Call user error callback */ HAL_UART_ErrorCallback(huart);//异常回调函数可增加提示 } } else { /* Call user error callback */ HAL_UART_ErrorCallback(huart); } } else { /* Non Blocking error : transfer could go on. Error is notified to user through user error callback */ HAL_UART_ErrorCallback(huart); huart->ErrorCode = HAL_UART_ERROR_NONE; } } return; } /* End if some error occurs */ /* UART in mode Transmitter ------------------------------------------------*/ if(((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET)) {//接回上面提到的TXEIE中断被触发,接着执行到此处【每发1个字节执行到此处】,下面有UART_Transmit_IT详细分析 UART_Transmit_IT(huart); return; } /* UART in mode Transmitter end --------------------------------------------*/ if(((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET)) {//如果上面的多个字节都发送完毕,则此刻TC标志被置位,如果中断使能,将进入到下面函数执行 UART_EndTransmit_IT(huart);//__HAL_UART_DISABLE_IT(huart, UART_IT_TC);关闭TC中断,还有个回调空白函数-发送完成函数HAL_UART_TxCpltCallback供用户增加想要的功能 return; } } static HAL_StatusTypeDef UART_Transmit_IT(UART_HandleTypeDef *huart) { uint16_t* tmp; /* Check that a Tx process is ongoing */ if(huart->gState == HAL_UART_STATE_BUSY_TX) { if(huart->Init.WordLength == UART_WORDLENGTH_9B) {//带有校验处理 tmp = (uint16_t*) huart->pTxBuffPtr; huart->Instance->DR = (uint16_t)(*tmp & (uint16_t)0x01FF); if(huart->Init.Parity == UART_PARITY_NONE) { huart->pTxBuffPtr += 2U; } else { huart->pTxBuffPtr += 1U; } } else {//不带校验发送 huart->Instance->DR = (uint8_t)(*huart->pTxBuffPtr++ & (uint8_t)0x00FF);//TDR发送寄存器写入数据,TXE标志被清零,待发送寄存器中的1字节数据被全部转移到发送移位寄存器中,此刻发送寄存器又为空,TXE中断再次被触发,由再次进入到串口中断函数,进入到此处执行,故而实现数据连续不间断发送【pTxBuffPtr++指向待发送下1字节数据】 } if(--huart->TxXferCount == 0U) {//待发送的字节数为0时,表示数据发送完毕 /* Disable the UART Transmit Complete Interrupt */ __HAL_UART_DISABLE_IT(huart, UART_IT_TXE);//必须关闭TXE中断,否则会一直进入,毕竟没数据发送时,TDR一直为空 /* Enable the UART Transmit Complete Interrupt */ __HAL_UART_ENABLE_IT(huart, UART_IT_TC);//打开发送完成中断,因为数据发送完毕,TC标志将置位,将再次进入到串口中断函数里执行,此时执行到前面的UART_EndTransmit_IT函数 } return HAL_OK; } else { return HAL_BUSY; } } HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout) {//串口阻塞接收函数【中断未打开】 uint16_t* tmp; uint32_t tickstart = 0U; /* Check that a Rx process is not already ongoing */ if(huart->RxState == HAL_UART_STATE_READY) { if((pData == NULL) || (Size == 0U)) { return HAL_ERROR; } /* Process Locked */ __HAL_LOCK(huart); huart->ErrorCode = HAL_UART_ERROR_NONE; huart->RxState = HAL_UART_STATE_BUSY_RX; /* Init tickstart for timeout managment */ tickstart = HAL_GetTick(); huart->RxXferSize = Size;//接收的最大数据量字节数 【因是阻塞模式,故事先知道接收多少字节数据】 huart->RxXferCount = Size;//还剩余的要接收的数据量字节数 /* Check the remain data to be received */ while(huart->RxXferCount > 0U) { huart->RxXferCount--;//每接收完1字节,则减1 if(huart->Init.WordLength == UART_WORDLENGTH_9B) {//带有校验 if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK) { return HAL_TIMEOUT; } tmp = (uint16_t*)pData; if(huart->Init.Parity == UART_PARITY_NONE) { *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF); pData +=2U; } else { *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF); pData +=1U; } } else {//不带校验的接收处理 if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK) {//等待RXNE标志置位,等待时间Timeout【特别说明,如果传递的Size大于实际收到的数据,则肯定会超时】,如果被置位,表示接收寄存器RDR收到数据 return HAL_TIMEOUT;//如果未被置位,则超时退出 } if(huart->Init.Parity == UART_PARITY_NONE) { *pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);//从DR读取数据,该操作会将RXNE标志复位,前面置位,故而形成循环,保证数据正确接收 } else { *pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F); } } } /* At end of Rx process, restore huart->RxState to Ready */ huart->RxState = HAL_UART_STATE_READY; /* Process Unlocked */ __HAL_UNLOCK(huart); return HAL_OK; } else { return HAL_BUSY; } } HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) {//串口中断接收函数 /* Check that a Rx process is not already ongoing */ if(huart->RxState == HAL_UART_STATE_READY) { if((pData == NULL) || (Size == 0U)) { return HAL_ERROR; } /* Process Locked */ __HAL_LOCK(huart); huart->pRxBuffPtr = pData;//接收的数据缓存指针 huart->RxXferSize = Size;//接收的最大数据量字节数 huart->RxXferCount = Size;//还剩余的要接收的数据量字节数 huart->ErrorCode = HAL_UART_ERROR_NONE; huart->RxState = HAL_UART_STATE_BUSY_RX; /* Process Unlocked */ __HAL_UNLOCK(huart); /* Enable the UART Parity Error Interrupt */ __HAL_UART_ENABLE_IT(huart, UART_IT_PE);//校验错误中断使能 /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */ __HAL_UART_ENABLE_IT(huart, UART_IT_ERR);//错误中断使能-帧错误,噪错误,满溢错误 /* Enable the UART Data Register not empty Interrupt */ __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);//接收中断使能【如果串口收到数据,则进入到串口处理函数HAL_UART_IRQHandler】 return HAL_OK; } else { return HAL_BUSY; } } 如果串口收到数据,则进入到串口处理函数HAL_UART_IRQHandler的下面部分执行 if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET)) {//打开串口中断,且有数据收到-RXNE被置位 UART_Receive_IT(huart); return; } static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart) { uint16_t* tmp; /* Check that a Rx process is ongoing */ if(huart->RxState == HAL_UART_STATE_BUSY_RX) { if(huart->Init.WordLength == UART_WORDLENGTH_9B) {//带有校验 tmp = (uint16_t*) huart->pRxBuffPtr; if(huart->Init.Parity == UART_PARITY_NONE) { *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF); huart->pRxBuffPtr += 2U; } else { *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF); huart->pRxBuffPtr += 1U; } } else {//不带校验 if(huart->Init.Parity == UART_PARITY_NONE) { *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);//接收数据寄存器RDR被读取【保存数据到接收buf,并指向下一个】,RXNE标志复位。【当下1字节数据8位全部都从接收移位寄存器转移到接收数据寄存器RDR后,RXNE再次被置位,将再次触发RXNE中断,再次到此处执行,如此循环直到收完全部数据】 } else { *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F); } } if(--huart->RxXferCount == 0U) {//收完全部数据后 /* Disable the IRDA Data Register not empty Interrupt */ __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);//关闭RXNE中断 /* Disable the UART Parity Error Interrupt */ __HAL_UART_DISABLE_IT(huart, UART_IT_PE);//关闭校验错误中断 /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */ __HAL_UART_DISABLE_IT(huart, UART_IT_ERR);//关闭错误中断 /* Rx process is completed, restore huart->RxState to Ready */ huart->RxState = HAL_UART_STATE_READY; HAL_UART_RxCpltCallback(huart);//接收完成中断回调函数,用户可以再这里做操作 return HAL_OK; } return HAL_OK; } else { return HAL_BUSY; } } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1617 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1543 浏览 1 评论
977 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
683 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1595 浏览 2 评论
1863浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
644浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
515浏览 3评论
531浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
504浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 09:08 , Processed in 0.799930 second(s), Total 78, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号