最近把PCF8563的日历驱动写好了,但是遇到些问题,特来请教各位大神,先把自己的代码贴上来:
`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: Charles Wang // // Create Date: 09/04//2014 // Design Name: PCF8563_Calendar // Module Name: PCF8563_Cal // Project Name: PCF8563_Calendar // Target Devices: EP4CE6E22C8 // Tool versions: Quartus II 13.1 // Description: 使用LED 数码管显示PCF8563中的日历(年、月、日) --顶层模块 // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module PCF8563_Cal(sys_clk,sys_rst_n,sda,scl,disp_seg,cs); input sys_clk;//总线时钟,50MHz input sys_rst_n;//异步复位,低电平有效 inout sda;//SDA 总线 output scl;//SCL 总线 output [7:0]disp_seg;//数码管段选 output [7:0]cs;//数码管位选 wire [7:0] year;//年数据 wire [7:0] month;//月数据 wire [7:0] day;//日数据 ////////////////////////////////////////////////////////////////////////////////// //例化I2C模块 PCF8563_I2C I2C(.sys_clk(sys_clk),.sys_rst_n(sys_rst_n),.sda(sda), .scl(scl),.year(year),.month(month),.day(day)); ////////////////////////////////////////////////////////////////////////////////// //例化LED数码管显示模块 PCF8563_LED LED(.sys_clk(sys_clk),.sys_rst_n(sys_rst_n),.disp_seg (disp_seg),.cs(cs),.year(year),.month(month),.day(day)); endmodule
`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: Charles Wang // // Create Date: 09/04//2014 // Design Name: PCF8563_Calendar // Module Name: PCF8563_I2C // Project Name: PCF8563_Calendar // Target Devices: EP4CE6E22C8 // Tool versions: Quartus II 13.1 // Description: 使用LED 数码管显示PCF8563中的日历(年、月、日) --I2C 总线模块 // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module PCF8563_I2C(sys_rst_n,sys_clk,scl,sda,year,month,day); input sys_clk;//总线时钟,50MHz input sys_rst_n;//异步复位,低电平有效 output scl;//SCL 总线 inout sda;//SDA 总线 output [7:0]year;//日历,年,数据 output [7:0]month;//日历,月,数据 output [7:0]day;//日历,日,数据 reg scl;//SCL 信号寄存器 reg sda_r;//SDA 信号寄存器 reg sda_link;//SDA 方向标志寄存器 reg [7:0]year_r;//年数据寄存器 reg [7:0]month_r;//月数据寄存器 reg [7:0]week_r;//周数据寄存器,读出来之后不显示 reg [7:0]day_r;//日数据寄存器 reg [7:0]slave_addr;//从机地址寄存器 reg [7:0]reg_addr;//数据地址寄存器 reg [4:0]state;//状态寄存器 reg [3:0]data_cnt;//数据计数器 reg [7:0]scl_cnt;//产生SCL 信号计数器 reg [2:0]cnt; ////////////////////////////////////////////////////////////////////////////////// //进程1、2、3: 产生 SCL 总线时钟 always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) scl_cnt <= 8'd0; else if(scl_cnt == 8'd199) scl_cnt <= 8'd0; else scl_cnt <= scl_cnt + 1'b1; end always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) cnt <= 3'd5; else case(scl_cnt) 8'd49: cnt <= 3'd1;//高电平中间 8'd99: cnt <= 3'd2;//下降沿 8'd149:cnt <= 3'd3;//低电平中间 8'd199:cnt <= 3'd0;//上升沿 default: cnt <= 3'd5; endcase end `define SCL_HIG (cnt == 3'd1) `define SCL_NEG (cnt == 3'd2) `define SCL_LOW (cnt == 3'd3) `define SCL_POS (cnt == 3'd0) always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) scl <= 1'b0; else if(`SCL_POS) scl <= 1'b1; else if(`SCL_NEG) scl <= 1'b0; end ////////////////////////////////////////////////////////////////////////////////// //状态机定义 parameter IDLE = 5'd1,//空闲 START1 = 5'd2,//产生起始信号 SLAVE_ADDR1 = 5'd3,//写从机地址 ACK1 = 5'd4,//从机应答 DAY_ADDR = 5'd5,//写日数据地址 ACK2 = 5'd6,//从机应答 RE_START1 = 5'd7,//再次产生起始信号 SLAVE_ADDR2 = 5'd8,//读从机地址 ACK3 = 5'd9,//从机应答 DAY_DATA = 5'd10,//读日数据 ACK4 = 5'd11,//主机应答 WK_DATA = 5'd12,//读周数据 ACK5 = 5'D13,//主机应答 MONTH_DATA = 5'd14,//读月数据 ACK6 = 5'd15,//主机应答 YEAR_DATA = 5'd16,//读年数据 NACK = 5'd17,//主机非应答 STOP = 5'd18;//产生停止信号 parameter SLAVE_AD_W = 8'ha2,//从机地址,写 SLAVE_AD_R = 8'ha3,//从机地址,读 YEAR_AD = 8'h08,//年数据地址 MONTH_AD = 8'h07,//月数据地址 DAY_AD = 8'h05;//日数据地址 ////////////////////////////////////////////////////////////////////////////////// //进程4:状态转换 always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) begin state <= IDLE; year_r <= 8'hff; month_r <= 8'hff; day_r <= 8'hff; week_r <= 8'hff; slave_addr <= 8'h0; reg_addr <= 8'h0; sda_r <= 1'b1; sda_link <= 1'b1; data_cnt <= 4'd0; end else case(state) IDLE: begin sda_r <= 1'b1; sda_link <= 1'b1; end START1: begin if(`SCL_HIG) begin sda_r <= 1'b0; sda_link <= 1'b1; state <= SLAVE_ADDR1; slave_addr <= SLAVE_AD_W; reg_addr <= DAY_AD; end else state <= START1; end SLAVE_ADDR1: begin if(`SCL_LOW) begin if(data_cnt == 4'd8) begin data_cnt <= 4'd0; state <= ACK1; sda_r <= 1'b1; sda_link <= 1'b0; end else begin data_cnt <= data_cnt + 1'b1; state <= SLAVE_ADDR1; case(data_cnt) 4'd0: sda_r <= slave_addr[7]; 4'd1: sda_r <= slave_addr[6]; 4'd2: sda_r <= slave_addr[5]; 4'd3: sda_r <= slave_addr[4]; 4'd4: sda_r <= slave_addr[3]; 4'd5: sda_r <= slave_addr[2]; 4'd6: sda_r <= slave_addr[1]; 4'd7: sda_r <= slave_addr[0]; default: ; endcase end end else state <= SLAVE_ADDR1; end ACK1: begin if(`SCL_HIG && (!sda)) begin state <= DAY_ADDR; reg_addr <= DAY_AD; end else if(`SCL_NEG) begin state <= DAY_ADDR; reg_addr <= DAY_AD; end else state <= ACK1; end DAY_ADDR: begin if(`SCL_LOW) begin if(data_cnt == 4'd8) begin data_cnt <= 4'd0; state <= ACK2; sda_r <= 1'b1; sda_link <= 1'b0; end else begin data_cnt <= data_cnt + 1'b1; state <= DAY_ADDR; case(data_cnt) 4'd0: sda_r <= reg_addr[7]; 4'd1: sda_r <= reg_addr[6]; 4'd2: sda_r <= reg_addr[5]; 4'd3: sda_r <= reg_addr[4]; 4'd4: sda_r <= reg_addr[3]; 4'd5: sda_r <= reg_addr[2]; 4'd6: sda_r <= reg_addr[1]; 4'd7: sda_r <= reg_addr[0]; default: ; endcase end end end ACK2: begin if(`SCL_HIG &&(!sda)) begin state <= RE_START1; sda_r <= 1'b1; sda_link <= 1'b1; end else if(`SCL_NEG) begin state <= RE_START1; sda_r <= 1'b1; sda_link <= 1'b1; end else state <= ACK2; end RE_START1: begin if(`SCL_HIG) begin sda_r <= 1'b0; sda_link <= 1'b1; state <= SLAVE_ADDR2; slave_addr <= SLAVE_AD_R; end else state <= RE_START1; end SLAVE_ADDR2: begin if(`SCL_LOW) begin if(data_cnt == 4'd8) begin data_cnt <= 4'd0; state <= ACK3; sda_r <= 1'b1; sda_link <= 1'b0; end else begin data_cnt <= data_cnt + 1'b1; state <= SLAVE_ADDR2; case(data_cnt) 4'd0: sda_r <= slave_addr[7]; 4'd1: sda_r <= slave_addr[6]; 4'd2: sda_r <= slave_addr[5]; 4'd3: sda_r <= slave_addr[4]; 4'd4: sda_r <= slave_addr[3]; 4'd5: sda_r <= slave_addr[2]; 4'd6: sda_r <= slave_addr[1]; 4'd7: sda_r <= slave_addr[0]; default: ; endcase end end else state <= SLAVE_ADDR2; end ACK3: begin if(`SCL_HIG &&(!sda)) begin state <= DAY_DATA; end else if(`SCL_NEG) begin state <= DAY_DATA; end else state <= ACK3; end DAY_DATA: begin if(`SCL_LOW && (data_cnt == 4'd8)) begin data_cnt <= 4'd0; state <= ACK4; sda_r <= 1'b1; sda_link <= 1'b0; end else if(`SCL_HIG) begin state <= DAY_DATA; data_cnt <= data_cnt + 1'b1; case(data_cnt) 4'd0: day_r[7] <= sda; 4'd1: day_r[6] <= sda; 4'd2: day_r[5] <= sda; 4'd3: day_r[4] <= sda; 4'd4: day_r[3] <= sda; 4'd5: day_r[2] <= sda; 4'd6: day_r[1] <= sda; 4'd7: day_r[0] <= sda; default: ; endcase end end ACK4: begin if(`SCL_LOW) begin sda_r <= 1'b0; state <= WK_DATA; end else if(`SCL_NEG) begin sda_r <= 1'b1; state <= WK_DATA; end else state <= ACK4; end WK_DATA: begin if(`SCL_LOW && (data_cnt == 4'd8)) begin data_cnt <= 4'd0; state <= ACK5; sda_r <= 1'b1; sda_link <= 1'b0; end else if(`SCL_HIG) begin state <= WK_DATA; data_cnt <= data_cnt + 1'b1; case(data_cnt) 4'd0: week_r[7] <= sda; 4'd1: week_r[6] <= sda; 4'd2: week_r[5] <= sda; 4'd3: week_r[4] <= sda; 4'd4: week_r[3] <= sda; 4'd5: week_r[2] <= sda; 4'd6: week_r[1] <= sda; 4'd7: week_r[0] <= sda; default: ; endcase end end ACK5: begin if(`SCL_LOW) begin sda_r <= 1'b0; state <= MONTH_DATA; end else if(`SCL_NEG) begin sda_r <= 1'b1; state <= MONTH_DATA; end else state <= ACK5; end MONTH_DATA: begin if(`SCL_LOW && (data_cnt == 4'd8)) begin data_cnt <= 4'd0; state <= ACK6; sda_r <= 1'b1; sda_link <= 1'b0; end else if(`SCL_HIG) begin state <= MONTH_DATA; data_cnt <= data_cnt + 1'b1; case(data_cnt) 4'd0: month_r[7] <= sda; 4'd1: month_r[6] <= sda; 4'd2: month_r[5] <= sda; 4'd3: month_r[4] <= sda; 4'd4: month_r[3] <= sda; 4'd5: month_r[2] <= sda; 4'd6: month_r[1] <= sda; 4'd7: month_r[0] <= sda; default: ; endcase end end ACK6: begin if(`SCL_LOW) begin sda_r <= 1'b0; state <= YEAR_DATA; end else if(`SCL_NEG) begin sda_r <= 1'b1; state <= YEAR_DATA; end else state <= ACK6; end YEAR_DATA: begin if(`SCL_LOW && (data_cnt == 4'd8)) begin data_cnt <= 4'd0; state <= NACK; sda_r <= 1'b1; sda_link <= 1'b0; end else if(`SCL_HIG) begin state <= YEAR_DATA; data_cnt <= data_cnt + 1'b1; case(data_cnt) 4'd0: year_r[7] <= sda; 4'd1: year_r[6] <= sda; 4'd2: year_r[5] <= sda; 4'd3: year_r[4] <= sda; 4'd4: year_r[3] <= sda; 4'd5: year_r[2] <= sda; 4'd6: year_r[1] <= sda; 4'd7: year_r[0] <= sda; default: ; endcase end end NACK: begin if(`SCL_LOW) begin state <= STOP; sda_r <= 1'b0; end else state <= NACK; end STOP: begin if(`SCL_HIG) begin state <= IDLE; sda_r <= 1'b1; end else state <= STOP; end default: state <= IDLE; endcase end assign year = year_r; assign month = month_r; assign day = day_r; assign sda = sda_link ? sda_r:1'bz; endmodule
`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: Charles Wang // // Create Date: 09/04//2014 // Design Name: PCF8563_Calendar // Module Name: PCF8563_LED // Project Name: PCF8563_Calendar // Target Devices: EP4CE6E22C8 // Tool versions: Quartus II 13.1 // Description: 使用LED 数码管显示PCF8563中的日历(年、月、日) --LED显示模块 // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module PCF8563_LED(sys_clk,sys_rst_n,year,month,day,disp_seg,cs); input sys_clk;//总线时钟,50MHz input sys_rst_n;//异步复位,低电平复位 input [7:0]year;//年数据 input [7:0]month;//月数据 input [7:0]day;//日数据 output[7:0]disp_seg;//数码管段选 output[7:0]cs;//数码管位选 reg [12:0]cs_cnt;//位选扫描时钟计数器 reg [2:0]cs_clk;//位选时钟 reg [7:0]cs;//位选寄存器 reg [7:0]disp_seg;//数码管段选寄存器 reg [3:0]data_buff;//日历数据寄存器 /////////////////////////////////////////////////////////////////////////////////// //进程1、2、3:产生位选扫描时钟 always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) begin cs_cnt <= 13'd0; end else if(cs_cnt == 13'd4999) begin cs_cnt <= 13'd0; end else begin cs_cnt <= cs_cnt + 1'b1; end end always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) begin cs_clk <= 3'd0; end else if(cs_cnt == 13'd4999) begin cs_clk <= cs_clk + 1'b1; end end always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) begin cs <= 8'hff; end else case(cs_clk) 3'd0: cs <= 8'b1111_1110; 3'd1: cs <= 8'b1111_1101; 3'd2: cs <= 8'b1111_1011; 3'd3: cs <= 8'b1111_0111; 3'd4: cs <= 8'b1110_1111; 3'd5: cs <= 8'b1101_1111; 3'd6: cs <= 8'b1011_1111; 3'd7: cs <= 8'b0111_1111; default: cs <= 8'b1111_1111; endcase end ////////////////////////////////////////////////////////////////////////////////// //进程3、4:LED 数码管显示 always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) begin data_buff <= 4'hf; end else case(cs) 8'b1111_1110: data_buff <= {day[3:0]}; 8'b1111_1101: data_buff <= {2'd0,day[5:4]}; 8'b1111_1011: data_buff <= {month[3:0]}; 8'b1111_0111: data_buff <= {3'd0,month[4]}; 8'b1110_1111: data_buff <= {year[3:0]}; 8'b1101_1111: data_buff <= {year[7:4]}; 8'b1011_1111: data_buff <= 4'hf; 8'b0111_1111: data_buff <= 4'hf; default : data_buff <= 4'hf; endcase end always@(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n) begin disp_seg <= 8'hff; end else case(data_buff) 4'h0 : disp_seg <= 8'hc0; // "0" 4'h1 : disp_seg <= 8'hf9; // "1" 4'h2 : disp_seg <= 8'ha4; // "2" 4'h3 : disp_seg <= 8'hb0; // "3" 4'h4 : disp_seg <= 8'h99; // "4" 4'h5 : disp_seg <= 8'h92; // "5" 4'h6 : disp_seg <= 8'h82; // "6" 4'h7 : disp_seg <= 8'hf8; // "7" 4'h8 : disp_seg <= 8'h80; // "8" 4'h9 : disp_seg <= 8'h90; // "9" 4'ha : disp_seg <= 8'h88; // "a" 4'hb : disp_seg <= 8'h83; // "b" 4'hc : disp_seg <= 8'hc6; // "c" 4'hd : disp_seg <= 8'ha1; // "d" 4'he : disp_seg <= 8'h86; // "e" 4'hf : disp_seg <= 8'h8e; // "f" default: disp_seg <= 8'hff; endcase end endmodule