/*************笔记****************
1、CudeMX中配置串口时,需要增加DMA功能,并使能串口中断!!!
Mode--Asynchronous Hardware Flow Control(RS232)--Disable
2、在stm32f1xx_it.c中,找到void USART1_IRQHandler(void),并在用户代码区加入UsartReceive_IDLE(&huart1);
备注:根据实际串口号,进行修改,变通,当出现多个串口时,在每个串口中断函数里,都要加入该函数。
extern void UsartReceive_IDLE(UART_HandleTypeDef *huart);
3、应用函数:UartExtInit(&huart1, DMA_MODE);//初始化串口1的DMA模式
UartPutStr(&huart1, TxBuffer, strlen((char *)TxBuffer));//发给串口1
len = UartGetStr(&huart1, RxBuffer); //从串口1读取一次数据
4、简化发送函数
#define sendmsg(huart,ExTxBuffer,...) sprintf((char*)ExTxBuffer, ##__VA_ARGS__);\
UartPutStr(&huart, ExTxBuffer, strlen((char *)ExTxBuffer))
sendmsg(huart1,TxBuffer,"a=%d",1);
5、
***********************************/
#include "uartext.h"
#include "cmsis_os.h"
#include "stdlib.h"
#define FULL_DUPLEX 1
#define HALF_DUPLEX 0
#define SET_RS485_CTR_RX(put) HAL_GPIO_WritePin(put->rs485Port,put->rs485Pin,put->rs485_ctr_invert?GPIO_PIN_SET:GPIO_PIN_RESET)
#define SET_RS485_CTR_TX(put) HAL_GPIO_WritePin(put->rs485Port,put->rs485Pin,put->rs485_ctr_invert?GPIO_PIN_RESET:GPIO_PIN_SET)
USART_RECEIVETYPE *UsartType = NULL;//[UART_USED_NUMBER] = {NULL,NULL,NULL,NULL,NULL,NULL};
USART_RECEIVETYPE* AddUtToArray(UART_HandleTypeDef *huart)
{
USART_RECEIVETYPE *put = NULL;
uint8_t found;
uint16_t len;
put = UsartType;
found = 0;
while(put != NULL)
{
if (put->huart == huart)
{
found = 1; //链表中已经存在该串口
break;
}
else
{
put = put->next;
}
}
len = sizeof(USART_RECEIVETYPE);
if(found == 0)
{
if(UsartType == NULL)
{
put = (USART_RECEIVETYPE *)malloc(len);
put->rxbuf = (uint8_t *)malloc(UART_RX_BUF_LEN);
//put->txbuf = (uint8_t *)malloc(UART_TX_BUF_LEN);
UsartType = put;
put->huart = huart;
put->next = NULL;
}
else
{
put = UsartType;
while(put->next != NULL)
put = put->next;
put->next = (USART_RECEIVETYPE *)malloc(len);
put = put->next;
put->rxbuf = (uint8_t *)malloc(UART_RX_BUF_LEN);
//put->txbuf = (uint8_t *)malloc(UART_TX_BUF_LEN);
put->huart = huart;
put->next = NULL;
}
}
return put;
}
USART_RECEIVETYPE* FindPut(UART_HandleTypeDef *huart)
{
USART_RECEIVETYPE *put = NULL;
put = UsartType;
while(put != NULL)
{
if (put->huart == huart)
{
break;
}
else
{
put = put->next;
}
}
return put;
}
/*****************************************************************************/
// 功能描述:串口扩展功能初始化
// 输入参数:*huart 待初始化串口,tr_mode:DMA或中断工作方式,wmode: 全双工/半双工
// port,pin:半双工时,发送接收切换控制pin脚
// 输出参数:无
// 返 回 值:无
// 编写时间:2016.10.25
// 作 者:Bruno.Hu
// 修改记录:
/*****************************************************************************/
void UartExtInit(UART_HandleTypeDef *huart, uint32_t WorkMode)
{
USART_RECEIVETYPE* put;
put = AddUtToArray(huart);
if(put != NULL)
{
if (WorkMode)
put->tx_mode = DMA_MODE;
else
put->tx_mode = IT_MODE;
put->duplex_mode = FULL_DUPLEX;
put->tx_finish_flag = UART_SENDOVER;
put->rx_finish_flag = 0;
if(put->tx_mode == DMA_MODE)
{
HAL_UART_Receive_DMA(put->huart, put->rxbuf, UART_RX_BUF_LEN);
}
else
{
HAL_UART_Receive_IT(put->huart, put->rxbuf, UART_RX_BUF_LEN);
}
__HAL_UART_ENABLE_IT(put->huart, UART_IT_IDLE);
}
}
/*****************************************************************************/
// 功能描述:设置成RS485半双工工作模式
// 输入参数:*huart 待初始化串口,
// 输出参数:无
// 返 回 值:无
// 编写时间:2016.10.25
// 作 者:Bruno.Hu
// 修改记录:
/*****************************************************************************/
int8_t UartExtRS485(UART_HandleTypeDef *huart, GPIO_TypeDef* port, uint16_t pin, uint8_t rs485_ctr_invert)
{
USART_RECEIVETYPE* put;
int8_t result = -1;
put = AddUtToArray(huart);
if(put != NULL)
{
put->duplex_mode = HALF_DUPLEX;
put->rs485Port = port;
put->rs485Pin = pin;
put->rs485_ctr_invert = rs485_ctr_invert;
SET_RS485_CTR_RX(put);
result = 0;
}
return result;
}
/*****************************************************************************/
// 功能描述:设置成RS485半双工工作模式
// 输入参数:*huart 待初始化串口,WorkMode: 0:中断模式 非0:DMA模式
// 输出参数:无
// 返 回 值:无
// 编写时间:2016.10.25
// 作 者:Bruno.Hu
// 修改记录:
/*****************************************************************************/
int8_t UartExtWorkMode(UART_HandleTypeDef *huart, uint8_t WorkMode)
{
USART_RECEIVETYPE* put;
int8_t result = -1;;
put = AddUtToArray(huart);
if(put != NULL)
{
if (WorkMode)
put->tx_mode = DMA_MODE;
else
put->tx_mode = IT_MODE;
result = 0;
}
return result;
}
/*****************************************************************************/
// 功能描述:设置成RS485半双工工作模式
// 输入参数:*huart 待初始化串口,WorkMode: 0:中断模式 非0:DMA模式
// 输出参数:无
// 返 回 值:无
// 编写时间:2016.10.25
// 作 者:Bruno.Hu
// 修改记录:
/*****************************************************************************/
int8_t UartExtStart(UART_HandleTypeDef *huart)
{
USART_RECEIVETYPE* put;
int8_t result = -1;;
put = FindPut(huart);
if(put != NULL)
{
if(put->tx_mode == DMA_MODE)
{
HAL_UART_Receive_DMA(put->huart, put->rxbuf, UART_RX_BUF_LEN);
}
else
{
HAL_UART_Receive_IT(put->huart, put->rxbuf, UART_RX_BUF_LEN);
}
__HAL_UART_ENABLE_IT(put->huart, UART_IT_IDLE);
}
return result;
}
/*****************************************************************************/
// 功能描述:串口扩展功能初始化
// 输入参数:*huart 待初始化串口,tr_mode:DMA或中断工作方式,wmode: 全双工/半双工
// port,pin:半双工时,发送接收切换控制pin脚
// 输出参数:无
// 返 回 值:无
// 编写时间:2016.10.25
// 作 者:Bruno.Hu
// 修改记录:
/*****************************************************************************/
//void UartExtInit(UART_HandleTypeDef *huart, UART_TRANSCEIVER_MODE tr_mode, UART_WORK_MODE wmode, GPIO_TypeDef* port, uint16_t pin, uint8_t rs485_ctr_invert)
//{
// USART_RECEIVETYPE* put;
//
// put = AddUtToArray(huart);
// if(put != NULL) {
// put->transceiver_mode = tr_mode;
// put->work_mode = wmode;
// put->rs485Port = port;
// put->rs485Pin = pin;
// put->rs485_ctr_invert = rs485_ctr_invert;
// put->tx_finish_flag = UART_SENDOVER;
// put->rx_finish_flag = 0;
// if(put->work_mode == UART_HALF_DUPLEX) {
// if(put->rs485_ctr_invert) {
// HAL_GPIO_WritePin(put->rs485Port,put->rs485Pin,GPIO_PIN_SET);
// } else {
// HAL_GPIO_WritePin(put->rs485Port,put->rs485Pin,GPIO_PIN_RESET);
// }
// }
// if(put->transceiver_mode == UART_DMA_MODE) {
// HAL_UART_Receive_DMA(put->huart, put->rxbuf, UART_RX_BUF_LEN);
// } else {
// HAL_UART_Receive_IT(put->huart,put->rxbuf,UART_RX_BUF_LEN);
// }
// __HAL_UART_ENABLE_IT(put->huart, UART_IT_IDLE);
// }
//}
/*****************************************************************************/
// 功能描述:通过指定串口发送数据
// 输入参数:*huart 待发送数据的串口,pdata:待发送数据,length:数据长度
// 输出参数:无
// 返 回 值:无
// 编写时间:2016.10.25
// 作 者:Bruno.Hu
// 修改记录:
/*****************************************************************************/
void UartPutStr(UART_HandleTypeDef *huart, const uint8_t *pdata, uint16_t Length)
{
USART_RECEIVETYPE* put;
//uint16_t len = 0;
uint32_t dly;
put = FindPut(huart);
if(put != NULL)
{
// while(put->tx_finish_flag == UART_SENDING) {
// osDelay(1);
// }
// for(i=0;(i<Length) && (i<UART_TX_BUF_LEN);i++) {
// put->txbuf[i] = pdata[i];
// len++;
// }
if(put->duplex_mode == HALF_DUPLEX)
{
SET_RS485_CTR_TX(put);
}
put->tx_finish_flag = UART_SENDING;
if(put->tx_mode == DMA_MODE)
{
//HAL_UART_DMAStop(put->huart);
HAL_UART_Transmit_DMA(put->huart, (uint8_t *)pdata, Length);
}
else
{
//HAL_UART_AbortTransmit_IT(put->huart);
HAL_UART_Transmit_IT(put->huart, (uint8_t *)pdata, Length);
}
dly = (Length * 10000) / put->huart->Init.BaudRate + 3;
while((put->tx_finish_flag != UART_SENDOVER) && dly)
{
osDelay(1);
dly--;
}
osDelay(5);
}
}
/*****************************************************************************/
// 功能描述:通过指定串口接收数据
// 输入参数:*huart 待接收数据的串口,pdata:接收到的数据存储区
// 输出参数:无
// 返 回 值:接收到数据的长度, 0 表示没有接收到
// 编写时间:2016.10.25
// 作 者:Bruno.Hu
// 修改记录:
/*****************************************************************************/
uint16_t UartGetStr(UART_HandleTypeDef *huart, uint8_t *pdata)
{
uint16_t i, rxlen = 0;
USART_RECEIVETYPE* put;
put = FindPut(huart);
if(put != NULL)
{
if(put->rx_finish_flag)
{
for(i = 0; i < put->rxlen; i++)
pdata[i] = put->rxbuf[i];
put->rx_finish_flag = 0;
rxlen = put->rxlen;
}
}
return rxlen;
}
/*****************************************************************************/
// 功能描述:串口空闲中断处理 (添加到 USARTn_IRQHandler 中断函数中去)
// 输入参数:*huart 待处理的串口
// 输出参数:无
// 返 回 值:无
// 编写时间:2016.10.25
// 作 者:Bruno.Hu
// 修改记录:
/*****************************************************************************/
void UsartReceive_IDLE(UART_HandleTypeDef *huart)
{
USART_RECEIVETYPE *put;
put = FindPut(huart);
if(put != NULL)
{
if((__HAL_UART_GET_FLAG(put->huart, UART_FLAG_IDLE) != RESET))
{
__HAL_UART_CLEAR_IDLEFLAG(put->huart);
if(put->tx_mode == DMA_MODE)
{
HAL_UART_DMAStop(put->huart);
//HAL_DMA_Abort(put->huart->hdmarx);
#ifdef __STM32F4xx_HAL_H
put->rxlen = UART_RX_BUF_LEN - put->huart->hdmarx->Instance->NDTR;
put->huart->RxState = HAL_UART_STATE_READY;
#endif
#ifdef __STM32F1xx_HAL_H
put->rxlen = UART_RX_BUF_LEN - put->huart->hdmarx->Instance->CNDTR;
put->huart->gState = HAL_UART_STATE_READY;
#endif
put->rx_finish_flag = 1;
HAL_UART_Receive_DMA(put->huart, put->rxbuf, UART_RX_BUF_LEN);
}
else
{
#ifdef __STM32F4xx_HAL_H
put->huart->RxState = HAL_UART_STATE_READY;
#endif
#ifdef __STM32F1xx_HAL_H
put->huart->gState = HAL_UART_STATE_READY;
#endif
__HAL_UART_DISABLE_IT(put->huart, UART_IT_RXNE);
put->rxlen = put->huart->RxXferSize - put->huart->RxXferCount;
put->rx_finish_flag = 1;
HAL_UART_Receive_IT(put->huart, put->rxbuf, UART_RX_BUF_LEN);
}
}
}
}
/*****************************************************************************/
// 功能描述:串口空闲中断处理 (添加到 USARTn_IRQHandler 中断函数中去)
// 输入参数:*huart 待处理的串口
// 输出参数:无
// 返 回 值:无
// 编写时间:2016.10.25
// 作 者:Bruno.Hu
// 修改记录:
/*****************************************************************************/
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
USART_RECEIVETYPE* put;
put = FindPut(huart);
if(put != NULL)
{
if(put->tx_mode == DMA_MODE)
{
__HAL_DMA_DISABLE(put->huart->hdmatx);
}
if(put->duplex_mode == HALF_DUPLEX)
{
SET_RS485_CTR_RX(put);
}
put->tx_finish_flag = UART_SENDOVER;
}
}
/*****************************************************************************/
// 功能描述:等待串口接收完成
// 输入参数:*huart 待处理的串口
// 输出参数:无
// 返 回 值:无
// 编写时间:2016.10.25
// 作 者:Bruno.Hu
// 修改记录:
/*****************************************************************************/
void UartTxFinish(UART_HandleTypeDef *huart, uint32_t timeout)
{
USART_RECEIVETYPE* put;
uint32_t TimeOut = 0;
put = FindPut(huart);
if(put != NULL)
{
while((put->tx_finish_flag == UART_SENDING) && (TimeOut < timeout))
{
osDelay(1);
TimeOut++;
}
}
}
//例子:
//void StartRS232Task(void const * argument)
//{
// osDelay(100);
// UartExtInit(&huart1, DMA_MODE);//用于RS232串口1,测试用
// uint16_t len;
// uint8_t RxBuffer[32],TxBuffer[32];
// for(;;)
// {
// len = UartGetStr(&huart1, RxBuffer); //从串口1读取一次数据
// if(len > 1)
// {
// sendmsg(huart1, TxBuffer, "%s", RxBuffer);
// }
// osMessagePut(QueWdtHandle, 0x02, 10);
// osDelay(2);
// }
//}
#ifndef __UART_EXT_HEADER__
#define __UART_EXT_HEADER__
#include "stm32f1xx_hal.h"
#include "usart.h"
#include "cmsis_os.h"
#define UART_RX_BUF_LEN 128
//#define UART_TX_BUF_LEN 128
#define UART_SENDING 1 //发送未完成
#define UART_SENDOVER 0 //发送完成
#define DMA_MODE 1
#define IT_MODE 0
#define sendmsg_Delay(huart,ExTxBuffer,...) sprintf((char*)ExTxBuffer, ##__VA_ARGS__);\
UartPutStr(&huart, ExTxBuffer, strlen((char *)ExTxBuffer));\
osDelay(strlen((char*)ExTxBuffer)+1)
#define sendmsg(huart,ExTxBuffer,...) sprintf((char*)ExTxBuffer, ##__VA_ARGS__);\
UartPutStr(&huart, ExTxBuffer, strlen((char *)ExTxBuffer))
typedef struct uart_node{
UART_HandleTypeDef *huart; //串口
uint8_t rx_finish_flag:1; //空闲接收标记
uint8_t tx_finish_flag:1; //发送完成标记
uint8_t tx_mode:1; //1: 表示用DMA模式,0: 表示用中断模式
uint8_t duplex_mode:1; //1: 全双工,0: 半双工设置
uint8_t rs485_ctr_invert:1; // RS485方向控制脚是否反转
GPIO_TypeDef* rs485Port; //半双工时,方向切换IO所用的端口
uint16_t rs485Pin; //半双工时,方向切换IO所用的PIN脚
uint16_t rxlen; //接收长度
uint8_t *rxbuf; //接收缓存
//uint8_t *txbuf;
struct uart_node *next;
}USART_RECEIVETYPE;
//void UartExtInit(UART_HandleTypeDef *huart, uint32_t MODE, GPIO_TypeDef* port, uint16_t pin, uint8_t rs485_ctr_invert);
//void RS485ExtInit(UART_HandleTypeDef *huart, uint32_t mode, GPIO_TypeDef* port, uint16_t pin, uint8_t rs485_ctr_invert);
//void UartExtInit(UART_HandleTypeDef *huart, UART_TRANSCEIVER_MODE tr_mode, UART_WORK_MODE wmode, GPIO_TypeDef* port, uint16_t pin, uint8_t rs485_ctr_invert);
void UartExtInit(UART_HandleTypeDef *huart, uint32_t WorkMode);
int8_t UartExtRS485(UART_HandleTypeDef *huart, GPIO_TypeDef* port, uint16_t pin, uint8_t rs485_ctr_invert);
void UartPutStr(UART_HandleTypeDef *huart, const uint8_t *pdata, uint16_t Length);
uint16_t UartGetStr(UART_HandleTypeDef *huart, uint8_t *pdata);
void UartTxFinish(UART_HandleTypeDef *huart, uint32_t timeout);
#endif
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!