TMF单片机开发框架精简版入门


前言

        无论在面向过程,还是面向对象的开发过程中,都要借助自顶向下模块化思想,按照合适的粒度,把业务需求分解成若干功能单元,然后这些功能单元转化成函数以供调用。当业务比较简单,例如某个按键被按下,我们直接调用led_on(),这样做貌似很合理,但果真如此吗?我们再细想一下,会发现这样写耦合程度很高。按键扫描函数和LED功能函数通常在不同的文件中实现,如果前者直接调用后者,会出现文件功能强依赖,不利于代码复用。另外在某些场合,例如中断服务程序,执行时间要尽可能的短,以便单片机执行其它指令。假设在串口中断服务程序中,需要接收许多来自上位机不同的指令,不能直接调用太多外部函数,做过多耗时的操作。至少保证在下一次中断来临前必须退出中断,否则会导致数据丢失。如果设置某些状态位来对应不同的指令状态,然后在主程序的while循环中,轮询这些状态位,当状态置位时,我们就去执行某些指令或调用某个函数,这样代码耦合程度就大大降低了。事实上,好多小伙伴已经这样做了。

        那么问题来了,这些状态位该如何管理呢?如果搞很多变量保存状态,在while循环中进行判断,再加上函数调用,会造成main函数十分臃肿,如何优雅的实现呢?

一、Why TMF精简版?

        TMF精简版作为一个入门级功能框架,仅实现状态置位和轮询功能,没有时间片和应答交互等功能,对于业务简单的单片机程序来说已经足够了。本篇文章先以TMF精简版为例,来实现按键控制一个LED的亮和灭。TMF独立于任何单片机平台,精简版资源要求较低,51单片机都可能使用。

二、代码编写步骤

1.创建tmf_task_list.h

#ifndef TMF_TASK_LIST_H
#define	TMF_TASK_LIST_H


任务列表
typedef enum
{
	/
	Add Task Definition here
	All tasks are named as TMF_TASK_ModuleName_TaskActionName
	/
	//LED
	TMF_TASK_TURN_LED_ON=0,
    TMF_TASK_TURN_LED_OFF,


	/
	Do not Delete the TMF_TOTAL_TASKS here
	/
	TMF_TOTAL_TASKS  //任务总数,不要删除
} TMF_Task_List_t;

//执行结果
typedef enum
{
	TASK_EXE_NONE = 0, //未执行
	TASK_EXE_SUCCESS, //执行成功
	TASK_EXE_FAIL //执行失败
} Task_Exe_Result_t;

#endif	/* TMF_TASK_LIST_H */

        上面定义了TMF_TASK_TURN_LED_ON和TMF_TASK_TURN_LED_OFF两个任务,分别表示LED点亮和LED熄灭。可以根据实际情况进行增减,其它地方不要修改。

2.创建tmf.h

#ifndef TMF_H
#define	TMF_H
/
#include "tmf_task_list.h"

#define TMF_Task_ID_t uint16_t

/
typedef struct
{
	unsigned char needToExec; //执行状态
	unsigned char execResult; //执行结果
	void (*exeEntry)();  //函数入口
} TMF_data_t;


//
//定义TMF结构体数组
//
extern TMF_data_t tmf[TMF_TOTAL_TASKS];
//

//TMF初始化函数
void TMF_Init(void);
//TMF轮询函数
void TMF_Poll(void);


//
//TMF执行函数
//
void TMF_Executor(TMF_Task_ID_t TMF_Task_ID);


//
TMF状态检查函数 IN: TMF_Task_ID
//
void TMF_Checker(TMF_Task_ID_t TMF_Task_ID);

//
TMF状态清除函数 IN: TMF_Task_ID
//
void TMF_Cleaner(TMF_Task_ID_t TMF_Task_ID);

//
TMF任务唤醒函数 IN: TMF_Task_ID
//
void TMF_ExeEvoker(TMF_Task_ID_t TMF_Task_ID);

//
//TMF设置执行结果 IN: TMF_Task_ID
//
void TMF_SetExeResult(TMF_Task_ID_t TMF_Task_ID, unsigned char ExeResult);


#endif	/* TMF_H */

3.创建tmf.c

#include "tmf.h"

//TMF初始化函数
void TMF_Init(void)
{
	TMF_Task_ID_t i;


    ///
    TMF Nodes init
    ///
	for (i = 0; i < TMF_TOTAL_TASKS; i++)
	{
		tmf[i].needToExec = FALSE;
		tmf[i].execResult = TASK_EXE_NONE;
		tmf[i].exeEntry = NULL;
	}
}

//TMF轮询函数
void TMF_Poll(void)
{
	TMF_Task_ID_t i;
	for (i = 0; i < TMF_TOTAL_TASKS; i++)
	{
		if (tmf[i].needToExec == TRUE)
		{
			TMF_Checker(i);
		}
	}
}

//
//TMF执行函数 IN: TMF_Task_ID
//
void TMF_Executor(TMF_Task_ID_t TMF_Task_ID)
{
    if(tmf[TMF_Task_ID].exeEntry!=NULL)
    {
        tmf[TMF_Task_ID].exeEntry();
    }
}

