单片机裸机多任务时间片切换

发布时间 2023-08-08 10:26:22作者: ike_li

一、

二、代码

/*

STM32F407ZGT6
168MHz
Flash size 1024Kbytes
RAM size 192KB
*/
#include "main.h"
#include <string.h>

#include "systick.h"
#include "usart1.h"
#include "timer2.h"

#include "led.h"
#include "key.h"

/*
整个系统的代码由一个计时器timer2中断发动,timer2 就像是一个发动机,
每隔一定的周期发动一次中断,利用这一个中断的时间去对指定任务的时间
片减1,在主循环中一直遍历系统中所有任务的时间片,如果时间片耗尽了,
则执行该任务。

*/

void task_1(void);
void task_2(void);
void task_3(void);
void task_process(void);
void task_timer(void);

typedef struct{
	void (*task)(void);//要执行的任务
	uint8_t  task_run_flag; //任务运行标志,0不运行 1运行
	uint32_t task_time_run;	//设置任务运行间隔时间ms
	uint32_t task_time_cnt; //运行计时
	
}task_t;

uint8_t TASK_NUM = 3;
static task_t My_Task[]={
{task_1,0,500,0},
{task_2,0,1000,0},
{task_3,0,2000,0}

};


int main(void)
{

  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	sys_tick_init();
	
	timer2_init();
	usart1_init(115200);
	
	led_init();
	key_init();
	KEY0_FLAG = 0;
	TIMER2_TICK = 0;
	
	task_timer2_callback = task_timer;
	
	//初始化时间
	for(int i=0;i<TASK_NUM;i++)
	{	
		My_Task[i].task_time_cnt = My_Task[i].task_time_run;
	}
	
	while (1)
	{ 		
		task_process();
	}
  
  
}

void task_process(void)
{
	
	for(int i=0;i<TASK_NUM;i++)
	{
	   if(My_Task[i].task_run_flag == 1)
	   {	
	   
		   (My_Task[i].task)();//调用任务函数
		   My_Task[i].task_run_flag = 0;
	   }
		
	}

}
void task_timer(void)
{

 	for(int i=0;i<TASK_NUM;i++)
	{
		My_Task[i].task_time_cnt--;
		if(My_Task[i].task_time_cnt == 0)
		{			
		  My_Task[i].task_time_cnt = My_Task[i].task_time_run;//重新赋值
		  My_Task[i].task_run_flag = 1;
		}		 
		
	}

}
void task_1(void)
{
    printf("task_1\n");
}

void task_2(void)
{
	printf("task_2\n");
}

void task_3(void)
{
	printf("task_3\n");
}

timer2

#ifndef TIMER2_H
#define TIMER2_H
#include "stm32f4xx.h"   // Device header

/*
通用定时器用法 
TIM2

PA0 TIM2_CH1_ETR
PA5 TIM2_CH1_ETR

外部触发输入(ETR),仅适用于 TIM2、 TIM3、 TIM4
串口使用

Tout =((arr+1)*(psc+1))/Tclk
Tout:定时器溢出的时间(单位us)
arr:重装载值,当计数达到重装载寄存器设置的数字后产生更新事件,并清零从头开始计数。
psc:时钟预分频数
Tclk:定时器工作频率,单位MHz

arr = 100 - 1
psc = 84 - 1
Tclk = 84MHz  定时器时钟84M
Tout =((arr+1)*(psc+1))/Tclk
Tout = 100*84/84 = 100 us = 0.1 ms

*/

//函数指针
typedef void (*timer2_callback)();
extern timer2_callback task_timer2_callback;

extern uint64_t TIMER2_TICK;//计数

void timer2_init(void);


#endif

#include "timer2.h"

#include "usart1.h"
#include "usart2_timer.h" 

timer2_callback task_timer2_callback;

uint64_t TIMER2_TICK = 0;

void timer2_init()
{
	
	//从数据手册19/203页时钟树可以知道 APB2 84MHz,APB1 42MHz
	//时钟树上分析实际应该是APB1 * 2 = 84MHz APB2*2 = 168MHz

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);	
	
  
	//定时器初始化
	//Tout =((arr+1)*(psc+1))/Tclk
	//Tout 定时器溢出的时间(单位us)
	//Tclk 定时器的输入时钟频率(MHz),定时器时钟源,这里是84MHz
	uint32_t arr = 1000 - 1;
	uint16_t psc = 84 - 1;  //Tout=(100*84)/84 = 1000 us = 1 ms  溢出中断一次
	
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_TimeBaseStructure.TIM_Period = arr; //重装载值,当定时器的计数值达到这个值,定时器会重新装载	
	TIM_TimeBaseStructure.TIM_Prescaler = psc; //预分频值,1-65536之间任意分频,设置了用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //系统时钟分频器 TIM_CKD_DIV1=0;TIM_CKD_DIV2=256;TIM_CKD_DIV4=512
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);	

	//中断优先级NVIC设置
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;  //先占优先级0级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;  //从优先级3级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
	NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器

    TIM_ClearFlag(TIM2, TIM_FLAG_Update);	  // 清除溢出中断标志
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); //使能指定的TIM2中断,允许更新中断
	TIM_Cmd(TIM2, ENABLE);  //使能TIMx		


}


//定时器中断服务程序
void TIM2_IRQHandler(void)
{
	
	//TIM更新溢出中断发生
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)  
	{	
		
		TIMER2_TICK++;         
        usart1_timer_handle();
        usart2_timer_handle();
		
		task_timer2_callback();
		
	}
	
	TIM_ClearITPendingBit(TIM2, TIM_IT_Update );  //清除TIMx更新中断标志 

}