STM32串口接收不定长数据

STM32串口接收不定长数据

1.配置串口

void USART1_Config(void)
{
	//初始化使用的端口 A9->TX   A10->Rx
	//初始化GPIO
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART1_InitStructure;	
	//使能时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	//配置波特率等
	USART1_InitStructure.USART_BaudRate = 115200;
	USART1_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//None
	USART1_InitStructure.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;//
	USART1_InitStructure.USART_Parity = USART_Parity_No;//No
	USART1_InitStructure.USART_StopBits = USART_StopBits_1;//1
	USART1_InitStructure.USART_WordLength = USART_WordLength_8b;//8b
	//配置
	USART_Init(USART1,&USART1_InitStructure);
//	USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
	//使能
	USART_Cmd(USART1,ENABLE);
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
	USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);
}

2.配置串口中断

void NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//配置串口中断	
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&NVIC_InitStructure);
	//DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE);
}

3.配置串口中断响应函数

/************定义联合体的意义是接收字节数>1的数,如浮点数**************/
/***********对于一帧多个字节数据可以直接使用数组来接受就OK了,不需要用联合体****/
union DataType{
	unsigned char s[4];
	unsigned int data;
}RxDataType;//共用内存地址思想,详见C语言

void USART1_IRQHandler(void)
{
	GPIO_WriteBit(GPIOB,GPIO_Pin_0 ,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_0)));
	if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET)//是否接受到一个字节
	{
		RxDataType.s[RxCounter++] = USART1->DR;
	}
	if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)//是否接受到一帧
	{
		USART1->SR;
		USART1->DR;						
		RxCounter=0;
	}
}

代码解释如上注释

以下为测试使用代码

串口发送代码

	GPIO_WriteBit(GPIOB,GPIO_Pin_0 ,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_0)));//LED闪烁辅助观察
	if(USART_GetITStatus(USART1,USART_IT_RXNE) != RESET)//是否接受到一个字节
	{
		RxDataType.s[RxCounter++] = USART1->DR;
	}
	if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)//是否接受到一帧
	{
		USART1->SR;
		USART1->DR;//这两句是清除状态位的,必须加上。如果提示未使用,定义一个uint8_t变量存储返回值即可						
		RxCounter=0;//一帧数据存储完毕,清零

STM32串口发送代码:

/***************这里我是定义外部中断使能发送的,可以直接发这段代码放在主函数while循环中也可以***/

void EXTI1_IRQHandler(void)
{
	GPIO_WriteBit(GPIOB,GPIO_Pin_1 ,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_1)));
	USART_SendData(USART1,0xAA);
	delay_ms(1);
	USART_SendData(USART1,RxDataType.s[0]);
	delay_ms(1);
	USART_SendData(USART1,RxDataType.s[1]);
	delay_ms(1);
	USART_SendData(USART1,RxDataType.s[2]);
	delay_ms(1);
	USART_SendData(USART1,RxDataType.s[3]);
	delay_ms(1);
	USART_SendData(USART1,0xFF);
	delay_ms(1);
	for(c = 0;c < 4;++c)
	{
		RxDataType.s[c] = 0;
	}
	EXTI_ClearITPendingBit(EXTI_Line1);
}

演示效果:
默认情况下,STM32发送给电脑的数据应该是0,对应的16进制应该是

AA 00 00 00 00 FF

初始状态发送0
当电脑发送11给STM32之后,STM32接收到数据并回传给电脑:

之所以接收到AA 11 00 00 00 FF后,数据变为了AA 00 00 00 00 FF,是因为我这边设置了发送一次之后即将所有位设置为0,代码见“发送代码”	
for(c = 0;c < 4;++c)
{
	RxDataType.s[c] = 0;
}


当电脑发送22 22给STM32之后,STM32接收到数据并回传给电脑:


当电脑发送88 88 88 88给STM32之后,STM32接收到数据并回传给电脑

其他

**在上位机和下位机之间发送和接收float、double类型的数据使用联合体即可**
### 解决STM32串口接收不定长数据的方法 对于STM32处理来自串口不定长数据,可以采取多种策略来确保可靠的数据传输和解析。一种常见方法是引入帧结构,在每条消息前加上起始标志符,并在结束处放置终止标志符或长度字段。 #### 使用帧头和校验机制 为了区分不同长度的消息并防止误判,可以在每一帧数据之前加入特定的起始字符序列作为帧头。例如: ```c #define START_BYTE_1 0xAA #define START_BYTE_2 0xBB ``` 当接收到这两个连续字节时,则认为新一帧数据开始到来。此外还可以设置一个简单的校验算法(如CRC),用于验证整个包的有效性[^4]。 #### 编写中断服务程序ISR 编写UART中断服务函数以实时监听是否有新的字符到达缓冲区。每当检测到完整的命令字符串后立即触发回调事件通知应用程序层做进一步处理。 ```c void USART_IRQHandler(void){ uint8_t ch; if(USART_GetITStatus(USARTx, USART_IT_RXNE) != RESET){ // Check RX buffer not empty interrupt flag. ch = USART_ReceiveData(USARTx); // Read received character. /* Process incoming byte */ HAL_UART_Receive_IT(&huart1,&ch,1); } } ``` 此代码片段展示了如何配置USART外设进入中断模式工作以及怎样读取单个输入字符[^2]。 #### 数据缓存管理 创建环形队列或其他形式先进先出(FIFO)存储器用来暂存尚未被完全组装好的报文分片直到满足预定义条件为止;比如遇到预期中的停止标记或者累计达到指定数量级之后再统一打包提交给高层协议栈解释执行。 #### 完整实例演示 下面给出一段更具体的实现方案,它利用了上述提到的技术要点组合而成的一个较为完善的解决方案: ```c #include "usart.h" // Define message structure with header and checksum fields typedef struct { uint8_t start_marker; // Start marker for frame synchronization size_t payload_length; // Length indicator preceding actual content bytes count char* payload; // Pointer pointing towards variable-sized user-defined information block uint16_t crc_value; // Cyclic redundancy check value computed over all previous members except itself } MessageFrame; volatile bool isReceivingMessage = false; uint8_t rxBuffer[MAX_FRAME_SIZE]; size_t currentRxIndex = 0; extern void HandleIncomingCommand(MessageFrame*); void UART_RxCallback(uint8_t dataByte){ static MessageFrame msgInProgress; if (!isReceivingMessage && dataByte == START_MARKER){ memset(&msgInProgress, 0, sizeof(msgInProgress)); isReceivingMessage = true; return; } if(isReceivingMessage){ switch(currentRxIndex++){ case 0: msgInProgress.payload_length = dataByte; break; default: if (currentRxIndex <= msgInProgress.payload_length + EXTRA_FIELDS_COUNT){ ((char*)&msgInProgress)[currentRxIndex - 1] = dataByte; if (currentRxIndex >= msgInProgress.payload_length + EXTRA_FIELDS_COUNT){ isReceivingMessage = false; currentRxIndex = 0; // Verify CRC before processing further... if(CheckCrcCorrectness(&msgInProgress)){ HandleIncomingCommand(&msgInProgress); }else{ // Error handling code here... } } } break; } } } __weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){ // This callback will be called when one byte has been successfully transferred via DMA or polling method. // Here we just pass this single-byte result into our custom handler function defined above. UART_RxCallback(huart->Instance->DR & 0xFF); } ``` 这段代码实现了基于STM32CubeMX库构建起来的基础框架,能够有效地应对各种复杂场景下的异步通讯需求[^1].
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值