用结构体把驱动层和应用层分开

用正点原子代码的usmart分析,如下:

usmart.h

usmart_config.c 实例:把结构体与具体驱动绑定一起

/*
正点原子的usmart串口的封装
涉及文件:usmart.h usmart.c usmart_config.c 还有外面使用的文件(应用层调用)

底层驱动的实现都在usmart.h usmart.c实现的,也就是具体的代码实现层都在这里
//---------------------------------------------------------------------------
usmart.h做的个事情
1、把驱动抽象,把具体实现的代码以结构体的方式抽象成接口;

typedef struct 
{
    void (*init)(u8);//init属性
    void (*show)(void);//show属性
}lcd_dev;

2、声明实体(因为实体在usmart_config.c定义,因为没有usmart_config.h,应用层只包含usmart.h);
extern lcd_dev demo实例;

3、声明usmart.c具体实现的函数(由于具体实现代码在usmart.c,但是实例在usmart_config.c,也就是usmart_config.c会调用usmart.c的函数)

void Myinit(u8 data);//具体实现
void Myshow(void);

//---------------------------------------------------------------------------
usmart.c把具体的设备的驱动实现了,也就是它是实实在在一个一个函数
例如:它具体实现 void Myshow(void);但是结构体是抽象为show:void (*show)(void);它不关心是谁的show

void Myinit(u8 data)
{
    具体实现细节
}
void Myshow(u8 data)
{
    具体实现细节
}
//---------------------------------------------------------------------------
总结:usmart.h的lcd_dev和usmart.c里面的实现函数,目前看没有半毛钱关系;
usmart.c里面实现的函数是实实在在只关注硬件驱动的事情。
//---------------------------------------------------------------------------
usmart_config.c
定义一个实体,并且把他的函数功能与usmart.c具体实现的函数,绑定在一起

lcd_dev demo实例
{
    .init = Myinit,//Myinit在
    .show = Myshow,
} 
有个疑问?usmart_config.c是不是可以省掉,lcd_dev demo实例可以在usmart.c实现

//---------------------------------------------------------------------------
为什么说会有分层的效果呢?
因为应用层只调用结构体的属性名字,如 demo实例.show;(当然事先应用层要先声明(extern lcd_dev demo实例))
外面调用的都是  demo实例.属性   以这种方式调用。只要具体的实例名称+抽象结构体属性的名字。
即外面可以写的天花乱坠,只要是demo实例.属性的调用方式

*/
//-------------------------------------------------------------------------
 /*usmart.h*/
 //以结构体的方式 抽象出设备的函数功能,应用层是这样调用的:具体设备名.exe、具体设备名.scan,应用的要包含实体的声明
 struct _m_usmart_dev
{
	struct _m_usmart_nametab *funs;	//函数名指针

	void (*init)(u8);				//初始化
	u8 (*cmd_rec)(u8*str);			//识别函数名及参数
	void (*exe)(void); 				//执行 
	void (*scan)(void);             //扫描
	u8 fnum; 				  		//函数数量
	u8 pnum;                        //参数数量
	u8 id;							//函数id
	u8 sptype;						//参数显示类型(非字符串参数):0,10进制;1,16进制;
	u16 parmtype;					//参数的类型
	u8  plentbl[MAX_PARM];  		//每个参数的长度暂存表
	u8  parm[PARM_LEN];  			//函数的参数
	u8 runtimeflag;					//0,不统计函数执行时间;1,统计函数执行时间,注意:此功能必须在USMART_ENTIMX_SCAN使能的时候,才有用
	u32 runtime;					//运行时间,单位:0.1ms,最大延时时间为定时器CNT值的2倍*0.1ms
};

extern struct _m_usmart_dev usmart_dev;				//在usmart_config.c里面定义

void usmart_init(u8 sysclk);//初始化
u8 usmart_cmd_rec(u8*str);	//识别
void usmart_exe(void);		//执行
void usmart_scan(void);     //扫描
u32 read_addr(u32 addr);	//读取指定地址的值
void write_addr(u32 addr,u32 val);//在指定地址写入指定的值
u32 usmart_get_runtime(void);	//获取运行时间
void usmart_reset_runtime(void);//复位运行时间


//-------------------------------------------------------------------------
/*usmart_config.c*/
struct _m_usmart_dev usmart_dev=
{
	usmart_nametab,
	usmart_init,
	usmart_cmd_rec,
	usmart_exe,
	usmart_scan,
	sizeof(usmart_nametab)/sizeof(struct _m_usmart_nametab),//函数数量
	0,	  	//参数数量
	0,	 	//函数ID
	1,		//参数显示类型,0,10进制;1,16进制
	0,		//参数类型.bitx:,0,数字;1,字符串	    
	0,	  	//每个参数的长度暂存表,需要MAX_PARM个0初始化
	0,		//函数的参数,需要PARM_LEN个0初始化
};

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值