我用CPLD驱动MAX7219传送16位参数的方法成功了。
我看单片机里都是一次传送8位数据,我也想用CPLD传送8位数据。
但是有个问题,就是MAX7219的LOAD引脚也就是片选,需要传送两次8位数据才锁存。
我传送一次8位数据锁存一次,仿真没问题。
代码如下:
module MAX7219
(
input clk_i,
input rst_i,
output reg sdin_o,//串行输出数据
output reg sclk_o,//串行时钟
output reg load_o,//更新da寄存器
output reg [7:0] data
);
reg [7:0] olddata;
reg [22:0] currentstate;
parameter s1 = 23'b000_0000_0000_0000_0000_0001;
parameter s2 = 23'b000_0000_0000_0000_0000_0010;//s1和S2状态设置译码寄存器
parameter s3 = 23'b000_0000_0000_0000_0000_0100;
parameter s4 = 23'b000_0000_0000_0000_0000_1000;//S3和S4状态设置亮度寄存器
parameter s5 = 23'b000_0000_0000_0000_0001_0000;//
//reg sclk_o;
reg [5:0]counter;
parameter
seg1 = 8'h01, //1.
seg2 = 8'h81, //2
seg3 = 8'h02, //3
seg4 = 8'h02, //4
seg5 = 8'h03, //1.
seg6 = 8'h03, //2
seg7 = 8'h04, //3
seg8 = 8'h09; //4
reg [2:0]cnt;
//产生时钟
always @(posedge clk_i)
begin
if(!rst_i) begin
counter<=6'd0;
sclk_o <= 1'b1;
end
else begin
if(counter==6'd9) begin
sclk_o <= ~sclk_o;
counter<=6'd0;
end
else counter<=counter+6'd1;
end
end
reg [2:0] sclk_cnt;//同步时钟计数器,7
//reg [4:0] sclk_cnt;//同步时钟计数器,7
always @(posedge sclk_o or negedge rst_i)
begin
if(!rst_i) sclk_cnt <= 3'b0;
else
case(currentstate)
s2,s4:
if(3'd7 == sclk_cnt)
sclk_cnt <= 3'b0;
else sclk_cnt <= sclk_cnt + 3'b1;
default: sclk_cnt <= 3'b0;
endcase
end
//主状态机
always @(posedge sclk_o or negedge rst_i)
begin
if(!rst_i) begin currentstate <=s1; cnt = 3'b0; end
else
case(currentstate)
s1: currentstate <= s2; //s1和S2状态设置译码寄存器
s2:begin
if(3'd7 == sclk_cnt) //8个时钟周期将数据送出去
currentstate <= s3;
else
currentstate <= s2;
end
s3: currentstate <= s4; //s1和S2状态设置译码寄存器
s4:begin
if(3'd7 == sclk_cnt) //8个时钟周期将数据送出去
currentstate <= s5;
else
currentstate <= s4;
end
s5: currentstate <= s1; //s1和S2状态设置译码寄存器
endcase
end
//各状态的处理
always @(posedge sclk_o or negedge rst_i)
begin
if(!rst_i)begin data <= 8'h00; olddata <= 8'h00; end
else case(currentstate)
s1:begin data <= 8'h0a; end //正常显示模式
s3:begin data <= 8'h04; end //正常显示模式
s2,s4: begin data <= data << 1; olddata <= olddata; end//循环移位 将高位送出
default: begin data <= 8'h00; olddata <= olddata; end
endcase
end
//----------数据串行---------
always @(posedge sclk_o or negedge rst_i)
begin
if(!rst_i) sdin_o <= 1'b0;
else case(currentstate)
s2,s4: sdin_o <= data[7];
default: sdin_o <= 1'b0;
endcase
end
//----------串行数据写有效LOAD----------
always @(posedge sclk_o or negedge rst_i)
begin
if(!rst_i) load_o <= 1'b1;
else case(currentstate)
s2,s4: begin load_o <= 1'b0; end //送数的时候处于低
default: load_o <= 1'b1; //非送数时候,拉高 锁存数据
endcase
end
endmodule
仿真波形如下:
可见传送一次8位数据,我传了两个8位数据0x0a,0x04,都是8个脉冲,但是都是传送之前LOAD拉低,传送完8位数据,LOAD拉高。
我想实现连续传送两次8位数据,16个时钟周期,代码如下
module MAX7219
(
input clk_i,
input rst_i,
output reg sdin_o,//串行输出数据
output reg sclk_o,//串行时钟
output reg load_o,//更新da寄存器
output reg [7:0] data
);
reg [7:0] olddata;
reg [22:0] currentstate;
parameter s1 = 23'b000_0000_0000_0000_0000_0001;
parameter s2 = 23'b000_0000_0000_0000_0000_0010;//s1和S2状态设置译码寄存器
parameter s3 = 23'b000_0000_0000_0000_0000_0100;
parameter s4 = 23'b000_0000_0000_0000_0000_1000;//S3和S4状态设置亮度寄存器
parameter s5 = 23'b000_0000_0000_0000_0001_0000;//
//reg sclk_o;
reg [5:0]counter;
parameter
seg1 = 8'h01, //1.
seg2 = 8'h81, //2
seg3 = 8'h02, //3
seg4 = 8'h02, //4
seg5 = 8'h03, //1.
seg6 = 8'h03, //2
seg7 = 8'h04, //3
seg8 = 8'h09; //4
reg [2:0]cnt;
//产生时钟
always @(posedge clk_i)
begin
if(!rst_i) begin
counter<=6'd0;
sclk_o <= 1'b1;
end
else begin
if(counter==6'd9) begin
sclk_o <= ~sclk_o;
counter<=6'd0;
end
else counter<=counter+6'd1;
end
end
reg [2:0] sclk_cnt;//同步时钟计数器,7
//reg [4:0] sclk_cnt;//同步时钟计数器,7
always @(posedge sclk_o or negedge rst_i)
begin
if(!rst_i) sclk_cnt <= 3'b0;
else
case(currentstate)
s2,s4:
if(3'd7 == sclk_cnt)
sclk_cnt <= 3'b0;
else sclk_cnt <= sclk_cnt + 3'b1;
default: sclk_cnt <= 3'b0;
endcase
end
//主状态机
always @(posedge sclk_o or negedge rst_i)
begin
if(!rst_i) begin currentstate <=s1; cnt = 3'b0; end
else
case(currentstate)
s1: currentstate <= s2; //s1和S2状态设置译码寄存器
s2:begin
if(3'd7 == sclk_cnt) //8个时钟周期将数据送出去
currentstate <= s3;
else
currentstate <= s2;
end
s3: currentstate <= s4; //s1和S2状态设置译码寄存器
s4:begin
if(3'd7 == sclk_cnt) //8个时钟周期将数据送出去
currentstate <= s5;
else
currentstate <= s4;
end
s5: currentstate <= s1; //s1和S2状态设置译码寄存器
endcase
end
//各状态的处理
always @(posedge sclk_o or negedge rst_i)
begin
if(!rst_i)begin data <= 8'h00; olddata <= 8'h00; end
else case(currentstate)
s1:begin data <= 8'h0a; end //正常显示模式
s3:begin data <= 8'h04; end //正常显示模式
s2,s4: begin data <= data << 1; olddata <= olddata; end//循环移位 将高位送出
default: begin data <= 8'h00; olddata <= olddata; end
endcase
end
//----------数据串行---------
always @(posedge sclk_o or negedge rst_i)
begin
if(!rst_i) sdin_o <= 1'b0;
else case(currentstate)
s2,s4: sdin_o <= data[7];
default: sdin_o <= 1'b0;
endcase
end
//----------串行数据写有效LOAD----------
always @(posedge sclk_o or negedge rst_i)
begin
if(!rst_i) load_o <= 1'b1;
else case(currentstate)
s2,s3,s4: begin load_o <= 1'b0; end //送数的时候处于低
default: load_o <= 1'b1; //非送数时候,拉高 锁存数据
endcase
end
endmodule
仿真结果如下
可以看到多了一个时钟周期,一共17个时钟周期。
请问高手,有什么办法让它凑够16个时钟周期。谢谢!
|