最近项目要用到stm32和wifi模块,接收处理TCP数据,在项目中遇到了一些问题,在此记录一下。

首先项目把wifi模块配置成透传模式了,所以可以对模块忽略不计,只在板子处理就好。 都知道TCP的传输是分“碎片”(fragment)的,一个完整的报文并不一定是在一个TCP包里传输的,可能是分离在多个报文中。 为了处理这个问题,需要对我们的数据做出一定的规定,有数据起始位和数据长度位,通过这两个控制位来对数据进行接收。 程序的逻辑图如下: stm32_solve_tcp (原谅我的灵魂画法) 处理流程如下: (1)首先将状态置为默认起始状态,接收一定长度的数据头,接收齐全进行比对。如果数据正确,进入状态2;如果不对,继续接收数据头。其中把数据头区域设置为缓冲区,依次往里读数据,旧数据移除。 (2)在状态二,接收指定长度的字节,转换为int数据,作为状态三接收数据长度的依据。 (3)在此状态,通过串口中断向数据区写入数据,直到接收正确长度的数据。 程序的处理流程相对比较简洁,在程序实现上还是遇到了一点问题,主要是脑子一直考虑不全。 首先我创建一个接收控制部分的缓冲区

1
u8 ctrl[4]={0xf,0xf,0xf,0xf};

数据的起始部分是四个数字0,需要用一个变量进行记录,统计接收到几个数据,而不能直接通过数组内的数据进行判断。

1
2
3
4
5
6
7
8
9
for (int i = 0; i < 3; ++i)
{
	ctrl[i]=ctrl[i+1];
}
ctrl[3]=Res;
if (num<4)
{
	num++;
}

使用num进行计数,然后将ctrl的数据依次更新。 等到num==4的时候数据接收完整,就可以进行状态进行判断了。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
if (flag == 0 && num==4)
{
	flag=1;
	num=0;
	for (int i = 0; i < 4; ++i)
	{
		if (ctrl[i]!=0)
		{
			
			num=4;
			flag=0;
		}
	}
}

如果数据正确就会进入状态2,否则重新置为状态1,为了方便触发函数,需要将num置为4,保证接收到一个数据就要进行判断一次。 进入状态2直接从串口接收数据,然后读取大小,接收后续的数据。等到数据接收完成触发处理程序即可。 这样似乎程序已经完整了,但是bug就是奇葩。wifi模块偶尔会丢失几个数据,结果就是会把后一帧的完成的数据读到上一帧里面去,然后后面的就全部都错了。 考虑到这样的情况,直接程序进行处理似乎不太方便,但是stm32有定时器啊,这下就方便啦!当程序隔了一定的时间依然没有接收到正确的内容,就该扔的扔,直接处理下一帧数据。 状态如下: stm32_solve_tcp_timer (嗯,再次请求原谅) 首先定义定时器中断相关

1
2
3
4
......                               
TIM_TimeBaseStructure.TIM_Period=1000;      
TIM_TimeBaseStructure.TIM_Prescaler=1000;     
......      

触发函数只需要将一个变量自增即可。 串口中断函数判断变量是不是到达阈值,如果到达阈值,就状态清零,缓冲区清零,还有接收大小清零。

1
2
3
4
5
6
 if (period==FRAME_PERIOD)
{
	USART2_RX_STA=0;
	flag=0;
	num=0;
}

这样程序就运行比较稳定了,虽然可能会有丢包的现象,但毕竟概率比较低了。