[C language] an easy-to-use circular queue and use example (AT framework taking EC200/600 as an example)

Keywords: C queue Embedded system Single-Chip Microcomputer stm32

1. Preface

Previous: https://blog.csdn.net/ylc0919/article/details/111050124
It's been ten months since I said I would send the second generation framework. It's hard to have time to summarize the harvest during this period. After writing the first generation AT queue, I have many ideas. For example, can one AT queue manage multiple AT modules; For example, the cyclic queue plus cyclic buffer of the AT framework takes up a lot of space. It can only write the corresponding serial number of the data to the queue, and temporarily fill the data frame when reading the queue; For example, if queues are used in many parts of the code, can you write a queue framework, copy the code directly each time, or use pointers to realize that multiple queues share a queue framework

After such a long time of practical verification, most of these conjectures have come to fruition.

2. Conclusion

In accordance with the Convention, the first conclusion is:
1. It is not practical for an AT queue to control multiple AT modules, because one AT module is stuck, which will cause all modules to fail to move. For EC600, it is normal for a network injection instruction to take more than ten seconds when the signal is poor. AT this time, the queue cannot process other instructions.
2. Cancel the circular buffer. Only the command sequence number is stored in the queue, which must be considered according to the situation. If the data to be processed has little correlation with time and the format is fixed, it is a very good way to store only the command serial number in the queue. If the data is changing all the time, this method is not very easy to use, but it is not unusable. You can open another queue in flash and write the current data to flash first, so as to not only maintain the power down, but also save memory.
3. Using pointers to implement multiple queues sharing a queue framework is no problem in theory, but I haven't found a simple and easy way to use. The code written is not as good as directly copying the queue framework and changing its name
4. Sort out a queue framework, which can be copied and modified directly when used, and can be used flexibly, which is exactly what this paper wants to write.

3. Circular queue

Next, put the code of each part of the circular queue, and make comments in important places.

3.1 write queue to queue header

The head of the queue runs ahead. If you catch up with the end of the queue, you will eat one.

void write_to_queue(MY_INFO_t info)
	//When the queue is full, the first written data will be overwritten (you can also return directly and ignore the newly added data)
	if(my_queue.rear==((my_queue.front+1)%MY_QUEUE_MAXNUM))	{
	//Write queue
	//The queue head enters a grid

3.2 read queue from tail

If the tail of the queue catches up with the head of the queue, it means that there is no data in the queue.
If you run the system, you can directly open a thread and put it in.
If the bare metal runs, it can be put into the 10ms event.

//The read queue is one tick for each call, and the timeout is n ticks
void read_from_queue(void)
	if(my_queue.flags.busy==0){	//Queue idle

			my_queue.info		=my_queue.info_queue[my_queue.rear];
			my_queue.otime		=0;
			my_queue.retryNum	=0;
			my_queue.rear		=(my_queue.rear+1)%MY_QUEUE_MAXNUM;		//The queue follows a grid			
			//data processing
	else{						//Queue busy										
		my_queue.otime++;								//ticks+1
		if(my_queue.otime>my_queue.info.oTime){			//The time is up
			if(my_queue.retryNum<my_queue.info.retryNum){//If the maximum number of retries is not reached

			else{										//Exception, retry reaches the upper limit, call error handling
				queue_error();							//error handling

3.3 get the number of data in the current queue

Mainly used for debugging

u16 get_queue_data_num(void)
	u16 ret=0;
	else if(my_queue.front<my_queue.rear)
	else if(my_queue.front==my_queue.rear)
	return ret;

3.4 emptying the queue

Just clear the queue structure directly

void clear_my_queue(void)

3.5 two important structures

This is the content of each piece of data to be filled in the queue. You can directly add variables here

typedef struct 
	u8 retryNum;		//Maximum number of retries
	u16 cmd;			//Information id
	u16 oTime;			//Timeout unit: ticks

This is the queue control structure,

typedef struct
		u8 busy:1;							
	u8 retryNum;							//Current number of retries
	u8 rstNum;								//Reset times, special treatment for multiple failures (not used yet)
	MY_INFO_t info_queue[MY_QUEUE_MAXNUM];	//All instruction ring queue
	MY_INFO_t info;							//Currently fetched instruction information
	u16 otime;								//Current command wait time
	u16 front;								//Queue header array subscript
	u16 rear;								//Queue tail array subscript

4. Effects and examples

There are too many codes. Only some screenshots are selected for display.

4.1 three read queue threads

Under LiteOS, I directly open a separate thread for each read queue.

4.2 AT frame write queue and EC200 initialization

To simplify the initialization code, I did not use a structure as a write queue parameter.

Instead of using strlen to get the length in the write queue function, I prefer to pass it in as a parameter.

4.3 AT frame read queue

Read the queue. There's nothing to say

4.4 EC200 maintains TCP long connection

Just follow the AT instruction manual

5. Download

5.1 circular queue


5.2 TCP long connection of at framework + EC200 (common with EC600)

It is necessary to refer to EC200At instruction manual.

Posted by webtailor on Fri, 19 Nov 2021 12:14:48 -0800