使用RT Thread设备框架封装一个I2C设备——DS3231

使用RT Thread设备框架封装一个I2C设备——DS3231

    • 前言
    • ENV配置
    • I2C测试
    • 将ds3231封装成一个字符设备
    • 结语

前言

学习rt thread的I2C的时候,恰巧手上的板子留了ds3231的位置,说起这个时钟芯片也是和我源远流长了,从51到stm32裸机,都是用GPIO和延时来模拟I2C的(体感上比另一款时钟芯片ds1302要准很多,所以从51过渡到M3还是选了它),因为比较熟悉,就先用它试一下RT Thread的I2C。

ENV配置

首先我是用ENV生成keil工程的,我这边是在board文件夹下的Kconfig里menu "On-chip Peripheral Drivers"下添加了如下这段(有就不用添加了)
menuconfig BSP_USING_I2C1
bool “Enable I2C1 BUS (software simulation)”
default y
select RT_USING_I2C
select RT_USING_I2C_BITOPS
select RT_USING_PIN
if BSP_USING_I2C1
config BSP_I2C1_SCL_PIN
int “i2c1 scl pin number”
range 0 99
default 24
config BSP_I2C1_SDA_PIN
int “I2C1 sda pin number”
range 0 99
default 25
endif

然后env里输入menuconfig在RT-Thread Components—>Device Drivers里如下选择:
使用RT Thread设备框架封装一个I2C设备——DS3231_第1张图片
使用RT Thread设备框架封装一个I2C设备——DS3231_第2张图片我这边板子是自己画的,scl和sda分别是PB7和PB8,在drv_gpio.c里可以看到:
使用RT Thread设备框架封装一个I2C设备——DS3231_第3张图片
按照这个选择两个io的引脚号,最后scons --target=mdk5重新生成一下工程。

I2C测试

这里只是验证一下rtt的iic框架是否能使用,只编写了读的代码,并在程序里读“秒”来做验证。注意ds3231是七位地址的,flags里选了RT_I2C_WR或RT_I2C_RD会自动帮你将3231的器件地址移位补最后一位(读或写),如果RT_I2C_NO_START选上的话就不会发送地址位,也就是addr写不写都一样了,直接发送buf里的数值。

#include "app_ds3231.h"

#define DS3231_BUS_NAME          "i2c1"  /* 传感器连接的I2C总线设备名称 */

static struct rt_i2c_bus_device *i2c_bus = RT_NULL;     /* I2C总线设备句柄 */
static rt_bool_t initialized = RT_FALSE;                /* 传感器初始化状态 */

/* 读传感器寄存器数据 */
static rt_err_t read_regs(struct rt_i2c_bus_device *bus, rt_uint8_t reg, rt_uint8_t len, void *buffer)
{
	  rt_err_t ret=RT_EOK;
    struct rt_i2c_msg msgs[2];
    rt_uint8_t mem_addr[2] = {0,0};

		/*写入寻址地址*/
	  msgs[0].addr = DS3231_Address;
		msgs[0].flags = RT_I2C_WR/*|RT_I2C_NO_START*/;
		mem_addr[0] = (rt_uint8_t) reg;
		msgs[0].buf  = (rt_uint8_t *) mem_addr;
    msgs[0].len  =  1;
		
		msgs[1].addr = DS3231_Address;
    msgs[1].flags = RT_I2C_RD/*|RT_I2C_NO_START*/;
    msgs[1].buf = (rt_uint8_t *)buffer;
    msgs[1].len = len;

    /* 调用I2C设备接口传输数据 */
		ret=rt_i2c_transfer(bus, msgs, 2);
//		rt_thread_mdelay(500);
//		rt_kprintf("ret=%d.\n",ret);
    if (ret == 2)
    {
        return RT_EOK;
    }
    else
    {
			  rt_kprintf("read error.\n");
        return -RT_ERROR;
    }
}
 
static uint8_t BCD2HEX(uint8_t val)   
{
    uint8_t temp;
    temp=val&0x0f;
    val>>=4;
    val&=0x0f;
    val*=10;
    temp+=val; 
    return temp;
}

