一天一个设计实例-实时时钟芯片PCF8563的接口电路、时序及程序设计

实时时钟芯片PCF8563的接口电路、时序及程序设计

1.1.1PCF8563 的主要技术性能与特点

PCF8563 是低功耗的 CMOS 实时时钟/日历芯片,它提供一个可编程时钟输出,一个中断输出和掉电检测器,所有的地址和数据通过 I2C 总线接口串行传递。最大总线速度为400Kbits/s,每次读写数据后,内嵌的字地址寄存器会自动产生增量。

(1)低工作电流:典型值为 0.25μ A( VDD=3.0V, Tamb=25℃时)。

(2)世纪标志

(3)大工作电压范围:1.0~5.5

(4)低休眠电流;典型值为 0.25μA(VDD=3.0V,Tamb=25℃)

(5) 400KHz 的 I2C 总线接口( VDD=1.8~5.5V 时)。

(6)可编程时钟输出频率为:32.768KHz, 1024Hz, 32Hz, 1Hz。

(7)报警和定时器。

(8)掉电检测器。

(9)内部集成的振荡器电容。

(10)片内电源复位功能。

(11) I2C 总线从地址:读,0A3H;写,0A2H。

(12)开漏中断引脚。

1.1.2PCF8563 的引脚功能与封装形式

图4‑22 管脚配置

图4‑23 二极管保护图

在PCF8563的引脚排列,其中VDD输入范围1.0~5.5V电源。OSCI和OSCO是振荡源,外接32.768kHz晶振。管脚 CLKOUT 可以输出可编程的方波。CLKOUT 频率寄存器决定方波的频率, CLKOUT 可以输出 32.768KHz( 缺省值), 1024, 32, 1Hz 的方波。CLKOUT为开漏输出管脚,通电时有效,无效时为高阻抗。/INT中断输出(开漏;低电平有效)。

表4‑10 管脚描述

符号

管脚号

描 述

OSCI

1

振荡器输入

OSCO

2

振荡器输出

/INT

3

中断输出(开漏;低电平有效)

VSS

4

SDA

5

串行数据 I/O

SCL

6

串行时钟输入

CLKOUT

7

时钟输出 (开漏)

VDD

8

正电源

PCF8563 有 16 个8位寄存器:一个可自动增量的地址寄存器,一个内置 32.768KHz 的振荡器(带有一个内部集成的电容),一个分频器(用于给实时时钟 RTC 提供源时钟),一个可编程时钟输出,一个定时器,一个报警器,一个掉电检测器和一个 400KHz I2C总线接口。所有 16 个寄存器设计成可寻址的 8 位并行寄存器,但不是所有位都有用。前两个寄存器(内存地址 00H, 01H)用于控制寄存器和状态寄存器,内存地址 02H~08H 用于时钟计数器(秒~年计数器),地址 09H~0CH 用于报警寄存器(定义报警条件),地址 0DH 控制CLKOUT 管脚的输出频率,地址 0EH 和 0FH 分别用于定时器控制寄存器和定时器寄存器。秒、分钟、小时、日、月、年、分钟报警、小时报警、日报警寄存器,编码格式为 BCD,星期和星期报警寄存器不以 BCD 格式编码。当一个 RTC 寄存器被读时,所有计数器的内容被锁存,因此,在传送条件下, 可以禁止对时钟/日历芯片的错读。

报警功能模式

一个或多个报警寄存器 MSB( AE=Alarm Enable 报警使能位)清0时,相应的报警条件有效,这样,一个报警将在每分钟至每星期范围内产生一次。设置报警标志位 AF(控制/状态寄存器2的位3)用于产生中断, AF 只可以用软件清除。

定时器

8位的倒计数器(地址 0FH)由定时器控制寄存器(地址 0EH,参见表 25)控制,定

时器控制寄存器用于设定定时器的频率( 4096, 64, 1,或 1/60Hz),以及设定定时器有效或无效。定时器从软件设置的 8 位二进制数倒计数,每次倒计数结束,定时器设置标志位TF,定时器标志位 TF 只可以用软件清除, TF 用于产生一个中断( /INT ),每个倒计数周期产生一个脉冲作为中断信号。TI/TP(参见表 7)控制中断产生的条件。当读定时器时,返回当前倒计数的数值。

CLKOUT 输出

管脚 CLKOUT 可以输出可编程的方波。CLKOUT 频率寄存器(地址 0DH;)决定方波的频率, CLKOUT 可以输出 32.768KHz( 缺省值), 1024, 32, 1Hz 的方波。CLKOUT为开漏输出管脚,通电时有效,无效时为高阻抗。

复位

PCF8563 包含一个片内复位电路,当振荡器停止工作时,复位电路开始工作。在复位状态下, I2C 总线初始化,寄存器 TF、 VL、 TD1、 TD0、 TESTC、 AE 被置逻辑1,其它的寄存器和地址指针被清0。

掉电检测器和时钟监控

PCF8563 内嵌掉电检测器,当 VDD 低于 Vlow 时,位 VL( Voltage Low,秒寄存器的位 7)被置1,用于指明可能产生不准确的时钟/日历信息, VL 标志位只可以用软件清除.当VDD 慢速降低(例如以电池供电)达到 Vlow 时,标志位 VL 被设置,这时可能会产生中断。

图4‑24 掉电检测

1.1.3PCF8563 的内部结构

图4‑25 PCF8563 的内部结构

1.1.4PCF8563 的寄存器

寄存器概况

标明“-”的位无效,标明“0”的位应置逻辑0。

表4‑11 寄存器概况

地址

