目录
timeslice是一个时间片轮询框架,完全解耦的时间片轮询框架,非常适合裸机单片机引用。接下来将该框架移植到stm32单片机运行,单片机只需用1个定时器作为时钟即可。
友情链接(项目示例):https://download.csdn.net/download/qq_36075612/88498232
1、硬件平台
STM32F401CEU6
内部Flash : 512Kbytes,SARM : 96 Kbytes
2.1、系统时钟配置

2.2、下载调试配置

2.3、TIM配置(1ms中断)

2.4、usart1配置

2.5、生成代码


2.6、编译工程

1、usart.c添加打印
- /* USER CODE BEGIN 1 */
- #include "stdio.h"
- #ifdef __GNUC__
- /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
- set to 'Yes') calls __io_putchar() */
- #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
- #else
- #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
- #endif /* __GNUC__ */
- /**
- * @brief Retargets the C library printf function to the USART.
- * @param None
- * @retval None
- */
- PUTCHAR_PROTOTYPE
- {
- /* Place your implementation of fputc here */
- /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
- HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
-
- return ch;
- }
-
- int fgetc(FILE * f)
- {
- uint8_t ch = 0;
- HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, 0xffff);
- return ch;
- }
-
- /* USER CODE END 1 */
2、tim1.c
- /* USER CODE BEGIN Header */
- /**
- ******************************************************************************
- * @file tim.c
- * @brief This file provides code for the configuration
- * of the TIM instances.
- ******************************************************************************
- * @attention
- *
- * Copyright (c) 2023 STMicroelectronics.
- * All rights reserved.
- *
- * This software is licensed under terms that can be found in the LICENSE file
- * in the root directory of this software component.
- * If no LICENSE file comes with this software, it is provided AS-IS.
- *
- ******************************************************************************
- */
- /* USER CODE END Header */
- /* Includes ------------------------------------------------------------------*/
- #include "tim.h"
-
- /* USER CODE BEGIN 0 */
-
- /* USER CODE END 0 */
-
- TIM_HandleTypeDef htim1;
-
- /* TIM1 init function */
- void MX_TIM1_Init(void)
- {
-
- /* USER CODE BEGIN TIM1_Init 0 */
-
- /* USER CODE END TIM1_Init 0 */
-
- TIM_ClockConfigTypeDef sClockSourceConfig = {0};
- TIM_MasterConfigTypeDef sMasterConfig = {0};
-
- /* USER CODE BEGIN TIM1_Init 1 */
-
- /* USER CODE END TIM1_Init 1 */
- htim1.Instance = TIM1;
- htim1.Init.Prescaler = 84-1;
- htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
- htim1.Init.Period = 1000-1;
- htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
- htim1.Init.RepetitionCounter = 0;
- htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
- if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
- {
- Error_Handler();
- }
- sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
- if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
- {
- Error_Handler();
- }
- sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
- sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
- if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
- {
- Error_Handler();
- }
- /* USER CODE BEGIN TIM1_Init 2 */
-
- /* USER CODE END TIM1_Init 2 */
-
- }
-
- void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
- {
-
- if(tim_baseHandle->Instance==TIM1)
- {
- /* USER CODE BEGIN TIM1_MspInit 0 */
-
- /* USER CODE END TIM1_MspInit 0 */
- /* TIM1 clock enable */
- __HAL_RCC_TIM1_CLK_ENABLE();
-
- /* TIM1 interrupt Init */
- HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 0, 0);
- HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
- /* USER CODE BEGIN TIM1_MspInit 1 */
-
- /* USER CODE END TIM1_MspInit 1 */
- }
- }
-
- void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
- {
-
- if(tim_baseHandle->Instance==TIM1)
- {
- /* USER CODE BEGIN TIM1_MspDeInit 0 */
-
- /* USER CODE END TIM1_MspDeInit 0 */
- /* Peripheral clock disable */
- __HAL_RCC_TIM1_CLK_DISABLE();
-
- /* TIM1 interrupt Deinit */
- HAL_NVIC_DisableIRQ(TIM1_UP_TIM10_IRQn);
- /* USER CODE BEGIN TIM1_MspDeInit 1 */
-
- /* USER CODE END TIM1_MspDeInit 1 */
- }
- }
-
- /* USER CODE BEGIN 1 */
- #include "stdio.h"
- int timeCount = 0;
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
- if(htim->Instance == TIM1){
- timeCount++;
- if(timeCount==1000){
- timeCount = 0;
- printf("time + 1s\n");
- }
- }
- }
-
- /* USER CODE END 1 */
3、在根目录创建timeslice文件夹,分别有list.c、list.h、thread_demo.c、thread_demo.h、timeslice.c、timeslice.h文件组成
1)、list.c
- #include "list.h"
-
- void list_init(ListObj* list)
- {
- list->next = list->prev = list;
- }
-
- void list_insert_after(ListObj* list, ListObj* node)
- {
- list->next->prev = node;
- node->next = list->next;
-
- list->next = node;
- node->prev = list;
- }
-
- void list_insert_before(ListObj* list, ListObj* node)
- {
- list->prev->next = node;
- node->prev = list->prev;
-
- list->prev = node;
- node->next = list;
- }
-
- void list_remove(ListObj* node)
- {
- node->next->prev = node->prev;
- node->prev->next = node->next;
-
- node->next = node->prev = node;
- }
-
- int list_isempty(const ListObj* list)
- {
- return list->next == list;
- }
-
- unsigned int list_len(const ListObj* list)
- {
- unsigned int len = 0;
- const ListObj* p = list;
- while (p->next != list)
- {
- p = p->next;
- len++;
- }
-
- return len;
- }
2)、list.h
- #ifndef _LIST_H
- #define _LIST_H
-
- #define offset_of(type, member) (unsigned long) &((type*)0)->member
- #define container_of(ptr, type, member) ((type *)((char *)(ptr) - offset_of(type, member)))
-
- typedef struct list_structure
- {
- struct list_structure* next;
- struct list_structure* prev;
- } ListObj;
-
- #define LIST_HEAD_INIT(name) {&(name), &(name)}
- #define LIST_HEAD(name) ListObj name = LIST_HEAD_INIT(name)
-
- void list_init(ListObj* list);
- void list_insert_after(ListObj* list, ListObj* node);
- void list_insert_before(ListObj* list, ListObj* node);
- void list_remove(ListObj* node);
- int list_isempty(const ListObj* list);
- unsigned int list_len(const ListObj* list);
-
- #define list_entry(node, type, member) \
- container_of(node, type, member)
-
- #define list_for_each(pos, head) \
- for (pos = (head)->next; pos != (head); pos = pos->next)
-
- #define list_for_each_safe(pos, n, head) \
- for (pos = (head)->next, n = pos->next; pos != (head); \
- pos = n, n = pos->next)
-
- #endif
3)、timeslice.c
- #include "timeslice.h"
-
- static LIST_HEAD(timeslice_task_list);
-
- void timeslice_exec(void)
- {
- ListObj* node;
- TimesilceTaskObj* task;
-
- list_for_each(node, ×lice_task_list)
- {
-
- task = list_entry(node, TimesilceTaskObj, timeslice_task_list);
- if (task->is_run == TASK_RUN)
- {
- task->task_hdl();
- task->is_run = TASK_STOP;
- }
- }
- }
-
- void timeslice_tick(void)
- {
- ListObj* node;
- TimesilceTaskObj* task;
-
- list_for_each(node, ×lice_task_list)
- {
- task = list_entry(node, TimesilceTaskObj, timeslice_task_list);
- if (task->timer != 0)
- {
- task->timer--;
- if (task->timer == 0)
- {
- task->is_run = TASK_RUN;
- task->timer = task->timeslice_len;
- }
- }
- }
- }
-
- unsigned int timeslice_get_task_num(void)
- {
- return list_len(×lice_task_list);
- }
-
- void timeslice_task_init(TimesilceTaskObj* obj, void (*task_hdl)(void), unsigned int id, unsigned int timeslice_len)
- {
- obj->id = id;
- obj->is_run = TASK_STOP;
- obj->task_hdl = task_hdl;
- obj->timer = timeslice_len;
- obj->timeslice_len = timeslice_len;
- }
-
- void timeslice_task_add(TimesilceTaskObj* obj)
- {
- list_insert_before(×lice_task_list, &obj->timeslice_task_list);
- }
-
- void timeslice_task_del(TimesilceTaskObj* obj)
- {
- if (timeslice_task_isexist(obj))
- list_remove(&obj->timeslice_task_list);
- else
- return;
- }
-
-
- unsigned char timeslice_task_isexist(TimesilceTaskObj* obj)
- {
- unsigned char isexist = 0;
- ListObj* node;
- TimesilceTaskObj* task;
-
- list_for_each(node, ×lice_task_list)
- {
- task = list_entry(node, TimesilceTaskObj, timeslice_task_list);
- if (obj->id == task->id)
- isexist = 1;
- }
-
- return isexist;
- }
-
- unsigned int timeslice_get_task_timeslice_len(TimesilceTaskObj* obj)
- {
- return obj->timeslice_len;
- }
4)、timeslice.h
- #ifndef _TIMESLICE_H
- #define _TIMESLICE_H
-
- #include "list.h"
-
- typedef enum {
- TASK_STOP,
- TASK_RUN
- } IsTaskRun;
-
- typedef struct timesilce
- {
- unsigned int id;
- void (*task_hdl)(void);
- IsTaskRun is_run;
- unsigned int timer;
- unsigned int timeslice_len;
- ListObj timeslice_task_list;
- } TimesilceTaskObj;
-
- void timeslice_exec(void);
- void timeslice_tick(void);
- void timeslice_task_init(TimesilceTaskObj* obj, void (*task_hdl)(void), unsigned int id, unsigned int timeslice_len);
- void timeslice_task_add(TimesilceTaskObj* obj);
- void timeslice_task_del(TimesilceTaskObj* obj);
- unsigned int timeslice_get_task_timeslice_len(TimesilceTaskObj* obj);
- unsigned int timeslice_get_task_num(void);
- unsigned char timeslice_task_isexist(TimesilceTaskObj* obj);
-
- #endif
5)、task_demo.c
- #include
- #include "timeslice.h"
- #include "gpio.h"
-
-
- // 创建5个任务对象
- TimesilceTaskObj task_1, task_2, task_3, task_4, task_5, task_led;
-
-
- // 具体的任务函数
- void task1_hdl(void)
- {
- printf(">> task 1 is running ...\n");
- }
-
-
- void task2_hdl(void)
- {
- printf(">> task 2 is running ...\n");
- }
-
-
- void task3_hdl(void)
- {
- printf(">> task 3 is running ...\n");
- }
-
-
- void task4_hdl(void)
- {
- printf(">> task 4 is running ...\n");
- }
-
-
- void task5_hdl(void)
- {
- printf(">> task 5 is running ...\n");
- }
-
- void led_hd1(void)
- {
- HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
- }
-
-
- // 初始化任务对象,并且将任务添加到时间片轮询调度中
- void task_init(void)
- {
- timeslice_task_init(&task_1, task1_hdl, 1, 10);
- timeslice_task_init(&task_2, task2_hdl, 2, 20);
- timeslice_task_init(&task_3, task3_hdl, 3, 30);
- timeslice_task_init(&task_4, task4_hdl, 4, 40);
- timeslice_task_init(&task_5, task5_hdl, 5, 50);
- timeslice_task_init(&task_led, led_hd1, 6, 1000);
-
- timeslice_task_add(&task_1);
- timeslice_task_add(&task_2);
- timeslice_task_add(&task_3);
- timeslice_task_add(&task_4);
- timeslice_task_add(&task_5);
- timeslice_task_add(&task_led);
- }
-
- void task_run(void)
- {
- task_init();
-
-
- printf(">> task num: %d\n", timeslice_get_task_num());
- printf(">> task len: %d\n", timeslice_get_task_timeslice_len(&task_3));
-
-
- timeslice_task_del(&task_2);
- printf(">> delet task 2\n");
- printf(">> task 2 is exist: %d\n", timeslice_task_isexist(&task_2));
-
-
- printf(">> task num: %d\n", timeslice_get_task_num());
-
-
- timeslice_task_del(&task_5);
- printf(">> delet task 5\n");
-
-
- printf(">> task num: %d\n", timeslice_get_task_num());
-
-
- printf(">> task 3 is exist: %d\n", timeslice_task_isexist(&task_3));
- timeslice_task_add(&task_2);
- printf(">> add task 2\n");
- printf(">> task 2 is exist: %d\n", timeslice_task_isexist(&task_2));
-
-
- timeslice_task_add(&task_5);
- printf(">> add task 5\n");
-
-
- printf(">> task num: %d\n", timeslice_get_task_num());
-
-
- printf("\n\n========timeslice running===========\n");
-
- while(1)
- {
- timeslice_exec();
- }
-
- }
6)、task_demo.h
- #ifndef _TASK_DEMO_H
- #define _TASK_DEMO_H
-
-
-
- void task_run(void);
-
-
- #endif
-
4、main.c
- /* USER CODE BEGIN Header */
- /**
- ******************************************************************************
- * @file : main.c
- * @brief : Main program body
- ******************************************************************************
- * @attention
- *
- * Copyright (c) 2023 STMicroelectronics.
- * All rights reserved.
- *
- * This software is licensed under terms that can be found in the LICENSE file
- * in the root directory of this software component.
- * If no LICENSE file comes with this software, it is provided AS-IS.
- *
- ******************************************************************************
- */
- /* USER CODE END Header */
- /* Includes ------------------------------------------------------------------*/
- #include "main.h"
- #include "tim.h"
- #include "usart.h"
- #include "gpio.h"
-
- /* Private includes ----------------------------------------------------------*/
- /* USER CODE BEGIN Includes */
- #include "stdio.h"
- #include "task_demo.h"
- /* USER CODE END Includes */
-
- /* Private typedef -----------------------------------------------------------*/
- /* USER CODE BEGIN PTD */
-
- /* USER CODE END PTD */
-
- /* Private define ------------------------------------------------------------*/
- /* USER CODE BEGIN PD */
-
- /* USER CODE END PD */
-
- /* Private macro -------------------------------------------------------------*/
- /* USER CODE BEGIN PM */
-
- /* USER CODE END PM */
-
- /* Private variables ---------------------------------------------------------*/
-
- /* USER CODE BEGIN PV */
-
- /* USER CODE END PV */
-
- /* Private function prototypes -----------------------------------------------*/
- void SystemClock_Config(void);
- /* USER CODE BEGIN PFP */
-
- /* USER CODE END PFP */
-
- /* Private user code ---------------------------------------------------------*/
- /* USER CODE BEGIN 0 */
-
- /* USER CODE END 0 */
-
- /**
- * @brief The application entry point.
- * @retval int
- */
- int main(void)
- {
- /* USER CODE BEGIN 1 */
-
- /* USER CODE END 1 */
-
- /* MCU Configuration--------------------------------------------------------*/
-
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
- HAL_Init();
-
- /* USER CODE BEGIN Init */
-
- /* USER CODE END Init */
-
- /* Configure the system clock */
- SystemClock_Config();
-
- /* USER CODE BEGIN SysInit */
-
- /* USER CODE END SysInit */
-
- /* Initialize all configured peripherals */
- MX_GPIO_Init();
- MX_USART1_UART_Init();
- MX_TIM1_Init();
- /* USER CODE BEGIN 2 */
- HAL_TIM_Base_Start_IT(&htim1);
- printf("heihei\r\n");
- task_run();
- /* USER CODE END 2 */
-
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- /* USER CODE END WHILE */
-
- /* USER CODE BEGIN 3 */
- }
- /* USER CODE END 3 */
- }
-
- /**
- * @brief System Clock Configuration
- * @retval None
- */
- void SystemClock_Config(void)
- {
- RCC_OscInitTypeDef RCC_OscInitStruct = {0};
- RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
-
- /** Configure the main internal regulator output voltage
- */
- __HAL_RCC_PWR_CLK_ENABLE();
- __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
-
- /** Initializes the RCC Oscillators according to the specified parameters
- * in the RCC_OscInitTypeDef structure.
- */
- RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
- RCC_OscInitStruct.HSEState = RCC_HSE_ON;
- RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
- RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
- RCC_OscInitStruct.PLL.PLLM = 25;
- RCC_OscInitStruct.PLL.PLLN = 168;
- RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
- RCC_OscInitStruct.PLL.PLLQ = 4;
- if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
- {
- Error_Handler();
- }
-
- /** Initializes the CPU, AHB and APB buses clocks
- */
- RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
- |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
- RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
- RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
- RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
- RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
-
- if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
- {
- Error_Handler();
- }
- }
-
- /* USER CODE BEGIN 4 */
-
- /* USER CODE END 4 */
-
- /**
- * @brief This function is executed in case of error occurrence.
- * @retval None
- */
- void Error_Handler(void)
- {
- /* USER CODE BEGIN Error_Handler_Debug */
- /* User can add his own implementation to report the HAL error return state */
- __disable_irq();
- while (1)
- {
- }
- /* USER CODE END Error_Handler_Debug */
- }
-
- #ifdef USE_FULL_ASSERT
- /**
- * @brief Reports the name of the source file and the source line number
- * where the assert_param error has occurred.
- * @param file: pointer to the source file name
- * @param line: assert_param error line source number
- * @retval None
- */
- void assert_failed(uint8_t *file, uint32_t line)
- {
- /* USER CODE BEGIN 6 */
- /* User can add his own implementation to report the file name and line number,
- ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
- /* USER CODE END 6 */
- }
- #endif /* USE_FULL_ASSERT */
分别添加以下6个文件:list.c、list.h、task_demo.c、task_demo.h、timeslice.c、timeslice.h。同时,把timslice目录下的.h文件包含进项目中来,如下所示:




注意:keil上需要勾选Use MicroLIB,否则CubeMX生成的串口工程无法打印问题


时间片轮询架构
其实该部分主要使用了面向对象的思维,使用结构体作为对象,并使用结构体指针作为参数传递,这样作可以节省资源,并且有着极高的运行效率。
其中最难的部分是侵入式链表的使用,这种链表在一些操作系统内核中使用十分广泛,这里是参考RT-Thread实时操作系统中的侵入式链表实现。
底层侵入式双向链表
该链表是linux内核中使用十分广泛,也十分经典,其原理具体可以参考文章:
https://www.cnblogs.com/skywang12345/p/3562146.html
好了,终于介绍完毕,以后裸机开发,有了此时间片论法,如虎添翼。感谢各位同仁参阅。
参考文章: