您的位置:首页 > 汽车 > 时评 > 网络技术服务_平面设计制作_视频号视频怎么看下载链接_南宁seo外包平台

网络技术服务_平面设计制作_视频号视频怎么看下载链接_南宁seo外包平台

2024/12/27 9:20:54 来源:https://blog.csdn.net/qq_39376872/article/details/144436169  浏览:    关键词:网络技术服务_平面设计制作_视频号视频怎么看下载链接_南宁seo外包平台
网络技术服务_平面设计制作_视频号视频怎么看下载链接_南宁seo外包平台

目录

一、标志位结束法

1、实现原理

2、代码

3、优缺点

优点:

缺点:

总结:

二、串口空闲中断

1、中断读取

2、DMA接收

3、优缺点

优点:

缺点:

三、定时器空闲超时

1、实现原理

2、代码

3、优缺点

优点:

缺点:


        前文的发送已经很好的实现了发送一个数据,但是接收端仅介绍了每次接收一个字符,如果是双方通信,例如发送端以串口发送如下:

1,125,238,475,359

        其中1表示命令号;125表示传感器1的数据,238表示传感器2的数据,475表示传感器3的数据,359表示传感器4的数据。

2,19,45,37,28

        其中2表示命令号;19表示设定模块1数据,45表示设定模块2数据,37表示设定模块3数据,28表示设定模块4数据。

可以看到两个命令是不等长的(但是每一个相同命令号的应是等长的)

        不等长意味着不能接收到第一个字符进行计数,固定长度后停止。

一、标志位结束法

1、实现原理

        在数据尾部加入特殊字符,一般在工业界采用'\r''\n'来作为帧尾,也就是说串口收到数据后进行数组的存储,当连续收到\r\n,则表示该帧结束。

2、代码