static void DS3231ReadTime(void)
{
	rt_err_t ret=RT_EOK;
	uint8_t date;
	uint8_t sec=0;

	ret=read_regs(i2c_bus,DS3231_SECOND,1,&date);
	sec=BCD2HEX(date);
	rt_kprintf("sec=%d.\n", (int)sec);
}


static void ds3231_init(const char *name)
{
    /* 查找I2C总线设备,获取I2C总线设备句柄 */
    i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(name);

    if (i2c_bus == RT_NULL)
    {
        rt_kprintf("can't find %s device!\n", name);
    }
    else
    {
        initialized = RT_TRUE;
//			rt_device_open(, RT_DEVICE_FLAG_RDWR);
    }
}

static void ds3231_sample(int argc, char *argv[])
{
    char name[RT_NAME_MAX];

    if (argc == 2)
    {
        rt_strncpy(name, argv[1], RT_NAME_MAX);
    }
    else
    {
        rt_strncpy(name, DS3231_BUS_NAME, RT_NAME_MAX);
    }

    if (!initialized)
    {
        /* 传感器初始化 */
        ds3231_init(name);
    }
    if (initialized)
    {
        /* 读取数据 */
        DS3231ReadTime();
    }
    else
    {
        rt_kprintf("initialize sensor failed!\n");
    }
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(ds3231_sample, ds3231_sample);

头文件里是这样的

#ifndef __APP_DS3231_H__
#define __APP_DS3231_H__

#include 
#include "board.h"
#include 
#include "drv_soft_i2c.h"

#define DS3231_Address      0x68 
#define DS3231_WriteAddress 0xD0    //器件写地址 
#define DS3231_ReadAddress  0xD1    //器件读地址
#define DS3231_SECOND       0x00    //秒
#define DS3231_MINUTE       0x01    //分
#define DS3231_HOUR         0x02    //时
#define DS3231_WEEK         0x03    //星期
#define DS3231_DAY          0x04    //日
#define DS3231_MONTH        0x05    //月
#define DS3231_YEAR         0x06    //年
//闹铃1            
#define DS3231_SALARM1ECOND 0x07    //秒
#define DS3231_ALARM1MINUTE 0x08    //分
#define DS3231_ALARM1HOUR   0x09    //时
#define DS3231_ALARM1WEEK   0x0A    //星期/日
//闹铃2
#define DS3231_ALARM2MINUTE 0x0b    //分
#define DS3231_ALARM2HOUR   0x0c    //时
#define DS3231_ALARM2WEEK   0x0d    //星期/日
#define DS3231_CONTROL      0x0e    //控制寄存器
#define DS3231_STATUS       0x0f    //状态寄存器
#define BSY                 2       //忙
#define OSF                 7       //振荡器停止标志
#define DS3231_XTAL         0x10    //晶体老化寄存器
#define DS3231_TEMPERATUREH 0x11    //温度寄存器高字节(8位)
#define DS3231_TEMPERATUREL 0x12    //温度寄存器低字节(高2位) 

#endif

用逻辑分析仪抓到的结果,读取一个数值不超过1ms.
使用RT Thread设备框架封装一个I2C设备——DS3231_第4张图片控制台里调用程序输出的结果:
使用RT Thread设备框架封装一个I2C设备——DS3231_第5张图片
完全OK.

将ds3231封装成一个字符设备

实现了读写功能,其他的暂时用不到就没写了。初始化的时候写入一个设定值,然后读取年月日时分秒打印出来。

#include "app_ds3231.h"


#define DS3231_I2C_BUS_NAME          "i2c1"  /* 传感器连接的I2C总线设备名称 */

static struct rt_i2c_bus_device *i2c_bus = RT_NULL;     /* I2C总线设备句柄 */
static rt_bool_t initialized = RT_FALSE;                /* 传感器初始化状态 */

static uint8_t BCD2HEX(uint8_t val)   
{
    uint8_t temp;
    temp=val&0x0f;
    val>>=4;
    val&=0x0f;
    val*=10;
    temp+=val; 
    return temp;
}

static uint8_t HEX2BCD(uint8_t val)    
{
    uint8_t i,j,k;
    i=val/10;
    j=val%10;
    k=j+(i<<4);
    return k;
}

/**设备结构体 */
struct ds3231_device
{
    struct rt_device         parent;
    struct rt_i2c_bus_device *bus;
};

/* RT-Thread device interface */
static rt_err_t ds3231_init(rt_device_t dev)
{
    return RT_EOK;
}

static rt_err_t ds3231_open(rt_device_t dev, rt_uint16_t oflag)
{
    return RT_EOK;
}

static rt_err_t ds3231_close(rt_device_t dev)
{
    return RT_EOK;
}

static rt_err_t ds3231_control(rt_device_t dev, int cmd, void *args)
{
    return RT_EOK;
}

static rt_size_t ds3231_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
	  rt_err_t ret=RT_EOK;
	  struct ds3231_device *ds3231;
    struct rt_i2c_msg msgs[2];
    rt_uint8_t mem_addr[2] = {0,0};
		RT_ASSERT(dev != 0);
    
		ds3231 = (struct ds3231_device *) dev;
		/*写入寻址地址*/
	  msgs[0].addr = DS3231_Address;
		msgs[0].flags = RT_I2C_WR;
		mem_addr[0] = (rt_uint8_t) pos;
		msgs[0].buf  = (rt_uint8_t *) mem_addr;
    msgs[0].len  =  1;
		
		msgs[1].addr = DS3231_Address;
    msgs[1].flags = RT_I2C_RD;
    msgs[1].buf = (rt_uint8_t *)buffer;
    msgs[1].len = 1;

    /* 调用I2C设备接口传输数据 */
		ret=rt_i2c_transfer(ds3231->bus, msgs, 2);
//		rt_kprintf("ret=%d.\n",ret);
		*(uint8_t *)(buffer)=BCD2HEX(   *(uint8_t *)(buffer)      );

    return (ret == 2) ? size : 0;
}

