UCOS-II学习计划(3)

第三周的学习聚焦于μCOS-II的信号量集机制和内存管理。通过阅读《嵌入式实时操作系统μCOS-II原理及应用》等资料,掌握了事件标志组管理。实验中,设计了涉及步进电机控制的三个任务,利用信号量集实现任务间的同步。同时,还规划了一个内存管理的示例程序,任务1受开关控制申请释放内存,任务2运行六次后释放,任务3则立即释放。实验中需注意中断函数OSIntEnter()和OSIntExit()的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第三周

学习任务:

1. 熟练掌握ucos-ii信号量集机制;(事件标志组管理)

2. 了解ucos-ii内存管理机制

参考:

嵌入式实时操作系统μCOS-II原理及应用 任哲编著

STM32F407 UCOS开发手册 正点原子

嵌入式实时操作系统uc/os-ii(第二版) 邵贝贝著

 

实验任务:

1. 应用信号量集编写三个task,task1用来控制步进电机的运动,task2发送一个信号,task3发送一个信号,当这两个task都发送了信号之后task1控制步进电机启动。

当启动开关按键5、6时,电机开启,task1用来等待,task2和task3发送信号

注:这里的外部中断函数要加 OSIntEnter() 及 OSIntExit() 

按键key.c

#include"key.h"
#include"stm32f2xx.h"

void KEY_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
 	//对pe0~pe5进行初始化
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
		
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; 
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOE, &GPIO_InitStructure);
	
	//GPIO_SetBits(GPIOE, GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5);
}

EXIT.c

#include"stm32f2xx.h"
#include"EXTI.h"
#include"key.h"
#include"bsp_gpio.h"

void EXTIX_Init(void)
{
    EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;  //中断分组结构
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);  //使能syscfg时钟,为什么用SYSCFG时钟
    
    KEY_Init();

    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource0); //设置IO口与中断线的映射关系,PE0连接到中断线0
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource1);  //PE1连接到中断线1
	
	//对外部中断的中断线进行初始化
    EXTI_InitStructure.EXTI_Line = EXTI_Line0|EXTI_Line1;   //中断线0和1
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;      //是否使能
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;         //模式,中断模式,event是事件
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;    //触发方式,下降沿方式表示需要下拉,下拉时电平拉低
    //EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTI_Init(&EXTI_InitStructure);  //初始化线上中断,设置触发条件等

	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;  //0,1,2,3
    NVIC_Init(&NVIC_InitStructure);   //配置中断分组,并使能中断
		
    NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //0,1,2,3
    NVIC_Init(&NVIC_InitStructure);   //配置中断分组,并使能中断
}

void EXTI0_IRQHandler(void) //中断服务函数0
{
	OSIntEnter();
    /*
	if(KEY0 == 0)
	{
		led_trun_off(LED1);
	}
	*/
	EXTI_ClearITPendingBit(EXTI_Line0);  //清除中断标志位
    OSIntExit();
}

void EXTI1_IRQHandler(void) //中断服务函数1
{
	OSIntEnter();
	/*
	if(KEY1 == 0)
	{
		led_trun_off(LED2);
	}
	*/
	EXTI_ClearITPendingBit(EXTI_Line1);  //清除LINE1上的中断标志位
	OSIntExit();
}

new_task.c

#include "new_task.h"
#include "bsp_gpio.h"
#include "trace.h"
#include "bsp_can.h"
#include "gpio.h"   //电机相关引脚
#include "pwm.h"     //pwm波控制电机转动
#include "motor.h"   //电机相关函数
#include "key.h"
#include "EXTI.h"
#include "includes.h"

//#define KEY0 0x01    //第0位置1
//#define KEY1 0x02	 //第1位置1

OS_FLAG_GRP  *EventFlags;          //定义一个事件标志组
INT8U err; 