寄存器名称

Bit7

Bit6

Bit5

Bit4

Bit3

Bit2

Bit1

Bit0

00H

控制/状态寄存器 1

TEST

0

STOP

0

TESTC

0

0

0

01H

控制/状态寄存器 2

0

0

0

TI/TP

AF

TF

AIE

TIE

0DH

CLKOUT 频率寄存器

FE

-

-

-

-

-

FD1

FD0

0EH

定时器控制寄存器

TE

-

-

-

-

-

TD1

TD0

0FH

定时器倒计数数值寄存器

定时器倒计数数值

BCD 格式寄存器概况

表4‑12  BCD 格式寄存器概况

地址

寄存器名称

Bit7

Bit6

Bit5

Bit4

Bit3

Bit2

Bit1

Bit0

02h

VL

00~59BCD 码格式数

03h

分钟

-

00~59BCD 码格式数

04h

小时

-

-

00~59BCD 码格式数

05h

-

-

01~31BCD 码格式数

06h

星期

-

-

-

-

-

0~6

07h

月/世纪

C

-

-

01~12 BCD 码格式数

08h

00~99 BCD 码格式数

09h

分钟报警

AE

00~59 BCD 码格式数

0Ah

小时报警

AE

-

00~23 BCD 码格式数

0BH

日报警

AE

-

01~31 BCD 码格式数

0CH

星期报警

AE

-

-

-

-

0~6

控制/状态寄存器1

表4‑13 控制/状态寄存器1位描述(地址 00H)

Bit

符号

描 述

7

TEST1

TEST1=0;普通模式TEST1=1;EXT_CLK 测试模式

5

STOP

STOP=0;芯片时钟运行STOP=1;所有芯片分频器异步置逻辑 0;芯片时钟停止运行,(CLKOUT 在 32.768kHz 时可用)

3

TESTC

TESTC=0;电源复位功能失效(普通模式时置逻辑 0);TESTC=1;电源复位功能有效

6,4,2,1,0

0

缺省值置逻辑 0

控制/状态寄存器2

表4‑14 控制/状态寄存器2位描述(地址 01H)

Bit

符号

描述

7,6,5

0

缺省值置逻辑 0

4

TI/TF

TI/TP=0:当 TF 有效时 INT 有效 (取决于 TIE 的状态)
TI/TP=1:INT 脉冲有效,参见表 8 (取决于 TIE 的状态)
注意:若 AF 和 AIE 都有效时,则 INT 一直有效

3

AF

当报警发生时, AF 被置逻辑 1;在定时器倒计数结束时,
TF 被置逻辑 1,它们在被软件重写前一直保持原有值,
若定时器和报警中断都请求时,中断源由 AF 和 TF 决定,
若要使清除一个标志位而防止另一标志位被重写,应运
用逻辑指令 AND,标志位 AF 和 TF 值描述参见表 9。

2

TF

1

AIE

标志位 AIE 和 TIE 决定一个中断的请求有效或无效,当
AF 或 TF 中一个为“1”时中断是 AIE 和 TIE 都置“ 1”
时的逻辑或。
AE=0:报警中断无效;AIE=1:报警中断有效
TIE=0:定时器中断无效;TIE=1:定时器中断有效

0

TIE

表4‑15 /INT 操作( bit TI/TP=1)

源时钟(Hz)

/INT 周期

n=1

n>1

4096

1/8192

1/4096

64

1/128

1/64

1

1/64

1/64

1/60

1/64

1/64

注 1. TF 和/INT 同时有效

注 2. n 为倒计数定时器的数值,当 n= 0 时定时器停止工作。

表4‑16 AF 和 TF 值描述

R/W

Bit:AF

Bit:TF

描述

描述

Read 读

0

1

报警标志无效

报警标志有效

0

1

定时器标志无效

定时器标志有效

Write 写

0

1

报警标志被清除

报警标志保持不变

0

1

定时器标志被清除

定时器标志保持不变

秒、分钟和小时寄存器

表4‑17 秒/VL 寄存器位描述(地址 02H)

Bit

符号

描 述

7

VL

VL=0:保证准确的时钟/日历数据
VL=1:不保证准确的时钟/日历数据

6~0

<秒>

代表 BCD 格式的当前秒数值,值为 00~99
例如:<秒>=1011001,代表 59 秒

表4‑18 分钟寄存器位描述(地址 03H)

Bit

符号

描 述

7

无效

6~0

<分钟>

代表 BCD 格式的当前分钟
数值,值为 00~59

表4‑19 小时寄存器位描述(地址 04H)

Bit

符 号

描 述

7~6

无效

5~0

<小时>

代表 BCD 格式的当前小
时数值,值为 00~23

日、星期、月/世纪和年寄存器

表4‑20 日寄存器位描述(地址 05H)

Bit

符号

描 述

7~6

无效

5~0

<日>

代表 BCD 格式的当前日数值,值
为 01~31。当年计数器的值是闰年
时, PCF8563 自动给二月增加一个
值,使其成为 29 天

表4‑21 星期寄存器位描述(地址 06H)

Bit

符号

描 述

7~3

无效

2~0

<星期>

代表当前星期数值 0~6,参见表 15,
这些位也可由用户重新分配

表4‑22 星期分配表

日( Day)

Bit2

Bit1

Bit0

星期日

0

0

0

星期一

0

0

1

星期二

0

1

0

星期三

0

1

1

星期四

1

0

0

星期五

1

0

1

星期六

1

1

0

表4‑23 月/世纪寄存器位描述(地址 07H)

Bit

符号

描 述

7

C

