相关资料

可以去小脚丫官网查询想要信息,链接 小脚丫STEP开源社区

相关模块

时钟分频

带复位的时钟分频:

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
/**
* 模块名: divide
* 描述: 带复位的时钟分频
* 输入: 分频时钟
* 输入: 复位信号
* 输出: 分频后的输出时钟
**/
module divide (
input clk, // 连接到FPGA的C1脚,频率为12MHz
input rst_n, // 复位信号(低电平有效)
output clkout // 分频后的时钟信号
);

parameter WIDTH = 3; //计数器的位数,计数的最大值为 2**WIDTH-1
parameter N = 5; //分频系数,请确保 N < 2**WIDTH-1,否则计数会溢出

reg [WIDTH-1:0] cnt_p,cnt_n; //cnt_p为上升沿触发时的计数器,cnt_n为下降沿触发时的计数器
reg clk_p,clk_n; //clk_p为上升沿触发时分频时钟,clk_n为下降沿触发时分频时钟

// 上升沿触发的模N计数器
always @ (posedge clk or negedge rst_n ) begin
if(!rst_n)
cnt_p<=0;
else if (cnt_p==(N-1))
cnt_p<=0;
else cnt_p<=cnt_p+1;
end

//上升沿触发的分频时钟输出
always @ (posedge clk or negedge rst_n) begin
if(!rst_n)
clk_p<=0;
else if (cnt_p<(N>>1))
clk_p<=0;
else
clk_p<=1;
end

// 下降沿触发的模N计数器
always @ (negedge clk or negedge rst_n) begin
if(!rst_n)
cnt_n<=0;
else if (cnt_n==(N-1))
cnt_n<=0;
else cnt_n<=cnt_n+1;
end

// 下降沿触发的分频时钟输出
always @ (negedge clk) begin
if(!rst_n)
clk_n<=0;
else if (cnt_n<(N>>1))
clk_n<=0;
else
clk_n<=1;
end

/* 经过运算,输出占空比为50%的时钟信号 */
/* 输出 = N是否为1 ? 不分频: (N是否时奇数 ? 特殊处理 : 直接输出其中一个信号即可) */
assign clkout = (N==1) ? clk : ( N[0]?(clk_p&clk_n):clk_p );

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
/**
* 模块名: divide
* 描述: 不带复位的时钟分频
* 输入: 分频时钟
* 输出: 分频后的输出时钟
**/
module divide (
input clk, // 连接到FPGA的C1脚,频率为12MHz
output clkout // 分频后的时钟信号
);

parameter WIDTH = 3; //计数器的位数,计数的最大值为 2**WIDTH-1
parameter N = 5; //分频系数,请确保 N < 2**WIDTH-1,否则计数会溢出

reg [WIDTH-1:0] cnt_p,cnt_n; //cnt_p为上升沿触发时的计数器,cnt_n为下降沿触发时的计数器
reg clk_p,clk_n; //clk_p为上升沿触发时分频时钟,clk_n为下降沿触发时分频时钟

// 上升沿触发的模N计数器
always @ (posedge clk) begin
if (cnt_p==(N-1))
cnt_p<=0;
else cnt_p<=cnt_p+1;
end

//上升沿触发的分频时钟输出
always @ (posedge clk) begin
if (cnt_p<(N>>1))
clk_p<=0;
else
clk_p<=1;
end

// 下降沿触发的模N计数器
always @ (negedge clk) begin
if (cnt_n==(N-1))
cnt_n<=0;
else cnt_n<=cnt_n+1;
end

// 下降沿触发的分频时钟输出
always @ (negedge clk) begin
if (cnt_n<(N>>1))
clk_n<=0;
else
clk_n<=1;
end

/* 经过运算,输出占空比为50%的时钟信号 */
/* 输出 = N是否为1 ? 不分频: (N是否时奇数 ? 特殊处理 : 直接输出其中一个信号即可) */
assign clkout = (N==1) ? clk : ( N[0]?(clk_p&clk_n):clk_p );

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
/**
* 模块名: debounce
* 描述: 消抖模块
* 输入: 1kHz时钟信号
* 输入: 未消抖信号
* 输出: 消抖信号
**/
module debounce(
input clk_1kHz, // 时钟信号
input key, // 输入
output reg key_out // 防抖后输出
);

reg [3:0]cnt; // 计数器

always @(posedge clk_1kHz)begin

