|
最近在研究RT_Thread的源码,发现i2c驱动里有个地方使用的封装的技术,很少见,又感觉很是精妙。所以特意写个测试模拟程序,并贴上来和大家分享。
个人觉得它非常经典。它使用的模拟的i2c。代码如下:
#include "stdafx.h"
typedef signed int rt_int32_t;
typedef unsigned int rt_uint32_t;
struct rt_i2c_bit_ops
{
void *data; /* private data for lowlevel routines */
void (*set_sda)(void *data, rt_int32_t state);
void (*set_scl)(void *data, rt_int32_t state);
rt_int32_t (*get_sda)(void *data);
rt_int32_t (*get_scl)(void *data);
void (*udelay)(rt_uint32_t us);
rt_uint32_t delay_us; /* scl and sda line delay */
rt_uint32_t timeout; /* in tick */
};
//结构体功能函数的使用 它的精妙之处在这里,用宏把结构体函数使用起来
#define SET_SDA(ops, val) ops->set_sda(ops->data, val)
#define SET_SCL(ops, val) ops->set_scl(ops->data, val)
#define GET_SDA(ops) ops->get_sda(ops->data)
#define GET_SCL(ops) ops->get_scl(ops->data)
//结构体功能函数的使用
#define SDA_L(ops) SET_SDA(ops, 0)
#define SDA_H(ops) SET_SDA(ops, 1)
#define SCL_L(ops) SET_SCL(ops, 0)
//提供对外使用
inline void i2c_delay(struct rt_i2c_bit_ops *ops)
{
ops->udelay((ops->delay_us + 1) >> 1);
}
inline void i2c_delay2(struct rt_i2c_bit_ops *ops)
{
ops->udelay(ops->delay_us);
}
//以下为rt_i2c_bit_ops指针函数
void i2c_set_sda(void *data, rt_int32_t state)
{
if(state)
{
printf("sda->H\r\n");
}else
{
printf("sda->L\r\n");
}
}
void i2c_set_scl(void *data, rt_int32_t state)
{
if(state)
{
printf("scl->H\r\n");
}else
{
printf("scl->L\r\n");
}
}
rt_int32_t i2c_get_sda(void *data)
{
printf("sda return 1\r\n");
return 1;
}
rt_int32_t i2c_get_scl(void *data)
{
printf("scl return 1\r\n");
return 1;
}
void udelay(rt_uint32_t us)
{
printf("udelay %d us\r\n",us);
}
//以上为rt_i2c_bit_ops指针函数
//模拟i2c的其他信号可以类似i2c_restart一样调用
static void i2c_restart(struct rt_i2c_bit_ops *ops)
{
SDA_H(ops);
i2c_delay(ops);
SDA_L(ops);
i2c_delay(ops);
SCL_L(ops);
}
int main(int argc, char* argv[])
{
rt_i2c_bit_ops i2c_ops;
i2c_ops.data = (void *)0x88;
i2c_ops.delay_us = 5;
i2c_ops.udelay = udelay;
i2c_ops.get_scl = i2c_get_scl;
i2c_ops.get_sda = i2c_get_sda;
i2c_ops.set_scl = i2c_set_scl;
i2c_ops.set_sda = i2c_set_sda;
printf("==========TEST===========!\n");
以上设置完专门的i2c接口后,类似与i2c_restart这样的i2c发送和接收的业务逻辑函数基本上不用修改了,直接按不同的i2c接口传参即可完成i2c的功能。
i2c_restart(&i2c_ops);
return 0;
}
|
阿莫论坛20周年了!感谢大家的支持与爱护!!
如果天空是黑暗的,那就摸黑生存;
如果发出声音是危险的,那就保持沉默;
如果自觉无力发光,那就蜷伏于牆角。
但是,不要习惯了黑暗就为黑暗辩护;
也不要为自己的苟且而得意;
不要嘲讽那些比自己更勇敢的人。
我们可以卑微如尘土,但不可扭曲如蛆虫。
|