华为LiteOS_任务挂起与恢复_面向对象编程思想之按键状态机
???????因为在做华为LiteOS任务挂起和恢复需要使用到按键去触发任务挂起和恢复动作,因为我就萌发出使用状态机这种架构做一个按键检测触发。回想已经也做过按键状态机,不过因为那时候是在裸机上做的按键状态机,比较简单,只有按下和释放功能,而且是单个按键检测的。 ???????这里我借此实验机会使用面向对象的编程思想设计一个可按用户按键个数的按键状态机。面向对象思想可以是驱动程序适合在多种平台快速移植开发,可读性高。 ???????状态机是一个抽象概念,表示把一个过程抽象为若干个状态之间的切换,这些状态之间存在一定的联系。状态机的设计主要包括4个要素: ①现态:是指当前所处的状态。 ②条件:当一个条件满足,将会触发一个动作,或者执行一次状态的迁移。 ③动作:表示条件满足后执行动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作要素不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。 ④次态:表示条件满足后要迁往的新状态。 ???????从上面解释可以清晰地知道,保存当前状态,判断条件是否满足,设置相应的动作标志(这是用于实际的事件触发的),然后将当前状态通过上面的条件判断设置到相应的下一个状态。 ???????这里我还提供了程序框图让大家参考,应该能解决大家对“有按键状态了,为什么还需要按键事件”这个问题,其实就是按键状态状态机循环扫描按键状态的根本,而按键事件时在按键状态中触发的动作。(按键实际状态只有:初始未按下态、按下态、长按态、释放态)
???????LiteOS 系统中的每一个任务都有多种运行状态,它们之间的转换称为任务状态迁移。如下图所示。 这里亮代码让大家理解了。 key.h
#ifndef __KEY_H
#define __KEY_H
#include "stm32f10x.h"
#include "usart1.h"
#define KEY_UP_GPIO_CLK RCC_APB2Periph_GPIOA
#define KEY_UP_GPIO_PORT GPIOA
#define KEY_UP_GPIO_PIN GPIO_Pin_0
#define KEY0_GPIO_CLK RCC_APB2Periph_GPIOE
#define KEY0_GPIO_PORT GPIOE
#define KEY0_GPIO_PIN GPIO_Pin_4
#define KEY1_GPIO_CLK RCC_APB2Periph_GPIOE
#define KEY1_GPIO_PORT GPIOE
#define KEY1_GPIO_PIN GPIO_Pin_3
#define KEY2_GPIO_CLK RCC_APB2Periph_GPIOE
#define KEY2_GPIO_PORT GPIOE
#define KEY2_GPIO_PIN GPIO_Pin_2
typedef enum {
KEY_NULL = 0,
KEY_WAIT_CONFIRM_DOWN,
KEY_CONFIRN_DOWN,
KEY_LONG_DOWN,
KEY_UP,
}Key_State_List;
typedef enum {
KEYUP = 0,
KEY0,
KEY1,
KEY2,
KEY_CLASS_NUM,
}Key_Class;
typedef struct {
uint32_t RCC_APB2Periph_GPIOx;
GPIO_TypeDef* GPIOx;
uint16_t GPIO_Pin_x;
GPIOMode_TypeDef GPIO_Mode;
}Key_Init;
typedef struct {
FunctionalState Key_Use_State;
BitAction Key_Press_Level;
BitAction Key_Current_Level;
uint8_t Key_Count;
Key_State_List Key_State;
Key_State_List Key_Event;
BitAction (* Read_Pin_Level)(Key_Init KeyInit);
}Key_State_Machine;
typedef struct {
Key_Init Key_Init;
Key_State_Machine Key_State_Machine;
}Key_Config;
#define Key_Long_Pree_Time 47
extern Key_Config KEY_CLASS[KEY_CLASS_NUM];
void Key_Config_parameter(void);
void Read_Key_State(void);
#endif
key.c
#include "key.h"
Key_Config KEY_CLASS[KEY_CLASS_NUM];
static BitAction Key_Read_Pin_Level(Key_Init KeyInit) {
return (BitAction)GPIO_ReadInputDataBit(KeyInit.GPIOx,KeyInit.GPIO_Pin_x);
}
void Creat_Key(Key_Init* KeyInit) {
uint8_t i;
GPIO_InitTypeDef GPIO_InitStructure;
for(i=0;i<KEY_CLASS_NUM;i++) {
KEY_CLASS[i].Key_Init = *(KeyInit+i);
RCC_APB2PeriphClockCmd(KEY_CLASS[i].Key_Init.RCC_APB2Periph_GPIOx,ENABLE);
GPIO_InitStructure.GPIO_Pin = KEY_CLASS[i].Key_Init.GPIO_Pin_x;
GPIO_InitStructure.GPIO_Mode = KEY_CLASS[i].Key_Init.GPIO_Mode;
GPIO_Init(KEY_CLASS[i].Key_Init.GPIOx,&GPIO_InitStructure);
KEY_CLASS[i].Key_State_Machine.Key_Use_State = ENABLE;
KEY_CLASS[i].Key_State_Machine.Key_Count = 0;
KEY_CLASS[i].Key_State_Machine.Key_Current_Level = Bit_RESET;
KEY_CLASS[i].Key_State_Machine.Key_State = KEY_NULL;
KEY_CLASS[i].Key_State_Machine.Read_Pin_Level = Key_Read_Pin_Level;
if(KEY_CLASS[i].Key_Init.GPIO_Mode == GPIO_Mode_IPD) {
KEY_CLASS[i].Key_State_Machine.Key_Press_Level = Bit_SET;
} else {
KEY_CLASS[i].Key_State_Machine.Key_Press_Level = Bit_RESET;
}
}
}
void Key_Config_parameter(void) {
Key_Init KeyInit[KEY_CLASS_NUM] = {
{KEY_UP_GPIO_CLK,KEY_UP_GPIO_PORT,KEY_UP_GPIO_PIN,GPIO_Mode_IPD},
{KEY0_GPIO_CLK,KEY0_GPIO_PORT,KEY0_GPIO_PIN,GPIO_Mode_IPU},
{KEY1_GPIO_CLK,KEY1_GPIO_PORT,KEY1_GPIO_PIN,GPIO_Mode_IPU},
{KEY2_GPIO_CLK,KEY2_GPIO_PORT,KEY2_GPIO_PIN,GPIO_Mode_IPU},
};
Creat_Key(KeyInit);
}
static void Get_Key_Level(void)
{
uint8_t i;
for(i=0;i<KEY_CLASS_NUM;i++) {
if(KEY_CLASS[i].Key_State_Machine.Key_Use_State==DISABLE) {
continue;
}
if(KEY_CLASS[i].Key_State_Machine.Read_Pin_Level(KEY_CLASS[i].Key_Init)==KEY_CLASS[i].Key_State_Machine.Key_Press_Level) {
KEY_CLASS[i].Key_State_Machine.Key_Current_Level = Bit_SET;
} else {
KEY_CLASS[i].Key_State_Machine.Key_Current_Level = Bit_RESET;
}
}
}
void Read_Key_State(void) {
uint8_t i;
Get_Key_Level();
for(i=0;i<KEY_CLASS_NUM;i++) {
switch(KEY_CLASS[i].Key_State_Machine.Key_State) {
case KEY_NULL:
if(KEY_CLASS[i].Key_State_Machine.Key_Current_Level==Bit_SET) {
KEY_CLASS[i].Key_State_Machine.Key_State = KEY_WAIT_CONFIRM_DOWN;
KEY_CLASS[i].Key_State_Machine.Key_Event = KEY_NULL;
} else {
KEY_CLASS[i].Key_State_Machine.Key_Event = KEY_NULL;
}
break;
case KEY_WAIT_CONFIRM_DOWN:
if(KEY_CLASS[i].Key_State_Machine.Key_Current_Level==Bit_SET) {
KEY_CLASS[i].Key_State_Machine.Key_State = KEY_CONFIRN_DOWN;
KEY_CLASS[i].Key_State_Machine.Key_Event = KEY_CONFIRN_DOWN;
KEY_CLASS[i].Key_State_Machine.Key_Count = 0;
} else {
KEY_CLASS[i].Key_State_Machine.Key_State = KEY_NULL;
KEY_CLASS[i].Key_State_Machine.Key_Event = KEY_NULL;
}
break;
case KEY_CONFIRN_DOWN:
if(KEY_CLASS[i].Key_State_Machine.Key_Current_Level!=Bit_SET) {
KEY_CLASS[i].Key_State_Machine.Key_State = KEY_NULL;
KEY_CLASS[i].Key_State_Machine.Key_Event = KEY_UP;
} else if((KEY_CLASS[i].Key_State_Machine.Key_Current_Level==Bit_SET) && (++KEY_CLASS[i].Key_State_Machine.Key_Count>=Key_Long_Pree_Time)){
KEY_CLASS[i].Key_State_Machine.Key_State = KEY_LONG_DOWN;
KEY_CLASS[i].Key_State_Machine.Key_Event = KEY_LONG_DOWN;
KEY_CLASS[i].Key_State_Machine.Key_Count = 0;
} else {
KEY_CLASS[i].Key_State_Machine.Key_Event = KEY_NULL;
}
break;
case KEY_LONG_DOWN:
if(KEY_CLASS[i].Key_State_Machine.Key_Current_Level!=Bit_SET) {
KEY_CLASS[i].Key_State_Machine.Key_State = KEY_NULL;
KEY_CLASS[i].Key_State_Machine.Key_Event = KEY_UP;
} else if(KEY_CLASS[i].Key_State_Machine.Key_Current_Level==Bit_SET) {
KEY_CLASS[i].Key_State_Machine.Key_Event = KEY_LONG_DOWN;
++KEY_CLASS[i].Key_State_Machine.Key_Count;
}
break;
default:
break;
}
}
}
main.c
#include "stm32f10x.h"
#include "los_sys.h "
#include "los_typedef.h"
#include "los_task.ph"
#include "led.h"
#include "usart1.h"
#include "key.h"
UINT32 Test1_Task_Handle;
UINT32 Test2_Task_Handle;
UINT32 Key_Task_Handle;
static UINT32 AppTaskCreate(void);
static UINT32 Creat_Test1_Task(void);
static UINT32 Creat_Test2_Task(void);
static UINT32 Creat_Key_Task(void);
static void Test1_Task(void);
static void Test2_Task(void);
static void Key_Task(void);
int main(void)
{
UINT32 uwRet = LOS_OK;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
Usart1_Config();
LED_GPIO_Config();
Key_Config_parameter();
printf("KEYUP = %d\r\n",KEY_CLASS[KEYUP].Key_Init.GPIO_Pin_x);
printf("KEY0 = %d\r\n",KEY_CLASS[KEY0].Key_Init.GPIO_Pin_x);
printf("KEY1 = %d\r\n",KEY_CLASS[KEY1].Key_Init.GPIO_Pin_x);
printf("KEY2 = %d\r\n",KEY_CLASS[KEY2].Key_Init.GPIO_Pin_x);
printf("正点原子战舰开发板-LiteOS-SRAM 动态创建多任务!\r\n\r\n");
uwRet = LOS_KernelInit();
if (uwRet != LOS_OK) {
printf("LiteOS核心初始化失败!任务代码0X%X\r\n",uwRet);
return LOS_NOK;
}
uwRet = AppTaskCreate();
if (uwRet != LOS_OK) {
printf("AppTaskCreate任务创建失败!任务代码0X%X\r\n",uwRet);
return LOS_NOK;
}
LOS_Start();
while(1){
GPIO_SetBits(GPIOB, GPIO_Pin_5);
GPIO_SetBits(GPIOE,GPIO_Pin_5);
}
}
static UINT32 AppTaskCreate(void)
{
UINT32 uwRet = LOS_OK;
uwRet = Creat_Test1_Task();
if (uwRet != LOS_OK) {
printf("Test1_Task任务创建失败!失败代码0X%X\r\n",uwRet);
return uwRet;
}
uwRet = Creat_Test2_Task();
if (uwRet != LOS_OK) {
printf("Test2_Task任务创建失败!失败代码0X%X\r\n",uwRet);
return uwRet;
}
uwRet = Creat_Key_Task();
if (uwRet != LOS_OK) {
printf("Key_Task 任务创建失败!失败代码0X%X\r\n",uwRet);
return uwRet;
}
return LOS_OK;
}
static UINT32 Creat_Test1_Task()
{
UINT32 uwRet = LOS_OK;
TSK_INIT_PARAM_S task_init_param;
task_init_param.usTaskPrio = 5;
task_init_param.pcName = "Test1_Task";
task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)Test1_Task;
task_init_param.uwStackSize = 1024;
uwRet = LOS_TaskCreate(&Test1_Task_Handle, &task_init_param);
return uwRet;
}
static UINT32 Creat_Test2_Task()
{
UINT32 uwRet = LOS_OK;
TSK_INIT_PARAM_S task_init_param;
task_init_param.usTaskPrio = 4;
task_init_param.pcName = "Test2_Task";
task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)Test2_Task;
task_init_param.uwStackSize = 1024;
uwRet = LOS_TaskCreate(&Test2_Task_Handle, &task_init_param);
return uwRet;
}
static UINT32 Creat_Key_Task() {
UINT32 uwRet = LOS_OK;
TSK_INIT_PARAM_S task_init_param;
task_init_param.usTaskPrio = 3;
task_init_param.pcName = "Key_Task";
task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)Key_Task;
task_init_param.uwStackSize = 1024;
uwRet = LOS_TaskCreate(&Key_Task_Handle,&task_init_param);
return uwRet;
}
static void Test1_Task(void) {
int i = 0;
while(1) {
if(i%2==0) {
GPIO_ResetBits(GPIOB, GPIO_Pin_5);
} else {
GPIO_SetBits(GPIOB, GPIO_Pin_5);
}
printf("任务1---1000ms\r\n");
i++;
if(i>100) i=0;
LOS_TaskDelay(1000);
}
}
static void Test2_Task(void) {
int i = 0;
while(1) {
if(i%2==0) {
GPIO_SetBits(GPIOE,GPIO_Pin_5);
} else {
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
}
printf("任务2---500ms\r\n");
i++;
if(i>100) i=0;
LOS_TaskDelay(500);
}
}
static void Key_Task(void) {
UINT32 uwRet = LOS_OK;
UINT8 i,trigger_state;
UINT32 j=0;
while(1) {
Read_Key_State();
for(i=0;i<KEY_CLASS_NUM;i++) {
trigger_state = KEY_CLASS[i].Key_State_Machine.Key_Event;
if((trigger_state==KEY_CONFIRN_DOWN) && (i==KEYUP)) {
printf("挂起LED_Test2_Task 任务!\r\n");
uwRet = LOS_TaskSuspend(Test2_Task_Handle);
if (uwRet == LOS_OK) {
printf("挂起LED_Test2_Task 任务成功!\r\n");
}
}
if((trigger_state==KEY_CONFIRN_DOWN) && (i==KEY0)) {
printf("恢复 LED_Test2_Task 任务!\r\n");
uwRet = LOS_TaskResume(Test2_Task_Handle);
if (uwRet == LOS_OK) {
printf("恢复 LED_Test2_Task 任务成功!\r\n");
}
}
if((trigger_state==KEY_LONG_DOWN) && (i==KEY1) && (KEY_CLASS[i].Key_State_Machine.Key_Count>=0)) {
KEY_CLASS[i].Key_State_Machine.Key_Count--;
++j;
printf("count = %d\r\n",j);
} else if((trigger_state==KEY_UP) && (i==KEY1)) {
j = 0;
}
}
LOS_TaskDelay(20);
}
}
实验现象如下图所示。 小编能力有限,希望大家多多体谅,大家一起相互学习探讨。 工程文件包:华为LiteOS任务挂起和恢复及按键状态机
|