生成串口代码的教程很多,也很简单,这里不做赘述 这里主要介绍一下printf重定向的方法,以及HAL_UART_Transmit和HAL_UART_Receive_IT函数导致的串口死锁问题
串口单字节发送函数 在usart.c中增加串口发送函数,方便后续开发,并能很好解决死锁问题
1 2 3 4 5 void uart4SendByte(uint8_t ch) { while((UART4->ISR&0X40) == 0); UART4->TDR = (uint8_t)ch; }
printf重定向 只需要在工程任意位置加入以下代码即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #ifdef __GNUC__ /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf set to 'Yes') calls __io_putchar() */ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif /* __GNUC__ */ /** * @brief Retargets the C library printf function to the USART. * @param None * @retval None */ PUTCHAR_PROTOTYPE { /* Place your implementation of fputc here */ /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */ //HAL_UART_Transmit(&huart4, (uint8_t *)&ch, 1, 0xFFFF); uart4SendByte(ch); //与HAL_UART_Transmit取其中一个即可 return ch; }
串口死锁 串口死锁的原因是HAL_UART_Transmit和HAL_UART_Receive_IT函数相互调用__HAL_LOCK(huart)导致串口状态被异常修改,返回HAL_BUSY 状态,无法再次进入中断接收数据
解决方法1 修改回调函数HAL_UART_RxCpltCallback,在里面做解锁操作,虽然不会再出现死锁现象,但是过多的异常检测会导致丢失部分数据,不建议使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle) { if(UartHandle->Instance == UART4) { uint16_t i = 0; while(HAL_UART_Receive_IT(&huart4, (uint8_t *)aRxBuffer, 1) != HAL_OK ) { if(i++ > 10000 ) { huart4.RxState = HAL_UART_STATE_READY; __HAL_UNLOCK(&huart4); } } } }
解决方法2 数据发送使用自定义函数,不要再调用HAL_UART_Transmit
1 2 3 4 5 void uart4SendByte(uint8_t ch) { while((UART4->ISR&0X40) == 0); UART4->TDR = (uint8_t)ch; }
解决方法3 修改HAL_UART_Transmit函数,将__HAL_LOCK(huart)和__HAL_UNLOCK(huart)注释掉,注意每次重新生成代码都要重新注释一下,并不是一个一劳永逸的方法,建议使用方法2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout) { uint8_t *pdata8bits; uint16_t *pdata16bits; uint32_t tickstart; /* Check that a Tx process is not already ongoing */ if (huart->gState == HAL_UART_STATE_READY) { if ((pData == NULL) || (Size == 0U)) { return HAL_ERROR; } //__HAL_LOCK(huart); huart->ErrorCode = HAL_UART_ERROR_NONE; huart->gState = HAL_UART_STATE_BUSY_TX; /* Init tickstart for timeout management */ tickstart = HAL_GetTick(); huart->TxXferSize = Size; huart->TxXferCount = Size; /* In case of 9bits/No Parity transfer, pData needs to be handled as a uint16_t pointer */ if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE)) { pdata8bits = NULL; pdata16bits = (uint16_t *) pData; } else { pdata8bits = pData; pdata16bits = NULL; } //__HAL_UNLOCK(huart); while (huart->TxXferCount > 0U) { if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK) { return HAL_TIMEOUT; } if (pdata8bits == NULL) { huart->Instance->TDR = (uint16_t)(*pdata16bits & 0x01FFU); pdata16bits++; } else { huart->Instance->TDR = (uint8_t)(*pdata8bits & 0xFFU); pdata8bits++; } huart->TxXferCount--; } if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK) { return HAL_TIMEOUT; } /* At end of Tx process, restore huart->gState to Ready */ huart->gState = HAL_UART_STATE_READY; return HAL_OK; } else { return HAL_BUSY; } }