电子工程师技术服务社区
公告
登录
|
注册
首页
技术问答
厂商活动
正点原子
板卡试用
资源库
下载
文章
社区首页
文章
美信DS3231时钟芯片操作实例-基于STM32的HAL库开发
分 享
扫描二维码分享
美信DS3231时钟芯片操作实例-基于STM32的HAL库开发
DS3231
STM32F0
i2c
hal库
xukejing
关注
发布时间: 2019-06-24
丨
阅读: 6478
# 1 引言 今天,我们要以美信DS3231为例,做一个小小的I2C操作教程。这篇教程的主控芯片使用了STM32F030,但是技术都是想通的,您也可以把这个方法应用到别的微控制器或平台。 本文为了照顾初级爱好者,没有死抠底层的细节。 全文的核心是一个基于HAL库通用函数接口的二次开发的教程。 这个教程可以无缝推广到ST全系列微控制器而不会有兼容性问题。 另外本人的代码风格也写得比较流畅飘逸,很适合初学者阅读。 当然,尽信书不如无书,小伙伴们读我的文章要得其神遗其形。 最近,本人在云汉芯城找到了一款高精度的采用I2C接口的RTC时钟芯片,来自美信,名字叫DS3231。DS3231的参考原理图如下: ![参考电路](https://cf05.ickimg.com/bbsimages/201906/e7327cf51f72ac0ac4ab5294dfccc021.jpg "参考电路") DS3231是一款16脚300 mil SO封装的低成本高精度RTC芯片,可以保存时、分、秒和年、月、日、星期。DS3231集成了正负3摄氏度的温度传感器和片上电源检测电路;另外还集成了精密的温补晶振,可以在日常生活的0至40温度范围内实现正负2ppm的精度,或者在-40至85度工业环境中保证正负3.5ppm的精度。 DS3231的特性框图如下: ![特性框图](https://cf05.ickimg.com/bbsimages/201906/22c4755ce5cde950e7d88abdc9e3a055.jpg "特性框图") 为了操作DS3231,我们还需要一个单片机控制板。正好,我前段时间已经做了一个STM32的小板子,它基于STM32F030F4P6单片机。这个单片机虽然小,但是五脏俱全,硬件I2C接口自然也是支持的。那么,今天我们就用STM32F030来做个DS3231的使用例子吧。为了让这个教程可以通用于ST系列的单片机,我们使用HAL库来开发。HAL是一种统一的代码接口,里面的功能函数拥有相同的函数名和输入变量。于是,虽然每个单片机工程的硬件抽象层驱动代码的具体内容是不一样的;但是,我们可以基于统一的HAL接口函数写出通用的驱动代码。 # 2 硬件连接 下面这个图中比较靠前的板子就是DS3231模块,引出了VCC、GND、SDA和SCL这4个线,即电源和I2C接口: ![模块硬件接线](https://cf05.ickimg.com/bbsimages/201906/b08e41f6aa31e12f2a0a7866ad3311c2.jpg "模块硬件接线") STM32F030F4P6的I2C接口的SCL和SDA分别在第17和18号引脚的PA9和PA10引脚上,我们也给它如下图接上,这样它们就能通信了。 ![主控板接线](https://cf05.ickimg.com/bbsimages/201906/bebb23b1940234eedb5073212b1674f7.jpg "主控板接线") # 3 配置STM32CubeMX 硬件连接上了以后,就要编写软件来驱动它了。我们打开STM32CubeMX,把引脚配置一下。主要是I2C接口,如下图所示: ![STM32CubeMX引脚配置](https://cf05.ickimg.com/bbsimages/201906/e47d94792415f6163ee4a4c33610183b.jpg "STM32CubeMX引脚配置") 得益于STM32系列单片机强大的引脚模式配置功能。我们可以给PA9和PA10引脚设置一下内部上拉。通过内部上拉,外部电路又可以省两个4.7K欧的上拉电阻,我真是太机智啦。内部上拉设置如下图所示: ![启用内部上拉](https://cf05.ickimg.com/bbsimages/201906/e486aa49734f83d90e197465abeb84f6.jpg "启用内部上拉") 虽然STM32F030支持最高1000KHz的I2C,但是DS3231最高只支持400KHz,所以我们设置通讯速率为Fast模式,即400KHz,如下图所示: ![速率设置](https://cf05.ickimg.com/bbsimages/201906/e748ad892f154b361d711d1d2ad4a859.jpg "速率设置") 然后,用STM32CubeMX导出Keil工程。在工程里,我们新建一个BSP目录,把我们的基于HAL的驱动代码都放到BSP目录里。目录结构如下图所示。这里我们添加了DS3231和LED的驱动函数。LED驱动并不是今天的主角,所以我们先不说他;主要说说DS3231吧。 ![自建BSP目录结构](https://cf05.ickimg.com/bbsimages/201906/d1c0f67bae227342997df3374a9f0e2f.jpg "自建BSP目录结构") # 4 编写DS3231的操作接口 HAL库里有两个重要的I2C操作函数,一个叫HAL_I2C_Master_Transmit,它在主模式下以阻塞模式发送数据到从机。其中要注意的是,如果从机目标设备的地址是7位地址,由于I2C时序要求数据左对齐,并且地址时序的第8位是读写控制位,所以7位地址需要预先左移一位。另一个叫HAL_I2C_Master_Receive,在主模式下以阻塞模式接收数据。 下面,让我们定义一下DS3231驱动的初始化、时间设置、时间读取和温度读取的函数名。其中,为了提高时间设置函数的易读性,我们设置一个结构体来做RTC时间数据的交互。以下代码都放入DS3231驱动的头文件里。 ![头文件里的函数定义](https://cf05.ickimg.com/bbsimages/201906/da0365e750954cbe0998412e71bd7d06.jpg "头文件里的函数定义") STM32CubeMX自动生成了main函数并在里面定义了I2C1的句柄I2C_HandleTypeDef hi2c1。我们的DS3231驱动初始化时候要把这个句柄作为输入变量赋值给驱动库的内部变量I2C_HandleTypeDef *i2c。DS3231驱动初始化代码如下图所示。图中的红色箭头对代码做了必要的注释。 ![驱动初始化函数](https://cf05.ickimg.com/bbsimages/201906/7a760728e7bd97fedfedabc4114cb5be.jpg "驱动初始化函数") 通过I2C获取时间和设置时间的函数基于HAL库里面的HAL_I2C_Master_Transmit和HAL_I2C_Master_Receive这两个接口函数来写。 读取时间时,先用HAL_I2C_Master_Transmit函数给DS3231发送操作时间的注册码,然后用HAL_I2C_Master_Receive把数据都收来放在buffer数组里,接着按地址解析数据放入结构体变量。 设置时间是,先把时间数据全部写入buffer,然后把buffer通过HAL_I2C_Master_Transmit发送给DS3231。 这两个函数的代码如下图所示: ![读函数和写函数](https://cf05.ickimg.com/bbsimages/201906/e1789a6f3680ad6ad04f736d48606f63.jpg "读函数和写函数") 获取温度的函数与获取时间的函数具有相同的运行过程,先发送读取温度的注册码,然后接受数据到buffer,接着解析buffer ![获取温度函数](https://cf05.ickimg.com/bbsimages/201906/963a397b8f4096262788a8178a175a19.jpg "获取温度函数") # 5 调用DS3231的操作函数 接着,我们回到main文件,把刚写的ds3231驱动库引用到main函数,如下图所示。这样,main文件里就可以调用我们刚写的那几个DS3231操作函数了。 ![主文件里引用前面写的ds3231库](https://cf05.ickimg.com/bbsimages/201906/b5621ffd0af7f01c7ecaba84a91fde8e.jpg "主文件里引用前面写的ds3231库") 定义时间结构体变量的初始值,用来设置初始时间。 ![定义时间结构体变量的初始值](https://cf05.ickimg.com/bbsimages/201906/feedea4bf1a766967d271149592cf815.jpg "定义时间结构体变量的初始值") 程序初始化过程如下图所示,其中,红色箭头已经对关键代码的功能做了注释。 ![程序初始化](https://cf05.ickimg.com/bbsimages/201906/d599f654bf551a12b05255ba31b85a50.jpg "程序初始化") 在while函数里循环读取时间和读取温度,然后用printf打印到UART1串口,如下图所示 ![while函数里的循环](https://cf05.ickimg.com/bbsimages/201906/92fd676b0a57b7eef463f0a1ba64532b.jpg "while函数里的循环") 之所以可以用printf输出到UART1。 为什么可以用printf呢?这是因为我们做了函数重定向,如下图所示 ![重定向](https://cf05.ickimg.com/bbsimages/201906/9e5062f674ae977f695fecf93f450b85.jpg "重定向") # 6 测试 我们把代码编译一下,确保0错误0警告。接着就可以烧写到STM32F030芯片上。我们是比较厉害的极客,写代码肯定是0 Error 0 Warning的。这个牛我又可以吹一年了。 ![0Error0Warning](https://cf05.ickimg.com/bbsimages/201906/cf83664343df4abfa432e3542a0cb148.jpg "0Error0Warning") 然后,把板子的串口连接到串口调试助手观察输出,结果如下图所示。我们可以发现DS3231的时间和温度输出都被正确读取了。 ![串口调试输出](https://cf05.ickimg.com/bbsimages/201906/003ec5a712d85adc7fc5d77a4f8bc32d.jpg "串口调试输出") 本教程讲完了,谢谢大家的观看!
原创作品,未经权利人授权禁止转载。详情见
转载须知
。
举报文章
点赞
(
2
)
xukejing
擅长:其他应用
关注
评论
(0)
登录后可评论,请
登录
或
注册
相关文章推荐
MK-米客方德推出工业级存储卡
Beetle ESP32 C3 蓝牙数据收发
Beetle ESP32 C3 wifi联网获取实时天气信息
开箱测评Beetle ESP32-C3 (RISC-V芯片)模块
正点原子数控电源DP100测评
DP100试用评测-----开箱+初体验
Beetle ESP32 C3环境搭建
【花雕体验】16 使用Beetle ESP32 C3控制8X32位WS2812硬屏之二
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回
我要举报该内容理由
×
广告及垃圾信息
抄袭或未经授权
其它举报理由
请输入您举报的理由(50字以内)
取消
提交