实验二:基本的组合逻辑电路

这里只展示2.3的一部分代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module decoder_3to8(in, out);
input [2:0] in;
output reg [7:0] out;

always@(in)
case(in)
3'b000 : out[7:0] = 8'b11111110;
3'b001 : out[7:0] = 8'b11111101;
3'b010 : out[7:0] = 8'b11111011;
3'b011 : out[7:0] = 8'b11110111;
3'b100 : out[7:0] = 8'b11101111;
3'b101 : out[7:0] = 8'b11011111;
3'b110 : out[7:0] = 8'b10111111;
default : out[7:0] = 8'b01111111;
endcase
endmodule

这里我需要提一点,就是always语句或者initial语句里面是数据流的形式,数据流的形式和其他形式的区别有以下几点

  • 左边的元素一定是reg类型的
  • 不允许使用assign赋值
  • @(…..)表示…..里面的值发生变化的时候就进入语句块

这里可以使用case(…)来模仿C里面的switch语句来进行赋值(真值表)
用逻辑函数也可以(做运算或者申明逻辑门[逻辑门之间使用wire连接])

对于4-16的亦是如此

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
module decoder_4to16(in, out);
input [3:0] in;
output reg [7:0] out;

always@(in)
begin
case(in)
4'b0000 : out[7:0] = 8'b11000000;
4'b0001 : out[7:0] = 8'b11111001;
4'b0010 : out[7:0] = 8'b10100100;
4'b0011 : out[7:0] = 8'b10110000;
4'b0100 : out[7:0] = 8'b10011001;
4'b0101 : out[7:0] = 8'b10010010;
4'b0110 : out[7:0] = 8'b10000010;
4'b0111 : out[7:0] = 8'b11111000;
4'b1000 : out[7:0] = 8'b10000000;
4'b1001 : out[7:0] = 8'b10011000;
4'b1010 : out[7:0] = 8'b10001000;
4'b1011 : out[7:0] = 8'b10000011;
4'b1100 : out[7:0] = 8'b11000110;
4'b1101 : out[7:0] = 8'b10100001;
4'b1110 : out[7:0] = 8'b10000110;
default : out[7:0] = 8'b10001110;
endcase
end
endmodule

最后使用结构声明来组装零件

1
2
3
4
5
6
7
8
9
10
11
module Last(SW, SEG, AN, LED);
input [15:0] SW; // 16位拨动开关
output [7:0] SEG; // 7段数码管驱动,低电平有效
output [7:0] AN; // 7段数码管片选信号,低电平有效
output [15:0] LED; // 16位LED显示

decoder_3to8(.in(SW[15:13]), .out(AN[7:0]));
decoder_4to16(.in(SW[3:0]), .out(SEG[7:0]));

assign LED[15:0] = SW[15:0];
endmodule

说明一下.xxx(yyy)说明yyy这个值传进结构声明中xxx这个变量,.in(SW[15:13])表示SW[15:13]这个东西放到decoder_3to8里面的in

实验三:简单的同步时许逻辑电路

首先就是滤波器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module divider(clk, clk_N);
input clk; // 系统时钟
output reg clk_N; // 分频后的时钟
parameter N = 100_000_000; // 1Hz的时钟,N=fclk/fclk_N
reg [31:0] counter; /* 计数器变量,通过计数实现分频。当计数器从0计数到(N/2-1)时,输出时钟翻转,计数器清零 */

initial
begin // 赋初始值
counter = 0;
clk_N = 0;
end
always @(posedge clk) // 时钟上升
begin
counter <= counter + 1;
if (counter > N / 2)
begin
clk_N <= ~clk_N;
counter <= 0;
end
end
endmodule

posedge代表上升的意思,这个就是clk(板子里面的E3)每一次上升就会触发,其实板子里面的E3会一直变化(速度非常快)这个就是板子里的E3变化了1亿次之后就会传输一个信号出去的意思

就是clk进.clk_N出clk变化100000000次,clk_N变化一次,这个就是分频的定义,所以说在always里面加上了一个if语句就是这个意思

1
2
3
4
5
6
7
8
9
module counter(clk, out);
input clk; // 计数时钟
output reg [2:0] out; // 计数值

always @(posedge clk) // 在时钟上升沿计数器加1
begin
out <= out + 1;
end
endmodule

计数器,就是每一次clk上升out就会加1,至于触发器怎么用,咱也不用管,就说明功能就完事了

第三个实验就是测试一下计数器和过滤器组合的原理

1
2
3
4
5
6
7
8
module divide_and_count(clk, out);
input clk;
output [2:0] out;
wire clk_tmp;

divider d1(.clk(clk), .clk_N(clk_tmp));
counter c1(.clk(clk_tmp), .out(out[2:0]));
endmodule

这个是不是有点像Java里面的装饰器,对传进来的信号进行逐级装饰,传递来的信号经过计数器的转化进行输出

实验四:只读存储器:打个表就行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
module rom8x4(addr, data);
input [2:0] addr; // 地址
output [3:0] data; // 地址addr处存储的数据
reg [3: 0] mem [7: 0]; // 8个4位的存储器

initial // 初始化存储器
begin
mem[0]=4'b0000;
mem[1]=4'b0010;
mem[2]=4'b0100;
mem[3]=4'b0110;
mem[4]=4'b1000;
mem[5]=4'b1010;
mem[6]=4'b1100;
mem[7]=4'b1110;
end

assign data[3:0] = mem[addr]; // 读取addr单元的值输出

endmodule

下面就是把信号分解成七位表示器了.上面提到过

最后把这些东西组在一块,又用到组织模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module dynamic_scan(clk, SEG, AN);
input clk; // 系统时钟
output [7:0] SEG; // 分别对应CA、CB、CC、CD、CE、CF、CG和DP
output [7:0] AN; // 8位数码管片选信
wire clk_tmp;
wire [2:0] num;
wire [3:0] code;

divider d1(.clk(clk), .clk_N(clk_tmp));
counter c1(.clk(clk_tmp), .out(num[2:0]));
decoder_3to8(.in(num[2:0]), .out(AN[7:0]));
rom8x4(.addr(num[2:0]), .data(code[3:0]));
decoder_4to16(.in(code[3:0]), .out(SEG[7:0]));

endmodule

可以使用wire连接,也可以直接你的输出就是我的输入

更新于

请我喝[茶]~( ̄▽ ̄)~*

Sukuna 微信支付

微信支付

Sukuna 支付宝

支付宝