if(!key) // 未按下按键,清除计数器
cnt<=0;
else if(cnt==4'd10)
cnt<=4'd10;
else
cnt<=cnt+1;

if(cnt==4'd9)
key_out<=1;
else
key_out<=0;

end

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
module debounce (
input clk, // 输入时钟
input rst, // 复位按键(低电平有效)
input [N-1:0] key, // 需要消抖的按键
output [N-1:0] key_pulse // 消抖后的输出信号
);

parameter N = 1; //要消除的按键的数量

reg [N-1:0] key_rst_pre; // 存储上一个触发时的按键值
reg [N-1:0] key_rst; // 存储当前时刻触发的按键值

wire [N-1:0] key_edge; // 检测到按键由高到低变化是产生一个高脉冲

always @(posedge clk or negedge rst) begin
if (!rst) begin
key_rst <= {N{1'b1}};
key_rst_pre <= {N{1'b1}};
end
else begin
key_rst <= key;
key_rst_pre <= key_rst;
end
end

assign key_edge = key_rst_pre & (~key_rst); // 脉冲边沿检测。当key检测到下降沿时,key_edge产生一个时钟周期的高电平

reg [17:0] cnt; // 产生延时所用的计数器,系统时钟12MHz,需要延时20ms,计数器至少18位

// 产生20ms延时,当检测到 key_edge 有效时计数器清零开始计数
always @(posedge clk or negedge rst) begin
if(!rst)
cnt <= 18'h0;
else if(key_edge)
cnt <= 18'h0;
else
cnt <= cnt + 1'h1;
end

reg [N-1:0] key_sec_pre; // 延时后检测电平寄存器变量
reg [N-1:0] key_sec;

// 延时后检测key
always @(posedge clk or negedge rst) begin
if (!rst)
key_sec <= {N{1'b1}};
else if (cnt==18'h3ffff)
key_sec <= key;
end

always @(posedge clk or negedge rst) begin
if (!rst)
key_sec_pre <= {N{1'b1}};
else
key_sec_pre <= key_sec;
end

assign key_pulse = key_sec_pre & (~key_sec);

endmodule

计数器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 模8计数器,频率: 1KHz 计数周期: 8
*/
reg [2:0] cnt_8; // 3位计数器

initial cnt_8 <= 3'd0;

always @(posedge clk_1kHz)begin
if(cnt_8==3'd7)
cnt_8<=3'd0; // 重置
else
cnt_8<=cnt_8+1; // 向上计数
end

数码管显示

非扫描型 (共阴极):

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
/** 
* 模块名: Display
* 描述: 数码管显示模块
**/
module Display(
input number, // 输入数字
output reg [8:0] seg, // 数码管信号(共阴极数码管)
);

initial begin
seg <= 9'h00;
end

always @(number)begin
case (number)
0: seg <= 9'h3f; // 表示0
1: seg <= 9'h06; // 表示1
2: seg <= 9'h5b; // 表示2
3: seg <= 9'h4f; // 表示3
4: seg <= 9'h66; // 表示4
5: seg <= 9'h6d; // 表示5
6: seg <= 9'h7d; // 表示6
7: seg <= 9'h07; // 表示7
8: seg <= 9'h7f; // 表示8
default: seg <= 9'h6f; // 表示9
endcase
end

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
/** 
* 模块名: Display
* 描述: 数码管显示模块
**/
module Display(
input clk_1kHz,
input [3:0] tens,
input [3:0] ones,
……
input [3:0] xxxx,
output reg [7:0] seg, // 数码管阳极信号
output reg [7:0] cat // 数码管阴极信号
);

initial begin
seg <= 8'b0000_0000;
cat <= 8'b1111_1111;
end

always @(cnt_8) begin
case (cnt_8)
/* 个位 */
0: begin
cat<=8'b1111_1110;

case (ones)
0: seg<=8'b0011_1111;
1: seg<=8'b0000_0110;
2: seg<=8'b0101_1011;
3: seg<=8'b0100_1111;
4: seg<=8'b0110_0110;
5: seg<=8'b0110_1101;
6: seg<=8'b0111_1101;
7: seg<=8'b0000_0111;
8: seg<=8'b0111_1111;
default: seg<=8'b0110_1111;
endcase
end
/* 十位 */
1: begin
cat<=8'b1111_1101;

case (ones)
0: seg<=8'b0011_1111;
1: seg<=8'b0000_0110;
2: seg<=8'b0101_1011;
3: seg<=8'b0100_1111;
4: seg<=8'b0110_0110;
5: seg<=8'b0110_1101;
6: seg<=8'b0111_1101;
7: seg<=8'b0000_0111;
8: seg<=8'b0111_1111;
default: seg<=8'b0110_1111;
endcase
end
……
default: begin
cat<=8'b0111_1111;

case (xxxx)
0: seg<=8'b0011_1111;
1: seg<=8'b0000_0110;
2: seg<=8'b0101_1011;
3: seg<=8'b0100_1111;
4: seg<=8'b0110_0110;
5: seg<=8'b0110_1101;
6: seg<=8'b0111_1101;
7: seg<=8'b0000_0111;
8: seg<=8'b0111_1111;
default: seg<=8'b0110_1111;
endcase
end
endcase
end

/**
* 模8计数器,频率: 1KHz 计数周期: 8
*/
reg [2:0] cnt_8; // 3位计数器

initial cnt_8 <= 3'd0;

always @(posedge clk_1kHz)begin
if(cnt_8==3'd7)
cnt_8<=3'd0; // 重置
else
cnt_8<=cnt_8+1; // 向上计数
end

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
/** 
* 模块名: Lattice_Display
* 描述: 点阵显示模块
* 输入: 1kHz时钟
* 输出: 行信号, 红列信号, 绿列信号
**/
module Lattice_Display(
input clk_1kHz, // 1KHz时钟

output reg [7:0] row, // 行信号(低电平有效)
output reg [7:0] col_r, // 红色列信号(高电平有效)
output reg [7:0] col_g // 绿色列信号(高电平有效)
);


always @(cnt_8)begin
case(cnt_8)
3'd7:begin row=8'b0111_1111;col_r<=8'b0000_0011;col_g<=8'b0000_0000;end // 第 7 行显示
3'd6:begin row=8'b1011_1111;col_r<=8'b0000_0011;col_g<=8'b0000_0000;end // 第 6 行显示
3'd5:begin row=8'b1101_1111;col_r<=8'b0000_0000;col_g<=8'b0000_0000;end // 第 5 行显示
3'd4:begin row=8'b1110_1111;col_r<=8'b0000_0000;col_g<=8'b0000_0011;end // 第 4 行显示
3'd3:begin row=8'b1111_0111;col_r<=8'b0000_0000;col_g<=8'b0000_0011;end // 第 3 行显示
3'd2:begin row=8'b1111_1011;col_r<=8'b0000_0000;col_g<=8'b0000_0000;end // 第 2 行显示
3'd1:begin row=8'b1111_1101;col_r<=8'b0000_0011;col_g<=8'b0000_0011;end // 第 1 行显示
3'd0:begin row=8'b1111_1110;col_r<=8'b0000_0011;col_g<=8'b0000_0011;end // 第 0 行显示
endcase
end

/**
* 模8计数器,频率: 1KHz 计数周期: 8
*/
reg [2:0] cnt_8; // 3位计数器

initial cnt_8 <= 3'd0;

always @(posedge clk_1kHz)begin
if(cnt_8==3'd7)
cnt_8<=3'd0; // 重置
else
cnt_8<=cnt_8+1; // 向上计数
end

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
/**
* 模块名: Beeper
* 描述: 蜂鸣器输出模块
* 输入: 10MHz时钟, 使能信号, 音节控制
* 输出: 蜂鸣器输出控制
**/
module Beeper
(
input clk_10MHz, // 10MHz时钟
input tone_en, // 蜂鸣器使能信号(高电平有效)
input [4:0] tone, // 蜂鸣器音节控制
output reg piano_out // 蜂鸣器控制输出
);

reg [15:0] time_end; // 计数器最大值

always@(tone) begin
case(tone)
5'd1: time_end = 16'd19110; //L1,
5'd2: time_end = 16'd17026; //L2,
5'd3: time_end = 16'd15169; //L3,
5'd4: time_end = 16'd14317; //L4,
5'd5: time_end = 16'd12755; //L5,
5'd6: time_end = 16'd11363; //L6,
5'd7: time_end = 16'd10124; //L7,

5'd8: time_end = 16'd9556; //M1,
5'd9: time_end = 16'd8513; //M2,
5'd10: time_end = 16'd7584; //M3,
5'd11: time_end = 16'd7159; //M4,
5'd12: time_end = 16'd6378; //M5,
5'd13: time_end = 16'd5682; //M6,
5'd14: time_end = 16'd5062; //M7,

5'd15: time_end = 16'd4782; //H1,
5'd16: time_end = 16'd4257; //H2,
5'd17: time_end = 16'd3792; //H3,
5'd18: time_end = 16'd3579; //H4,
5'd19: time_end = 16'd3189; //H5,
5'd20: time_end = 16'd2841; //H6,
5'd21: time_end = 16'd2531; //H7,

default:time_end = 16'd65535;
endcase
end

reg [17:0] time_cnt;

// 模 time_end 计数器
always@(posedge clk_10MHz) begin
if(!tone_en) begin
time_cnt <= 1'b0; // 始终保持0
end
else if(time_cnt >= time_end) begin
time_cnt <= 1'b0; // 重置
end
else begin
time_cnt <= time_cnt + 1'b1; // 向上计数
end
end

// 根据计数器的周期,翻转蜂鸣器控制信号
always@(posedge clk_10MHz) begin
if(time_cnt == time_end) begin
piano_out <= ~piano_out; // 翻转
end
else begin
piano_out <= piano_out; // 保持
end
end

endmodule