做时钟显示如果用单片机做,会产生很大的累积误差,本程序采用时钟芯片PCF8563
一:芯片主要电气特性:
1)大工作电压范围:1.0~5.5V
2)400KHz 的 I2C 总线接口(VDD=1.8~5.5V 时)。
时钟频率最大400KH
3)i2C 总线从地址:读,0A3H;写,0A2H .
二:管脚
top.v:
moduletop(ext_clk_25m,ext_rst_n,dtube_cs_n,dtube_data,rtc_iic_sck,rtc_iic_sda ); inputext_clk_25m; inputext_rst_n; output [3:0] dtube_cs_n; output [6:0] dtube_data; outputrtc_iic_sck; inoutrtc_iic_sda; wire [7:0]rtc_secd,rtc_mini,rtc_hour; wireiicrd_req; wireiicwr_req; wire [7:0] iic_addr; wire [7:0] iic_rddb; wire [7:0] iic_wrdb; wireiic_ack; rtc_controlleruut_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_controlleruut_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_4uut_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:
`timescale1ns/1psmoduleiic_controller(clk,rst_n,iicwr_req,iicrd_req,iic_addr,iic_wrdb,iic_rddb,iic_ack,scl,sda ); inputclk; //时钟信号inputrst_n; //复位信号inputiicwr_req; //写请求信号inputiicrd_req; //读请求信号input [7:0]iic_addr; //读入地址寄存器input [7:0]iic_wrdb; //写入数据寄存器outputreg[7:0]iic_rddb;//读入数据寄存器outputiic_ack; //读写应答信号outputregscl; //配置时钟信号inoutsda; //配置数据信号parameterI2C_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; //停止传输信号parameterDEVICE_WRADD=8'HA2, //写地址DEVICE_RDADD=8'HA3; //读地址parameterI2C_FREQ=250, //时钟频率SEND_BIT=8; //发送数据位数//-------------------------------------------------reg [7:0]cnt;//scl计数寄存器reg [2:0]byte_cnt;//数据位寄存器reg [3:0]state_c,state_n;//状态寄存器regsdar; //sda输出寄存器regsdalink; //sda方向控制器0-input1-outputassignscl_hs=(cnt==1'b0+1'b1); assignscl_hc=(cnt==(I2C_FREQ>>2)); assignscl_ls=(cnt==(I2C_FREQ>>1)); assignscl_lc=(cnt==(I2C_FREQ>>2)*3); //iic时钟信号产生逻辑always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)begincnt<=1'b0;endelseif(cnt==I2C_FREQ-1'b1)begincnt<=1'b0;endelsebegincnt<=cnt+1'b1;endendalways@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginscl<=1'b0;endelseif(cnt>=1'b0 &&cnt <= (I2C_FREQ>>1)-1'b1)beginscl<=1'b1;endelsebeginscl<=1'b0;endend//iic状态机控制信号always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginstate_c<=I2C_ILDE; endelsebeginstate_c<=state_n; endendalways@(*)begincase(state_c) I2C_ILDE: if((iicwr_req==1'b1||iicrd_req==1'b1)&&scl_hs==1'b1)beginstate_n<=I2C_START; endelsebeginstate_n<=I2C_ILDE; endI2C_START: if(scl_ls==1'b1)beginstate_n<=I2C_WR_IDADDR; endelsebeginstate_n<=I2C_START; endI2C_WR_IDADDR: if(scl_lc==1'b1&&byte_cnt==3'd0)beginstate_n<=I2C_WR_ACK1; endelsebeginstate_n<=I2C_WR_IDADDR; endI2C_WR_ACK1: if(scl_ls==1'b1&&byte_cnt==SEND_BIT-1'b1)beginstate_n<=I2C_WR_REGADDR; endelsebeginstate_n<=I2C_WR_ACK1; endI2C_WR_REGADDR: if(scl_lc==1'b1&&byte_cnt==3'd0)beginstate_n<=I2C_WR_ACK2; endelsebeginstate_n<=I2C_WR_REGADDR; endI2C_WR_ACK2: if(scl_ls==1'b1&&(byte_cnt==SEND_BIT-1'b1)&&iicwr_req)beginstate_n<=I2C_WR_DATA; endelseif(scl_ls==1'b1&&(byte_cnt==SEND_BIT-1'b1)&&iicrd_req)beginstate_n<=I2C_RS_START; endelsebeginstate_n<=I2C_WR_ACK2; endI2C_WR_DATA: if(scl_lc==1'b1&&(byte_cnt==3'd0))beginstate_n<=I2C_WR_ACK3; endelsebeginstate_n<=I2C_WR_DATA; endI2C_WR_ACK3: if(scl_ls==1'b1&&byte_cnt==SEND_BIT-1'b1)beginstate_n<=I2C_STOP; endelsebeginstate_n<=I2C_WR_ACK3; endI2C_RS_START: if(scl_ls==1'b1)beginstate_n<=I2C_RD_IDADDR; endelsebeginstate_n<=I2C_RS_START; endI2C_RD_IDADDR: if(scl_lc==1'b1&&byte_cnt==3'd0)beginstate_n<=I2C_RD_ACK; endelsebeginstate_n<=I2C_RD_IDADDR; endI2C_RD_ACK: if(scl_ls==1'b1&&(byte_cnt==SEND_BIT-1'b1))beginstate_n<=I2C_RD_DATA; endelsebeginstate_n<=I2C_RD_ACK; endI2C_RD_DATA: if(scl_ls==1'b1&&byte_cnt==SEND_BIT-1'b1)beginstate_n<=I2C_RD_NPACK; endelsebeginstate_n<=I2C_RD_DATA; endI2C_RD_NPACK: if(scl_ls==1'b1&&SEND_BIT-2'd2)beginstate_n<=I2C_STOP; endelsebeginstate_n<=I2C_RD_NPACK; endI2C_STOP: if(scl_ls==1'b1)beginstate_n<=I2C_ILDE; endelsebeginstate_n<=I2C_STOP; enddefault:state_n<=I2C_ILDE; endcaseend//数据位寄存器控制always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginbyte_cnt<=3'd0;endelsebegincase(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)beginbyte_cnt<=byte_cnt-1'b1;endI2C_WR_ACK1,I2C_WR_ACK2,I2C_WR_ACK3: if(scl_lc==1'b1)beginbyte_cnt<=SEND_BIT-1'b1;endI2C_RD_ACK: if(scl_ls==1'b1)beginbyte_cnt<=SEND_BIT-1'b1;endI2C_RD_NPACK: if(scl_lc==1'b1)beginbyte_cnt<=byte_cnt-1'b1;enddefault: ; endcaseendend//数据输入输出控制always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginsdar<=1'b1;sdalink<=1'b1;iic_rddb<=8'd0;endelsebegincase(state_c) I2C_ILDE: beginsdar<=1'b1;sdalink<=1'b1;endI2C_START: beginif(scl_hc==1'b1)beginsdar<=1'b0;endendI2C_WR_IDADDR: beginif(scl_lc==1'b1)beginsdar<=DEVICE_WRADD[byte_cnt]; endendI2C_WR_ACK1: beginif(scl_lc==1'b1)beginsdar<=1'b1;sdalink<=1'b0;endendI2C_WR_REGADDR: beginif(scl_lc==1'b1)beginsdar<=iic_addr[byte_cnt]; sdalink<=1'b1;endendI2C_WR_ACK2: beginif(scl_lc==1'b1)beginsdar<=1'b1;sdalink<=1'b0;endendI2C_WR_DATA: beginif(scl_lc==1'b1)beginsdar<=iic_wrdb[byte_cnt]; sdalink<=1'b1;endendI2C_WR_ACK3: beginif(scl_lc==1'b1)beginsdar<=1'b1;sdalink<=1'b0;endendI2C_RS_START: beginif(scl_hc==1'b1)beginsdar<=1'b0;endelseif(scl_lc==1'b1)beginsdar<=1'b1;sdalink<=1'b1;endendI2C_RD_IDADDR: beginif(scl_lc==1'b1)beginsdar<=DEVICE_RDADD[byte_cnt]; endendI2C_RD_ACK: beginif(scl_lc==1'b1&&byte_cnt==SEND_BIT-1'b1)beginsdalink<=1'b0;endendI2C_RD_DATA: beginif(scl_hc==1'b1)beginiic_rddb[byte_cnt+1'b1]<=sda;sdar<=1'b1;endendI2C_RD_NPACK: beginif(scl_lc==1'b1)beginsdalink<=1'b1;sdar<=1'b0;endendI2C_STOP: beginif(scl_lc==1'b1)beginsdalink<=1'b1;sdar<=1'b0;endelseif(scl_hc==1'b1)beginsdar<=1'b1;endenddefault: ; endcaseendendassignsda=sdalink?sdar:1'bz;assigniic_ack=(state_n==I2C_STOP)&&scl_hs==1'b1;endmodule
rtc_controller.v:
`timescale1ns/1psmodulertc_controller(clk,rst_n,iicwr_req,iicrd_req,iic_addr,iic_wrdb,iic_rddb,iic_ack,rtc_hour,rtc_mini,rtc_secd ); inputclk; inputrst_n; outputregiicrd_req; outputregiicwr_req; outputreg[7:0]iic_addr; outputreg[7:0]iic_wrdb; input [7:0] iic_rddb; inputiic_ack; outputreg[7:0]rtc_hour; outputreg[7:0]rtc_mini; outputreg[7:0]rtc_secd; //--------------------------------------------parameterRTC_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@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)begincnt<=1'b0;endelseif(cnt<18'd249_999)begincnt<=cnt+1'b1;endelsebegincnt<=1'b0;endendwiretimer1_10ms=(cnt==18'd49_999);wiretimer2_10ms=(cnt==18'd149_999);wiretimer3_10ms=(cnt==18'd249_999);//状态控制always@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginstate_c<=RTC_IDLE; endelsebeginstate_c<=state_n; endendalways@(*)begincase(state_c) RTC_IDLE: beginif(timer1_10ms==1'b1)beginstate_n<=RTC_RD_SECD; endelsebeginstate_n<=RTC_IDLE; endendRTC_RD_SECD: beginif(iic_ack==1'b1)beginstate_n<=RTC_WAIT1; endelsebeginstate_n<=RTC_RD_SECD; endendRTC_WAIT1: beginif(timer2_10ms==1'b1)beginstate_n<=RTC_RD_MINI; endelsebeginstate_n<=RTC_WAIT1; endendRTC_RD_MINI: beginif(iic_ack==1'b1)beginstate_n<=RTC_WAIT2; endelsebeginstate_n<=RTC_RD_MINI; endendRTC_WAIT2: beginif(timer3_10ms==1'b1)beginstate_n<=RTC_RD_HOUR; endelsebeginstate_n<=RTC_WAIT2; endendRTC_RD_HOUR: beginif(iic_ack==1'b1)beginstate_n<=RTC_IDLE; endelsebeginstate_n<=RTC_RD_HOUR; endenddefault:state_n<=RTC_IDLE; endcaseendalways@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginiicwr_req<=1'b0;iicrd_req<=1'b0;iic_addr<=1'b0;iic_wrdb<=1'b0;endelsebegincase(state_c) RTC_RD_SECD: beginiicwr_req<=1'b0;iicrd_req<=1'b1;iic_addr<=8'd2;iic_wrdb<=1'b0;endRTC_RD_MINI: beginiicwr_req<=1'b0;iicrd_req<=1'b1;iic_addr<=8'd3;iic_wrdb<=1'b0;endRTC_RD_HOUR: beginiicwr_req<=1'b0;iicrd_req<=1'b1;iic_addr<=8'd4;iic_wrdb<=1'b0;enddefault: beginiicwr_req<=1'b0;iicrd_req<=1'b0;iic_addr<=1'b0;iic_wrdb<=1'b0;endendcaseendendalways@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginrtc_hour<=1'b0;rtc_mini<=1'b0;rtc_secd<=1'b0;endelsebegincase(state_c) RTC_RD_SECD: beginif(iic_ack==1'b1)beginrtc_secd<={1'b0,iic_rddb[6:0]};endelsebeginrtc_secd<=rtc_secd; endendRTC_RD_MINI: beginif(iic_ack==1'b1)beginrtc_mini<={1'b0,iic_rddb[6:0]};endelsebeginrtc_mini<=rtc_mini; endendRTC_RD_HOUR: beginif(iic_ack==1'b1)beginrtc_hour<={1'b0,iic_rddb[6:0]};endelsebeginrtc_hour<=rtc_hour; endendendcaseendendendmodule
seg_4.v:
`timescale1ns/1psmoduleseg_4(clk,rst_n,dis_data,dtube_cs_n,dtube_data ); inputclk; //时钟信号25MHzinputrst_n; //复位信号ainput [15:0] dis_data;//outputreg[3:0] dtube_cs_n; //段选数据位outputreg[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@(posedgeclkornegedgerst_n)beginif(rst_n==1'b0)beginTimeH<=1'b0; TimeL<=1'b0; TimeH1<=1'b0;TimeL1<=1'b0;endelsebeginTimeH<=dis_data[7:4]; TimeL<=dis_data[3:0];aTimeH1<=dis_data[15:12]; TimeL1<=dis_data[11:8]; endendinitialdiv_cnt=0;//赋初值为0//延时计数器模块always@ (posedgeclkornegedgerst_n) beginif(!rst_n) div_cnt<=8'd0;elseif(div_cnt==17'd80000)div_cnt<=8'd0; elsediv_cnt<=div_cnt+1'b1;end//显示当前的数据模块always@(posedgeclkornegedgerst_n) beginif(!rst_n) display_num<=4'h0;elseif(div_cnt<17'd20000)display_num<=TimeL; elseif((div_cnt>17'd20000)&(div_cnt <17'd40000)) display_num<=TimeH; elseif((div_cnt>17'd40000)&(div_cnt < 17'd60000)) display_num<=TimeL1; elsedisplay_num<=TimeH1; end//段选数据译码模块(共阴数码管) always@(*) beginif(!rst_n) dtube_data<=8'h00;elsebegincase(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;endcaseendend//位选选译模块always@(posedgeclkornegedgerst_n) beginif(!rst_n) dtube_cs_n<=4'b1111;elseif(div_cnt<=17'd20000)dtube_cs_n<=4'b1110;elseif((div_cnt>17'd20000)&(div_cnt <=17'd40000)) dtube_cs_n<=4'b1101;elseif((div_cnt>17'd40000)&(div_cnt <=17'd60000)) dtube_cs_n<=4'b1011;elsedtube_cs_n<=4'b0111;endendmodule