void USART1_IRQHandler(void)                	//串口1中断服务程序
{u8 Res;
#if SYSTEM_SUPPORT_OS 		//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.OSIntEnter();    
#endifif(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾){Res =USART_ReceiveData(USART1);	//读取接收到的数据if((USART_RX_STA&0x8000)==0)//接收未完成{if(USART_RX_STA&0x4000)//接收到了0x0d{if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始else USART_RX_STA|=0x8000;	//接收完成了 }else //还没收到0X0D{	if(Res==0x0d)USART_RX_STA|=0x4000;else{USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;USART_RX_STA++;if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  }		 }}   		 } 
#if SYSTEM_SUPPORT_OS 	//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.OSIntExit();  											 
#endif
} 
#endif	

        在主函数判断即可实现。

		if(USART_RX_STA&0x8000){					   len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度printf("\r\n您发送的消息为:\r\n\r\n");for(t=0;t<len;t++){USART_SendData(USART1, USART_RX_BUF[t]);//向串口1发送数据while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束}USART_RX_STA=0; //一定要清除接收标志}

3、优缺点

优点:
  1. 易于解析

    • 固定的结束符:使用固定的字符如\r\n作为帧结束符,可以让接收端程序简单地检测到数据帧的结束,容易实现数据包的分帧与解析。
    • 简化的协议设计:接收端只需要检查收到的数据流中是否出现了\r\n,就能知道一帧数据的结尾,不需要复杂的帧长度或校验机制。
  2. 广泛兼容性

    • 标准化的结束符\r\n是许多通信协议中标准的结束符(如ASCII协议、Modbus、Telnet等)。采用此约定的通信系统非常普遍,兼容性好。
    • 跨平台支持:不同的操作系统(如Windows、Linux)和编程环境对\r\n的支持也非常广泛,使得协议更具跨平台的兼容性。
  3. 错误检测能力

    • 如果在数据流中间收到了\r\n,而没有完全接收到完整的帧,接收端可以利用这种信息判断数据不完整或者错误,增加了一定的容错能力。
  4. 便于调试和查看

    • 在一些串口调试工具中,\r\n作为帧尾,可以方便地让开发人员快速识别数据帧的结束,增强了调试过程的可视性。
缺点:
  1. 数据中可能出现特殊字符

    • 数据内容与帧尾冲突:如果数据本身有\r\n字符(比如文本数据或二进制数据),会导致接收端错误地认为数据帧结束,从而导致错误的帧解析。虽然可以使用转义字符或特殊的约定(如用某些分隔符代替\r\n),但这种方法可能增加协议的复杂性。
  2. 数据帧的长度不定

    • 使用\r\n作为帧结束符时,每个数据帧的长度可能不一样,造成接收端需要动态调整内存或缓冲区来存储不同长度的数据帧。对于高数据速率或大数据量传输的情况,可能需要更精确的控制和优化。
  3. 性能问题

    • 逐字符处理:如果数据量较大,每次接收时需要逐字符检测是否遇到\r\n,这样会增加CPU负担,特别是在高数据速率下。
    • 帧边界检测开销:每次检测\r\n的过程可能会影响实时性,尤其是在嵌入式系统中,可能需要额外的处理时间来确认是否达到了帧尾。
  4. 不适合二进制数据

    • 如果传输的是二进制数据流,\r\n可能与数据中的其他字节重叠,导致误判帧的结束。这种情况下需要采用其他更可靠的帧分隔符,如固定长度或基于长度的协议。
  5. 对实时性要求较高的系统不太适用

    • 对于实时性要求较高的系统,帧的结束符可能导致额外的延迟,尤其是在接收到大数据流时,可能需要等待完整的\r\n符号才能解析一帧数据,造成一定的延迟。
总结:

        使用 \r\n 作为帧结束符有许多优点,如简单易用、协议兼容性好和易于调试。但也有一些缺点,主要是在数据帧长度不确定、数据中可能出现\r\n字符,以及性能和实时性问题。

        在设计串口通信协议时,使用\r\n作为帧尾是一个不错的选择,尤其适合字符型数据和简单的协议,但对于高吞吐量、大数据量或包含二进制数据的通信场景,可能需要使用更精确的帧分隔方案(如固定长度帧或基于长度的协议)。

二、串口空闲中断

        比如给上位机给单片机一次性发送了8个字节,就会产生8次RXNE中断,1次IDLE中断。

        空闲态中断会在串口接收线处于空闲状态一段时间时触发。结合空闲态中断,接收端可以基于空闲时间来判断帧的结束。

	// 使能串口接收中断USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);// 使能串口空闲中断USART_ITConfig(DEBUG_USARTx, USART_IT_IDLE, ENABLE);	

1、中断读取

        可以看到在总中断中判断当前是接收中断还是空闲中断,如果是空闲中断则单次数据结束。此处可以添加一个flag标志,在main中判断即可。

// 串口中断服务函数
void DEBUG_USART_IRQHandler(void)
{if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET){		test_data.data[test_data.len] = USART_ReceiveData(DEBUG_USARTx);if(++test_data.len > data_size - 2) //让第 data_size - 1 位置一直是空终止位{test_data.len = 0;                //演示从简处理,如果接收超过尺寸从头开始覆盖}	  }	 if(USART_GetITStatus(DEBUG_USARTx,USART_IT_IDLE)!=RESET){	USART_ReceiveData(DEBUG_USARTx);	        //查阅参考手册 软件序列清除标志位流程test_data.data[test_data.len] = '\0';     //以空闲中断认为接收完成 设置空终止位test_data.flag = 1;			                  //赋值标志作为程序判断是否完成}	 }

2、DMA接收

        可以看到在总中断中判断当前是否空闲中断,如果是空闲中断则单次数据结束。此处可以添加一个flag标志,在main中判断即可。如果空闲则把接收数据做个处理或输出一个标志。

void USART1 IROHandler(void)
{uint8 ClearFlag;uint16 count =0://处理接收空闲中断if(USART_GetITStatuS(USART1,USART_IT_IDLE)!=RESET){//清除标志:先读SR,再读DRClearFlag = USART1->SR;ClearFlag = USART1->DR;/*获取接收数据个数 */count = DMA_GetCurrDataCounter(DMA1 Channe15);Touch_tx_flag=1024-count;    //已收到多少个数据/*处理数据,将DMA搬运的数据 复制到发送处  当然不用发送就不用写这个了*/memcpy((uint8 t *)Touch tx buffer,(uint8 t *)Touch rx buffer,Touch tx flag);/*DMA接收复位 */DMA_Cmd(DMA1_Channel5,DISABLE);DMA_SetCurrDatacounter(DMA1_channe15,1024);DMA_Cmd(DMA1_Channe15,ENABLE);}
}

        在main中,记得清除flag等。

3、优缺点

优点:
  1. 无额外字符干扰

    • 不需要额外添加特殊字符(如\r\n)来标识数据帧的结束,因此对于数据中可能包含这些特殊字符的情况(如文本或二进制数据流),不会发生干扰。
  2. 实时性较好

    • 空闲中断通常会在数据接收完成后触发,能够实时感知数据传输的结束,避免了轮询和等待帧结束标志的时间延迟。
  3. 适用于二进制数据

    • 该方法适合于包含二进制数据的协议,因为它不依赖于数据内容,可以避免数据帧中包含分隔符或特殊字符的冲突。
缺点:
  1. 可能出现误判

    • 如果数据传输的速度非常慢,或者接收的数据量小且间隔较长,空闲时间过长可能会被误判为一帧数据结束。例如,如果数据传输中有较长的静默期,空闲中断可能会提前触发。
  2. 空闲检测延迟

    • 空闲状态的判断是基于一定的时间窗口(如几百微秒到几毫秒),如果数据帧没有及时接收完整,可能会导致检测到空闲状态后才处理数据,增加处理延迟。
  3. 硬件资源消耗

    • 空闲中断需要硬件中断资源,如果系统中有多个串口或者大量的空闲中断,可能会增加中断处理的复杂性,影响系统的实时性。
  4. 实时性较低

    • 由于空闲状态是基于“静默期”判断的,它的实时性可能比其他基于定时器或流控制的方案要低。尤其是高速数据流时,空闲中断可能没有办法及时捕获数据帧结束的时机。

三、定时器空闲超时

1、实现原理

        可以看到串口空闲虽好,但是无法调节时间,因此可以和定时器进行结合。例如如果收到一次数据且进入了空闲中断或接收中断(可自行选择),idle_timeout_count开始递减至0,主函数可以判断如果为0说明数据已结束,则可以处理接收数据的数组。

2、代码

#include "stm32f10x.h"#define UART_RX_BUFFER_SIZE 1024
#define IDLE_TIMEOUT 1000  // 空闲时长设置为1000ms,即1秒// 接收缓冲区和索引
uint8_t uart_rx_buffer[UART_RX_BUFFER_SIZE];
uint16_t uart_rx_index = 0;
volatile uint32_t idle_timeout_count = 0;  // 计时器,用于空闲时长控制void USARTx_Init(void)
{// USART1初始化,略过,参照前面的配置// 启用空闲中断USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);// 配置定时器来模拟空闲时长SysTick_Config(SystemCoreClock / 1000);  // 每1ms中断一次
}void SysTick_Handler(void)
{if (idle_timeout_count > 0) {idle_timeout_count--;}
}void USART1_IRQHandler(void)
{// 判断是否是空闲中断if (USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) {// 清除空闲中断标志USART_ClearITPendingBit(USART1, USART_IT_IDLE);// 读取当前接收到的数据uint8_t received_byte = USART_ReceiveData(USART1);// 将接收到的数据存入缓冲区uart_rx_buffer[uart_rx_index++] = received_byte;// 重置空闲计时器idle_timeout_count = IDLE_TIMEOUT;  // 重新开始空闲计时// 如果缓冲区已满,处理数据帧if (uart_rx_index >= UART_RX_BUFFER_SIZE) {process_uart_data(uart_rx_buffer, uart_rx_index);uart_rx_index = 0;  // 重置索引,准备接收下一帧数据}}
}void process_uart_data(uint8_t* data, uint16_t len)
{// 这里可以对接收到的数据进行帧解析、校验等操作// 例如输出数据,或者将数据存入其他地方处理for (uint16_t i = 0; i < len; i++) {printf("Received byte: %c\n", data[i]);}
}

3、优缺点

优点:

  • 灵活性高: 用户可以调整 IDLE_TIMEOUT 变量的值来控制数据帧的结束时长,增加灵活性。比如可以设定不同的数据帧结束时间以适应不同的应用场景。
  • 响应及时: 通过定时器的使用,可以确保在一定时间内没有新的数据时,我们能及时处理完接收到的帧。

缺点:

  • 额外的定时器开销: 需要使用系统定时器(如 SysTick)来检测空闲时长,可能会对系统的其他定时任务产生一定影响。
  • 延迟可能较长: 如果设置的空闲时长较长,可能会导致数据处理的延迟。需要根据实际应用的需求平衡延迟和空闲时间。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com