使用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里如下选择:

我这边板子是自己画的,scl和sda分别是PB7和PB8,在drv_gpio.c里可以看到:

按照这个选择两个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 <rtthread.h>
#include "board.h"
#include <rtdevice.h>
#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.

将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_OPSat24cxx_drv.parent.ops       = &ds3231_ops;
#elseds3231_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的软件包里更新了这个芯片,早了两周,很尴尬,感觉白写了,用别人写的现成的不香吗?!那就写在这里当成自己的学习记录吧。

使用RT Thread设备框架封装一个I2C设备——DS3231相关推荐

  1. Linux添加一个i2c设备,手把手教你写Linux I2C设备驱动

    Linux I2C驱动是嵌入式Linux驱动开发人员经常需要编写的一种驱动,因为凡是系统中使用到的I2C设备,几乎都需要编写相应的I2C驱动去配置和控制它,例如 RTC实时时钟芯片.音视频采集芯片.音 ...

  2. Linux 设备驱动篇之I2c设备驱动

    ******************************************************************************************** 装载声明:希望 ...

  3. linux 脚本给设备节点权限,[Linux] I2C设备读写及文件节点创建

    Linux Kernel Version:3.0.35 Platform:Freescale DSA2L 通过I2C读取VGA屏的EDID信息(主要是分辨率),解析后喂给CH7036芯片(LVDS转V ...

  4. MTK开发板设备树的修改---I2C设备 3.18内核

    修改kernel-3.18\drivers\misc\mediatek\mach\mt6797\amt6797_evb_m\dct\dct\codegen.dws目录下的DWS文件,在对应的I2C_C ...

  5. 注册一个i2c设备时发生的一个错误(s3c-i2c s3c2440-i2c.1: cannot get bus (error -110))

    错误提示:s3c-i2c s3c2440-i2c.1: cannot get bus (error -110) 来源: kernel/drivers/i2c/busses/i2c-s3c2410.c: ...

  6. 从零开始完成Yolov5目标识别(四)封装一个跨设备的YOLOv5检测软件

    往期文章 从零开始完成YOLOv5目标识别(三)用PyQt5展示YOLOv5的识别结果​​​​​从零开始完成Yolov5目标识别(二)制作并训练自己的训练集 ​​​​​​从零开始完成Yolov5目标识 ...

  7. platform框架--Linux MISC杂项框架--Linux INPUT子系统框架--串行集成电路总线I2C设备驱动框架--串行外设接口SPI 设备驱动框架---通用异步收发器UART驱动框架

    platform框架 input. pinctrl. gpio 子系统都是 Linux 内核针对某一类设备而创建的框架, input子系统是管理输入的子系统 pinctrl 子系统重点是设置 PIN( ...

  8. Linux设备驱动程序架构分析之一个I2C驱动实例

    作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz 内核版本:3.10.1 编写一个I2C设备驱动程序的工作可分为两部分,一是定义和注册I2C设备,即i2c_clien ...

  9. 嵌入式Linux中I2C设备驱动程序的研究与实现

    I2C是"Inter Integrated Circuit Bus"的缩写,中文译成"内部集成电路总线", 它是Philips 公司于20 世纪80 年代研发成 ...

最新文章

  1. 位居全国第一- 丰收节交易会·内蒙古:名特优新农产品数量
  2. LinkedHashSet VS HashSet
  3. leetcode48. 旋转图像
  4. html 替换反斜杠,在URL直接替换反斜杠反斜杠
  5. 音视频开发(13)---视频监控系统必须知道的一些基础知识
  6. .net webapi导出html,C#(.Net Core WebAPI)之API文档的生成(Swagger)
  7. vue el-tree 同时向后台传递选中和半选节点数据 (回显数据勾选问题已解决)
  8. spss多元线性回归散点图_SPSS线性回归|别人不想告诉你的其他操作我都总结好了(中)...
  9. 软件工程期末复习题库
  10. 便携CAN分析仪图文使用指导
  11. Excel·VBA自定义函数扩展VLOOKUP
  12. mysql中varbinary什么意思_sql中varbinary 是什么数据类型
  13. Leetcode 1235. 规划兼职工作(DAY 73) ---- 动态规划学习期(上午去上高数课了 课下老师说上次旷课不扣平时分嘻嘻)
  14. 容器化技术(Docker相关)
  15. Delphi7微信、支付宝扫码支付源码
  16. mosquitto分析
  17. java1.7 apk 签名_【keytool jarsigner工具的使用】Android 使用JDK1.7的工具 进行APK文件的签名,以及keystore文件的使用...
  18. centos7安装bbr
  19. Prime算法和Krustal算法(转自博客园华山大师兄)
  20. 暴力破解及端口扫描详解

热门文章

  1. cloudstack搭建
  2. 利用Xshell+Proxifier实现全局代理上网
  3. aptitude 命令详解
  4. mysql数据库事务类型
  5. IAR工具中扩展名为icf的文件
  6. 网络安全能力成熟度模型介绍
  7. 【阅读笔记】《大话数据挖掘》定义和功能
  8. peakcoo分享:行李秤方案芯片CSU18M88
  9. 卡农?菜商?车手?话务员?“电诈”界的黑话知多少?
  10. mac php phpize,macOS 中使用 phpize 动态添加 PHP 扩展的错误解决方法