您现在的位置是:知识 >>正文
pcf8563 time typedef pcf datastruct
知识5人已围观
简介```html PCF8563 这颗 RTC 芯片,玩过嵌入式的人多半碰过。I²C 接口,低功耗,走时还算稳,价格也便宜。但一提到它的数据结构,不少人就卡壳——寄存器地址和 C 语言 typedef ...
PCF8563 这颗 RTC 芯片,玩过嵌入式的人多半碰过。I²C 接口,低功耗,走时还算稳,价格也便宜。但一提到它的数据结构,不少人就卡壳——寄存器地址和 C 语言 typedef 之间那层映射,写驱动的时候总得翻数据手册。
我最初用 PCF8563 是在一个电表项目上。MCU 通过 I²C 每秒钟读一次时间,结果发现秒寄存器的 bit7 是个标志位,直接读出来当数值用,时间就乱了。那次之后我才认真把它的寄存器结构理了一遍。
寄存器映射与位域陷阱
PCF8563 的时间寄存器从 0x02 到 0x08,依次是秒、分、时、日、星期、月、年。每个寄存器 8 位,但有效数据只占低 7 位,最高位各有用途:秒寄存器的 bit7 是 VL(电压低)标志,分和时没有特殊位,日寄存器的 bit6 和 bit7 是世纪位和月份最高位……这些细节不处理,读出来的 BCD 码就是错的。
所以定义 typedef 的时候,不能简单用 uint8_t 数组。我习惯这样写:
typedef struct { uint8_t sec; uint8_t min; uint8_t hour; uint8_t day; uint8_t weekday; uint8_t month; uint8_t year; } pcf8563_time_t; 但这样还不够。BCD 码和二进制之间的转换得单独做函数。有人喜欢在结构体里直接放转换后的十进制值,我觉得那样反而容易混淆——驱动层和业务层要分开。
实际驱动中的处理方式
我现在的做法是:结构体保持原始 BCD 码,另写两个函数 bcd2dec 和 dec2bcd。读取时先 I²C 连续读 7 个字节,再逐字节转成十进制存到另一个结构体里。这样调试的时候用逻辑分析仪抓波形,看到的和寄存器值一致,不容易出错。
有个细节:PCF8563 的星期寄存器是 0 到 6,但具体哪天算 0 由用户自己定。我一般把星期一设为 0,因为项目里周报都是从周一开始算。这个没有标准,数据手册也没规定,纯看应用层怎么约定。
另外,世纪位在月寄存器的 bit7。跨世纪的时候要特别处理,虽然现在离 2100 年还远,但写驱动时留个判断总没坏处。我见过一个开源库直接忽略这个位,结果 2099 年 12 月 31 日之后日期就跳回 2000 年——当然那是后话。
typedef 的取舍
有人问我为什么不直接用 struct tm。答案是:PCF8563 的年份只有两位,struct tm 的 tm_year 是从 1900 年开始的偏移量,直接映射反而多一层转换。自己定义 pcf8563_time_t 更直观,字段名和寄存器一一对应,看代码就知道在读哪个地址。
还有一点:I²C 读写要保证原子性。PCF8563 没有锁存机制,如果读秒的时候刚好进位,分和时可能不一致。我的做法是连续读两次,比较秒值,如果第二次比第一次小,说明发生了进位,重新读一遍。这个技巧在数据手册里没写,是实际调试中总结出来的。
最后提一下报警和定时器寄存器,它们也是类似的结构,但位域更复杂。报警分钟寄存器的 bit7 是 AE(报警使能),定时器控制寄存器的 bit7 是 TE。这些位如果不用 typedef 封装,直接操作寄存器很容易漏掉。
写驱动这件事,typedef 只是工具,关键还是把数据手册翻烂。我桌上那本打印的 PCF8563 手册,第 12 页到 18 页已经翻得起毛边了。
```Tags:
上一篇:显示网站不安全登录不上去怎么办
下一篇:如何制作网站教程视频讲解
相关文章
宝塔面板怎么解析域名
知识宝塔面板解析域名这事儿,说穿了就两步:先在DNS服务商那里把域名指到服务器IP,再在宝塔里把域名绑到站点上。顺序别搞反,否则你绑了半天,浏览器照样给你报错。 先讲个我踩过的坑。之前帮朋友弄个博客,他在 ...
【知识】
阅读更多福建防渗膜排名
知识福建做防渗膜这行,真正有自己生产线、能稳定供货的厂家,两只手数得过来。网上那些“十大品牌”“权威排名”,十有八九是推广位竞价排的,点进去连工厂大门朝哪开都不知道。我跑过闽侯、南安、晋江几个厂区,说点实 ...
【知识】
阅读更多webshell软件
知识拿到一个webshell,第一件事不是急着翻文件,而是先判断它能不能活过今晚。我见过太多人兴冲冲上传了一个php大马,结果连目录都没列完,就被管理员连锅端了。webshell这东西,本质就是一段跑在服 ...
【知识】
阅读更多