/***********************头文件****************************/ #include "main.h" #include "sys.h" #include "delay.h" #include "led.h" #include "exti.h" #include "includes.h" #include "timer.h" /***********************指针变量****************************/ OS_EVENT * sem_TaskC; //任务C信号量指针 OS_EVENT * sem_Mutex; //互斥信号量 OS_EVENT * q_Msg; //消息队列 void * MsgGrp[256]; //消息队列存储地址,最大支持256个消息 /***********************全局变量****************************/ u16 *I3_Num; static u16 I3_InNum; // 存储邮箱消息 u32 PB4_Num; //存储按键次数 u8 flag_Exit; //执行按键函数中断标志位 uint8_t taskA_Num = 0 ;//记录任务A小灯闪烁次数 /**********************START 任务****************************/ #define START_TASK_PRIO 3 //开始任务的优先级 #define START_STK_SIZE 128 //设置任务堆栈大小 OS_STK START_TASK_STK[START_STK_SIZE];//任务任务堆栈 void start_task(void *pdata);//任务函数 /**********************任务A*********************************/ #define LEDA_TASK_PRIO 4 //设置任务优先级 #define LEDA_STK_SIZE 128 //设置任务堆栈大小 OS_STK LEDA_TASK_STK[LEDA_STK_SIZE]; //任务堆栈 void ledA_task(void *pdata); //任务函数 /**********************任务B********************************/ #define LEDB_TASK_PRIO 5 //设置任务优先级 #define LEDB_STK_SIZE 128 //设置任务堆栈大小 OS_STK LEDB_TASK_STK[LEDB_STK_SIZE]; //任务堆栈 void ledB_task(void *pdata); //任务函数 /**********************任务C********************************/ #define LEDC_TASK_PRIO 6 //设置任务优先级 #define LEDC_STK_SIZE 128 //设置任务堆栈大小 OS_STK LEDC_TASK_STK[LEDC_STK_SIZE]; //任务堆栈 void ledC_task(void *pdata); //任务函数 /**********************任务D********************************/ #define LEDD_TASK_PRIO 9 //设置任务优先级 #define LEDD_STK_SIZE 128 //设置任务堆栈大小 OS_STK LEDD_TASK_STK[LEDD_STK_SIZE]; //任务堆栈 void ledD_task(void *pdata); //任务函数 /*********************任务E********************************/ #define LEDE_TASK_PRIO 10 //设置任务优先级 #define LEDE_STK_SIZE 128 //设置任务堆栈大小 OS_STK LEDE_TASK_STK[LEDE_STK_SIZE]; //任务堆栈 void ledE_task(void *pdata); //任务函数 /*********************任务F ********************************/ #define LEDF_TASK_PRIO 7 //设置任务优先级 #define LEDF_STK_SIZE 128 //设置任务堆栈大小 OS_STK LEDF_TASK_STK[LEDF_STK_SIZE]; //任务堆栈 void ledF_task(void *pdata); //任务函数 /********************按键检测任务****************************/ #define KEYG_TASK_PRIO 11 //设置任务优先级 #define KEYG_STK_SIZE 128 //设置任务堆栈大小 OS_STK KEYG_TASK_STK[KEYG_STK_SIZE]; //任务堆栈 void keyG_task(void *pdata); //任务函数 /********************主函数****************************/ int main(void) { HSI_SetSysClock(16, 336, 2, 7); //使用HSI配置系统时钟为168M TIM3_Int_Init(4999, 8399); //时钟初始化 delay_init(168); //延时初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断分组配置 LED_Init(); //LED初始化 EXTIX_Init(); //外部中断初始化 OSInit(); //UCOS初始化 OSTaskCreate(start_task, (void*)0, (OS_STK*)&START_TASK_STK[START_STK_SIZE-1], START_TASK_PRIO); //创建开始任务 OSStart(); //开始任务 } /****************************************************** //创建UCOS开始任务 //提供外设初始化、创建信号量、创建邮箱、创建消息队列 、创建信号量集、创建任务、初始化统计任务等等 ********************************************************/ void start_task(void *pdata) { OS_CPU_SR cpu_sr = 0; pdata=pdata; u8 err; //错误标志码 sem_TaskC = OSSemCreate(0); //创建信号量 msg_TaskC = OSMboxCreate((void*) 0);//创建消息邮箱 sem_Mutex = OSMutexCreate(8, &err); //创建互斥信号量 设置优先级为8 q_Msg = OSQCreate(&MsgGrp[0],256); //创建消息队列 OSStatInit(); //开启统计任务 OS_ENTER_CRITICAL(); //进入临界区(关闭中断) OSTaskCreate(ledA_task,(void*)0,(OS_STK*)&LEDA_TASK_STK[LEDA_STK_SIZE-1],LEDA_TASK_PRIO);//创建任务A OSTaskCreate(ledB_task,(void*)0,(OS_STK*)&LEDB_TASK_STK[LEDB_STK_SIZE-1],LEDB_TASK_PRIO);//创建任务B OSTaskCreate(ledC_task,(void*)0,(OS_STK*)&LEDC_TASK_STK[LEDC_STK_SIZE-1],LEDC_TASK_PRIO);//创建任务C OSTaskCreate(ledD_task,(void*)0,(OS_STK*)&LEDD_TASK_STK[LEDD_STK_SIZE-1],LEDD_TASK_PRIO);//创建任务D OSTaskCreate(ledE_task,(void*)0,(OS_STK*)&LEDE_TASK_STK[LEDE_STK_SIZE-1],LEDE_TASK_PRIO);//创建任务E OSTaskCreate(ledF_task,(void*)0,(OS_STK*)&LEDF_TASK_STK[LEDF_STK_SIZE-1],LEDF_TASK_PRIO);//创建任务F OSTaskCreate(keyG_task,(void*)0,(OS_STK*)&KEYG_TASK_STK[KEYG_STK_SIZE-1],KEYG_TASK_PRIO);//创建任务G OSTaskSuspend(START_TASK_PRIO);//挂起开始任务 OS_EXIT_CRITICAL(); //退出临界区(开中断) } /********************任务A任务函数**************************** 1. 任务A小灯以1Hz的频率闪烁 2. 当任务A的小灯闪烁10次过后,任务A挂起,任务B执行 *************************************************************/ void ledA_task(void *pdata) { pdata=pdata; NVIC_InitTypeDef NVIC_InitStructure; while(1) { if(21 <= taskA_Num) { LED0 = 1; NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; //定时器3中断 NVIC_InitStructure.NVIC_IRQChannelCmd=DISABLE; NVIC_Init(&NVIC_InitStructure); OSTaskSuspend(LEDA_TASK_PRIO);//当小灯闪烁10次后,挂起任务A } } } /********************任务B任务函数**************************** 1. 任务B小灯以10Hz的频率闪烁 2. 当任务B的小灯闪烁20次过后,任务B挂起,给任务C发信号量 *************************************************************/ void ledB_task(void *pdata) { pdata=pdata; u8 taskB_Num = 0 ;//记录任务A小灯闪烁次数 while(1) { LED1 = 0; delay_ms(50); LED1 = 1; delay_ms(50); taskB_Num++; if(20 <= taskB_Num) { OSSemPost(sem_TaskC);//给任务C发信号量 OSTaskSuspend(LEDB_TASK_PRIO);//当小灯闪烁20次后,挂起任务B } } } /********************任务C任务函数**************************** 1. 任务C接收到任务B的信号量时,任务C执行 2. 对于外部中断的触发次数进行计数,并通过邮箱发送给任务C 3. 中断次数小于5时,任务C小灯以1Hz频率闪烁, 中断次数大于等于5,且小于10时,任务C小灯以10Hz频率闪烁 4. 任务C把通过邮箱接收到的数据填入队列 *************************************************************/ void ledC_task(void *pdata) { pdata=pdata; u8 err; while (1) { OSSemPend(sem_TaskC, 0, &err); //请求信号量 I3_Num = (u16* )OSMboxPend(msg_TaskC, 10, &err); //请求邮箱 if (I3_Num != NULL) //如果消息邮箱没有消息,返回空指针。 { I3_InNum = *I3_Num; OSQPost(q_Msg, I3_Num); //发送队列消息 } if (I3_InNum < 5) { LED2 = 0; delay_ms(500); LED2 = 1; delay_ms(500); } else if (I3_InNum >= 5 && I3_InNum < 10) { LED2 = 0; delay_ms(50); LED2 = 1; delay_ms(50); } OSSemPost(sem_TaskC); } } /********************任务D任务函数**************************** 1、任务D获取到互斥量时任务D小灯常亮,未获取到时任务D小灯长灭 2、当外部输入1为高电平时,任务D尝试获取互斥量, 当外部输入1为低电平时,任务D释放互斥量 *************************************************************/ void ledD_task(void *pdata) { pdata=pdata; u8 err; while(1) { if (KEY0 == 0) //外部输入1(PI_15)为高电平,尝试获取互斥信号量 { OSMutexPend(sem_Mutex, 10, &err); if (err != 10u) { LED3 = 0; } } if (KEY0 == 1) //外部输入1为低电平,释放互斥信号量 { OSMutexPost(sem_Mutex); LED3 = 1; } delay_ms(10); //任务调度 } } /********************任务E任务函数**************************** 1、任务E获取到互斥量时任务E小灯常亮,未获取到时任务E小灯长灭 2、当外部输入2为高电平时,任务E尝试获取互斥量, 当外部输入2为低电平时,任务E释放互斥量 *************************************************************/ void ledE_task(void *pdata) { pdata=pdata; u8 err; while(1) { if (KEY1 == 0) //外部输入2为高电平,尝试获取互斥信号量 { OSMutexPend(sem_Mutex, 10, &err); if (err != 10u) { LED4 = 0; } } if (KEY1 == 1) //外部输入2为低电平,释放互斥信号量 { OSMutexPost(sem_Mutex); LED4 = 1; } delay_ms(10); } } /********************任务F任务函数**************************** 1、任务E获取到互斥量时任务E小灯常亮,未获取到时任务E小灯长灭 2、当外部输入2为高电平时,任务E尝试获取互斥量, 当外部输入2为低电平时,任务E释放互斥量 *************************************************************/ void ledF_task(void *pdata) { pdata=pdata; u8 err; u8 num; u8 *p; while(1) { p = OSQPend(q_Msg, 0, &err); //请求消息队列 if (p != NULL) { num = *p % 8; } switch (num) { case 0: LED5 = 1; LED6 = 1; LED7 = 1; LED8 = 1; LED9 = 1; LED10 = 1; LED11 = 1; LED12 = 1; LED13 = 1; LED14 = 1; LED15 = 1; break; case 1: LED5 = 0; LED6 = 1; LED7 = 1; LED8 = 1; LED9 = 1; LED10 = 1; LED11 = 1; LED12 = 1; LED13 = 1; LED14 = 1; LED15 = 1; break; case 2: LED5 = 0; LED6 = 0; LED7 = 1; LED8 = 1; LED9 = 1; LED10 = 1; LED11 = 1; LED12 = 1; LED13 = 1; LED14 = 1; LED15 = 1; break; case 3: LED5 = 0; LED6 = 0; LED7 = 0; LED8 = 1; LED9 = 1; LED10 = 1; LED11 = 1; LED12 = 1; LED13 = 1; LED14 = 1; LED15 = 1; break; case 4: LED5 = 0; LED6 = 0; LED7 = 0; LED8 = 0; LED9 = 1; LED10 = 1; LED11 = 1; LED12 = 1; LED13 = 1; LED14 = 1; LED15 = 1; break; case 5: LED5 = 0; LED6 = 0; LED7 = 0; LED8 = 0; LED9 = 0; LED10 = 1; LED11 = 1; LED12 = 1; LED13 = 1; LED14 = 1; LED15 = 1; break; case 6: LED5 = 0; LED6 = 0; LED7 = 0; LED8 = 0; LED9 = 0; LED10 = 0; LED11 = 1; LED12 = 1; LED13 = 1; LED14 = 1; LED15 = 1; break; case 7: LED5 = 0; LED6 = 0; LED7 = 0; LED8 = 0; LED9 = 0; LED10 = 0; LED11 = 0; LED12 = 1; LED13 = 1; LED14 = 1; LED15 = 1; break; case 8: LED5 = 0; LED6 = 0; LED7 = 0; LED8 = 0; LED9 = 0; LED10 = 0; LED11 = 0; LED12 = 0; LED13 = 1; LED14 = 1; LED15 = 1; break; case 9: LED5 = 0; LED6 = 0; LED7 = 0; LED8 = 0; LED9 = 0; LED10 = 0; LED11 = 0; LED12 = 0; LED13 = 0; LED14 = 1; LED15 = 1; break; case 10: LED5 = 0; LED6 = 0; LED7 = 0; LED8 = 0; LED9 = 0; LED10 = 0; LED11 = 0; LED12 = 0; LED13 = 0; LED14 = 0; LED15 = 1; break; case 11: LED5 = 0; LED6 = 0; LED7 = 0; LED8 = 0; LED9 = 0; LED10 = 0; LED11 = 0; LED12 = 0; LED13 = 0; LED14 = 0; LED15 = 0; break; default: LED5 = 0; LED6 = 0; LED7 = 0; LED8 = 0; LED9 = 0; LED10 = 0; LED11 = 0; LED12 = 0; LED13 = 0; LED14 = 0; LED15 = 0; break; } delay_ms(20); //任务调度 } } //按键检测任务 void keyG_task(void *pdata) { pdata=pdata; NVIC_InitTypeDef NVIC_InitStructure; while (1) { if (flag_Exit == 1) { NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;//外部中断4 NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;//使能外部中断通道 NVIC_Init(&NVIC_InitStructure);//配置 PB4_Num++; OSMboxPost(msg_TaskC, &PB4_Num); //发送邮箱消息 delay_ms(500); NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;//外部中断4 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道 NVIC_Init(&NVIC_InitStructure);//配置 flag_Exit = 0; } } } //外部中断4服务程序---由PB4下降沿触发 //中断服务程序不能调用可能会导致任务调度的函数 void EXTI4_IRQHandler(void) { OSIntEnter(); //进入中断处理 flag_Exit = 1; EXTI_ClearITPendingBit(EXTI_Line4);//清除LINE4上的中断标志位 OSIntExit(); //退出中断处理 } //定时器3中断服务函数 void TIM3_IRQHandler(void) { OSIntEnter(); //进入中断处理 if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断 { LED0=!LED0;//LED0翻转 taskA_Num++; } TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除中断标志位 OSIntExit(); //退出中断处理 }