世纪位;C=0 指定世纪数为 20××, C=1
指定世纪数为 19××, “××”为年寄存器
中的值,参见表 18。当年寄存器中的值由
99 变为 00 时,世纪位会改变。

6~5

无用

4~0

<月>

代表 BCD 格式的当前月份,值为 01~12;
参见表 17。

表4‑24 月分配表

月份

Bit4

Bit3

Bit2

Bit1

Bit0

一月

0

0

0

0

1

二月

0

0

0

1

0

三月

0

0

0

1

1

四月

0

0

1

0

0

五月

0

0

1

0

1

六月

0

0

1

1

0

七月

0

0

1

1

1

八月

0

1

0

0

0

九月

0

1

0

0

1

十月

1

0

0

0

0

十一月

1

0

0

0

1

十二月

1

0

0

1

0

表4‑25 年寄存器位描述(地址 08H)

Bit

符号

描 述

7~0

<年>

代表 BCD 格式的当前年数值,值为 00~99。

报警寄存器

当一个或多个报警寄存器写入合法的分钟、小时、日或星期数值并且它们相应的 AE( Alarm Enable )位为逻辑0,以及这些数值与当前的分钟、小时、日或星期数值相等,标志位 AF( Alarm Flag)被设置, AF 保存设置值直到被软件清除为止, AF 被清除后,只有在时间增量与报警条件再次相匹配时才可再被设置。报警寄存器在它们相应位 AE 置为逻辑1时将被忽略。

表4‑26 分钟报警寄存器位描述(地址 09H)

Bit

符号

描 述

7

AE

AE=0,分钟报警有效;AE=1,分钟报警无效

6~0

<分钟报警>

代表 BCD 格式的分钟报警数值,值为 00~59

表4‑27 小时报警寄存器位描述(地址 0AH)

Bit

符号

描 述

7AE

AE=0;

小时报警有效;AE=1;小时报警无效

6~0

<小时报警>

代表 BCD 格式的小时报警数值,值为 00~23

表4‑28 日报警寄存器位描述(地址 0BH)

Bit

符号

描 述

7

AE

AE=0;日报警有效。AE=1;日报警无效。

6~0

<日报警>

代表 BCD 格式的日报警数值,值为 00~31

表4‑29 星期报警寄存器位描述(地址 0CH)

Bit

符号

描 述

7

AE

AE=0;星期报警有效。AE=1;星期报警无效

6~0

<星期报警>

代表 BCD 格式的星期报警数值,值为 0~6

CLKOUT 频率寄存器

表4‑30 CLKOUT 频率寄存器位描述(地址 0DH)

Bit

符号

描 述

7

FE

FE=0;CLKOUT 输出被禁止并设成高阻抗。
FE=1;CLKOUT 输出有效。

6~2

无效

1
0

FD1
FD0

用于控制 CLKOUT 的频率输出管脚(fCLKOUT ),
参见表 24。

表4‑31 CLKOUT 频率选择表

FD1

FD0

fCLKOUT

0

0

32.768kHz

0

1

1024Hz

1

0

32Hz

1

1

1Hz

倒计数定时器寄存器

定时器寄存器是一个8位字节的倒计数定时器,它由定时器控制器中位 TE 决定有效或无效,定时器的时钟也可以由定时器控制器选择,其它定时器功能,如中断产生,由控制/状态寄存器2控制。为了能精确读回倒计数的数值, I2C 总线时钟 SCL 的频率应至少为所选定定时器时钟频率的两倍。

表4‑32 定时器控制器寄存器位描述(地址 OEH)

Bit

符号

描 述

7

TE

TE=0;定时器无效。TE=1;定时器有效。

6~2

无用

1

TD1

定时器时钟频率选择位,决定倒计数定时
器的时钟频率,参见表 26,不用时 TD1
和 TD0 应设为“11”(1/60Hz),以降低电
源损耗。

0

TD0

表4‑33 定时器时钟频率选择

TD1

TD0

定时器时钟频率(Hz)

0

0

4096

0

1

64

1

0

1

1

1

1/60

表4‑34 定时器倒计数数值寄存器位描述(地址 OFH)

Bit

符 号

描 述

7~0

<定时器倒计数数值>

倒计数数值“n”,
倒计数周期=n/时钟频率

1.1.5PCF8563 的常见应用原理图

原理图中典型应用如下:

图4‑26 PCF8563原理图中典型应用

FPGA中的应用:

SCL、SDA引脚只需要链接到FPGA的普通I/O引脚就可以,常见电路如下:

图4‑27 PCF8563 FPGA中的应用

CPU中的应用:

在CPU中应用时,首先要确定下CPU型号是什么。关键这个CPU有没有IIC接口,如果有,将PCF8563接IIC接口。注意IIC接口要有上拉电阻。倘若使用的CPU没有IIC接口,比如STC单片机除最新的STC8以外的其他系列,则任意选择通用IO口均可。

图4‑28 PCF8563 CPU中的应用

其他电路:

其他电路同上。

1.1.6PCF8563和DS1302的区别

pcf8563是i2c接口,有倒计时,分频输出,中断等功能。ds1302功能比较单一,也不是标准接口,但价格较pcf8563便宜。

pcf8563和ds1302都是时钟芯片,不过PCF8563要精确一些,要pcf8563和ds1302哪个比较好,根据自己的需求来选择。

1.1.7PCF8563的功能分析

时序主要参考IIC时序,在此不再赘述,主要分析下功能操作。

实时时钟芯片,一旦初始化后,它就会随着现实的时钟一直计数。要明白 PCF8563 芯片最主要的关键,就是“传输时序”和“芯片本身的寄存器分配