static rt_size_t ds3231_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
	  rt_err_t ret=RT_EOK;
	  struct ds3231_device *ds3231;
    struct rt_i2c_msg msgs[2];
    rt_uint8_t mem_addr[2] = {0,0};
		
		rt_uint8_t value=HEX2BCD(*(uint8_t *)(buffer));
		
		RT_ASSERT(dev != 0);
    
		ds3231 = (struct ds3231_device *) dev;
		/*写入寻址地址*/
	  msgs[0].addr = DS3231_Address;
		msgs[0].flags = RT_I2C_WR;
		mem_addr[0] = (rt_uint8_t) pos;
		msgs[0].buf  = (rt_uint8_t *) mem_addr;
    msgs[0].len  =  1;
		
		msgs[1].addr = DS3231_Address;
    msgs[1].flags = RT_I2C_WR | RT_I2C_NO_START;
    msgs[1].buf = &value;
    msgs[1].len = 1;

    /* 调用I2C设备接口传输数据 */
		ret=rt_i2c_transfer(ds3231->bus, msgs, 2);
//		rt_kprintf("ret=%d.\n",ret);
	  return (ret == 2) ? size : 0;
}

#ifdef RT_USING_DEVICE_OPS
/** at24cxx设备操作ops */
const static struct rt_device_ops ds3231_ops =
{
    ds3231_init,
    ds3231_open,
    ds3231_close,
    ds3231_read,
    ds3231_write,
    ds3231_control
};
#endif
/**
* @brief ds3231设备注册
* @param[in]  *fm_device_name     设备名称
* @param[in]  *i2c_bus            i2c总线设备名称
* @param[in]  *user_data        用户数据 
* @return  函数执行结果
* - RT_EOK    执行成功
* - Others     失败
*/
rt_err_t ds3231_register(const char *fm_device_name, const char *i2c_bus/*, void *user_data*/)
{
    static struct ds3231_device ds3231_drv;
    struct rt_i2c_bus_device *bus;

    bus = rt_i2c_bus_device_find(i2c_bus);
    if (bus == RT_NULL)
    {
        return RT_ENOSYS;
    }

    ds3231_drv.bus = bus;
    ds3231_drv.parent.type      = RT_Device_Class_Char;
#ifdef RT_USING_DEVICE_OPS
    at24cxx_drv.parent.ops       = &ds3231_ops;
#else
    ds3231_drv.parent.init      = ds3231_init;
    ds3231_drv.parent.open      = ds3231_open;
    ds3231_drv.parent.close     = ds3231_close;
    ds3231_drv.parent.read      = ds3231_read;
    ds3231_drv.parent.write     = ds3231_write;
    ds3231_drv.parent.control   = ds3231_control;
#endif

//    ds3231_drv.parent.user_data = user_data;

    return rt_device_register(&ds3231_drv.parent, fm_device_name, RT_DEVICE_FLAG_RDWR);
}


