学习rt thread的I2C的时候,恰巧手上的板子留了ds3231的位置,说起这个时钟芯片也是和我源远流长了,从51到stm32裸机,都是用GPIO和延时来模拟I2C的(体感上比另一款时钟芯片ds1302要准很多,所以从51过渡到M3还是选了它),因为比较熟悉,就先用它试一下RT Thread的I2C。
首先我是用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里如下选择:
我这边板子是自己画的,scl和sda分别是PB7和PB8,在drv_gpio.c里可以看到:
按照这个选择两个io的引脚号,最后scons --target=mdk5重新生成一下工程。
这里只是验证一下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.
控制台里调用程序输出的结果:
完全OK.
实现了读写功能,其他的暂时用不到就没写了。初始化的时候写入一个设定值,然后读取年月日时分秒打印出来。
#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的软件包里更新了这个芯片,早了两周,很尴尬,感觉白写了,用别人写的现成的不香吗?!那就写在这里当成自己的学习记录吧。