下面看下PCF8563寄存器的内容,详见芯片Datasheet。

调用过程大致如下:

普通模式:

发送写器件从地址

发送器件子地址,控制/状态寄存器地址

预置秒

预置分

预置时

写控制寄存器数据

初始化:

发送 8‘hA2/8'b10100010访问字节,发送写器件从地址。

查询应答信号;

发送 8’h00/ 8'b00000000 访问字节,设置控制/状态寄存器1;

查询应答信号

发送8'b 00000010访问字节,PCF8563 的秒寄存器的地址。

查询应答信号

发送8'b xxxxxxxx访问字节,PCF8563 的预置秒。

查询应答信号,秒预置指示灯

写控制寄存器数据

发送8'b 00000011访问字节,PCF8563 的分寄存器的地址。

查询应答信号

发送8'b xxxxxxxx访问字节,PCF8563 的预置分。

查询应答信号

发送8'b 00000100访问字节,PCF8563 的时寄存器的地址。

查询应答信号

发送8'b xxxxxxxx访问字节,PCF8563 的预置时。

查询应答信号

调用:

发送 8‘hA2/8'b10100010访问字节,发送读器件从地址。

查询应答信号

发送8'b 00000010访问字节,PCF8563 的秒寄存器的地址。查询应答信号

读秒钟数据

发送8'b 00000011访问字节,PCF8563 的分寄存器的地址。查询应答信号

读分钟数据

发送8'b 00000100访问字节,PCF8563 的时寄存器的地址。查询应答信号

读小时数据

重复上述内容

EXT_CLK 测试模式:

测试模式用于在线测试、建立测试模式和控制 RTC 的操作。测试模式由控制/状态寄存器1的位 TEST1 设定,这时 CLKOUT 管脚成为输入管脚。在测试模式状态下,通过 CLKOUT 管脚输入的频率信号代替片内的 64Hz 频率信号,每 64个上升沿将产生1秒的时间增量。

注意:进入 EXT_CLK 测试模式时时钟不与片内 64Hz 始终时钟同步,也确定不出预分频的状态。

1.进入 EXT_CLK 测试模式;设置控制/状态寄存器1的位7(TEST=1)。

2.设置控制/状态寄存器1的位5(STOP=1)。

3.清除控制/状态寄存器1的位5(STOP=0)。

4.设置时间寄存器(秒、分钟、小时、日、星期、月/世纪和年)为期望值。

5.提供 32 个时钟脉冲给 CLKOUT。

6.读时间寄存器观察第一次变化。

7.提供 64 个时钟脉冲给 CLKOUT。

8.读时间寄存器观察第二次变化; 需要读时间寄存器的附加增量时, 重复步骤7和8。

1.1.8 PCF8563的功能实现

根据以上分析,建立如下基础模块的结构图

图4‑29 PCF8563基础模块(PCF8563_basemod.v)的建模图

图4‑29是 PCF8563基础模块的建模图,内容包含命令控制模块与IIC IP模块,功能函数模块负责最基础的读写操作,命令控制模块则负责功能调度,准备访问字节等任务。换之,函数功能模块的右边是驱动硬件资源的顶层信号。

表4‑35 PCF8563 (pcf8563_basemod.v)模块间信号定义

模块间信号

管脚

传输方向

作用/说明

iCall

信号为命令控制模块发送给IIC IP模块。

iCall为2位,其中 [1]为写操作, [0]为读操作。

oDone

oDone为IIC IP模块发送给命令控制模块。

oDone为操作完成信号。

iAddr

命令控制模块发送给IIC IP模块

读/写操作的地址

iData

命令控制模块发送给IIC IP模块

写数据内容

oData

功能函数模块发送给命令控制模块

读数据内容

时序

见上述分析

表4‑36 PCF8563 (pcf8563_basemod.v)顶层模块信号定义

顶层模块

输入管脚

作用/说明

输出管脚

作用/说明

iCall

iCall位宽为 8,作用是调用时给的操作模式。

oDone

操作完成信号

iData

写数据内容

SCL

传感器SCL引脚

oData

读数据内容

SDA

传感器读取/写入数据

时序

见上述时序分析

下面分析下iic.v模块

图4‑30 PCF8563 IIC ip模块(iic.v)的结构图

相关的介绍详见代码说明。

代码4‑5 PCF8563 IIC ip模块(iic.v)

1.//****************************************************************************//

2.//# @Author: 碎碎思

3.//# @Date:   2019-05-23 22:05:43

4.//# @Last Modified by:   zlk

5.//# @WeChat Official Account: OpenFPGA

6.//# @Last Modified time: 2019-06-01 19:44:49

7.//# Description:

8.//# @Modification History: 2019-05-29 21:12:34

9.//# Date                By             Version             Change Description:

10.//# ========================================================================= #

11.//# 2019-05-29 21:12:34

12.//# ========================================================================= #

13.//# |                                                                       | #

14.//# |                                OpenFPGA                               | #

15.//****************************************************************************//

