FPGA-使用RTC时钟芯片进行时钟读取(数码管显示)
芯片 进行 显示 读取 FPGA 时钟 rtc 数码管
2023-09-14 09:13:03 时间
做时钟显示如果用单片机做,会产生很大的累积误差,本程序采用时钟芯片PCF8563 一:芯片主要电气特性: 1)大工作电压范围:1.0~5.5V 2)400KHz 的 I2C 总线接口(VDD=1.8~5.5V 时)。 ![]() 时钟频率最大400KH 3)i2C 总线从地址:读,0A3H;写,0A2H . 二:管脚 ![]() 电路接线图: ![]() |
top.v:
module top(ext_clk_25m,ext_rst_n,dtube_cs_n,dtube_data,rtc_iic_sck,rtc_iic_sda
);
input ext_clk_25m;
input ext_rst_n;
output [3:0] dtube_cs_n;
output [6:0] dtube_data;
output rtc_iic_sck;
inout rtc_iic_sda;
wire [7:0]rtc_secd,rtc_mini,rtc_hour;
wire iicrd_req;
wire iicwr_req;
wire [7:0] iic_addr;
wire [7:0] iic_rddb;
wire [7:0] iic_wrdb;
wire iic_ack;
rtc_controller uut_rtc(
.clk(ext_clk_25m),
.rst_n(ext_rst_n),
.iicwr_req(iicwr_req),
.iicrd_req(iicrd_req),
.iic_addr(iic_addr),
.iic_wrdb(iic_wrdb),
.iic_rddb(iic_rddb),
.iic_ack(iic_ack),
.rtc_hour(rtc_hour),
.rtc_mini(rtc_mini),
.rtc_secd(rtc_secd)
);
iic_controller uut_iic(
.clk(ext_clk_25m),
.rst_n(ext_rst_n),
.iicwr_req(iicwr_req),
.iicrd_req(iicrd_req),
.iic_addr(iic_addr),
.iic_wrdb(iic_wrdb),
.iic_rddb(iic_rddb),
.iic_ack(iic_ack),
.scl(rtc_iic_sck),
.sda(rtc_iic_sda)
);
seg_4 uut_seg(
.clk(ext_clk_25m),
.rst_n(ext_rst_n),
.dis_data({rtc_mini,rtc_secd}),
.dtube_cs_n(dtube_cs_n),
.dtube_data(dtube_data)
);
endmodule
iic.v:
`timescale 1ns / 1ps
module iic_controller(clk,rst_n,iicwr_req,iicrd_req,iic_addr,iic_wrdb,iic_rddb,iic_ack,scl,sda
);
input clk; //时钟信号
input rst_n; //复位信号
input iicwr_req; //写请求信号
input iicrd_req; //读请求信号
input [7:0]iic_addr; //读入地址寄存器
input [7:0]iic_wrdb; //写入数据寄存器
output reg[7:0]iic_rddb;//读入数据寄存器
output iic_ack; //读写应答信号
output reg scl; //配置时钟信号
inout sda; //配置数据信号
parameter I2C_ILDE =4'D0, //起始状态
I2C_START =4'D1, //起始信号
//写信号
I2C_WR_IDADDR =4'D2, //(写指令)
I2C_WR_ACK1 =4'D3, //应答信号
I2C_WR_REGADDR =4'D4, //驱动写地址
I2C_WR_ACK2 =4'D5, //应答信号
I2C_WR_DATA =4'D6, //写数据
I2C_WR_ACK3 =4'D7, //应答信号
//读信号
I2C_RS_START =4'D8, //复位起始信号
I2C_RD_IDADDR =4'D9, //(读信号)
I2C_RD_ACK =4'D10, //应答信号
I2C_RD_DATA =4'D11, //读数据
I2C_RD_NPACK =4'D12, //应答信号
I2C_STOP =4'D13; //停止传输信号
parameter DEVICE_WRADD = 8'HA2, //写地址
DEVICE_RDADD = 8'HA3; //读地址
parameter I2C_FREQ =250, //时钟频率
SEND_BIT =8; //发送数据位数
//-------------------------------------------------
reg [7:0]cnt;//scl计数寄存器
reg [2:0]byte_cnt;//数据位寄存器
reg [3:0]state_c,state_n;//状态寄存器
reg sdar; //sda输出寄存器
reg sdalink; //sda方向控制器 0-input 1-output
assign scl_hs =(cnt==1'b0+1'b1);
assign scl_hc =(cnt==(I2C_FREQ>>2));
assign scl_ls =(cnt==(I2C_FREQ>>1));
assign scl_lc =(cnt==(I2C_FREQ>>2)*3);
//iic时钟信号产生逻辑
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
cnt<=1'b0;
end
else if(cnt==I2C_FREQ-1'b1)begin
cnt<=1'b0;
end
else begin
cnt<=cnt+1'b1;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
scl <= 1'b0;
end
else if(cnt >=1'b0 &&cnt <= (I2C_FREQ>>1)-1'b1)begin
scl <= 1'b1;
end
else begin
scl <= 1'b0;
end
end
//iic状态机控制信号
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
state_c<=I2C_ILDE;
end
else begin
state_c<=state_n;
end
end
always@(*)begin
case(state_c)
I2C_ILDE:
if((iicwr_req==1'b1||iicrd_req==1'b1)&&scl_hs==1'b1)begin
state_n<=I2C_START;
end
else begin
state_n<=I2C_ILDE;
end
I2C_START:
if(scl_ls==1'b1)begin
state_n<=I2C_WR_IDADDR;
end
else begin
state_n<=I2C_START;
end
I2C_WR_IDADDR:
if(scl_lc==1'b1&&byte_cnt==3'd0)begin
state_n<=I2C_WR_ACK1;
end
else begin
state_n<=I2C_WR_IDADDR;
end
I2C_WR_ACK1:
if(scl_ls==1'b1&&byte_cnt==SEND_BIT-1'b1)begin
state_n<=I2C_WR_REGADDR;
end
else begin
state_n<=I2C_WR_ACK1;
end
I2C_WR_REGADDR:
if(scl_lc==1'b1&&byte_cnt==3'd0)begin
state_n<=I2C_WR_ACK2;
end
else begin
state_n<=I2C_WR_REGADDR;
end
I2C_WR_ACK2:
if(scl_ls==1'b1&&(byte_cnt==SEND_BIT-1'b1)&&iicwr_req)begin
state_n<=I2C_WR_DATA;
end
else if(scl_ls==1'b1&&(byte_cnt==SEND_BIT-1'b1)&&iicrd_req)begin
state_n<=I2C_RS_START;
end
else begin
state_n<=I2C_WR_ACK2;
end
I2C_WR_DATA:
if(scl_lc==1'b1&&(byte_cnt==3'd0))begin
state_n<=I2C_WR_ACK3;
end
else begin
state_n<=I2C_WR_DATA;
end
I2C_WR_ACK3:
if(scl_ls==1'b1&&byte_cnt==SEND_BIT-1'b1)begin
state_n<=I2C_STOP;
end
else begin
state_n<=I2C_WR_ACK3;
end
I2C_RS_START:
if(scl_ls==1'b1)begin
state_n<=I2C_RD_IDADDR;
end
else begin
state_n<=I2C_RS_START;
end
I2C_RD_IDADDR:
if(scl_lc==1'b1&&byte_cnt==3'd0)begin
state_n<=I2C_RD_ACK;
end
else begin
state_n<=I2C_RD_IDADDR;
end
I2C_RD_ACK:
if(scl_ls==1'b1&&(byte_cnt==SEND_BIT-1'b1))begin
state_n<=I2C_RD_DATA;
end
else begin
state_n<=I2C_RD_ACK;
end
I2C_RD_DATA:
if(scl_ls==1'b1&&byte_cnt==SEND_BIT-1'b1)begin
state_n<=I2C_RD_NPACK;
end
else begin
state_n<=I2C_RD_DATA;
end
I2C_RD_NPACK:
if(scl_ls==1'b1&&SEND_BIT-2'd2)begin
state_n<=I2C_STOP;
end
else begin
state_n<=I2C_RD_NPACK;
end
I2C_STOP:
if(scl_ls==1'b1)begin
state_n<=I2C_ILDE;
end
else begin
state_n<=I2C_STOP;
end
default:state_n<=I2C_ILDE;
endcase
end
//数据位寄存器控制
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
byte_cnt<=3'd0;
end
else begin
case(state_c)
I2C_ILDE:
byte_cnt<=SEND_BIT-1'b1;
I2C_WR_IDADDR,I2C_WR_REGADDR,I2C_WR_DATA,
I2C_RD_IDADDR,I2C_RD_DATA:
if(scl_hs==1'b1)begin
byte_cnt<=byte_cnt-1'b1;
end
I2C_WR_ACK1,I2C_WR_ACK2,I2C_WR_ACK3:
if(scl_lc==1'b1)begin
byte_cnt<=SEND_BIT-1'b1;
end
I2C_RD_ACK:
if(scl_ls==1'b1)begin
byte_cnt<=SEND_BIT-1'b1;
end
I2C_RD_NPACK:
if(scl_lc==1'b1)begin
byte_cnt<=byte_cnt-1'b1;
end
default: ;
endcase
end
end
//数据输入输出控制
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
sdar<=1'b1;
sdalink<=1'b1;
iic_rddb<=8'd0;
end
else begin
case(state_c)
I2C_ILDE:
begin
sdar<=1'b1;
sdalink<=1'b1;
end
I2C_START:
begin
if(scl_hc==1'b1)begin
sdar<=1'b0;
end
end
I2C_WR_IDADDR:
begin
if(scl_lc==1'b1)begin
sdar<=DEVICE_WRADD[byte_cnt];
end
end
I2C_WR_ACK1:
begin
if(scl_lc==1'b1)begin
sdar<=1'b1;
sdalink<=1'b0;
end
end
I2C_WR_REGADDR:
begin
if(scl_lc==1'b1)begin
sdar<=iic_addr[byte_cnt];
sdalink<=1'b1;
end
end
I2C_WR_ACK2:
begin
if(scl_lc==1'b1)begin
sdar<=1'b1;
sdalink<=1'b0;
end
end
I2C_WR_DATA:
begin
if(scl_lc==1'b1)begin
sdar<=iic_wrdb[byte_cnt];
sdalink<=1'b1;
end
end
I2C_WR_ACK3:
begin
if(scl_lc==1'b1)begin
sdar<=1'b1;
sdalink<=1'b0;
end
end
I2C_RS_START:
begin
if(scl_hc==1'b1)begin
sdar<=1'b0;
end
else if(scl_lc==1'b1)begin
sdar<=1'b1;
sdalink<=1'b1;
end
end
I2C_RD_IDADDR:
begin
if(scl_lc==1'b1)begin
sdar<=DEVICE_RDADD[byte_cnt];
end
end
I2C_RD_ACK:
begin
if(scl_lc==1'b1&&byte_cnt==SEND_BIT-1'b1)begin
sdalink<=1'b0;
end
end
I2C_RD_DATA:
begin
if(scl_hc==1'b1)begin
iic_rddb[byte_cnt+1'b1]<=sda;
sdar<=1'b1;
end
end
I2C_RD_NPACK:
begin
if(scl_lc==1'b1)begin
sdalink<=1'b1;
sdar<=1'b0;
end
end
I2C_STOP:
begin
if(scl_lc==1'b1)begin
sdalink<=1'b1;
sdar<=1'b0;
end
else if(scl_hc==1'b1)begin
sdar<=1'b1;
end
end
default: ;
endcase
end
end
assign sda =sdalink?sdar:1'bz;
assign iic_ack=(state_n==I2C_STOP)&&scl_hs==1'b1;
endmodule
rtc_controller.v:
`timescale 1ns / 1ps
module rtc_controller(clk,rst_n,iicwr_req,iicrd_req,iic_addr,iic_wrdb,iic_rddb,iic_ack,rtc_hour,rtc_mini,rtc_secd
);
input clk;
input rst_n;
output reg iicrd_req;
output reg iicwr_req;
output reg[7:0]iic_addr;
output reg[7:0]iic_wrdb;
input [7:0] iic_rddb;
input iic_ack;
output reg[7:0]rtc_hour;
output reg[7:0]rtc_mini;
output reg[7:0]rtc_secd;
//--------------------------------------------
parameter RTC_IDLE =4'D0,
RTC_RD_SECD=4'D1,
RTC_WAIT1 =4'D2,
RTC_RD_MINI=4'D3,
RTC_WAIT2 =4'D4,
RTC_RD_HOUR=4'D5;
//--------------------------------------------
reg [17:0]cnt;
reg [3:0] state_c,state_n;
//10ms定时器
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
cnt<=1'b0;
end
else if(cnt<18'd249_999)begin
cnt<=cnt+1'b1;
end
else begin
cnt<=1'b0;
end
end
wire timer1_10ms =(cnt==18'd49_999);
wire timer2_10ms =(cnt==18'd149_999);
wire timer3_10ms =(cnt==18'd249_999);
//状态控制
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
state_c<=RTC_IDLE;
end
else begin
state_c<=state_n;
end
end
always@(*)begin
case(state_c)
RTC_IDLE:
begin
if(timer1_10ms==1'b1)begin
state_n<=RTC_RD_SECD;
end
else begin
state_n<=RTC_IDLE;
end
end
RTC_RD_SECD:
begin
if(iic_ack==1'b1)begin
state_n<=RTC_WAIT1;
end
else begin
state_n<=RTC_RD_SECD;
end
end
RTC_WAIT1:
begin
if(timer2_10ms==1'b1)begin
state_n<=RTC_RD_MINI;
end
else begin
state_n<=RTC_WAIT1;
end
end
RTC_RD_MINI:
begin
if(iic_ack==1'b1)begin
state_n<=RTC_WAIT2;
end
else begin
state_n<=RTC_RD_MINI;
end
end
RTC_WAIT2:
begin
if(timer3_10ms==1'b1)begin
state_n<=RTC_RD_HOUR;
end
else begin
state_n<=RTC_WAIT2;
end
end
RTC_RD_HOUR:
begin
if(iic_ack==1'b1)begin
state_n<=RTC_IDLE;
end
else begin
state_n<=RTC_RD_HOUR;
end
end
default:state_n<=RTC_IDLE;
endcase
end
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
iicwr_req<=1'b0;
iicrd_req<=1'b0;
iic_addr<=1'b0;
iic_wrdb<=1'b0;
end
else begin
case(state_c)
RTC_RD_SECD:
begin
iicwr_req<=1'b0;
iicrd_req<=1'b1;
iic_addr<=8'd2;
iic_wrdb<=1'b0;
end
RTC_RD_MINI:
begin
iicwr_req<=1'b0;
iicrd_req<=1'b1;
iic_addr<=8'd3;
iic_wrdb<=1'b0;
end
RTC_RD_HOUR:
begin
iicwr_req<=1'b0;
iicrd_req<=1'b1;
iic_addr<=8'd4;
iic_wrdb<=1'b0;
end
default:
begin
iicwr_req<=1'b0;
iicrd_req<=1'b0;
iic_addr<=1'b0;
iic_wrdb<=1'b0;
end
endcase
end
end
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
rtc_hour<=1'b0;
rtc_mini<=1'b0;
rtc_secd<=1'b0;
end
else begin
case(state_c)
RTC_RD_SECD:
begin
if(iic_ack==1'b1)begin
rtc_secd<={1'b0,iic_rddb[6:0]};
end
else begin
rtc_secd<=rtc_secd;
end
end
RTC_RD_MINI:
begin
if(iic_ack==1'b1)begin
rtc_mini<={1'b0,iic_rddb[6:0]};
end
else begin
rtc_mini<=rtc_mini;
end
end
RTC_RD_HOUR:
begin
if(iic_ack==1'b1)begin
rtc_hour<={1'b0,iic_rddb[6:0]};
end
else begin
rtc_hour<=rtc_hour;
end
end
endcase
end
end
endmodule
seg_4.v:
`timescale 1ns / 1ps
module seg_4(clk,rst_n,dis_data,dtube_cs_n,dtube_data
);
input clk; //时钟信号25MHz
input rst_n; //复位信号a
input [15:0] dis_data;//
output reg[3:0] dtube_cs_n; //段选数据位
output reg[6:0] dtube_data;//位选数据位
reg [3:0]TimeH; //两位输入高位 [0]
reg [3:0]TimeL; //两位输入低位 [1]
reg [3:0]TimeH1; //两位输入高位 [2]
reg [3:0]TimeL1; //两位输入低位 [3]
reg [3:0] display_num; //当前显示数据
reg [16:0] div_cnt; //延时计数器计数位
always@(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
TimeH<=1'b0;
TimeL<=1'b0;
TimeH1<=1'b0;
TimeL1<=1'b0;
end
else begin
TimeH <=dis_data[7:4];
TimeL <=dis_data[3:0];a
TimeH1<=dis_data[15:12];
TimeL1<=dis_data[11:8];
end
end
initial div_cnt = 0;//赋初值为0
//延时计数器模块
always@ (posedge clk or negedge rst_n)
begin
if(!rst_n)
div_cnt <= 8'd0;
else if(div_cnt==17'd80000)
div_cnt <= 8'd0;
else
div_cnt <= div_cnt+1'b1;
end
//显示当前的数据模块
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
display_num <= 4'h0;
else if(div_cnt < 17'd20000)
display_num <= TimeL;
else if((div_cnt>17'd20000)&(div_cnt <17'd40000))
display_num <= TimeH;
else if((div_cnt>17'd40000)&(div_cnt < 17'd60000))
display_num <=TimeL1;
else
display_num <=TimeH1;
end
//段选数据译码模块(共阴数码管)
always @(*)
begin
if(!rst_n)
dtube_data <= 8'h00;
else begin
case(display_num)
4'h0: dtube_data <= 8'h3f;
4'h1: dtube_data <= 8'h06;
4'h2: dtube_data <= 8'h5b;
4'h3: dtube_data <= 8'h4f;
4'h4: dtube_data <= 8'h66;
4'h5: dtube_data <= 8'h6d;
4'h6: dtube_data <= 8'h7d;
4'h7: dtube_data <= 8'h07;
4'h8: dtube_data <= 8'h7f;
4'h9: dtube_data <= 8'h6f;
default:dtube_data <= 8'h00;
endcase
end
end
//位选选译模块
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
dtube_cs_n <= 4'b1111;
else if(div_cnt <= 17'd20000)
dtube_cs_n <= 4'b1110;
else if((div_cnt>17'd20000)&(div_cnt <=17'd40000))
dtube_cs_n <= 4'b1101;
else if((div_cnt>17'd40000)&(div_cnt <=17'd60000))
dtube_cs_n <= 4'b1011;
else
dtube_cs_n <=4'b0111;
end
endmodule
相关文章
- MLPerf权威发榜!英伟达「史上最强GPU」H100,被这个12nm芯片碾压
- 可编程 USB 转串口适配器开发板芯片驱动文件说明
- 阿里平头哥发布羽阵611、羽阵612芯片,可应用于零售、物流、航空等领域
- VK3610I高抗干扰防呆功能10键触摸检测芯片资料分享
- 蜂窝智能手表市场大有可为!展锐发布全新穿戴芯片W217,还将推出W117 Turnkey方案
- 生物信息数据分析教程视频——14-芯片数据的表达差异分析
- 大算力芯片,向左(定制)还是向右(通用)?
- 美国芯片法案效应显现:将带动3466亿美元投资,创造34708个职位!
- 芯片的后半场,“提速”依旧是第一要务,那除此之外呢?
- 2800 亿《芯片法案》,对中国芯片产业影响几何?
- FS8025B是一款PD/QC协议诱骗芯片
- 英特尔CEO:芯片制造业需要进行更多的整合
- 警惕概念营销:RISC-V能否成为中国芯片弯道超车的希望?
- Linux在芯片中驰骋(芯片跑linux)
- 研究人员开发出一种能弹钢琴的气动计算机存储“芯片”
- 触景无限、地平线、云天励飞、天数智芯获2019 AI+芯片最佳成长奖 | CCF-GAIR 2019
- 硅芯片已经 OUT 了?韩国推出超环保“纸制芯片”
- 服务器芯片要被高通逆袭?英特尔不以为然