static rt_device_t ds3231_dev;

static void rt_ds3231_init(const char *name)
{
  rt_err_t ret;

	/* 查找I2C总线设备,获取I2C总线设备句柄 */
	i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(name);
	ret = ds3231_register("ds3231", "i2c1");
	if(RT_EOK!=ret)
	{
		  rt_kprintf("ds3231 regist failed!\n", "ds3231");
		  return;
	}
	ds3231_dev = rt_device_find("ds3231");
	if (ds3231_dev == RT_NULL)
	{
			rt_kprintf("ds3231 run failed! can't find %s device!\n", "ds3231");
			return;
	}
	rt_device_open(ds3231_dev, RT_DEVICE_FLAG_RDWR);
	if (i2c_bus == RT_NULL)
	{
			rt_kprintf("can't find %s device!\n", name);
	}
	else
	{
			initialized = RT_TRUE;
			rt_device_open(ds3231_dev, RT_DEVICE_FLAG_RDWR);
	}
}

static void ds3231_sample(int argc, char *argv[])
{
//    float humidity, temperature;
    char name[RT_NAME_MAX];
    uint8_t date[6]={0,0,0,0,0,0};
	  const uint8_t date_set[6]={20,3,25,11,38,0};//2020年3月25日11时38分0秒
//    humidity = 0.0;
//    temperature = 0.0;

    if (argc == 2)
    {
        rt_strncpy(name, argv[1], RT_NAME_MAX);
    }
    else
    {
        rt_strncpy(name, DS3231_I2C_BUS_NAME, RT_NAME_MAX);
    }

    if (!initialized)
    {
        /* 传感器初始化 */
        rt_ds3231_init(name);
			  
			  rt_device_write(ds3231_dev, DS3231_YEAR,   date_set,   1);
				rt_device_write(ds3231_dev, DS3231_MONTH,  date_set+1, 1);
				rt_device_write(ds3231_dev, DS3231_DAY,    date_set+2, 1);
				rt_device_write(ds3231_dev, DS3231_HOUR,   date_set+3, 1);
				rt_device_write(ds3231_dev, DS3231_MINUTE, date_set+4, 1);
				rt_device_write(ds3231_dev, DS3231_SECOND, date_set+5, 1);
    }
    if (initialized)
    {
        /* 读取温湿度数据 */
//			  DS3231ReadTime();
        rt_device_read(ds3231_dev, DS3231_YEAR,   date, 1);
				rt_device_read(ds3231_dev, DS3231_MONTH,  date+1, 1);
				rt_device_read(ds3231_dev, DS3231_DAY,    date+2, 1);
				rt_device_read(ds3231_dev, DS3231_HOUR,   date+3, 1);
				rt_device_read(ds3231_dev, DS3231_MINUTE, date+4, 1);
				rt_device_read(ds3231_dev, DS3231_SECOND, date+5, 1);
			
			rt_kprintf("20%d-%d-%d %d:%d:%d.\n", (int)date[0],(int)date[1],(int)date[2],(int)date[3],(int)date[4],(int)date[5]);
    }
    else
    {
        rt_kprintf("initialize sensor failed!\n");
    }
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(ds3231_sample, ds3231 sample);

控制台调用结果:
使用RT Thread设备框架封装一个I2C设备——DS3231_第6张图片

结语

调试这个是三月初调试的,结果调试结束后发现rt thread的软件包里更新了这个芯片,早了两周,很尴尬,感觉白写了,用别人写的现成的不香吗?!那就写在这里当成自己的学习记录吧。

你可能感兴趣的:(使用RT Thread设备框架封装一个I2C设备——DS3231)