声明:通过学习小梅哥的笔记代码,以下是我做的仿真及总结,大神勿喷
一、八位七段数码管
思路: 我们要做一个八位的七段数码管,位选八位(每位16个数即2的4次方,四位数,数码管是八位,则需要输入的数据4*8=32位),段选七位。
首先,八位的数码管显示,采用1ms的扫描则第一个模块需要一个分频时钟。其次,扫描位选则第二个模块是一个八位的移位寄存器。然后,32(总数据位数)/8(总共的数码管位数)=4(每位数码管位数),第三个模块是一个八选一的多路器(MUX8)。最后,把的出的4位数据送入查找表,依次对应段选作为显示,第四个模块是一个16选1的查找表(LUT)。
功能图:
代码:
//八位的移位寄存器
always @ (posedge clk_1K or negedge rst_n)
if(!rst_n)
sel_r <= 8'b0000_0001;
else if(sel_r == 8'b1000_0000)
sel_r <= 8'b0000_0001;
else
sel_r <= sel_r << 1; //左移位
//组合逻辑八选一多路器
always @ (*)
case(sel_r) //sel_r位选通道,data_tmp为数码管显示的数字
8'b0000_0001:data_tmp = disp_data[3:0];
8'b0000_0010:data_tmp = disp_data[7:4];
8'b0000_0100:data_tmp = disp_data[11:8];
8'b0000_1000:data_tmp = disp_data[15:12];
8'b0001_0000:data_tmp = disp_data[19:16];
8'b0010_0000:data_tmp = disp_data[23:20];
8'b0100_0000:data_tmp = disp_data[27:24];
8'b1000_0000:data_tmp = disp_data[31:28];
default:data_tmp = 4'b0000;
endcase
//数码管段选16选1查找表
always @ (*)
case(data_tmp) //seg段选
4'h0:seg = 7'b1000000;
4'h1:seg = 7'b1111001;
4'h2:seg = 7'b0100100;
4'h3:seg = 7'b0110000;
4'h4:seg = 7'b0011001;
4'h5:seg = 7'b0010010;
4'h6:seg = 7'b0000010;
4'h7:seg = 7'b1111000;
4'h8:seg = 7'b0000000;
4'h9:seg = 7'b0010000;
4'ha:seg = 7'b0001000;
4'hb:seg = 7'b0000011;
4'hc:seg = 7'b1000110;
4'hd:seg = 7'b0100001;
4'he:seg = 7'b0000110;
4'hf:seg = 7'b0001110;
default: seg = 7'b0000000;
endcase
仿真时序图:
二、并行数据改串行
思路: 把时钟五分频,为sck_pluse,每sck_pluse出现一次,32位的SHCP_EDGE_CNT计数一次,再用32位的SHCP_EDGE_CNT对应一个32位的查找表,偶数时输出数据,奇数时不输出数据。
总的来说就是把时钟五分频,再减缓一倍输出速率(偶出奇不出),相当于clk频率缩小5*2=10倍,来计16数,对应查找表从而输出串行数据。
模块框图:
代码:
//把clk5分频,计5分频脉冲sck_pluse
always@(posedge clk or negedge rst_n)
if(!rst_n)
divider_cnt <= 16'd0;
else if(divider_cnt == 4)
divider_cnt <= 16'd0;
else
divider_cnt <= divider_cnt + 1'b1;
assign sck_pluse = (divider_cnt == 4);
//每当5分频脉sck_pluse冲到来时开始计数32位的SHCP_EDGE_CNT
reg [4:0]SHCP_EDGE_CNT;//SH_CP EDGE counter
always@(posedge clk or negedge rst_n)
if(!rst_n)
SHCP_EDGE_CNT <= 5'd0;
else if(sck_pluse)begin
if(SHCP_EDGE_CNT == 5'd31)
SHCP_EDGE_CNT <= 5'd0;
else
SHCP_EDGE_CNT <= SHCP_EDGE_CNT + 1'd1;
end
else
SHCP_EDGE_CNT <= SHCP_EDGE_CNT;
//32位的SHCP_EDGE_CNT对应16位的查找表(LUT16)从而串行输出输入的数据data。
wire[15:0] r_data;
always@(posedge clk or negedge rst_n) //ST_CP在每开始读取新的输入时,为高电平。SH_CP在偶数时低电平,奇数时高点品
if(!rst_n)begin
SH_CP <= 1'b0;
ST_CP <= 1'b0;
DS <= 1'b0;
end
else begin
case(SHCP_EDGE_CNT)
5'd0:begin SH_CP <= 1'b0; ST_CP <= 1'b1; DS <=r_data[15]; end
5'd1:begin SH_CP <= 1'b1; ST_CP <= 1'b0;end
5'd2:begin SH_CP <= 1'b0; DS <= r_data[14];end
5'd3:begin SH_CP <= 1'b1; end
5'd4:begin SH_CP <= 1'b0; DS <= r_data[13];end
5'd5:begin SH_CP <= 1'b1; end
5'd6:begin SH_CP <= 1'b0; DS <= r_data[12];end
5'd7:begin SH_CP <= 1'b1; end
5'd8:begin SH_CP <= 1'b0; DS <= r_data[11];end
5'd9:begin SH_CP <= 1'b1; end
5'd10:begin SH_CP <= 1'b0; DS <= r_data[10];end
5'd11:begin SH_CP <= 1'b1; end
5'd12:begin SH_CP <= 1'b0; DS <= r_data[9];end
5'd13:begin SH_CP <= 1'b1; end
5'd14:begin SH_CP <= 1'b0; DS <= r_data[8];end
5'd15:begin SH_CP <= 1'b1; end
5'd16:begin SH_CP <= 1'b0; DS <= r_data[7];end
5'd17:begin SH_CP <= 1'b1; end
5'd18:begin SH_CP <= 1'b0; DS <= r_data[6];end
5'd19:begin SH_CP <= 1'b1; end
5'd20:begin SH_CP <= 1'b0; DS <= r_data[5];end
5'd21:begin SH_CP <= 1'b1; end
5'd22:begin SH_CP <= 1'b0; DS <= r_data[4];end
5'd23:begin SH_CP <= 1'b1; end
5'd24:begin SH_CP <= 1'b0; DS <= r_data[3];end
5'd25:begin SH_CP <= 1'b1; end
5'd26:begin SH_CP <= 1'b0; DS <= r_data[2];end
5'd27:begin SH_CP <= 1'b1; end
5'd28:begin SH_CP <= 1'b0; DS <= r_data[1];end
5'd29:begin SH_CP <= 1'b1; end
5'd30:begin SH_CP <= 1'b0; DS <= r_data[0];end
5'd31:begin SH_CP <= 1'b1; end
endcase
end
仿真时序图:
三、把前两个大模块级联
下面再把仿真后的并行16位{1‘b1,seg,sel},送入HC595中,使其产生串行结果,功能图如下: