STM32F103移植FreeRTOSシリーズ8:FreeRTOS割り込み管理(実戦記事の最後にコード添付)

main.c

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
#include "FreeRTOS.h"
#include "task.h"
/************************************************
 ALIENTEK 战舰STM32F103开发板 FreeRTOS实验4-1
 FreeRTOS中断测试-库函数版本
 技术支持:www.openedv.com
 淘宝店铺:http://eboard.taobao.com 
 关注微信公众平台微信号:"正点原子",免费获取STM32资料。
 广州市星翼电子科技有限公司  
 作者:正点原子 @ALIENTEK
************************************************/

//任务优先级
#define START_TASK_PRIO			1
//任务堆栈大小	
#define START_STK_SIZE 			256  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);

//任务优先级
#define INTERRUPT_TASK_PRIO		2
//任务堆栈大小	
#define INTERRUPT_STK_SIZE 		256  
//任务句柄
TaskHandle_t INTERRUPTTask_Handler;
//任务函数
void interrupt_task(void *p_arg);

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 
	delay_init();	    				//延时函数初始化	 
	uart_init(115200);					//初始化串口
	LED_Init();		  					//初始化LED
	TIM3_Int_Init(10000-1,7200-1);		//初始化定时器3,定时器周期1S
	TIM5_Int_Init(10000-1,7200-1);		//初始化定时器5,定时器周期1S
	
	//创建开始任务
    xTaskCreate((TaskFunction_t )start_task,            //任务函数
                (const char*    )"start_task",          //任务名称
                (uint16_t       )START_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   //任务句柄              
    vTaskStartScheduler();          //开启任务调度
}

//开始任务任务函数
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
    //创建中断测试任务
    xTaskCreate((TaskFunction_t )interrupt_task,  			//任务函数
                (const char*    )"interrupt_task", 			//任务名称
                (uint16_t       )INTERRUPT_STK_SIZE,		//任务堆栈大小
                (void*          )NULL,						//传递给任务函数的参数
                (UBaseType_t    )INTERRUPT_TASK_PRIO,		//任务优先级
                (TaskHandle_t*  )&INTERRUPTTask_Handler); 	//任务句柄
	vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}

//中断测试任务函数 
void interrupt_task(void *pvParameters)
{
	static u32 total_num=0;
    while(1)
    {
          
		total_num+=1;
		printf("秒数%d\r\n",total_num);
		if(total_num%5==0) 
		{
			printf("关闭中断.............\r\n");
			portDISABLE_INTERRUPTS();				//关闭中断
			delay_xms(5000);						//延时5s
			printf("打开中断.............\r\n");	//打开中断
			portENABLE_INTERRUPTS();
		}
        LED0=~LED0;
        vTaskDelay(1000);
    }
} 

このコードは、STM32F103rct6 開発ボードと FreeRTOS オペレーティング システムの割り込みテスト用のコードです。このコードでは、遅延関数、シリアル ポートの初期化、LED およびタイマーの初期化など、いくつかの初期化が最初に実行されます。次に、開始タスク ( start_task) と割り込みテスト タスク ( interrupt_task) の 2 つのタスクを作成します。

start_task関数は開始タスクのタスク関数であり、その中に割り込みテストタスク()のタスクが作成されますinterrupt_task

interrupt_taskこの関数はテストタスクを中断するためのタスク関数で、カウンタを使用してtotal_num秒数を記録し、現在の秒数をシリアルポート経由で出力します。秒数が 5 で割り切れる場合、割り込みをオフにし、5 秒待ってから割り込みをオンにします。次に、LED の状態を制御して割り込みの影響をシミュレートし、vTaskDelay1 秒の遅延を使用します。

vTaskStartScheduler最後に、開いているタスク スケジューラを使用してタスクを開始します。ただし、タイマー 3 の割り込み優先順位は管理可能な configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY=5 よりも高いため、割り込みがオフになっている場合はタイマー 3 をマスクすることはできません。

time.c

#include "timer.h"
#include "led.h"
#include "led.h"
#include "usart.h"
//	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK战舰STM32开发板
//定时器 驱动代码	   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/9/3
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved									  
//   	 

//通用定时器3中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM3_Int_Init(u16 arr,u16 psc)
{
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
	
	//定时器TIM3初始化
	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
 
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断

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

	TIM_Cmd(TIM3, ENABLE);  //使能TIMx					 
}

//通用定时器5中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器5!
void TIM5_Int_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //时钟使能
	
	//定时器TIM5初始化
	TIM_TimeBaseStructure.TIM_Period = arr; 					//设置在下一个更新事件装入活动的自动重装载寄存器周期的值	
	TIM_TimeBaseStructure.TIM_Prescaler =psc; 					//设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 	//设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
	TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); 			//根据指定的参数初始化TIMx的时间基数单位
 
	TIM_ITConfig(TIM5,TIM_IT_Update,ENABLE ); 					//使能指定的TIM5中断,允许更新中断

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

	TIM_Cmd(TIM5, ENABLE);  									//使能TIM5					 
}

//定时器3中断服务函数
void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断
	{
		printf("TIM3输出.......\r\n");
	}
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  //清除中断标志位
}

//定时器5中断服务函数
void TIM5_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM5,TIM_IT_Update)==SET) //溢出中断
	{
		printf("TIM5输出.......\r\n");
	}
	TIM_ClearITPendingBit(TIM5,TIM_IT_Update);  //清除中断标志位
}


1) タイマー 3 のプリエンプション優先順位を configMAX_SYSCALL_INTERRUPT_PRIORITY よりも高い 4 に設定します。これにより、割り込みを無効にするために関数 portDISABLE_INTERRUPTS() が呼び出されたときにタイマー 3 は影響を受けません。

2) タイマー 5 のプリエンプション優先順位を configMAX_SYSCALL_INTERRUPT_PRIORITY と同じ 5 に設定します。これにより、関数 portDISABLE_INTERRUPTS() を呼び出して割り込みを無効にすると、タイマー 5 の割り込みが無効になります。

(3) と (4)、タイマ 3 とタイマ 5 のシリアル ポート出力情報。

実験結果:

 図 4.5.2.1 から、最初は割り込みが禁止されていなかったため、TIM3 と TIM5 の両方が正常に動作していることがわかります (上部の赤いボックスで示されている部分)。タスクinterrupt_task()が5回実行されると割り込みがオフになりますが、このときTIM5の割り込み優先度はconfigMAX_SYSCALL_INTERRUPT_PRIORITYと同じ5であるため、TIM5はオフになります。ただし、TIM3 の割り込み優先度は configMAX_SYSCALL_INTERRUPT_PRIORITY よりも高く、クローズされないため、赤枠で示すように、TIM3 は正常に実行されます。割り込みが 5 秒間閉じられた後、関数 portENABLE_INTERRUPTS() が呼び出され、割り込みが再度有効になります。割り込みを再度有効にした後、TIM5 は動作を再開します (下の赤枠で示されている部分)。

STMF103RCT6に基づく移植

リンク: https://pan.baidu.com/s/1EMmsif-3p9PURFykejDzCw?pwd=rtos 
抽出コード: rtos

おすすめ

転載: blog.csdn.net/qq_51519091/article/details/131559547