Zen的小站

小舟从此逝,江海寄余生

0%

【verilog】学习

文章概览

verilog HDL(Hardware Description Language)

用代码写数字器件的连接

image-20230119183007408

有两种实现方式

1
2
3
4
5
6
7
8
module mux2_1(a, b, s, y); //模块名、模块接口名
input a, b, s; // 定义输入端口
output y; // 定义输出端口

/* s为0时,选择a输出;
s为1时,选择b输出。*/
assign y = (s == 0) ? a : b; //输出信号
endmodule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module mux2_1(a, b, s, y);
input a, b, s;
output y;
reg y; //reg 表示寄存器

always @(a, b, s) //当有a,b,s中任一值变化,将触发
begin
if(!s) y = a;
else y = b;
end

always @(*) //当有a,b,s中任一值变化,将触发
switch

endmodule

实例代码解读

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
module pwm_buzzer(
input clk , //时钟输入
input rst_n , //复位按键输入
input key_in , //按键输入

output reg buzzer //驱动蜂鸣器
);

wire press ; //线,连接按键标志信号

//引用按键模块
key_debounce u_key_debounce(
.clk (clk ),
.rst_n (rst_n ),
.key (key_in ),
.press (press )
);

//定义音符时序周期数
localparam M0 = 98800,
M1 = 95600,
M2 = 85150,
M3 = 75850,
M4 = 71600,
M5 = 63750,
M6 = 56800,
M7 = 50600;

//信号定义
reg [16:0] cnt0 ; //计数每个音符对应的时序周期
reg [10:0] cnt1 ; //计数每个音符重复次数
reg [5 :0] cnt2 ; //计数曲谱中音符个数

reg [16:0] pre_set ; //预装载值
wire [16:0] pre_div ; //占空比

reg [10:0] cishu ; //定义不同音符重复不同次数
wire [10:0] cishu_div ; //音符重复次数占空比

reg flag ; //歌曲种类标志:0小星星,1两只老虎
reg [5 :0] YINFU ; //定义曲谱中音符个数

//歌曲种类标志位
always @(posedge clk or negedge rst_n) begin //每个时钟信号触发
if(!rst_n) begin
flag <= 1'b0;
end
else if(press) begin
flag <= ~flag;
end
end

//重设音符的个数
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
YINFU <= 48;
else if(flag == 1'b1)
YINFU <= 36;
else
YINFU <= 48;
end

//计数每个音符的周期,也就是表示音符的一个周期
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt0 <= 0;
end
else if(press)
cnt0 <= 0;
else begin
if(cnt0 == pre_set - 1)
cnt0 <= 0;
else
cnt0 <= cnt0 + 1;
end
end

//计数每个音符重复次数,也就是表示一个音符的响鸣持续时长
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt1 <= 0;
end
else if(press)
cnt1 <= 0;
else begin
if(cnt0 == pre_set - 1)begin
if(cnt1 == cishu)
cnt1 <= 0;
else
cnt1 <= cnt1 + 1;
end
end
end

//计数有多少个音符,也就是曲谱中有共多少个音符
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt2 <= 0;
end
else if(press)
cnt2 <= 0;
else begin
if(cnt1 == cishu && cnt0 == pre_set - 1) begin
if(cnt2 == YINFU - 1) begin
cnt2 <= 0;
end
else
cnt2 <= cnt2 + 1;
end
end
end

//定义音符重复次数
always @(*) begin //当pre_set值变化时触发
case(pre_set)
M0:cishu = 242;
M1:cishu = 250;
M2:cishu = 281;
M3:cishu = 315;
M4:cishu = 334;
M5:cishu = 375;
M6:cishu = 421;
M7:cishu = 472;
endcase
end

//曲谱定义
always @(*) begin
if(flag == 1'b0) begin
case(cnt2) //小星星歌谱
0 : pre_set = M1;
1 : pre_set = M1;
2 : pre_set = M5;
3 : pre_set = M5;
4 : pre_set = M6;
5 : pre_set = M6;
6 : pre_set = M5;
7 : pre_set = M0;

8 : pre_set = M4;
9 : pre_set = M4;
10: pre_set = M3;
11: pre_set = M3;
12: pre_set = M2;
13: pre_set = M2;
14: pre_set = M1;
15: pre_set = M0;

16: pre_set = M5;
17: pre_set = M5;
18: pre_set = M4;
19: pre_set = M4;
20: pre_set = M3;
21: pre_set = M3;
22: pre_set = M2;
23: pre_set = M0;

24: pre_set = M5;
25: pre_set = M5;
26: pre_set = M4;
27: pre_set = M4;
28: pre_set = M3;
29: pre_set = M3;
30: pre_set = M2;
31: pre_set = M0;

32: pre_set = M1;
33: pre_set = M1;
34: pre_set = M5;
35: pre_set = M5;
36: pre_set = M6;
37: pre_set = M6;
38: pre_set = M5;
39: pre_set = M0;

40: pre_set = M4;
41: pre_set = M4;
42: pre_set = M3;
43: pre_set = M3;
44: pre_set = M2;
45: pre_set = M2;
46: pre_set = M1;
47: pre_set = M0;
endcase
end
else begin
case(cnt2) //两只老虎歌谱
0 : pre_set = M1;
1 : pre_set = M2;
2 : pre_set = M3;
3 : pre_set = M1;
4 : pre_set = M1;
5 : pre_set = M2;
6 : pre_set = M3;
7 : pre_set = M1;
8 : pre_set = M3;
9 : pre_set = M4;
10: pre_set = M5;
11: pre_set = M0;

12: pre_set = M3;
13: pre_set = M4;
14: pre_set = M5;
15: pre_set = M0;

16: pre_set = M5;
17: pre_set = M6;
18: pre_set = M5;
19: pre_set = M4;
20: pre_set = M3;
21: pre_set = M1;
22: pre_set = M5;
23: pre_set = M6;
24: pre_set = M5;
25: pre_set = M4;
26: pre_set = M3;
27: pre_set = M1;
28: pre_set = M2;
29: pre_set = M5;
30: pre_set = M1;
31: pre_set = M0;

32: pre_set = M2;
33: pre_set = M5;
34: pre_set = M1;
35: pre_set = M0;
endcase
end
end

assign pre_div = pre_set >> 1; //除以2
assign cishu_div = cishu * 4 / 5;

//向蜂鸣器输出脉冲
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
buzzer <= 1'b1;
end
else if(pre_set != M0) begin
if(cnt1 < cishu_div) begin
if(cnt0 < pre_div) begin
buzzer <= 1'b1;
end
else begin
buzzer <= 1'b0;
end
end
else begin
buzzer <= 1'b1;
end
end
else
buzzer <= 1'b1;
end

endmodule


多想多做,发篇一作

-------------本文结束感谢您的阅读-------------
// 在最后添加