//
TMF任务检查 IN: TMF_Task_ID
//
void TMF_Checker(TMF_Task_ID_t TMF_Task_ID)
{

	if (tmf[TMF_Task_ID].execResult == TASK_EXE_SUCCESS)
	{
		TMF_Cleaner(TMF_Task_ID);
	}

	else if (tmf[TMF_Task_ID].needToExec == TRUE)
	{
		TMF_Executor(TMF_Task_ID);
	}
}
//
//TMF任务清除 IN: TMF_Task_ID
//
void TMF_Cleaner(TMF_Task_ID_t TMF_Task_ID)
{
	tmf[TMF_Task_ID].needToExec = FALSE;
	tmf[TMF_Task_ID].execResult = TASK_EXE_NONE;
}
//
//TMF任务唤醒 IN: TMF_Task_ID
//
void TMF_ExeEvoker(TMF_Task_ID_t TMF_Task_ID)
{
	tmf[TMF_Task_ID].needToExec = TRUE;
}

//
//TMF任务结果
//IN: TMF_Task_ID
//
void TMF_SetExeResult(TMF_Task_ID_t TMF_Task_ID, unsigned char ExeResult)
{
	tmf[TMF_Task_ID].execResult = ExeResult;
}

4.创建key.h

#ifndef  __KEY_H
#define  __KEY_H

#include "tmf_task_list.h"
#include "tmf.h"

typedef struct
{
	unsigned char key_status;//按键状态
	unsigned char enter_times;//进入次数
    unsigned char led_status;//灯状态位
}Key_Data_t;

typedef enum 
{
    KEY_STATUS_PRESSED=0,
    KEY_STATUS_RELEASED
}Key_Status_t;

typedef enum
{
    LED_STATUS_ON=0,
    LED_STATUS_OFF
}Led_Status_t;

//按键检测间隔 ms
//需要结合定时器,本示例没有用
#define KEY_DETECT_DELAY  20

//读取按键,请修改成具体单片机的端口
#define READ_KEY RA5


extern Key_Data_t key;

void Key_Init(void);

void Key_Scan(void);


#endif

5.创建key.c

#include "key.h"

void Key_Init(void)
{
    //按键端口初始化为输入
    //to do

    //假设按下为低电平,上拉使能或使用外部上拉电阻
    //to do

    key.key_status=KEY_STATUS_RELEASED;
    key.led_status=LED_STATUS_OFF;
}

void Key_Scan(void)
{
    //假设按下为低电平
    if(READ_KEY==0)
    {
        if(key.key_status==KEY_STATUS_RELEASED)//防抖处理
        {
            key.key_status=KEY_STATUS_PRESSED;
            key.enter_times=1;
        }
        else if(key.key_status==KEY_STATUS_PRESSED)
        {
            key.enter_times++;
            if(key.enter_times==2)
            {
                if(key.led_status==LED_STATUS_OFF)
                {
                    key.led_status=LED_STATUS_ON;
                    //唤醒任务
                    TMF_ExeEvoker(TMF_TASK_TURN_LED_ON);
                }
                else if(key.led_status==LED_STATUS_ON)
                {
                    key.led_status=LED_STATUS_OFF;
                    //唤醒任务
                    TMF_ExeEvoker(TMF_TASK_TURN_LED_OFF);
                }
            }
        }

    }
    else
    {
        key.key_status=KEY_STATUS_RELEASED;
    }
}

6.创建led.h

#ifndef __LED_H
#define __LED_H

//包含必要的头文件
//#include <...> 

void led_init(void);

void led_on(void);

void led_off(void);


#endif

7.创建led.c

#include "led.h"

void led_init(void)
{
    //端口初始化为输出
    //设置初始电平,使灯关闭
}

void led_on(void)
{
    //改变引脚电平,使灯亮
}

void led_off(void)
{
    //改变引脚电平,使灯灭
}

8.创建tmf_led_init.h

#ifndef __TMF_LED_INIT_H
#define __TMF_LED_INIT_H
//
#include "tmf_task_list.h"
#include "tmf.h"
#include "led.h"
//

void tmf_led_init(void);

void tmf_led_on(void);

void tmf_led_off(void);


#endif

9.创建tmf_led.init.c

#include "tmf_led_init.h"

void tmf_led_init(void)
{
    tmf[TMF_TASK_TURN_LED_ON].exeEntry=tmf_led_on;

    tmf[TMF_TASK_TURN_LED_OFF].exeEntry=tmf_led_off;
}

void tmf_led_on(void)
{
    led_on();
    TMF_SetExeResult(TMF_TASK_TURN_LED_ON,TASK_EXE_SUCCESS);
}

void tmf_led_off(void)
{
    led_off();
    TMF_SetExeResult(TMF_TASK_TURN_LED_OFF,TASK_EXE_SUCCESS);
}

10.修改tmf.h

        在#include "tmf_task_list.h" 下面增加#include "tmf_led_init.h"。

11.修改tmf.c

//TMF初始化函数
void TMF_Init(void)
{
	TMF_Task_ID_t i;


    ///
    TMF Nodes init
    ///
	for (i = 0; i < TMF_TOTAL_TASKS; i++)
	{
		tmf[i].needToExec = FALSE;
		tmf[i].execResult = TASK_EXE_NONE;
		tmf[i].exeEntry = NULL;
	}

    //新增初始化代码
    tmf_led_init();
}

12.创建main.h

#ifndef __MAIN_H
#define __MAIN_H



#include "tmf_task_list.h"
#include "tmf.h"

#include "key.h"
#include "led.h"

Key_Data_t key;

//
#endif

13.创建main.c

#include "main.h"


void main(void)
{
    TMF_Init();
    Key_init();
    led_init();

    while(1)
    {
        TMF_Poll();//轮询
        Key_Scan();//按键扫描
    }

}


总结

    以上就是今天要讲的内容,本文仅仅简单介绍了TMF简化版的使用,请大家根据实际平台作必要修改。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值