双骰子点阵显示
本篇博客依旧是代码经过时序仿真验证,个人感觉没什么问题,可能点阵显示会出现问题,但微调即可。大段文本均由GPT生成。
目前这一版代码为上板子后正确代码!且更新引脚图
项目概述
-
功能描述:
通过随机数生成器产生两个骰子的随机点数,并通过点阵 LED 显示这两个骰子的点数。点阵显示包含红色和绿色两种颜色。 -
主要模块:
dice
:顶层模块,用于实例化和连接各子模块。random
和random2
:随机数生成模块。dot_matrix
:点阵 LED 驱动模块。test
:用于定时触发骰子更新的测试模块。
模块设计与实现
顶层模块 dice
module dice(row, r_col, g_col, rst, clk, start1, start2, clk_div, dice1, dice2);
input rst;
input clk;
input start1, start2;
output [7:0] row; // 行控制信号
output [7:0] r_col; // 红色列控制信号
output [7:0] g_col; // 绿色列控制信号
output clk_div;
output [3:0] dice1, dice2;
// 实例化 test 模块
test u_test(
.clk(clk),
.rst(rst),
.dice1(dice1),
.dice2(dice2),
.clk_div(clk_div)
);
// 实例化 dot_matrix 模块
dot_matrix u_dot_matrix (
.clk(clk),
.rst(rst),
.dice1(dice1),
.dice2(dice2),
.row(row),
.r_col(r_col),
.g_col(g_col)
);
endmodule
随机数生成模块
模块 random
该模块基于 4 位 LFSR(线性反馈移位寄存器)生成随机数,并将结果映射到骰子点数范围(1-9)。
需要注意,这里九个数值产生概率应该不相同,如果想要概率相同的话可能需要拓展线性寄存器位数,使之达到9的公倍数,再进行映射。
module random(
input clk,
input wire rst,
input wire roll,
output reg [3:0] dice
);
reg [3:0] lfsr;
initial begin
lfsr <= 4'b1001; // 初始化 LFSR,不为 0
dice <= 4'b0000;
end
always @(posedge roll or posedge rst) begin
if (rst) begin
lfsr <= 4'b1001;
dice <= 4'b0000;
end else if (roll) begin
lfsr <= {lfsr[2:0], lfsr[3] ^ lfsr[2]};
dice <= (lfsr % 9) + 1;
end
end
endmodule
module random2(
input clk,
input wire rst,
input wire roll,
output reg [3:0] dice
);
reg [3:0] lfsr;
initial begin
lfsr <= 4'b0001;
dice <= 4'b0000;
end
always @(posedge roll or posedge rst) begin
if (rst) begin
lfsr <= 4'b0001;
dice <= 4'b0000;
end else if (roll) begin
lfsr <= {lfsr[2:0], lfsr[3] ^ lfsr[2]};
dice <= (lfsr % 9) + 1;
end
end
endmodule
点阵 LED 驱动模块
dot_matrix
模块将骰子点数转换为点阵显示的模式,并通过行列扫描驱动点阵。
module dot_matrix (
input wire clk, // 时钟信号
input wire rst, // 复位信号
input wire [3:0] dice1, // 输入骰子数字(1-9)
input wire [3:0] dice2, //第二个骰子
output reg [7:0] row, // 行信号(ROW7 - ROW0)
output reg [7:0] r_col, // 红色列信号(R_COL7 - R_COL0)
output reg [7:0] g_col // 绿色列信号
);
reg [7:0] row_patterns; // 行信号
reg [2:0] red_patterns[2:0]; // 红色列信号
reg [2:0] green_patterns[2:0]; //绿色信号
reg [2:0] scan_index; // 当前扫描行索引(0~7)
reg [1:0] sel; //这是来选择列信号的,每一个时钟周期变化一次
initial //参数初始化
begin
r_col <= 8'b0000_0000;
g_col <= 8'b0000_0000;
end
always@(*)begin //给红色信号的低三位赋值
case(dice1)
4'b0001:begin //1
red_patterns[0] = 3'b000;
red_patterns[1] = 3'b010;
red_patterns[2] = 3'b000;
end
4'b0010:begin //2
red_patterns[0] = 3'b001;
red_patterns[1] = 3'b000;
red_patterns[2] = 3'b100;
end
4'b0011:begin //3
red_patterns[0] = 3'b100;
red_patterns[1] = 3'b010;
red_patterns[2] = 3'b001;
end
4'b0100:begin //4
red_patterns[0] = 3'b101;
red_patterns[1] = 3'b000;
red_patterns[2] = 3'b101;
end
4'b0101:begin //5
red_patterns[0] = 3'b101;
red_patterns[1] = 3'b010;
red_patterns[2] = 3'b101;
end
4'b0110:begin //6
red_patterns[0] = 3'b111;
red_patterns[1] = 3'b000;
red_patterns[2] = 3'b111;
end
4'b0111:begin //7
red_patterns[0] = 3'b111;
red_patterns[1] = 3'b010;
red_patterns[2] = 3'b111;
end
4'b1000:begin //8
red_patterns[0] = 3'b111;
red_patterns[1] = 3'b101;
red_patterns[2] = 3'b111;
end
4'b1001:begin //9
red_patterns[0] = 3'b111;
red_patterns[1] = 3'b111;
red_patterns[2] = 3'b111;
end
default:begin //默认都不亮
red_patterns[0] = 3'b000;
red_patterns[1] = 3'b000;
red_patterns[2] = 3'b000;
end
endcase
case(dice2) //给绿色信号的高三位赋值
4'b0001:begin //1
green_patterns[0] = 3'b000;
green_patterns[1] = 3'b010;
green_patterns[2] = 3'b000;
end
4'b0010:begin //2
green_patterns[0] = 3'b001;
green_patterns[1] = 3'b000;
green_patterns[2] = 3'b100;
end
4'b0011:begin //3
green_patterns[0] = 3'b100;
green_patterns[1] = 3'b010;
green_patterns[2] = 3'b001;
end
4'b0100:begin //4
green_patterns[0] = 3'b101;
green_patterns[1] = 3'b000;
green_patterns[2] = 3'b101;
end
4'b0101:begin //5
green_patterns[0] = 3'b101;
green_patterns[1] = 3'b010;
green_patterns[2] = 3'b101;
end
4'b0110:begin //6
green_patterns[0] = 3'b111;
green_patterns[1] = 3'b000;
green_patterns[2] = 3'b111;
end
4'b0111:begin //7
green_patterns[0] = 3'b111;
green_patterns[1] = 3'b010;
green_patterns[2] = 3'b111;
end
4'b1000:begin //8
green_patterns[0] = 3'b111;
green_patterns[1] = 3'b101;
green_patterns[2] = 3'b111;
end
4'b1001:begin //9
green_patterns[0] = 3'b111;
green_patterns[1] = 3'b111;
green_patterns[2] = 3'b111;
end
default:begin
green_patterns[0] = 3'b000;
green_patterns[1] = 3'b000;
green_patterns[2] = 3'b000;
end
endcase
end
// 行扫描逻辑
always @(posedge clk or posedge rst) begin
if (rst) begin
scan_index <= 3'd0; // 初始化索引
end else begin
if(scan_index<3'b111)begin
scan_index <= scan_index + 1; // 每个时钟周期更新一行
end
else begin
scan_index <= 3'b000;
end
if(sel < 2'b10)begin
sel <= sel + 1 ;
end
else begin
sel <= 2'b00;
end
end
end
reg [2:0]flag;//计八个数
initial begin
flag<=0;
end
// 显示点阵逻辑
always @(posedge clk or posedge rst) begin
if (rst) begin
row <= 8'b1111_1111; // 所有行禁用
r_col <= 8'b0000_0000; // 红色列全灭
g_col <= 8'b0000_0000;
end else begin
if(flag==3'b000)begin
row <= 8'b01111111; // 使用移位来进行赋值
r_col[2:0] <= red_patterns[0];//将红色低三位赋值给列
g_col <= 8'b0000_0000;
flag <=flag +1 ;
end
if(flag==3'b001) begin
row <= 8'b10111111;
r_col[2:0] <= red_patterns[1];//将绿色高三位赋值给列信号
flag <= flag+1;
end
if(flag==3'b010)begin
row <= 8'b1101_1111;
r_col[2:0] <= red_patterns[2];
flag <= flag +1;
end
if(flag == 3'b011)begin
row <= 8'b1110_1111;
flag <= flag +1;
r_col <= 8'b0000_0000;
end
if(flag == 3'b100)begin
row <= 8'b1111_0111;
flag <= flag+1;
end
if(flag ==3'b101)begin
row <= 8'b1111_1011;
g_col[7:5] <= green_patterns[0];
flag <= flag+1;
end
if(flag == 3'b110)begin
row <= 8'b1111_1101;
g_col[7:5] <= green_patterns[1];
flag <= flag+1;
end
if(flag == 3'b111)begin
row <= 8'b1111_1110;
g_col[7:5] <= green_patterns[2];
flag <= 3'b000;
end
end
end
endmodule
测试模块 test
test
模块通过计数器周期性触发骰子更新。
时钟周期选择1kHz!
module test( //测试模块用于根据时钟信号,每0.2秒进行扔骰子操作
input clk, //时钟选择1kHz
input wire rst, // 复位信号
output [3:0] dice1, // 输出随机数(0-9)
output [3:0] dice2,
output reg clk_div
);
reg start; //设置start信号,由时钟控制
reg [7:0] count; //20计数器,即选择5位
reg cnt;
initial begin
count <= 8'b0000_0000;
start <= 1'b0;
cnt <= 1'b0;
end
// 实例化第二个随机数生成器
random2 u_random2 (
.clk(clk),
.rst(rst), // 连接复位信号
.roll(start), // 连接掷骰子触发信号
.dice(dice2) // 连接第二个骰子的随机数输出
);
// 实例化第一个随机数生成器
random u_random1 (
.clk(clk),
.rst(rst), // 连接复位信号
.roll(start), // 连接掷骰子触发信号
.dice(dice1) // 连接第一个骰子的随机数输出
);
always @(posedge clk or posedge rst) begin
clk_div <= start;
if (rst) begin
start <= 1'b0;
count <= 8'b0;
end else if (count < 8'd200) begin
count <= count + 1;
start <= 1'b0;
end else begin
count <= 8'b0;
start <= 1'b1; // 触发掷骰子
end
end
endmodule
仿真模块
`timescale 1ms / 10ns
module tb_dice;
// 输入信号
reg clk;
reg rst;
reg start1,start2;
// 输出信号
wire [7:0] row; // 行控制信号
wire [7:0] r_col; // 红色列控制信号
wire [7:0] g_col; // 绿色列控制信号
wire clk_div;
// 内部信号(通过访问模块内部)
wire [3:0] dice1; // 第一个骰子信号
wire [3:0] dice2; // 第二个骰子信号
// 实例化被测模块(DUT: Device Under Test)
dice uut (
.rst(rst),
.clk(clk),
.start1(start1),
.start2(start2),
.row(row),
.r_col(r_col),
.g_col(g_col),
.clk_div(clk_div),
.dice1(dice1),
.dice2(dice2)
);
// 时钟生成器
initial clk = 0;
always #0.5 clk = ~clk; // 时钟周期 1ms
// 仿真逻辑
initial begin
rst=0;
#10000;
rst = 1;
#1; // 等待 10ns
rst = 0; // 释放复位信号
#1;
$stop; // 结束仿真
end
endmodule
引脚图
总结
通过以上模块化设计,成功实现了双骰子的随机生成和点阵显示。
以下是博客的完整版本,包括推荐代码仓库的部分,用于分享您的代码:
仓库推荐
这是我们的 GitHub 仓库,仓库里有我们整理和归纳的其他北邮信通的资料,如果对您有用,还请您进入我们仓库给我们一个免费的star,这对我们很重要!
- 仓库地址: GitHub 仓库
- 更多北邮作业示例
欢迎访问我们的代码仓库,获取更多示例与教程!