本帖最后由 52Hertz 于 2021-12-5 13:16 编辑
刚看完小梅哥的视频,花了几个钟头写成了作业,就两个功能,24小时计时和用串口设置时间。默认波特率为115200,上电开始从00:00:00计时,开发板是720,漏洞坑定有,还请各位指正。
这是最顶层文件
module digital_clock(
clk,
reset_n,
sh_cp,
st_cp,
rx,
ds
);
input clk;
input reset_n;
input rx;
output sh_cp;
output st_cp;
output ds;
reg [31:0] disp_data;
reg [25:0] counter;
parameter second_cnt = 26'h2FAF080;
smg_top smg_top_demo(
.clk(clk),
.reset_n(reset_n),
.sh_cp(sh_cp),
.st_cp(st_cp),
.ds(ds),
.disp_data(disp_data)
);
wire [7:0] data;
wire rx_done;
uart_byte_rx uart_byte_rx_demo(
.clk(clk),
.reset_n(reset_n),
.baud_set(3'd4),
.uart_rx(rx),
.data_byte(data),
.rx_done(rx_done)
);
reg [1:0] set_done;
reg [7:0]second;
reg [7:0]minute;
reg [7:0]hour;
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
set_done <= 0;
else if(set_done == 2'd3)
set_done <= 1'd0;
else if(rx_done)
set_done <= set_done + 1'd1;
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
counter <= 0;
else if(counter == second_cnt - 1'b1)
counter <= 0;
else
counter <= counter + 1'b1;
end
reg clk_second;
always@(posedge clk or negedge reset_n)begin//产生秒脉冲
if(!reset_n)
clk_second <= 1'b0;
else if(counter == second_cnt - 1'b1)
clk_second <= 1'b1;
else
clk_second <= 1'b0;
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
second <= 8'd0;
else if((rx_done )&&(set_done == 2'd2))
second <= data;
else if(clk_second)begin
if((second[7:4] == 4'd5)&&(second[3:0] == 4'd9))begin
second <=8'd0;
end
else if(second[3:0] == 4'd9)begin
second[7:4] <= second[7:4] + 1;
second[3:0] <= 4'd0;
end
else
second[3:0] <= second[3:0] + 1'b1;
end
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
minute <= 8'd0;
else if((rx_done )&&(set_done == 2'd1))
minute <= data;
else if(clk_second)begin
if((second[7:4] == 4'd5)&&(second[3:0] == 4'd9))begin
if((minute[7:4]== 4'd5)&&(minute[3:0]== 4'd9))
minute <= 8'd0;
else if(minute[3:0] == 4'd9)begin
minute[7:4] <= minute[7:4] + 1'b1;
minute[3:0] <= 4'd0;
end
else
minute[3:0] <= minute[3:0] + 1'b1;
end
end
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
hour <= 8'd0;
else if((rx_done )&&(set_done == 2'd0))
hour <= data;
else if(clk_second)begin
if((second[7:4] == 4'd5)&&(second[3:0] == 4'd9)&&(minute[7:4] == 4'd5)&&(minute[3:0] == 4'd9))begin
if((hour[7:4]==4'd2)&&(hour[3:0] == 4'd3))
hour <= 8'd0;
else if(hour[3:0] == 4'd9)begin
hour[3:0] <= 4'd0;
hour[7:4] <= hour[7:4] + 1'b1;
end
else
hour[3:0] <= hour[3:0] + 1'b1;
end
end
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
disp_data <= 32'd0;
else if(clk_second)
disp_data <= {second[3:0],second[7:4],minute[3:0],minute[7:4],hour[3:0],hour[7:4],8'd0};
end
endmodule
这是smg_top模块
module smg_top(
clk,
reset_n,
sh_cp,
st_cp,
ds,
disp_data
);
input clk;
input reset_n;
input [31:0]disp_data;
output sh_cp;
output st_cp;
output ds;
wire[7:0] sel;
wire[7:0] seg;
wire [15:0] data;
assign data = {seg,sel};
smg_dispaly smg_display_demo(
.clk(clk),
.reset_n(reset_n),
.disp_data(disp_data),
.sel(sel),
.seg(seg)
);
smg_hc595 smg_hc595_demo(
.clk(clk),
.reset_n(reset_n),
.data(data),
.sh_cp(sh_cp),
.st_cp(st_cp),
.en(1'b1),
.ds(ds)
);
endmodule
这是smg译码和hc595驱动模块,都被例化在smg_top文件中
module smg_dispaly(
clk,
reset_n,
disp_data,
sel,
seg
);
input clk;
input reset_n;
input [31:0] disp_data;//要现实的数据一共对应八位数码管的八位
output reg [7:0] sel;//位选输出
output reg [7:0] seg;//译码输出 a-h : seg[0]-seg[7]
reg clk_div;
reg [14:0]div_cnt;
reg [2:0]num_cnt;
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
div_cnt <= 15'd0;
else if(div_cnt == 24999)
div_cnt <= 15'd0;
else
div_cnt <= div_cnt + 1'd1;
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
clk_div <= 1;
else if(div_cnt == 24999)
clk_div <= 1'b1;
else
clk_div <= 0;
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
num_cnt <= 0;
else if(clk_div)
num_cnt <= num_cnt + 1;
end
always@(*)begin
case(num_cnt)
0: sel <= 8'b00000001;
1: sel <= 8'b00000010;
2: sel <= 8'b00000100;
3: sel <= 8'b00001000;
4: sel <= 8'b00010000;
5: sel <= 8'b00100000;
6: sel <= 8'b01000000;
7: sel <= 8'b10000000;
endcase
end
reg [3:0]disp_temp;
always@(*)begin
case(num_cnt)
0: disp_temp <= disp_data[31:28];
1: disp_temp <= disp_data[27:24];
2: disp_temp <= disp_data[23:20];
3: disp_temp <= disp_data[19:16];
4: disp_temp <= disp_data[15:12];
5: disp_temp <= disp_data[11:8];
6: disp_temp <= disp_data[7:4];
7: disp_temp <= disp_data[3:0];
endcase
end
always@(*)begin
case(disp_temp)
4'h0: seg = 8'hc0;
4'h1: seg = 8'hf9;
4'h2: seg = 8'ha4;
4'h3: seg = 8'hb0;
4'h4: seg = 8'h99;
4'h5: seg = 8'h92;
4'h6: seg = 8'h82;
4'h7: seg = 8'hf8;
4'h8: seg = 8'h80;
4'h9: seg = 8'h90;
4'ha: seg = 8'h88;
4'hb: seg = 8'h83;
4'hc: seg = 8'hc6;
4'hd: seg = 8'ha1;
4'he: seg = 8'h86;
4'hf : seg = 8'h8e;
endcase
end
endmodule
module smg_hc595(
clk,
reset_n,
data,
sh_cp,
st_cp,
en,
ds
);
input clk;
input reset_n;
input [15:0] data;
input en;
output reg sh_cp;
output reg st_cp;
output reg ds;
reg [5:0] shcp_edge_cnt;
reg [15:0] r_data;
always@(posedge clk)begin
if(en)
r_data <= data;
end
reg[2:0] div_cnt;
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
div_cnt <= 0;
else if(div_cnt == 1'b1)
div_cnt <= 0;
else
div_cnt <= div_cnt + 1'b1;
end
wire sck;
assign sck = (div_cnt == 1'b1);
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
shcp_edge_cnt <= 0;
else if(sck)begin
if(shcp_edge_cnt == 6'd32)
shcp_edge_cnt <= 0;
else
shcp_edge_cnt <= shcp_edge_cnt + 1'b1;
end
else
shcp_edge_cnt <= shcp_edge_cnt;
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)begin
sh_cp <= 1'b0;
st_cp <= 1'b0;
ds <= 1'b0;
end
else begin
case(shcp_edge_cnt)
0:begin sh_cp <= 1'd0; ds <= r_data[15];end
1:begin sh_cp <= 1'd1;st_cp <= 1'd0;end
2:begin sh_cp <= 1'd0; st_cp <= 1'd0;ds <= r_data[14];end
3:sh_cp <= 1'd1;
4:begin sh_cp <= 1'd0; st_cp <= 1'd0;ds <= r_data[13];end
5:sh_cp <= 1'd1;
6:begin sh_cp <= 1'd0; st_cp <= 1'd0;ds <= r_data[12];end
7:sh_cp <= 1'd1;
8:begin sh_cp <= 1'd0; st_cp <= 1'd0;ds <= r_data[11];end
9:sh_cp <= 1'd1;
10:begin sh_cp <= 1'd0; st_cp <= 1'd0;ds <= r_data[10];end
11:sh_cp <= 1'd1;
12:begin sh_cp <= 1'd0; st_cp <= 1'd0;ds <= r_data[9];end
13:sh_cp <= 1'd1;
14:begin sh_cp <= 1'd0; st_cp <= 1'd0;ds <= r_data[8];end
15:sh_cp <= 1'd1;
16:begin sh_cp <= 1'd0; st_cp <= 1'd0;ds <= r_data[7];end
17:sh_cp <= 1'd1;
18:begin sh_cp <= 1'd0; st_cp <= 1'd0;ds <= r_data[6];end
19:sh_cp <= 1'd1;
20:begin sh_cp <= 1'd0; st_cp <= 1'd0;ds <= r_data[5];end
21:sh_cp <= 1'd1;
22:begin sh_cp <= 1'd0; st_cp <= 1'd0;ds <= r_data[4];end
23:sh_cp <= 1'd1;
24:begin sh_cp <= 1'd0; st_cp <= 1'd0;ds <= r_data[3];end
25:sh_cp <= 1'd1;
26:begin sh_cp <= 1'd0; st_cp <= 1'd0;ds <= r_data[2];end
27:sh_cp <= 1'd1;
28:begin sh_cp <= 1'd0; st_cp <= 1'd0;ds <= r_data[1];end
29:sh_cp <= 1'd1;
30:begin sh_cp <= 1'd0; st_cp <= 1'd0;ds <= r_data[0];end
31:sh_cp <= 1'd1;
32:st_cp <= 1'd1;
default : begin sh_cp <= 1'b0;st_cp <= 1'b0;ds <= 1'b0;end
endcase
end
end
endmodule
最后的是串口接收模块,和smg_top一起被例化在digital_clock顶层文件中
module uart_byte_rx(
clk,
reset_n,
baud_set,
uart_rx,
data_byte,
rx_done
);
assign reset=~reset_n;
input clk; //模块全局时钟输入,50M
input reset_n; //复位信号输入,低有效
input [2:0]baud_set; //波特率设置
input uart_rx; //串口输入信号
output [7:0]data_byte; //串口接收的1byte数据
output rx_done; //1byte数据接收完成标志
reg [7:0]data_byte;
reg rx_done;
reg uart_rx_sync1; //同步寄存器
reg uart_rx_sync2; //同步寄存器
reg uart_rx_reg1; //数据寄存器
reg uart_rx_reg2; //数据寄存器
reg [15:0]bps_DR; //分频计数最大值
reg [15:0]div_cnt; //分频计数器
reg bps_clk; //波特率时钟
reg [7:0] bps_cnt; //波特率时钟计数器
reg uart_state;//接收数据状态
wire uart_rx_nedge;
reg [2:0]START_BIT;
reg [2:0]STOP_BIT;
reg [2:0]data_byte_pre [7:0];
//同步串行输入信号,消除亚稳态
always@(posedge clk or posedge reset)
if(reset)begin
uart_rx_sync1 <= 1'b0;
uart_rx_sync2 <= 1'b0;
end
else begin
uart_rx_sync1 <= uart_rx;
uart_rx_sync2 <= uart_rx_sync1;
end
//数据寄存器
always@(posedge clk or posedge reset)
if(reset)begin
uart_rx_reg1 <= 1'b0;
uart_rx_reg2 <= 1'b0;
end
else begin
uart_rx_reg1 <= uart_rx_sync2;
uart_rx_reg2 <= uart_rx_reg1;
end
//下降沿检测
assign uart_rx_nedge = !uart_rx_reg1 & uart_rx_reg2;
always@(posedge clk or posedge reset)
if(reset)
bps_DR <= 16'd324;
else begin
case(baud_set)
0:bps_DR <= 16'd324;
1:bps_DR <= 16'd162;
2:bps_DR <= 16'd80;
3:bps_DR <= 16'd53;
4:bps_DR <= 16'd26;
default:bps_DR <= 16'd324;
endcase
end
//counter
always@(posedge clk or posedge reset)
if(reset)
div_cnt <= 16'd0;
else if(uart_state)begin
if(div_cnt == bps_DR)
div_cnt <= 16'd0;
else
div_cnt <= div_cnt + 1'b1;
end
else
div_cnt <= 16'd0;
// bps_clk gen
always@(posedge clk or posedge reset)
if(reset)
bps_clk <= 1'b0;
else if(div_cnt == 16'd1)
bps_clk <= 1'b1;
else
bps_clk <= 1'b0;
//bps counter
always@(posedge clk or posedge reset)
if(reset)
bps_cnt <= 8'd0;
else if(bps_cnt == 8'd159 | (bps_cnt == 8'd12 && (START_BIT > 2)))
bps_cnt <= 8'd0;
else if(bps_clk)
bps_cnt <= bps_cnt + 1'b1;
else
bps_cnt <= bps_cnt;
always@(posedge clk or posedge reset)
if(reset)
rx_done <= 1'b0;
else if(bps_cnt == 8'd159)
rx_done <= 1'b1;
else
rx_done <= 1'b0;
always@(posedge clk or posedge reset)
if(reset)begin
START_BIT <= 3'd0;
data_byte_pre[0] <= 3'd0;
data_byte_pre[1] <= 3'd0;
data_byte_pre[2] <= 3'd0;
data_byte_pre[3] <= 3'd0;
data_byte_pre[4] <= 3'd0;
data_byte_pre[5] <= 3'd0;
data_byte_pre[6] <= 3'd0;
data_byte_pre[7] <= 3'd0;
STOP_BIT <= 3'd0;
end
else if(bps_clk)begin
case(bps_cnt)
0:begin
START_BIT <= 3'd0;
data_byte_pre[0] <= 3'd0;
data_byte_pre[1] <= 3'd0;
data_byte_pre[2] <= 3'd0;
data_byte_pre[3] <= 3'd0;
data_byte_pre[4] <= 3'd0;
data_byte_pre[5] <= 3'd0;
data_byte_pre[6] <= 3'd0;
data_byte_pre[7] <= 3'd0;
STOP_BIT <= 3'd0;
end
6 ,7 ,8 ,9 ,10,11:START_BIT <= START_BIT + uart_rx_sync2;
22,23,24,25,26,27:data_byte_pre[0] <= data_byte_pre[0] + uart_rx_sync2;
38,39,40,41,42,43:data_byte_pre[1] <= data_byte_pre[1] + uart_rx_sync2;
54,55,56,57,58,59:data_byte_pre[2] <= data_byte_pre[2] + uart_rx_sync2;
70,71,72,73,74,75:data_byte_pre[3] <= data_byte_pre[3] + uart_rx_sync2;
86,87,88,89,90,91:data_byte_pre[4] <= data_byte_pre[4] + uart_rx_sync2;
102,103,104,105,106,107:data_byte_pre[5] <= data_byte_pre[5] + uart_rx_sync2;
118,119,120,121,122,123:data_byte_pre[6] <= data_byte_pre[6] + uart_rx_sync2;
134,135,136,137,138,139:data_byte_pre[7] <= data_byte_pre[7] + uart_rx_sync2;
150,151,152,153,154,155:STOP_BIT <= STOP_BIT + uart_rx_sync2;
default:
begin
START_BIT <= START_BIT;
data_byte_pre[0] <= data_byte_pre[0];
data_byte_pre[1] <= data_byte_pre[1];
data_byte_pre[2] <= data_byte_pre[2];
data_byte_pre[3] <= data_byte_pre[3];
data_byte_pre[4] <= data_byte_pre[4];
data_byte_pre[5] <= data_byte_pre[5];
data_byte_pre[6] <= data_byte_pre[6];
data_byte_pre[7] <= data_byte_pre[7];
STOP_BIT <= STOP_BIT;
end
endcase
end
always@(posedge clk or posedge reset)
if(reset)
data_byte <= 8'd0;
else if(bps_cnt == 8'd159)begin
data_byte[0] <= data_byte_pre[0][2];
data_byte[1] <= data_byte_pre[1][2];
data_byte[2] <= data_byte_pre[2][2];
data_byte[3] <= data_byte_pre[3][2];
data_byte[4] <= data_byte_pre[4][2];
data_byte[5] <= data_byte_pre[5][2];
data_byte[6] <= data_byte_pre[6][2];
data_byte[7] <= data_byte_pre[7][2];
end
always@(posedge clk or posedge reset)
if(reset)
uart_state <= 1'b0;
else if(uart_rx_nedge)
uart_state <= 1'b1;
else if(rx_done || (bps_cnt == 8'd12 && (START_BIT > 2)) || (bps_cnt == 8'd155 && (STOP_BIT < 3)))
uart_state <= 1'b0;
else
uart_state <= uart_state;
endmodule