单片机串口使用乒乓缓存进行组帧代码

由于有项目需要使用串口进行固件升级,采用的协议为Ymode,这个协议很多串口软件都支持,如果使用单缓存的话,在处理串口数据时又同时接收到串口数据可能会导致整个缓存出现混乱,导致数据丢失,所以在数据传输的过程中采用乒乓缓存机制,用于加速同时存在串口操作及数据处理操作的设备。‌其核心思想是使用两个缓存区交替进行数据的读写操作,从而提高设备的吞吐量和处理速度。

//串口支持的协议枚举,自己定义
enum PROTOCOL_TYPE
{
	COMMAND = 0,
	COMMAND_BURST,
	UPLOAD_SOH,
	UPLOAD_STX,
	UPLOAD_EOT,
	UPLOAD_ACK,
	UPLOAD_NAK,
	UPLOAD_CAN,
	UPLOAD_CNC,
	UPLOAD_CRT,


	UNKNOW_TYPE=0xff,
};


#define BUFFER_LEN (1030)

#define COMMAND_LEN (32)
#define YMODE_SOH_LEN (128+5)
#define YMODE_STX_LEN (1024+5)

#define COMMAND_HEAD (0xaa)
#define COMMAND_BURST_HEAD (0x55)

#define SOH (0x01)      /* start of 128-byte data packet */  
#define STX (0x02)      /* start of 1024-byte data packet */  
#define EOT (0x04)      /* end of transmission */  
#define EOT_CRT (0x20)  /* CRT end of transmission */  
#define ACK (0x06)      /* receive OK */  
#define NAK (0x15)      /* receiver error; retry */  
#define CAN (0x18)      /* two of these in succession aborts transfer */  
#define CNC (0x43)      /* character 'C' */  

struct buffer_t
{
	int cnt;
	char buf_uart[BUFFER_LEN];
	char type;
	char flag;
};

struct buffer_pq_t
{

	struct buffer_t buf1;
	struct buffer_t buf2;
	char position;  //正在存储的buf

};


struct protocol_info_t
{
	char head;
	char type;
	short head_len;
};
//串口协议查找表
struct protocol_info_t protocol[]=
{
	{ COMMAND_HEAD , COMMAND , COMMAND_LEN},
	{ COMMAND_BURST_HEAD , COMMAND_BURST , 1024},
	{ SOH , UPLOAD_SOH , YMODE_SOH_LEN},
	{ STX , UPLOAD_STX , YMODE_STX_LEN},
	{ EOT , UPLOAD_EOT , 1},
	{ ACK , UPLOAD_ACK , 1},
	{ NAK , UPLOAD_NAK , 1},
	{ CAN , UPLOAD_CAN , 1},
	{ CNC , UPLOAD_CNC , 1},
//	{ 0x20 ,UPLOAD_CRT , 128},
};


struct buffer_pq_t uart_recvbuf={.buf1.type = UNKNOW_TYPE,.buf2.type = UNKNOW_TYPE,0};

//存储数据到缓存中
int put_buf(struct buffer_pq_t* pq , char data, int len)
{
	int i =0;
	int flag = 0;
	int test = 0;

	if(pq->position == 0 ) //第一个缓存
	{
		if(len + pq->buf1.cnt > BUFFER_LEN)
		{
			//print_str("put_buf1 err len\r\n");
			return -1;
		}

		flag = 0;
		if(pq->buf1.cnt == 0) //从协议表中查找对应协议的数据长度,用于后续的组帧操作
		{
			for(i=0;i < (  sizeof(protocol)/sizeof(protocol[0]) );i++)
			{
				if(data == protocol[i].head)
				{
					pq->buf1.type = protocol[i].type;
					flag = 1;
					break;
				}
			}

			if(flag == 0 )
			{
				//print_str(" unknow1 protocol\r\n");
				return -1;
			}
		}

		if(pq->buf1.type == UNKNOW_TYPE)
		{
				uart_buf_unref(&pq->buf1);
				return -1;
		}

		pq->buf1.buf_uart[pq->buf1.cnt] = data; //存储数据
		pq->buf1.cnt+=1;


		if(pq->buf1.type == protocol[pq->buf1.type].type)
		{
            //当组帧完成后,切换存储buffer
			if(pq->buf1.cnt >=  protocol[pq->buf1.type].head_len) 
			{
				pq->position = 1;
				pq->buf1.flag = 1;
			}
		}

		
	}
	else //第二个缓存
	{
		if(len + pq->buf2.cnt > BUFFER_LEN)
		{
			//print_str("put_buf2 err len\r\n");
			return -1;
		}

		flag = 0;
		if(pq->buf2.cnt == 0)
		{
			for(i=0;i < (  sizeof(protocol)/sizeof(protocol[0]) );i++)
			{
				if(data == protocol[i].head)
				{
					pq->buf2.type = protocol[i].type;
					flag = 1;
					break;
				}
			}
			if(flag == 0)
			{
				//print_str(" unknow2 protocol\r\n");
				return -1;
			}
		}

		if(pq->buf2.type == UNKNOW_TYPE)
		{
				uart_buf_unref(&pq->buf2);
				return -1;
		}

		pq->buf2.buf_uart[pq->buf2.cnt] = data;
		pq->buf2.cnt+=1;

		if(pq->buf2.type == protocol[pq->buf2.type].type)
		{
			if(pq->buf2.cnt >=  protocol[pq->buf2.type].head_len)
			{
				pq->position = 0;
				pq->buf2.flag = 1;
			}
		}

	}
	return 0;
}


// 从乒乓buffer中获取数据
struct buffer_t* get_uart_buf(void)
{

	if(uart_recvbuf.position == 0)
	{
		if(uart_recvbuf.buf2.flag == 0)
			return NULL;
		else
			return &uart_recvbuf.buf2;
	}
	else
	{
		if(uart_recvbuf.buf1.flag == 0)
			return NULL;
		else
			return &uart_recvbuf.buf1;

	}

}


//数据使用完后释放
 int uart_buf_unref(struct buffer_t* buf_p)
{
	if(buf_p != NULL)
	{
		buf_p->cnt = 0;
		buf_p->flag = 0;
		buf_p->type = UNKNOW_TYPE;
	}
	return 0;
}

//整个缓存结构状态清零
 void uart_buf_reset()
 {

	uart_recvbuf.buf1.cnt = 0;
	uart_recvbuf.buf1.flag = 0;
	uart_recvbuf.buf1.type = UNKNOW_TYPE;

	uart_recvbuf.buf2.cnt = 0;
	uart_recvbuf.buf2.flag = 0;
	uart_recvbuf.buf2.type = UNKNOW_TYPE;

	uart_recvbuf.position = 0;

 }


//使用方法

int main()
{
        struct buffer_t* buf_recv;

		buf_recv = get_uart_buf();
		if(buf_recv != NULL)
		{

        //将接受的数据回写回去
		for(int i =0;i<buf_recv->cnt;i++)
			uart_write(SYSTEM_UART_A_APB, buf_recv->buf_uart[i]);

		#if 0
			if(buf_recv->type == COMMAND)
			{
				start = 1;
				uart_buf_unref(buf_recv);
				continue;
			}
			ymodem_rx_put(buf_recv->buf_uart,buf_recv->cnt);
		#endif

			uart_buf_unref(buf_recv); //释放缓存数据

		}
		else
		{
			//接收超时处理
		}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JKLTYU_0_0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值