void init_new_task(void)
{	
	INT8U  err1;
	INT8U  err2;
	INT8U  err3;

	KEY_Init();
	EXTIX_Init();
	GPIO9_Set_Init();          //PB9控制电机转动方向
	GPIO12_Set_Init();			//PB12使能开关
	GPIO_SetBits(GPIOB, GPIO_Pin_12);     //PB12使能开关

	EventFlags = OSFlagCreate(0, &err);     //0是初始化值,创建信号量集

	err1 = OSTaskCreateExt((void (*)(void *)) Start_task1,
								(void		 * ) 0,
								(OS_STK 	 * )&TASK1[TASK1_STK_SIZE-1],
								(INT8U		   ) TASK1_PRIO,
								(INT16U 	   ) TASK1_PRIO,
								(OS_STK 	 * )&TASK1[0],
								(INT32U 	   ) TASK1_STK_SIZE,
								(void		 * ) 0,
								(INT16U 	   )(OS_TASK_OPT_STK_CLR | OS_TASK_OPT_STK_CHK));
	assert_param(OS_ERR_NONE == err1);
	OSTaskNameSet(TASK1_PRIO, (INT8U *)"task1", &err1);

	err2 = OSTaskCreateExt((void (*)(void *)) Start_task2,
                            (void 		 * ) 0,
                            (OS_STK		 * )&TASK2[TASK2_STK_SIZE-1],
                            (INT8U		   ) TASK2_PRIO,
                            (INT16U		   ) TASK2_PRIO,
                            (OS_STK		 * )&TASK2[0],
                            (INT32U		   ) TASK2_STK_SIZE,
                            (void 		 * ) 0,
                            (INT16U		   )(OS_TASK_OPT_STK_CLR | OS_TASK_OPT_STK_CHK));
    assert_param(OS_ERR_NONE == err2);
    OSTaskNameSet(TASK2_PRIO, (INT8U *)"task2", &err2);

    err3 = OSTaskCreateExt((void (*)(void *)) Start_task3,
                            (void 		 * ) 0,
                            (OS_STK		 * )&TASK3[TASK3_STK_SIZE-1],
                            (INT8U		   ) TASK3_PRIO,
                            (INT16U		   ) TASK3_PRIO,
                            (OS_STK		 * )&TASK3[0],
                            (INT32U		   ) TASK3_STK_SIZE,
                            (void 		 * ) 0,
                            (INT16U		   )(OS_TASK_OPT_STK_CLR | OS_TASK_OPT_STK_CHK));
    assert_param(OS_ERR_NONE == err3);
    OSTaskNameSet(TASK3_PRIO, (INT8U *)"task3", &err3);
	
}


void Start_task1(void)
{		
	while(1)
	{
		OSFlagPend(EventFlags,       //请求信号量集
				  (OS_FLAGS)3,       //请求第0位和第1位信号
				  OS_FLAG_WAIT_SET_ALL,  //信号都为1时表示有效
				  0,          			//timeout
				  &err);
		Start_Pwm();           //电机开始转动函数
		APP_TRACE("接收到任务2和任务3的信号,电机开启\r\n");
		OSTimeDlyHMSM(0, 0, 4, 0);
	}	
}


void Start_task2(void)
{
	while(1)
	{	
		if(KEY0 == 0)
		{
			//OSTimeDlyHMSM(0, 0, 0, 500);
			OSFlagPost(EventFlags,   	//发送信号量集
					  (OS_FLAGS)1, 		//给第0位发送信号
					  OS_FLAG_SET,		//信号置1
					  &err);
			APP_TRACE("开关6打开,任务2信号发送成功\r\n");
			OSTimeDlyHMSM(0, 0, 2, 0);
		}
	}	
}

void Start_task3(void)
{
	while(1)
	{
		if(KEY1 == 0)
		{
			OSFlagPost(EventFlags,   	//发送信号量集
					  (OS_FLAGS)2, 		//给第1位发送信号
					  OS_FLAG_SET,		//信号置1
					  &err);
			APP_TRACE("开关5打开,任务3信号发送成功\r\n");
			OSTimeDlyHMSM(0, 0, 2, 0);
		}
	}	
}

2. 自行设计ucos-ii内存管理demo程序。

 思路:任务1由开关6、5控制申请、释放

            任务2运行 6 次后释放内存

            任务3申请后就释放

#include "new_task.h"
#include "bsp_gpio.h"
#include "trace.h"
#include "bsp_can.h"
#include "key.h"
#include "EXTI.h"
#include "includes.h"

OS_MEM *CommTxBuffer;          //定义内存分区指针
INT8U CommTxPart[20][40];      //定义分区和内存块
INT8U err; 

