使用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里如下选择:
我这边板子是自己画的,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相关推荐
- Linux添加一个i2c设备,手把手教你写Linux I2C设备驱动
Linux I2C驱动是嵌入式Linux驱动开发人员经常需要编写的一种驱动,因为凡是系统中使用到的I2C设备,几乎都需要编写相应的I2C驱动去配置和控制它,例如 RTC实时时钟芯片.音视频采集芯片.音 ...
- Linux 设备驱动篇之I2c设备驱动
******************************************************************************************** 装载声明:希望 ...
- linux 脚本给设备节点权限,[Linux] I2C设备读写及文件节点创建
Linux Kernel Version:3.0.35 Platform:Freescale DSA2L 通过I2C读取VGA屏的EDID信息(主要是分辨率),解析后喂给CH7036芯片(LVDS转V ...
- MTK开发板设备树的修改---I2C设备 3.18内核
修改kernel-3.18\drivers\misc\mediatek\mach\mt6797\amt6797_evb_m\dct\dct\codegen.dws目录下的DWS文件,在对应的I2C_C ...
- 注册一个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: ...
- 从零开始完成Yolov5目标识别(四)封装一个跨设备的YOLOv5检测软件
往期文章 从零开始完成YOLOv5目标识别(三)用PyQt5展示YOLOv5的识别结果从零开始完成Yolov5目标识别(二)制作并训练自己的训练集 从零开始完成Yolov5目标识 ...
- platform框架--Linux MISC杂项框架--Linux INPUT子系统框架--串行集成电路总线I2C设备驱动框架--串行外设接口SPI 设备驱动框架---通用异步收发器UART驱动框架
platform框架 input. pinctrl. gpio 子系统都是 Linux 内核针对某一类设备而创建的框架, input子系统是管理输入的子系统 pinctrl 子系统重点是设置 PIN( ...
- Linux设备驱动程序架构分析之一个I2C驱动实例
作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz 内核版本:3.10.1 编写一个I2C设备驱动程序的工作可分为两部分,一是定义和注册I2C设备,即i2c_clien ...
- 嵌入式Linux中I2C设备驱动程序的研究与实现
I2C是"Inter Integrated Circuit Bus"的缩写,中文译成"内部集成电路总线", 它是Philips 公司于20 世纪80 年代研发成 ...
最新文章
- 位居全国第一- 丰收节交易会·内蒙古:名特优新农产品数量
- LinkedHashSet VS HashSet
- leetcode48. 旋转图像
- html 替换反斜杠,在URL直接替换反斜杠反斜杠
- 音视频开发(13)---视频监控系统必须知道的一些基础知识
- .net webapi导出html,C#(.Net Core WebAPI)之API文档的生成(Swagger)
- vue el-tree 同时向后台传递选中和半选节点数据 (回显数据勾选问题已解决)
- spss多元线性回归散点图_SPSS线性回归|别人不想告诉你的其他操作我都总结好了(中)...
- 软件工程期末复习题库
- 便携CAN分析仪图文使用指导
- Excel·VBA自定义函数扩展VLOOKUP
- mysql中varbinary什么意思_sql中varbinary 是什么数据类型
- Leetcode 1235. 规划兼职工作(DAY 73) ---- 动态规划学习期(上午去上高数课了 课下老师说上次旷课不扣平时分嘻嘻)
- 容器化技术(Docker相关)
- Delphi7微信、支付宝扫码支付源码
- mosquitto分析
- java1.7 apk 签名_【keytool jarsigner工具的使用】Android 使用JDK1.7的工具 进行APK文件的签名,以及keystore文件的使用...
- centos7安装bbr
- Prime算法和Krustal算法(转自博客园华山大师兄)
- 暴力破解及端口扫描详解