基于串口校时的数字时
刚看完小梅哥的视频,完成了基于串口校时的数字时钟,作业要求如下:
使用ACX720开发板编写一个可通过串口修改时间的简易数字钟
1、使用数码管显示,能够显示时分秒。
2、能够接收串口发送过来的设置时间的信息,并修改时间。
3、能够将当前时间值通过串口以1秒一次的速率发送到电脑。
本工程实现了作业的基本要求
顶层文件
module uart_clock(
input clk,
input reset_n,
input time_rx,//向FPGA输入想显示的时间
output ds,
output sh_cp,
output st_cp,
output uart_tx
);
wire rx_done;
wire [7:0] rx_data;
wire ctrl;
wire [31:0] time_set;
uart_byte_rx uart_byte_rx_u(
.clk (clk),
.reset_n (reset_n),
.uart_rx (time_rx),
.baud_set (4),
.data (rx_data),
.rx_done (rx_done)
);
uart_cmd uart_cmd_u(
.clk (clk),
.reset_n (reset_n),
.rx_data (rx_data),
.rx_done (rx_done),
.ctrl (ctrl),
.time_set(time_set)
);
//****一秒产生一个使能信号
reg [32:0] cnt;//计时一秒钟
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
cnt<=0;
else if(cnt>=49999999)
cnt<=0;
else cnt<=cnt+1;
end
reg time_1s;//一秒钟产生一个使能信号
reg trans_go;
always @(posedge clk or negedge reset_n) begin
if(!reset_n)
time_1s<=0;
else if(cnt==49999999)begin
time_1s<=1;
trans_go<=1;
end
else begin time_1s<=0;
trans_go<=0;
end
end
//******//
reg [31:0] time_set_r;//time_set_r[7:0] time_set_r[15:8] time_set_r[23:16] time_set_r[31:24]
always @(posedge clk or negedge reset_n) begin
if(!reset_n)
time_set_r<=0;
else if(ctrl)begin
time_set_r<=time_set;
end
else if(time_1s)begin
time_set_r[3:0]<=time_set_r[3:0]+1;//秒位加一
if(time_set_r[3:0]==4'd9)begin//秒位的个位和十位
if((time_set_r[7:4]==4'd5))begin//59->00,分的个位加一
time_set_r[7:4]<=4'd0;
time_set_r[3:0]<=4'd0;
time_set_r[11:8]<=time_set_r[11:8]+1;
end
else begin //秒的个位9->0,秒的十位加一
time_set_r[7:4]<=time_set_r[7:4]+1;
time_set_r[3:0]<=4'd0;
end
end
if(time_set_r[11:8]==4'd9)begin//分位的个位和十位
if((time_set_r[15:12]==4'd5)&&(time_set_r[7:4]==4'd5)&&(time_set_r[3:0]==4'd9))begin//59->00,小时的个位加一
time_set_r[15:12]<=4'd0;
time_set_r[11:8]<=4'd0;
time_set_r[19:16]<=time_set_r[19:16]+1;
end
else if ((time_set_r[7:4]==4'd5)&&(time_set_r[3:0]==4'd9))begin //分的个位9->0,分的十位加一
time_set_r[15:12]<=time_set_r[15:12]+1;
time_set_r[11:8]<=4'd0;
end
end
if(time_set_r[19:16]==4'd3)begin//小时位清零
if((time_set_r[23:20]==4'd2)&&(time_set_r[15:12]==4'd5)&&(time_set_r[11:8]==4'd9)&&(time_set_r[7:4]==4'd5)&&(time_set_r[3:0]==4'd9))begin
time_set_r[23:20]<=4'd0;
time_set_r[19:16]<=4'd0;
end
end
if (time_set_r[19:16]==4'd9)begin //小时位十位加一
if((time_set_r[15:12]==4'd5)&&(time_set_r[11:8]==4'd9)&&(time_set_r[7:4]==4'd5)&&(time_set_r[3:0]==4'd9))begin
time_set_r[23:20]<=time_set_r[23:20]+1;
time_set_r[19:16]<=4'd0;
end
end
end
end
//**输入32位的数据(8个4位的数据)显示
//reg [31:0] disp_data;
wire ds,sh_cp,st_cp;
hex8_test hex8_test_u(
.clk (clk),
.reset_n (reset_n),
.disp_data (time_set_r),
.ds (ds),
.sh_cp (sh_cp),
.st_cp (st_cp)
);
//**发送到串口助手
wire [31:0] data40;
assign data40={time_set_r[7:0],time_set_r[15:8],time_set_r[23:16],time_set_r[31:24]};是
wire trans_done;
uart_tx_data4 uart_tx_data4_u(
.clk (clk),
.reset_n (reset_n),
.data40 (data40),
.trans_go (trans_go),
.uart_tx (uart_tx),
.trans_done (trans_done)
);
endmodule
以下是顶层文件中需要的子程序。
串口接受单个字节的程序
module uart_byte_rx(
input clk,
input reset_n,
input uart_rx,
input [2:0]baud_set,
output reg [7:0]data,
output reg rx_done
);
reg [2:0]sta_bit;
reg [2:0]sto_bit;
reg [1:0] uart_rx_r;
always@(posedge clk ) begin
uart_rx_r[0]<=uart_rx;
uart_rx_r[1]<=uart_rx_r[0];
end
wire pedge_uart_rx;
wire nedge_uart_rx;
assign pedge_uart_rx=(uart_rx_r==2'b01);
assign nedge_uart_rx=(uart_rx_r==2'b10);
reg [8:0] bps_dr;
always @(*)
case(baud_set)
0: bps_dr=1000000000/9600/16/20-1;
1: bps_dr=1000000000/19200/16/20-1;
2: bps_dr=1000000000/38400/16/20-1;
3: bps_dr=1000000000/57600/16/20-1;
4: bps_dr=1000000000/115200/16/20-1;
default:bps_dr=1000000000/9600/16/20-1;
endcase
wire bps_clk_16x;
reg [8:0] div_cnt;
assign bps_clk_16x=(div_cnt==bps_dr/2);
reg rx_en;
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
rx_en<=0;
else if(nedge_uart_rx)
rx_en<=1;
else if(rx_done||(sta_bit>=4))
rx_en<=0;
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
div_cnt<=0;
else if(rx_en)begin
if(div_cnt==bps_dr)
div_cnt<=0;
else div_cnt<=div_cnt+1;
end
else div_cnt<=div_cnt;
end
reg [7:0] bps_cnt;
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
bps_cnt<=0;
else if(rx_en)begin
if(bps_clk_16x) begin
if(bps_cnt==160)
bps_cnt<=0;
else
bps_cnt<=bps_cnt+1;
end
else
bps_cnt<=bps_cnt;
end
else bps_cnt<=0;
end
// reg width name number
reg [2:0]r_data[7:0];
always@(posedge clk or negedge reset_n)begin
if(!reset_n)begin
sta_bit<=0;
sto_bit<=0;
r_data[0]<=0;
r_data[1]<=0;
r_data[2]<=0;
r_data[3]<=0;
r_data[4]<=0;
r_data[5]<=0;
r_data[6]<=0;
r_data[7]<=0;
end
else if(bps_clk_16x)begin
case(bps_cnt)
0:begin
sta_bit<=0;
sto_bit<=0;
r_data[0]<=0;
r_data[1]<=0;
r_data[2]<=0;
r_data[3]<=0;
r_data[4]<=0;
r_data[5]<=0;
r_data[6]<=0;
r_data[7]<=0;
end
5,6,7,8,9,10,11 :sta_bit<=sta_bit+uart_rx;
21,22,23,24,25,26,27:r_data[0] <=r_data[0]+uart_rx;
37,38,39,40,41,42,43:r_data[1] <= r_data[1] + uart_rx;
53,54,55,56,57,58,59:r_data[2] <= r_data[2] + uart_rx;
69,70,71,72,73,74,75:r_data[3] <= r_data[3] + uart_rx;
85,86,87,88,89,90,91:r_data[4] <= r_data[4] + uart_rx;
101,102,103,104,105,106,107:r_data[5] <= r_data[5] + uart_rx;
117,118,119,120,121,122,123:r_data[6] <= r_data[6] + uart_rx;
133,134,135,136,137,138,139:r_data[7] <= r_data[7] + uart_rx;
149,150,151,152,153,154,155:sto_bit <= sto_bit + uart_rx;
default:;
endcase
end
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
data<=0;
else if(bps_clk_16x&&(bps_cnt==160))begin
data[0]<=(r_data[0]>=4);
data[1]<=(r_data[1]>=4);
data[2]<=(r_data[2]>=4);
data[3]<=(r_data[3]>=4);
data[4]<=(r_data[4]>=4);
data[5]<=(r_data[5]>=4);
data[6]<=(r_data[6]>=4);
data[7]<=(r_data[7]>=4);
end
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
rx_done<=0;
else if((div_cnt==bps_dr/2)&&(bps_cnt==160))
rx_done<=1;
else rx_done<=0;
end
endmodule
串口接受一帧数据(多字节)的控制程序
module uart_cmd(
input clk,
input reset_n,
input [7:0] rx_data,
input rx_done,
output reg ctrl,
output reg [31:0]time_set
);
reg r_rx_done;
always@(posedge clk)
r_rx_done<= rx_done;
// reg width name number
reg [7:0] data_str [5:0];
always@(posedge clk ) begin
if(rx_done)begin
data_str[5]<=#1 rx_data;
data_str[4]<=#1data_str[5];
data_str[3]<=#1data_str[4];
data_str[2]<=#1data_str[3];
data_str[1]<=#1data_str[2];
data_str[0]<=#1data_str[1];
end
end
always@(posedge clk or negedge reset_n ) begin
if(!reset_n)begin
ctrl<=#1 0;
time_set<=#1 0;
end
else if(r_rx_done) begin
if((data_str[0]==8'h55)&&(data_str[5]==8'hF0))begin
time_set[7:0]<=#1 data_str[4];
time_set[15:8]<=#1 data_str[3];
time_set[23:16]<=#1data_str[2];
time_set[31:24]<=#1 data_str[1];
ctrl<=#1 1;
end
end
else begin
ctrl<=#1 0;
end
end
endmodule
数码管显示的顶层程序(例化两个程序来驱动数码管显示)
module hex8_test(
input clk,
input reset_n,
input [31:0] disp_data,
output ds,
output sh_cp,
output st_cp
);
wire [7:0] sel;
wire [7:0] seg;
//assign disp_data=32'h23579bdf;
hex8_2 hex8_2_u(
clk,
reset_n,
disp_data,
sel,
seg
);
wire [15:0]data;
assign data={seg,sel};
wire s_en;
assign s_en=1;
hc595_driver hc595_driver_u(
clk,
reset_n,
data,
s_en,
ds,
sh_cp,
st_cp
);
endmodule
数码管例化的程序——1.数码管数据
module hex8_2 (
input clk,
input reset_n,
input [31:0] disp_data,
output reg [7:0] sel,
output reg [7:0] seg
);
reg clk_1k;
reg [15:0] div_cnt;
always @(posedge clk or negedge reset_n) begin
if(!reset_n)
div_cnt<=0;
else if(div_cnt>=49999)
div_cnt<=0;
else div_cnt<=div_cnt+1;
end
always @(posedge clk or negedge reset_n) begin
if(!reset_n)
clk_1k<=0;
else if(div_cnt==49999)
clk_1k<=1;
else
clk_1k<=0;
end
reg[2:0] num_cnt;
always @(posedge clk or negedge reset_n) begin
if(!reset_n)
num_cnt<=0;
else if(clk_1k)
num_cnt<=num_cnt+1;
end
always @(posedge clk)
case(num_cnt)
0:sel<=8'b0000_0001;
1:sel<=8'b0000_0010;
2:sel<=8'b0000_0100;
3:sel<=8'b0000_1000;
4:sel<=8'b0001_0000;
5:sel<=8'b0010_0000;
6:sel<=8'b0100_0000;
7:sel<=8'b1000_0000;
default:;
endcase
reg [3:0] disp_tmp;
always @(posedge clk)
case(num_cnt)
7:disp_tmp<=disp_data[31:28];
6:disp_tmp<=disp_data[27:24];
5:disp_tmp<=disp_data[23:20];
4:disp_tmp<=disp_data[19:16];
3:disp_tmp<=disp_data[15:12];
2:disp_tmp<=disp_data[11:8];
1:disp_tmp<=disp_data[7:4];
0:disp_tmp<=disp_data[3:0];
default:;
endcase
always @(posedge clk)
case(disp_tmp)
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;
default:;
endcase
endmodule
数码管例化的程序——2.驱动HC595
module hc595_driver(
input clk,
input reset_n,
input [15:0] data,
input s_en,
output reg ds,
output reg sh_cp,
output reg st_cp
);
reg [15:0] r_data;
always @(posedge clk ) begin
if(s_en)
r_data<=data;
end
reg [7:0] divider_cnt;
always @(posedge clk or negedge reset_n) begin
if(!reset_n)
divider_cnt<=0;
else if(divider_cnt==1)
divider_cnt<=0;
else
divider_cnt<=divider_cnt+1;
end
wire sck_plus;
assign sck_plus=(divider_cnt==1);
reg [5:0] shcp_edge_cnt;
always @(posedge clk or negedge reset_n) begin
if(!reset_n)
shcp_edge_cnt<=0;
else if(sck_plus)begin
if(shcp_edge_cnt==32)
shcp_edge_cnt<=0;
else
shcp_edge_cnt<=shcp_edge_cnt+1;
end
end
always @(posedge clk or negedge reset_n) begin
if(!reset_n)begin
ds<=0;
sh_cp<=0;
st_cp<=0;
end
else begin
case(shcp_edge_cnt)
0:begin sh_cp<=0;st_cp<=0;ds<=r_data[15];end
1:begin sh_cp<=1;end
2:begin sh_cp<=0;ds<=r_data[14];end
3:begin sh_cp<=1;end
4:begin sh_cp<=0;ds<=r_data[13];end
5:begin sh_cp<=1;end
6:begin sh_cp<=0;ds<=r_data[12];end
7:begin sh_cp<=1;end
8:begin sh_cp<=0;ds<=r_data[11];end
9:begin sh_cp<=1;end
10:begin sh_cp<=0;ds<=r_data[10];end
11:begin sh_cp<=1;end
12:begin sh_cp<=0;ds<=r_data[9];end
13:begin sh_cp<=1;end
14:begin sh_cp<=0;ds<=r_data[8];end
15:begin sh_cp<=1;end
16:begin sh_cp<=0;ds<=r_data[7];end
17:begin sh_cp<=1;end
18:begin sh_cp<=0;ds<=r_data[6];end
19:begin sh_cp<=1;end
20:begin sh_cp<=0;ds<=r_data[5];end
21:begin sh_cp<=1;end
22:begin sh_cp<=0;ds<=r_data[4];end
23:begin sh_cp<=1;end
24:begin sh_cp<=0;ds<=r_data[3];end
25:begin sh_cp<=1;end
26:begin sh_cp<=0;ds<=r_data[2];end
27:begin sh_cp<=1;end
28:begin sh_cp<=0;ds<=r_data[1];end
29:begin sh_cp<=1;end
30:begin sh_cp<=0;ds<=data[0];end
31:begin sh_cp<=1;end
32:st_cp<=1;
default: begin ds<=0;
sh_cp<=0;
st_cp<=0;
end
endcase
end
end
endmodule
串口发送多个字节到上位机的程序
module uart_tx_data4(
input clk,
input reset_n,
input [31:0]data40,
input trans_go,
output uart_tx,
output reg trans_done
);
reg [7:0] data;
reg send_go;
wire tx_done;
reg [3:0] cnt;
reg [1:0] state;
uart_byte_tx uart_byte_tx11(
.data (data) ,
.send_go (send_go) ,
.clk (clk) ,
.reset_n (reset_n) ,
.baud_set (4) ,
.uart_tx (uart_tx) ,
.tx_done (tx_done)
);
always@(posedge clk or negedge reset_n )begin
if(!reset_n)begin
trans_done<=0;
send_go<=0;
state<=0;
data<=0;
cnt<=0;end
else begin
case(state)
0: begin
trans_done<=0;
if(trans_go)begin
data<=data40[7:0];
send_go<=1;
state<=1;
end
end
1 :begin
cnt<=1;
send_go<=0;
if(tx_done)begin
if(cnt==3)begin
state<=0;
send_go<=0;
trans_done<=1;
cnt<=0;
end
else begin
data<=data40[8*cnt+8+:8];
cnt<=cnt+1;
send_go<=1;
state<=1;
end end
else begin
send_go<=0;
cnt<=cnt;
data<=data;
end
end
default:;
endcase
end
end
endmodule
串口发送单个字节到上位机的程序(串口发送多个字节需要例化的程序)
module uart_byte_tx(
input [7:0] data,
input send_go,
input clk,
input reset_n,
input [2:0] baud_set,
output reg uart_tx,
output reg tx_done
);
reg [20:0]bps_dr;
always @(*)
case(baud_set)
0:bps_dr=1000000000/9600/20;
1:bps_dr=1000000000/19200/20;
2:bps_dr=1000000000/38400/20;
3:bps_dr=1000000000/57600/20;
4:bps_dr=1000000000/115200/20;
default: bps_dr=1000000000/9600/20;
endcase
reg send_en;
reg [7:0] r_data;
always @(posedge clk or negedge reset_n )begin
if(!reset_n)
send_en<=0;
else if(send_go)
send_en<=1;
else if(tx_done)
send_en<=0;
end
always @(posedge clk or negedge reset_n)begin
if(!reset_n)
r_data<=0;
else if(send_go)
r_data<=data;
else r_data<=r_data;
end
wire bps_clk;
assign bps_clk=(div_cnt==1);
reg [20:0] div_cnt;
always @(posedge clk or negedge reset_n )begin
if(!reset_n)
div_cnt<=0;
else if(send_en)
if(div_cnt==bps_dr-1)
div_cnt<=0;
else div_cnt<=div_cnt+1;
else div_cnt<=0;
end
reg [3:0] bps_cnt;
always @(posedge clk or negedge reset_n )begin
if(!reset_n)
bps_cnt<=0;
else if(send_en)begin
if(bps_clk)begin
if(bps_cnt==11)
bps_cnt<=0;
else
bps_cnt<=bps_cnt+1;
end
end
else
bps_cnt<=0;
end
always@(posedge clk or negedge reset_n )
if(!reset_n)begin
uart_tx<=1;
end
else begin
case(bps_cnt)
0:;
1:uart_tx<=0;
2:uart_tx<=r_data[0];
3:uart_tx<=r_data[1];
4:uart_tx<=r_data[2];
5:uart_tx<=r_data[3];
6:uart_tx<=r_data[4];
7:uart_tx<=r_data[5];
8:uart_tx<=r_data[6];
9:uart_tx<=r_data[7];
10:uart_tx<=1;
11:begin uart_tx<=1;end
default:uart_tx<=1;
endcase
end
always@(posedge clk or negedge reset_n )
if(!reset_n)
tx_done<=0;
else if((bps_clk==1) &&(bps_cnt==10))
tx_done<=1;
else if(bps_cnt==0)
tx_done<=0;
else
tx_done<=0;
endmodule