void init_new_task(void)
{	
	INT8U  err1;
	INT8U  err2;
	INT8U  err3;

	KEY_Init();
	EXTIX_Init();

	CommTxBuffer = OSMemCreate(CommTxPart,   //内存分区的首地址
							    20, 		//分区内存块的数目
								40, 		//每个内存块的长度
								&err);

	err1 = OSTaskCreateExt((void (*)(void *)) Start_task1,
								(void		 * ) 0,
								(OS_STK 	 * )&TASK1[TASK1_STK_SIZE-1],
								(INT8U		   ) TASK1_PRIO,
								(INT16U 	   ) TASK1_PRIO,
								(OS_STK 	 * )&TASK1[0],
								(INT32U 	   ) TASK1_STK_SIZE,
								(void		 * ) 0,
								(INT16U 	   )(OS_TASK_OPT_STK_CLR | OS_TASK_OPT_STK_CHK));
	assert_param(OS_ERR_NONE == err1);
	OSTaskNameSet(TASK1_PRIO, (INT8U *)"task1", &err1);

	err2 = OSTaskCreateExt((void (*)(void *)) Start_task2,
                            (void 		 * ) 0,
                            (OS_STK		 * )&TASK2[TASK2_STK_SIZE-1],
                            (INT8U		   ) TASK2_PRIO,
                            (INT16U		   ) TASK2_PRIO,
                            (OS_STK		 * )&TASK2[0],
                            (INT32U		   ) TASK2_STK_SIZE,
                            (void 		 * ) 0,
                            (INT16U		   )(OS_TASK_OPT_STK_CLR | OS_TASK_OPT_STK_CHK));
    assert_param(OS_ERR_NONE == err2);
    OSTaskNameSet(TASK2_PRIO, (INT8U *)"task2", &err2);

    err3 = OSTaskCreateExt((void (*)(void *)) Start_task3,
                            (void 		 * ) 0,
                            (OS_STK		 * )&TASK3[TASK3_STK_SIZE-1],
                            (INT8U		   ) TASK3_PRIO,
                            (INT16U		   ) TASK3_PRIO,
                            (OS_STK		 * )&TASK3[0],
                            (INT32U		   ) TASK3_STK_SIZE,
                            (void 		 * ) 0,
                            (INT16U		   )(OS_TASK_OPT_STK_CLR | OS_TASK_OPT_STK_CHK));
    assert_param(OS_ERR_NONE == err3);
    OSTaskNameSet(TASK3_PRIO, (INT8U *)"task3", &err3);
	
}


void Start_task1(void)
{		
	INT8U *Intptr;     //定义指针
	while(1)
	{
		if(KEY0 == 0)
		{
			Intptr = OSMemGet(CommTxBuffer, &err);    //申请内存
			APP_TRACE("任务1申请了内存块\r\n");
			if((KEY1 == 0)&&(Intptr != NULL))
			{
				OSMemPut(CommTxBuffer,       //内存分区的指针
							Intptr); 		 //待释放内存块的指针	
				APP_TRACE("任务1释放了内存块\r\n");			
			}		
		}
		OSTimeDlyHMSM(0, 0, 2, 0);
	}	
}


void Start_task2(void)
{
	INT8U *Intptr;     //定义指针
	INT8U Times;
	while(1)
	{	
		Intptr = OSMemGet(CommTxBuffer, &err);    //申请内存
		APP_TRACE("任务2申请了内存块\r\n");
		if((Times > 6)&&(Intptr != NULL))
		{
			OSMemPut(CommTxBuffer, Intptr);       
			APP_TRACE("任务2释放了内存块\r\n");				 	
		}
		Times++;
		OSTimeDlyHMSM(0, 0, 2, 0);
	}	
}

void Start_task3(void)
{
	INT8U *Intptr;     //定义指针
	while(1)
	{
		/*
		Intptr = OSMemGet(CommTxBuffer, &err);    //申请内存
		APP_TRACE("任务3申请了内存块\r\n");
		OSMemPut(CommTxBuffer, Intptr);       
		APP_TRACE("任务3释放了内存块\r\n");	
		*/
	}	
	OSTimeDlyHMSM(0, 0, 2, 0);
}


 版权声明:本文为博主原创文章,未经博主允许不得转载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值