第三周
学习任务:
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);
}
版权声明:本文为博主原创文章,未经博主允许不得转载。