The application of linked list in embedded - based on GitHub open source project MultiTimer

Project Description

MultiTimer is a software timer that can be expanded infinitely. The project source address is linked: the project address
is a linked list of unidirectional leading nodes used in the use of the software timer.
For the basic knowledge of linked list, you can review the previous blog: Linked List Basics
This blog mainly introduces the application of linked list in embedded.

Code portability

The development board used is the punctual atom explorer F407. First, use the STM32CubMx configuration to complete the project and realize the basic serial port printing.
CubMx basic configuration:
insert image description here
insert image description here

Then transfer the downloaded source file:
insert image description here
transplant to the generated project file:
insert image description herethen open the project and add the following code to the code block.

/* USER CODE BEGIN PTD */
#include <stdio.h>
#include "multi_timer.h"
struct Timer timer1;

struct Timer timer2;

void timer1_callback()
{
    
    
	printf("T1 timeout \r\n");
	HAL_GPIO_TogglePin(L1_GPIO_Port,L1_Pin);
}

void timer2_callback()
{
    
    
	printf("T2 timeout \r\n");
  HAL_GPIO_TogglePin(L0_GPIO_Port,L0_Pin);
	
}
/* USER CODE END PTD */
/* USER CODE BEGIN 2 */

printf("multi timer test...\r\n");

//重复计时 周期为500次,即500ms=0.5s
timer_init(&timer1,timer1_callback,500,500,0);
timer_start(&timer1);

//单次计时 周期为50次,即50ms
timer_init(&timer2,timer2_callback,50,0,0);
timer_start(&timer2);
/* USER CODE END 2 */

Add the callback function of systick:

/* USER CODE BEGIN 4 */

void HAL_SYSTICK_Callback()
{
    
    
		timer_ticks();//1ms ticks;	
}
/* USER CODE END 4 */

Add the following content to the interrupt handler function stm32f4xx_it.c:

void SysTick_Handler(void)
{
    
    
  /* USER CODE BEGIN SysTick_IRQn 0 */
	HAL_SYSTICK_IRQHandler();
  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */
	
  /* USER CODE END SysTick_IRQn 1 */
}

Start the timer in while(1)

 while (1)
  {
    
    
		timer_loop();
  }

Experimental phenomena

Timer 1 acts once in 0.5s, and timer 2 acts once in 0.05s! ! !
insert image description here

Detailed analysis of linked list timer code

Timer structure initialization - linked list

typedef struct Timer {
    
    
    uint32_t        cur_ticks;          /* 当前滴答时间 */
    uint32_t        cur_expired_time;   /* 记录当前所经历的时间 */
    uint32_t        timeout;    /* 溢出时间 */
    uint32_t        repeat;     /* 下次延时所添加的时间 */
    void *          arg;        /* 回调函数参数 */
    void            (*timeout_cb)(void *arg); /* 定时器溢出时间回调函数 */
    struct Timer*   next;       /* 链表的next指针 */
} Timer;

Timer initialization function: Initialize the structure members, pass in the timer structure handle, callback function, overflow time, reload overflow time, and callback function parameters.

void timer_init(struct Timer* handle, void (*timeout_cb)(void *arg), \
      uint32_t timeout, uint32_t repeat, void *arg)
{
    
    
    
    handle->timeout_cb          = timeout_cb;      
    handle->timeout             = timeout;
    handle->repeat              = repeat;
    handle->cur_ticks           = _timer_ticks;  
    handle->cur_expired_time    = handle->timeout;
    handle->arg                 = arg;
}

Start the timer: Add the timer structure to the linked list, using the header insertion method.

int timer_start(struct Timer* handle)
{
    
    
    struct Timer* target = head_handle;

    while(target) {
    
    
        if(target == handle) {
    
    
            return -1;  //already exist.
        }            
        target = target->next;
    }
    handle->next = head_handle;
    head_handle  = handle;
    return 0;
}

Stop the timer and delete the timer from the linked list. Use the secondary pointer to delete an element in the linked list.

int timer_stop(struct Timer* handle)
{
    
    
    struct Timer** curr;
    for(curr = &head_handle; *curr;) {
    
    
        struct Timer* entry = *curr;
        if(entry == handle) {
    
    
            *curr = entry->next;
            return 0; // found specified timer
        } else {
    
    
            curr = &entry->next;
        }            
    }

    return 0;
}

timer function

void timer_loop(void)
{
    
    
	/*初始化定时器结构体*/
    struct Timer* target;
    /*target 赋值为头结点;头结点不为空;顺次向下*/
    for(target = head_handle; target; target = target->next) {
    
    
    /*如果滴答时间-当前定时器启动后的滴答时间>=定时器溢出时间*/
        if(_timer_ticks - target->cur_ticks >= target->cur_expired_time) {
    
    
            printf("cur_ticks: %u, cur_expired_time: %u, _timer_ticks: %u\r\n", 
                    target->cur_ticks, target->cur_expired_time, _timer_ticks);
            /*配置单次触发或者多次触发定时器*/
            if(target->repeat == 0) {
    
    
                timer_stop(target);
            } else {
    
    
            		/*定时器当前的滴答时间=系统sys定时器的计数时间*/
                target->cur_ticks = _timer_ticks;
                /*定时器下次再定时的溢出时间*/
                target->cur_expired_time = target->repeat;
            }            
            /*调用回调函数*/
            target->timeout_cb(target->arg);
        }
    }
}

The number of ticks that the timer increases each time, each time increases by 1ms;

void timer_ticks(void)
{
    
    
    _timer_ticks += CFG_TIMER_1_TICK_N_MS;

}

Linked list insertion method

tail insertion

The method of adding a node to a singly linked list: previously used is to add a linked list element from the head, the head insertion algorithm only needs to insert from the head, the time complexity is O(1), and the algorithm is excellent.

In addition, the tail insertion method is introduced:
the idea of ​​the tail insertion method is to find the node whose next pointer points to NULL at the end, and then replace the next pointer with the node that needs to be inserted.

int timer_start(struct Timer* handle)
{
    
    
	/** 
	 * 算法2 —— 向单链表尾部添加节点
	 * 时间复杂度O(n)
	 * Mculover666
	 */
	struct Timer* target = head_handle;
	if(head_handle == NULL)
	{
    
    
		/* 链表为空 */
		head_handle = handle;
		handle->next = NULL;
	}
	else
	{
    
    
		/* 链表中存在节点,遍历找最后一个节点 */
		while(target->next != NULL)
		{
    
    
			if(target == handle)
				return -1;
			target = target->next;
		}
		target->next = handle;
		handle->next = NULL;
	}
	return 0;
}

So far, it is introduced that the software timer is realized through the linked list, and multiple software timers can be realized, and the detailed explanation of the timer code is completed.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324127271&siteId=291194637