16.`timescale 1 ns/ 1 ns

17.module iic

18.(

19.    input CLOCK, RESET,

20.     output SCL,

21.     inout SDA,

22.     input [1:0]iCall,    // Call/Done 有两位,即表示该模块有读功能还有写功能

23.     output oDone,        // 产生完成信号

24.     input [7:0]iAddr,    // 写入地址 iAddr

25.     input [7:0]iData,    // 写入数据 iData

26.     output [7:0]oData    // 读出数据 oData

27.);

28.     parameter FCLK = 10'd125, FHALF = 10'd62, FQUARTER = 10'd31; //(1/400E+3)/(1/50E+6)

29.     parameter THIGH = 10'd30, TLOW = 10'd65, TR = 10'd15, TF = 10'd15;

30.     parameter THD_STA = 10'd30, TSU_STA = 10'd30, TSU_STO = 10'd30;

31.     parameter WRFUNC1 = 5'd7;

32.     parameter WRFUNC2 = 5'd9, RDFUNC = 5'd19;

33.

34.     parameter slave_address={4'b1010, 3'b001, 1'b0};        //器件IIC地址

35.     parameter slave_address1={4'b1010, 3'b001, 1'b0};        //写操作地址

36.    parameter slave_address2={4'b1010, 3'b001, 1'b1};       //读操作地址

37.

38.

39.     reg [4:0]i;

40.     reg [4:0]Go;

41.    reg [9:0]C1;

42.     reg [7:0]D1;

43.     reg rSCL,rSDA;

44.     reg isAck, isDone, isQ;

45.

46.     always @ ( posedge CLOCK or negedge RESET )

47.         if( !RESET )

48.              begin

49.                    { i,Go } <= { 5'd0,5'd0 };

50.                     C1 <= 10'd0;

51.                     D1 <= 8'd0;

52.                     { rSCL,rSDA,isAck,isDone,isQ } <= 5'b11101;

53.                end

54.          else if( iCall[1] )

55.              case( i )

56.

57.                    0: // Start

58.                     begin

59.                          isQ = 1;

60.                          rSCL <= 1'b1;

61.

62.                         if( C1 == 0 ) rSDA <= 1'b1;

63.                          else if( C1 == (TR + THIGH) ) rSDA <= 1'b0;

64.

65.                          if( C1 == (FCLK) -1) begin C1 <= 10'd0; i <= i + 1'b1; end

66.                          else C1 <= C1 + 1'b1;

67.                     end

68.

69.                     1: // Write Device Addr

70.                     begin D1 <= slave_address; i <= 5'd7; Go <= i + 1'b1; end

71.

72.                     2: // Wirte Word Addr

73.                     begin D1 <= iAddr; i <= WRFUNC1; Go <= i + 1'b1; end

74.

75.                    3: // Write Data

76.                     begin D1 <= iData; i <= WRFUNC1; Go <= i + 1'b1; end

77.

78.                     /*************************/

79.

80.                     4: // Stop

81.                     begin

82.                         isQ = 1'b1;

83.

84.                         if( C1 == 0 ) rSCL <= 1'b0;

85.                         else if( C1 == FQUARTER ) rSCL <= 1'b1;

86.

87.                          if( C1 == 0 ) rSDA <= 1'b0;

88.                          else if( C1 == (FQUARTER + TR + TSU_STO ) ) rSDA <= 1'b1;

89.

90.                          if( C1 == (FQUARTER + FCLK) -1 ) begin C1 <= 10'd0; i <= i + 1'b1; end

91.                          else C1 <= C1 + 1'b1;

92.                     end

93.

94.                     5:

95.                     begin isDone <= 1'b1; i <= i + 1'b1; end

96.

97.                     6:

98.                     begin isDone <= 1'b0; i <= 5'd0; end

99.

100.                     /*******************************/ //function

101.

102.                     7,8,9,10,11,12,13,14:

103.                     begin

104.                         isQ = 1'b1;

105.                          rSDA <= D1[14-i];

106.

107.                          if( C1 == 0 ) rSCL <= 1'b0;

108.                          else if( C1 == (TF + TLOW) ) rSCL <= 1'b1;

109.

110.                          if( C1 == FCLK -1 ) begin C1 <= 10'd0; i <= i + 1'b1; end

111.                          else C1 <= C1 + 1'b1;

112.                     end

113.

114.                     15: // waiting for acknowledge

115.                     begin

116.                         isQ = 1'b0;

117.                         if( C1 == FHALF ) isAck <= SDA;

118.

119.                          if( C1 == 0 ) rSCL <= 1'b0;

120.                          else if( C1 == FHALF ) rSCL <= 1'b1;

121.

122.                          if( C1 == FCLK -1 ) begin C1 <= 10'd0; i <= i + 1'b1; end

123.                          else C1 <= C1 + 1'b1;

124.                     end

125.

126.                     16:

127.                     if( isAck != 0 ) i <= 5'd0;

128.                     else i <= Go;

129.

130.                     /*******************************/ // end function

131.

132.                endcase

133.

134.          else if( iCall[0] )

135.              case( i )

136.

137.                    0: // Start

138.                     begin

139.                         isQ = 1;

140.                         rSCL <= 1'b1;

141.

142.                         if( C1 == 0 ) rSDA <= 1'b1;

143.                          else if( C1 == (TR + THIGH) ) rSDA <= 1'b0;

144.

145.                          if( C1 == FCLK -1 ) begin C1 <= 10'd0; i <= i + 1'b1; end

146.                          else C1 <= C1 + 1'b1;

147.                     end

148.

149.                     1: // Write Device Addr (Write)

150.                     begin D1 <= slave_address1; i <= 5'd9; Go <= i + 1'b1; end

151.

152.                     2: // Wirte Word Addr

153.                     begin D1 <= iAddr; i <= WRFUNC2; Go <= i + 1'b1; end

154.

155.                     3: // Start again

156.                     begin

157.                         isQ = 1'b1;

158.

159.                         if( C1 == 0 ) rSCL <= 1'b0;

160.                          else if( C1 == FQUARTER ) rSCL <= 1'b1;

161.                          else if( C1 == (FQUARTER + TR + TSU_STA + THD_STA + TF)  ) rSCL <= 1'b0;

162.

163.                          if( C1 == 0 ) rSDA <= 1'b0;

164.                          else if( C1 == FQUARTER ) rSDA <= 1'b1;

165.                          else if( C1 == ( FQUARTER + TR + THIGH) ) rSDA <= 1'b0;

166.

167.                          if( C1 == (FQUARTER + FCLK + FQUARTER) -1 ) begin C1 <= 10'd0; i <= i + 1'b1; end

168.                          else C1 <= C1 + 1'b1;

169.                     end

170.

171.                     4: // Write Device Addr ( Read )

172.                     begin D1 <= slave_address2; i <= 5'd9; Go <= i + 1'b1; end

173.

174.                     5: // Read Data

175.                     begin D1 <= 8'd0; i <= RDFUNC; Go <= i + 1'b1; end

176.

177.                     6: // Stop

178.                     begin

179.                         isQ = 1'b1;

180.

181.                    if( C1 == 0 ) rSCL <= 1'b0;

182.                         else if( C1 == FQUARTER ) rSCL <= 1'b1;

183.

184.                          if( C1 == 0 ) rSDA <= 1'b0;

185.                          else if( C1 == (FQUARTER + TR + TSU_STO) ) rSDA <= 1'b1;

186.

187.                          if( C1 == (FCLK + FQUARTER) -1 ) begin C1 <= 10'd0; i <= i + 1'b1; end

188.                          else C1 <= C1 + 1'b1;

189.                     end

190.

191.                     7:

192.                     begin isDone <= 1'b1; i <= i + 1'b1; end

193.

194.                     8:

195.                     begin isDone <= 1'b0; i <= 5'd0; end

196.

197.                     /*******************************/ //function

198.

199.                     9,10,11,12,13,14,15,16:

200.                     begin

201.                         isQ = 1'b1;

202.

203.                          rSDA <= D1[16-i];

204.

205.                          if( C1 == 0 ) rSCL <= 1'b0;

206.                         else if( C1 == (TF + TLOW) ) rSCL <= 1'b1;

207.

208.                          if( C1 == FCLK -1 ) begin C1 <= 10'd0; i <= i + 1'b1; end

209.                          else C1 <= C1 + 1'b1;

210.                     end

211.

212.                     17: // waiting for acknowledge

213.                     begin

214.                         isQ = 1'b0;

215.

216.                          if( C1 == FHALF ) isAck <= SDA;

217.

218.                          if( C1 == 0 ) rSCL <= 1'b0;

219.                          else if( C1 == FHALF ) rSCL <= 1'b1;

220.

221.                          if( C1 == FCLK -1 ) begin C1 <= 10'd0; i <= i + 1'b1; end

222.                          else C1 <= C1 + 1'b1;

223.                     end

224.

225.                     18:

226.                     if( isAck != 0 ) i <= 5'd0;

227.                     else i <= Go;

228.

229.                     /*****************************/

230.

231.                     19,20,21,22,23,24,25,26: // Read

232.                     begin

233.                         isQ = 1'b0;

234.                         if( C1 == FHALF ) D1[26-i] <= SDA;

235.

236.                          if( C1 == 0 ) rSCL <= 1'b0;

237.                          else if( C1 == FHALF  ) rSCL <= 1'b1;

238.

239.                          if( C1 == FCLK -1 ) begin C1 <= 10'd0; i <= i + 1'b1; end

240.                          else C1 <= C1 + 1'b1;

241.                     end

242.

243.                     27: // no acknowledge

244.                     begin

245.                         isQ = 1'b1;

246.                         //if( C1 == 100 ) isAck <= SDA;

247.

248.                          if( C1 == 0 ) rSCL <= 1'b0;

249.                          else if( C1 == FHALF ) rSCL <= 1'b1;

250.

251.                          if( C1 == FCLK -1 ) begin C1 <= 10'd0; i <= Go; end

252.                          else C1 <= C1 + 1'b1;

253.                     end

254.

255.                     /*************************************/ // end fucntion

256.

257.                endcase

258.

259.     /***************************************/

260.

261.    assign SCL = rSCL;

262.     assign SDA = isQ ? rSDA : 1'bz;

263.    assign oDone = isDone;

264.     assign oData = D1;

265.

266.    /***************************************/

267.

268.endmodule

注意以上IIC模块使用的时候,要修改写操作地址 /读操作地址。

图4‑31 PCF8563 功能函数模块(pcf8563_ ctrlmod.v)的建模图

表4‑37 Call/Done 的位宽内容

内容

[7]

控制/状态寄存器1

[6]

写入秒钟

[5]

写入分钟

[4]

写入时钟

[3]

预留

[2]

读取秒钟

[1]

读取分钟

[0]

读取时钟

代码4‑6 PCF8563功能函数模块(pcf8563_ ctrlmod.v)

1.//****************************************************************************//

2.//# @Author: 碎碎思

3.//# @Date:   2019-05-19 20:55:44

4.//# @Last Modified by:   zlk

5.//# @WeChat Official Account: OpenFPGA

6.//# @Last Modified time: 2019-05-29 20:56:25

7.//# Description:

8.//# @Modification History: 2019-05-19 20:58:05

9.//# Date                By             Version             Change Description:

10.//# ========================================================================= #

11.//# 2019-05-19 20:58:05

12.//# ========================================================================= #

13.//# |                                                                       | #

14.//# |                                OpenFPGA                               | #

15.//****************************************************************************//

16.module pcf8563_ctrlmod

17.(

18.    input CLOCK, RST_n,

19.     input [7:0]iCall,

20.     output oDone,

21.     input [7:0]iData,

22.     output [1:0]oCall,

23.     input iDone,

24.     output [7:0]oAddr, oData

25.);

26.

27.parameter    psub_address=8'b0000_0000;        //PCF8563 第一个控制寄存器的地址

28.parameter    psub_address1=8'b0000_0010;      //PCF8563 的秒寄存器的地址

29.parameter    psub_address2=8'b0000_0011;       //PCF8563 的分寄存器的地址

30.parameter    psub_address3=8'b0000_0100;       //PCF8563 的时寄存器的地址

31.

32.

33.     reg [7:0]D1,D2;

34.

35.     always @ ( posedge CLOCK or negedge RST_n )

36.         if( !RST_n )

37.              begin

38.                    D1 <= 8'd0;

39.                     D2 <= 8'd0;

40.                end

41.          else

42.              case( iCall[7:0] )

43.

44.                    8'b1000_0000 : // psub_address & control_data

45.                     begin D1 = psub_address;  D2 <= iData; end  //D2 <= 8'b0000_0000;

46.

47.                    8'b0100_0000 : // Write second

48.                     begin D1 <= psub_address1; D2 <= iData; end //8'b00100100

49.

50.                     8'b0010_0000 : // Write minit

51.                     begin D1 <= psub_address2; D2 <= iData; end//8'b01010111

52.

53.                     8'b0001_0000 : // Write hour

54.                     begin D1 <= psub_address3; D2 <= iData; end//8'b00000111

55.

56.                     8'b0000_0100 : // Read second

57.                     begin D1 = psub_address1; end

58.

59.                     8'b0000_0010 : // Read minit

60.                     begin D1 = psub_address2; end

61.

62.                     8'b0000_0001 : // Read hour

63.                     begin D1 = psub_address3; end

64.

65.

66.                endcase

67.

68.     reg [1:0]i;

69.     reg [1:0]isCall;

70.     reg isDone;

71.

72.     always @ ( posedge CLOCK or negedge RST_n )

73.         if( !RST_n )

74.              begin

75.                     i <= 2'd0;

76.                     isCall <= 2'b00;

77.                     isDone <= 1'b0;

78.                end

79.          else if( iCall[7:4] ) // Write action

80.              case( i )

81.

82.                    0 :

83.                     if( iDone ) begin isCall <= 2'b00; i <= i + 1'b1; end

84.                     else begin isCall <= 2'b10; end

85.

86.                     1 :

87.                     begin isDone <= 1'b1; i <= i + 1'b1; end

88.

89.                     2 :

90.                     begin isDone <= 1'b0; i <= 2'd0; end

91.

92.                endcase

93.          else if( iCall[2:0] ) // Read action

94.              case( i )

95.

96.                    0 :

97.                     if( iDone ) begin isCall <= 2'b00; i <= i + 1'b1; end

98.                     else begin isCall <= 2'b01; end

99.

100.                     1 :

101.                     begin isDone <= 1'b1; i <= i + 1'b1; end

102.

103.                     2 :

104.                     begin isDone <= 1'b0; i <= 2'd0; end

105.

106.                endcase

107.

108.      assign oDone = isDone;

109.      assign oCall = isCall;

110.      assign oAddr = D1;

111.      assign oData = D2;

112.

113.endmodule

按照图4‑29将PCF8563模块进行封装,代码如下:

代码4‑7 PCF8563模块封装

1.//****************************************************************************//

2.//# @Author: 碎碎思

3.//# @Date:   2019-05-19 20:56:01

4.//# @Last Modified by:   zlk

5.//# @WeChat Official Account: OpenFPGA

6.//# @Last Modified time: 2019-05-26 17:17:11

7.//# Description:

8.//# @Modification History: 2019-05-19 20:57:52

9.//# Date                By             Version             Change Description:

10.//# ========================================================================= #

11.//# 2019-05-19 20:57:52

12.//# ========================================================================= #

13.//# |                                                                       | #

14.//# |                                OpenFPGA                               | #

15.//****************************************************************************//

16.module pcf8563_basemod

17.(

18.    input CLOCK, RST_n,

19.     output RTC_SCL,

20.     inout RTC_SDA,

21.     input [7:0]iCall,

22.     output oDone,

23.     input [7:0]iData,

24.     output [7:0]oData

25.);

26.    wire [7:0]AddrU1;

27.     wire [7:0]DataU1;

28.     wire [1:0]CallU1;

29.

30.     pcf8563_ctrlmod U1

31.     (

32.         .CLOCK( CLOCK ),

33.          .RST_n( RST_n ),

34.          .iCall( iCall ),  // < top

35.          .oDone( oDone ),    // > top

36.          .iData( iData ),    // > top

37.          .oCall( CallU1 ),  // > U2

38.          .iDone( DoneU2 ),    // < U2

39.          .oAddr( AddrU1 ),    // > U2

40.          .oData( DataU1 )     // > U2

41.     );

42.

43.

44.     iic U2

45.     (

46.         .CLOCK( CLOCK ),

47.          .RESET( RST_n ),

48.          .SCL( RTC_SCL ),   // > top

49.          .SDA( RTC_SDA ),         // <> top

50.          .iCall( CallU1 ),            // < U1

51.          .oDone( DoneU2 ),              // > U1

52.          .iAddr( AddrU1 ),              // > U1

53.          .iData( DataU1 ),              // > U1

54.          .oData( oData )                // > top

55.     );

56.

57.endmodule

完成后的RTL电路如图4‑32所示,和图4‑29一样。

图4‑32 PCF8563模块RTL

图4‑33 pcf8563_demo结构框图

图4‑33是pcf8563_demo结构框图。核心操作先初始化 PCF8563基础模块,然后无间断从哪里读取时钟,分钟还有秒钟,最后驱动至 SMG 基础模块。具体内容让我们来看代码。

代码4‑8 pcf8563调用示例

1.//****************************************************************************//

2.//# @Author: 碎碎思

3.//# @Date:   2019-05-19 01:42:42

4.//# @Last Modified by:   zlk

5.//# @WeChat Official Account: OpenFPGA

6.//# @Last Modified time: 2019-05-29 21:00:12

7.//# Description:

8.//# @Modification History: 2019-05-19 01:52:19

9.//# Date                By             Version             Change Description:

10.//# ========================================================================= #

11.//# 2019-05-19 01:52:19

12.//# ========================================================================= #

13.//# |                                                                       | #

14.//# |                                OpenFPGA                               | #

15.//****************************************************************************//

16.module pcf8563_demo

17.(

18.    input CLOCK, RST_n,

19.     output RTC_SCL,

20.     inout RTC_SDA,

21.     output [7:0]SMG_Data,

22.     output [5:0]Scan_Sig

23.);

24.     wire DoneU1;

25.     wire [7:0]DataU1;

26.

27.//    [3:0]LED;

28.

29.    parameter             pre_second=  8'b00100100;             //预置秒 , 24 秒

30.    parameter             pre_minute=  8'b01010111;            //预置分 , 57 分

31.    parameter             pre_hour  =  8'b00000111;                //预置时, 7 时

32.    parameter             control_data=8'b00000000;         //PCF8563 第一个控制寄存器的控制字

33.     pcf8563_basemod U1

34.    (

35.        .CLOCK( CLOCK ),

36.         .RST_n( RST_n ),

37.         .RTC_SCL( RTC_SCL ),

38.         .RTC_SDA( RTC_SDA ),

39.         .iCall( isCall ),

40.         .oDone( DoneU1 ),

41.         .iData( D1 ),

42.         .oData( DataU1 )

43.    );

44.

45.     smg_interface U2

46.     (

47.         .CLOCK( CLOCK ),

48.          .RST_n( RST_n ),

49.          .SMG_Data( SMG_Data ),          // > top

50.          .Scan_Sig( Scan_Sig ),          // > top

51.          .Number_Sig( Number_Sig )          // < core

52.     );

53.

54.   reg [3:0]i;

55.    reg [13:0]isCall;

56.    reg [7:0]D1,alarm_registies;

57.    reg [23:0]Number_Sig;

58.

59.    always @ ( posedge CLOCK or negedge RST_n )

60.        if( !RST_n )

61.             begin

62.                  i <= 4'd0;

63.                  isCall <= 8'd0;

64.                    D1 <= 8'd0;

65.                    Number_Sig <= 24'd0;

66.              end

67.         else

68.             case( i )

69./***********************************************************************

70.以下内容为核心操作的部分内容,步骤 0 设置pcf8563,步骤 1 初始化时钟,步骤 2 初始

71.化分钟,步骤 3 初始化秒钟并且开启计时。

72.***********************************************************************/

73.                  0:

74.                    if( DoneU1 ) begin  isCall[7] <= 1'b0;i <= i + 1'b1; end

75.                    else begin  isCall[7] <= 1'b1;D1 <= control_data ; end

76.

77.                    1:

78.                    if( DoneU1 ) begin isCall[6] <= 1'b0; i <= i + 1'b1;end

79.                    else begin isCall[6] <= 1'b1; D1 <= pre_second; end

80.

81.                    2:

82.                    if( DoneU1 ) begin isCall[5] <= 1'b0; i <= i + 1'b1; end

83.                    else begin isCall[5] <= 1'b1; D1 <= pre_minute; end

84.

85.                    3:

86.                    if( DoneU1 ) begin isCall[4] <= 1'b0; i <= i + 1'b1; end

87.                    else begin isCall[4] <= 1'b1; D1 <= pre_hour; end

88.

89.                    4:

90.                    i <= i + 1'b1;

91.

92./***********************************************************************

93.步骤 4 读取秒钟然后暂存至 D2[7:0],步骤 5 读取分钟然后暂存至 D2[15:8],步骤 6 读

94.取时钟然后暂存至 D2[23:16]。

95.***********************************************************************/

96.                    5:

97.                    if( DoneU1 ) begin Number_Sig[7:0] <= DataU1; isCall[2] <= 1'b0; i <= i + 1'b1;end

98.                    else begin isCall[2] <= 1'b1; end

99.

100.                    6:

101.                    if( DoneU1 ) begin Number_Sig[15:8] <= DataU1; isCall[1] <= 1'b0; i <= i + 1'b1; end

102.                    else begin isCall[1] <= 1'b1; end

103.

104.                    7:

105.                    if( DoneU1 ) begin Number_Sig[23:16] <= DataU1; isCall[0] <= 1'b0; i <= i + 1'b1; end

106.                    else begin isCall[0] <= 1'b1; end

107.

108.                    8:

109.                    i <= 4'd5;

110.

111.              endcase

112.

113.endmodule

综合完毕后下载程序,如果数码管从 07-58-24 开始起跑,表示实验成功。

上述代码使用过程中需要修改IIC IP里的读写操作地址,然后直接修改时分秒的数值就可以了,其他操作只需要理清操作顺序就可以了。

(0)

相关推荐