任务:
电路图设计:
设计:
模块1:1.先设计一个计数时钟,为了仿真方便,这里把1000ns当作1s。
创建一个计数器second_lim,当计数到1000/20时清零,即1s。
秒显示器second_show,每当second_shwo小于59且second_lim清零时second_show加一,second_shwo小于59且second_lim清零时second_show清零。
分显示器minute_show,每当minute_show小于59且second_show等于59且second_lim清零时minute_show加一,minute_show等于59且second_show等于59且second_lim清零时minute_show清零。
时显示器hour_show,每当hour_show小于23且minute_show等于59且second_show等于59且second_lim清零时minute_show加一,hour_show等于23且minute_show等于59且second_show等于59且second_lim清零时hour_show清零。
2.一个接口接收设置时间的数据,当出现完整的设置时间数据和设置信号时,便直接把时间修改。
3.遵循uart协议的串口发送模块,把数据发送给电脑。
模块2:之前的uart串口接收模块可以直接用来接收设置时间的数据,一次可以接收八位数据,即要接收三次才能接收到时,分,秒。
设置数据寄存器set_tim_regist[23:0],存储时,分,秒数据。
一个计数器,计数到3便发送设置时间的数据并产生一个设置时间的信号给模块1.
完整代码如下:
module uart_receive_1( //part1 clk , reset , baud_rate , uart_tx, data , rx_done, send_en ); input clk ; input reset ; input [2:0]baud_rate ; input uart_tx ; output reg [7:0]data ; output reg rx_done ; output reg send_en ; reg [2:0]r_data[7:0] ;//接收每一位数据 reg [2:0]sta_bit ; reg [2:0]sto_bit ; reg [17:0]bit_tim ;//每一位持续的时间(计数) always@(baud_rate) //在这里一个 码元由一位组成,所以波特率=比特率 begin case(baud_rate) //常见的串口传输波特率 3'd0 : bit_tim = 1000000000/300/20 ; //波特率为300 3'd1 : bit_tim = 1000000000/1200/20 ; //波特率为1200 3'd2 : bit_tim = 1000000000/2400/20 ; //波特率为2400 3'd3 : bit_tim = 1000000000/9600/20 ; //波特率为9600 3'd4 : bit_tim = 1000000000/19200/20 ; //波特率为19200 3'd5 : bit_tim = 1000000000/115200/20 ; //波特率为115200 default bit_tim = 1000000000/9600/20 ; //多余的寄存器位置放什么:默认速率 endcase end wire [17:0]bit_tim_16 ;//每1/16位的持续时间(计数) assign bit_tim_16 = bit_tim / 16; wire [8:0]bit16_mid ; //在中心点产生采样脉冲 assign bit16_mid = bit_tim_16 / 2 ; //边沿检测 reg [1:0]edge_detect ; always @( posedge clk or negedge reset ) begin if (!reset ) edge_detect <= 2'd0 ; else begin edge_detect[0] <= uart_tx ; edge_detect[1] <= edge_detect[0] ; end end wire byte_sta_neg ; assign byte_sta_neg = ( edge_detect == 2'b10 ) ? 1 : 0 ;//输入的数据开始出现下降沿,说明出现了起始位(一直运行?) reg receive_en ;//接收使能端 reg [17:0]div_cnt ;//每1/16bit内的计数 reg [7:0]bit16_cnt ;//计数到了第几个状态(10位,每位分成16份,总共160个状态) always @( posedge clk or negedge reset ) begin if (!reset ) receive_en <= 1'd0 ; else if ( byte_sta_neg ) //检测到下降沿,使能段有效(只要有下降沿就使能?) receive_en <= 1'd1 ; else if ( (rx_done) || (sta_bit >= 3'd4 )) receive_en <= 1'd0 ; //检测到结束信号,使能端无效 else if ( ( bit16_cnt == 8'd159 ) && (div_cnt == bit_tim_16 - 1'd1 ) )//跑完159后re_en置零 receive_en <= 1'd0 ; end always@( posedge clk or negedge reset ) begin if ( ! reset ) div_cnt <= 18'd0 ; else if (receive_en) begin if ( div_cnt == bit_tim_16 - 1'd1 )//计数,每1/16bit清零 div_cnt <= 18'd0 ; else div_cnt <= div_cnt + 1'b1 ; end else div_cnt <= 18'd0 ; end reg bit16_pulse ;//产生采样脉冲 always@( posedge clk or negedge reset ) begin if ( ! reset ) bit16_pulse <= 18'd0 ; else if (receive_en) if ( div_cnt == bit16_mid ) bit16_pulse <= 1'd1 ; else bit16_pulse <= 1'd0 ; else bit16_pulse <= 1'd0 ; end always@( posedge clk or negedge reset ) begin if ( ! reset ) bit16_cnt <= 8'd0 ; else if (receive_en) begin if (( bit16_cnt == 8'd159 ) && (div_cnt == bit_tim_16 - 1'd1 )) bit16_cnt <= 8'd0 ; else if ( div_cnt == bit_tim_16 - 1'd1 ) bit16_cnt <= bit16_cnt + 1'b1 ; end end always@(posedge clk or negedge reset) begin if(!reset) begin sta_bit <= 3'd0 ; r_data[0] <= 3'd0 ; r_data[1] <= 3'd0 ; r_data[2] <= 3'd0 ; r_data[3] <= 3'd0 ; r_data[4] <= 3'd0 ; r_data[5] <= 3'd0 ; r_data[6] <= 3'd0 ; r_data[7] <= 3'd0 ; sto_bit <= 3'd0 ; end else if (bit16_pulse)//舍弃前5后4取中7 case(bit16_cnt) 0: begin sta_bit <= 3'd0 ; r_data[0] <= 3'd0 ; r_data[1] <= 3'd0 ; r_data[2] <= 3'd0 ; r_data[3] <= 3'd0 ; r_data[4] <= 3'd0 ; r_data[5] <= 3'd0 ; r_data[6] <= 3'd0 ; r_data[7] <= 3'd0 ; sto_bit <= 3'd0 ; end 5,6,7,8,9,10,11 : sta_bit <= sta_bit + uart_tx ; 21,22,23,24,25,26,27 : r_data[0] <= r_data[0] + uart_tx ; 37,38,39,41,42,43,44 : r_data[1] <= r_data[1] + uart_tx ; 53,54,55,56,57,58,59 : r_data[2] <= r_data[2] + uart_tx ; 69,70,71,72,73,74,75 : r_data[3] <= r_data[3] + uart_tx ; 85,86,87,88,89,90,91 : r_data[4] <= r_data[4] + uart_tx ; 101,102,103,104,105,106,107 : r_data[5] <= r_data[5] + uart_tx ; 117,118,119,120,121,122,123 : r_data[6] <= r_data[6] + uart_tx ; 133,134,135,136,137,138,139 : r_data[7] <= r_data[7] + uart_tx ; 149,150,151,152,153,154,155 : sto_bit <= sto_bit + uart_tx ; default ; endcase end always@( posedge clk or negedge reset ) begin if ( ! reset ) rx_done <= 0 ; else if ( ( bit16_cnt == 8'd159 ) && (div_cnt == bit_tim_16 - 1'd1 ) )//跑完159后产生一个rx_done信号 rx_done <= 1'd1 ; else if (rx_done <= 8'd1 ) rx_done <= 1'd0 ; end always@( posedge clk or negedge reset ) begin if ( ! reset ) send_en <= 1'd0 ; else if( rx_done == 1) send_en <= 1'd1 ; else if( send_en == 1) send_en <= 1'd0 ; end always@( posedge clk or negedge reset )//接收完数据发出rx_done后,把数据从r_data传递给data begin if ( ! reset ) data <= 8'd0 ; else if ( rx_done ) begin data[0] = ( r_data[0] >3 ) ? 1 : 0 ; data[1] = ( r_data[1] >3 ) ? 1 : 0 ; data[2] = ( r_data[2] >3 ) ? 1 : 0 ; data[3] = ( r_data[3] >3 ) ? 1 : 0 ; data[4] = ( r_data[4] >3 ) ? 1 : 0 ; data[5] = ( r_data[5] >3 ) ? 1 : 0 ; data[6] = ( r_data[6] >3 ) ? 1 : 0 ; data[7] = ( r_data[7] >3 ) ? 1 : 0 ; end else if ( receive_en ) data <= 8'd0 ; end endmodule
module digital_clk( //part2 clk, set_tim, set_sig, reset, dis_tim, send_signal, send_computer, uart_data ); input clk ; input [7:0]set_tim ; input set_sig ; input reset ; output reg [23:0]dis_tim ; output reg send_signal ; output reg send_computer ; output reg uart_data ; parameter second_miao = 1_000 / 20 ; //把1000ns当1s parameter minute_fen = 60_000 / 20 ; //1minute 计数 parameter hour_shi = 3600_000 / 20 ;//1hour 计数 reg [1:0]set_sig_cnt ;//计算接收到的数据位数 always@(posedge clk or negedge reset ) if (!reset) set_sig_cnt <= 2'd0 ; else if ( set_sig ) set_sig_cnt <= set_sig_cnt + 1 ; else if ( 3 <= set_sig_cnt ) set_sig_cnt <= 2'd0 ; reg [23:0]set_tim_registor ; //接收串口数据并存储 always@(posedge clk or negedge reset ) if (!reset) set_tim_registor <= 24'd0 ; else if ( set_sig ) set_tim_registor <= {set_tim_registor[15:0],set_tim } ; //设置秒钟的显示 reg [7:0]second_lim ; reg [7:0]second_show ; always@( posedge clk or negedge reset) if (!reset)begin second_lim <= 8'd0 ; end else if (second_miao - 1 <= second_lim ) second_lim <= 8'd0 ; else second_lim <= second_lim + 1 ; always@( posedge clk or negedge reset)//显示秒 if (!reset)begin second_show <= 8'd0 ; end else if ( 3 <= set_sig_cnt ) second_show <= set_tim_registor[7:0] ; else if ( 3 > set_sig_cnt ) begin if ( ( 59 <= second_show ) && ( second_miao - 1 <= second_lim ) ) //60秒计满,秒归零 second_show <= 8'd0 ; else if ( ( 59 > second_show ) && ( second_miao - 1 <= second_lim ) ) second_show <= second_show + 1 ; end //设置分钟的显示 reg [7:0]minute_show ; always@( posedge clk or negedge reset)//显示分 if (!reset) minute_show <= 8'd0 ; else if ( 3 <= set_sig_cnt ) minute_show <= set_tim_registor[15:8] ; else if ( 3 > set_sig_cnt ) begin if ( ( 59 > minute_show ) && ( 59 <= second_show ) && ( second_miao - 1 <= second_lim ) ) // 60秒计满,分 + 1 minute_show <= minute_show + 1 ; else if ( ( 59 <= minute_show ) && ( 59 <= second_show ) && ( second_miao - 1 <= second_lim ) )//59分59秒计满 分归零 minute_show <= 8'd0 ; end //设置时的显示 reg [7:0]hour_show ; always@( posedge clk or negedge reset)//显示时 if (!reset) hour_show <= 8'd0 ; else if ( 3 <= set_sig_cnt ) hour_show <= set_tim_registor[23:16] ; else if ( 3 > set_sig_cnt ) begin if ( ( 23 > hour_show ) && ( 59 <= minute_show ) && ( 59 <= second_show ) && ( second_miao - 1 <= second_lim ) )//59分59秒计满 时+1 hour_show <= hour_show + 1 ; else if ( ( 23 <= hour_show ) && ( 59 <= minute_show ) && ( 59 <= second_show ) && ( second_miao - 1 <= second_lim ) )//23时59分59秒计满 时归零 hour_show <= 8'd0 ; end reg [7:0]second_dis ;//秒的十进制转换 always@(*) case(second_show) 10 : second_dis = 8'b0001_0000 ; 11 : second_dis = 8'b0001_0001 ; 12 : second_dis = 8'b0001_0010 ; 13 : second_dis = 8'b0001_0011 ; 14 : second_dis = 8'b0001_0100 ; 15 : second_dis = 8'b0001_0101 ; 16 : second_dis = 8'b0001_0110 ; 17 : second_dis = 8'b0001_0111 ; 18 : second_dis = 8'b0001_1000 ; 19 : second_dis = 8'b0001_1001 ; 20 : second_dis = 8'b0010_0000 ; 21 : second_dis = 8'b0010_0001 ; 22 : second_dis = 8'b0010_0010 ; 23 : second_dis = 8'b0010_0011 ; 24 : second_dis = 8'b0010_0100 ; 25 : second_dis = 8'b0010_0101 ; 26 : second_dis = 8'b0010_0110 ; 27 : second_dis = 8'b0010_0111 ; 28 : second_dis = 8'b0010_1000 ; 29 : second_dis = 8'b0010_1001 ; 30 : second_dis = 8'b0011_0000 ; 31 : second_dis = 8'b0011_0001 ; 32 : second_dis = 8'b0011_0010 ; 33 : second_dis = 8'b0011_0011 ; 34 : second_dis = 8'b0011_0100 ; 35 : second_dis = 8'b0011_0101 ; 36 : second_dis = 8'b0011_0110 ; 37 : second_dis = 8'b0011_0111 ; 38 : second_dis = 8'b0011_1000 ; 39 : second_dis = 8'b0011_1001 ; 40 : second_dis = 8'b0100_0000 ; 41 : second_dis = 8'b0100_0001 ; 42 : second_dis = 8'b0100_0010 ; 43 : second_dis = 8'b0100_0011 ; 44 : second_dis = 8'b0100_0100 ; 45 : second_dis = 8'b0100_0101 ; 46 : second_dis = 8'b0100_0110 ; 47 : second_dis = 8'b0100_0111 ; 48 : second_dis = 8'b0100_1000 ; 49 : second_dis = 8'b0100_1001 ; 50 : second_dis = 8'b0101_0000 ; 51 : second_dis = 8'b0101_0001 ; 52 : second_dis = 8'b0101_0010 ; 53 : second_dis = 8'b0101_0011 ; 54 : second_dis = 8'b0101_0100 ; 55 : second_dis = 8'b0101_0101 ; 56 : second_dis = 8'b0101_0110 ; 57 : second_dis = 8'b0101_0111 ; 58 : second_dis = 8'b0101_1000 ; 59 : second_dis = 8'b0101_1001 ; default second_dis = second_show ; endcase reg [7:0]minute_dis ;//分的十进制转换 always@(*) case(minute_show) 10 : minute_dis = 8'b0001_0000 ; 11 : minute_dis = 8'b0001_0001 ; 12 : minute_dis = 8'b0001_0010 ; 13 : minute_dis = 8'b0001_0011 ; 14 : minute_dis = 8'b0001_0100 ; 15 : minute_dis = 8'b0001_0101 ; 16 : minute_dis = 8'b0001_0110 ; 17 : minute_dis = 8'b0001_0111 ; 18 : minute_dis = 8'b0001_1000 ; 19 : minute_dis = 8'b0001_1001 ; 20 : minute_dis = 8'b0010_0000 ; 21 : minute_dis = 8'b0010_0001 ; 22 : minute_dis = 8'b0010_0010 ; 23 : minute_dis = 8'b0010_0011 ; 24 : minute_dis = 8'b0010_0100 ; 25 : minute_dis = 8'b0010_0101 ; 26 : minute_dis = 8'b0010_0110 ; 27 : minute_dis = 8'b0010_0111 ; 28 : minute_dis = 8'b0010_1000 ; 29 : minute_dis = 8'b0010_1001 ; 30 : minute_dis = 8'b0011_0000 ; 31 : minute_dis = 8'b0011_0001 ; 32 : minute_dis = 8'b0011_0010 ; 33 : minute_dis = 8'b0011_0011 ; 34 : minute_dis = 8'b0011_0100 ; 35 : minute_dis = 8'b0011_0101 ; 36 : minute_dis = 8'b0011_0110 ; 37 : minute_dis = 8'b0011_0111 ; 38 : minute_dis = 8'b0011_1000 ; 39 : minute_dis = 8'b0011_1001 ; 40 : minute_dis = 8'b0100_0000 ; 41 : minute_dis = 8'b0100_0001 ; 42 : minute_dis = 8'b0100_0010 ; 43 : minute_dis = 8'b0100_0011 ; 44 : minute_dis = 8'b0100_0100 ; 45 : minute_dis = 8'b0100_0101 ; 46 : minute_dis = 8'b0100_0110 ; 47 : minute_dis = 8'b0100_0111 ; 48 : minute_dis = 8'b0100_1000 ; 49 : minute_dis = 8'b0100_1001 ; 50 : minute_dis = 8'b0101_0000 ; 51 : minute_dis = 8'b0101_0001 ; 52 : minute_dis = 8'b0101_0010 ; 53 : minute_dis = 8'b0101_0011 ; 54 : minute_dis = 8'b0101_0100 ; 55 : minute_dis = 8'b0101_0101 ; 56 : minute_dis = 8'b0101_0110 ; 57 : minute_dis = 8'b0101_0111 ; 58 : minute_dis = 8'b0101_1000 ; 59 : minute_dis = 8'b0101_1001 ; default minute_dis = minute_show ; endcase reg [7:0]hour_dis ;//时的十进制转换 always@(*) case(hour_show) 10 : hour_dis = 8'b0001_0000 ; 11 : hour_dis = 8'b0001_0001 ; 12 : hour_dis = 8'b0001_0010 ; 13 : hour_dis = 8'b0001_0011 ; 14 : hour_dis = 8'b0001_0100 ; 15 : hour_dis = 8'b0001_0101 ; 16 : hour_dis = 8'b0001_0110 ; 17 : hour_dis = 8'b0001_0111 ; 18 : hour_dis = 8'b0001_1000 ; 19 : hour_dis = 8'b0001_1001 ; 20 : hour_dis = 8'b0010_0000 ; 21 : hour_dis = 8'b0010_0001 ; 22 : hour_dis = 8'b0010_0010 ; 23 : hour_dis = 8'b0010_0011 ; default hour_dis = hour_show ; endcase //输出 always@(posedge clk or negedge reset )//接收到设置时间的信号后,输出该时间信号 if (!reset) dis_tim <= 24'd0 ; else if ( 3 <= set_sig_cnt ) begin dis_tim <= set_tim_registor ; end else dis_tim <= { hour_dis , minute_dis , second_dis } ; always@(posedge clk or negedge reset )//设置输出时间值的标志信号:发送到数码管 if (!reset) send_signal <= 0 ; else if ( 3 <= set_sig_cnt ) send_signal <= 1 ; else if ( ( 3 > set_sig_cnt) && ( second_miao - 1 <= second_lim ) ) send_signal <= 1 ; else send_signal <= 0 ; //遵循uart协议发送到电脑 always@(posedge clk or negedge reset )//设置输出时间值的标志信号:发送到电脑 if (!reset) send_computer <= 0 ; else if ( second_miao - 1 <= second_lim ) send_computer <= 1 ; else send_computer <= 0 ; reg send_computer_en ;//发送使能标志 reg send_computer_done ;//发送结束标志 always@(posedge clk or negedge reset )//设置输出时间值的标志信号:发送到电脑 if (!reset) send_computer_en <= 0 ; else if ( send_computer ) send_computer_en <= 1 ; else if ( send_computer_done ) send_computer_en <= 0 ; reg [5:0]com_cnt ;//串口输出状态计数 always@(posedge clk or negedge reset )//设置串口输出数据 结束标志信号 if (!reset) send_computer_done <= 0 ; else if ( send_computer ) send_computer_done <= 0 ; else if ( com_cnt == 6'd29 ) send_computer_done <= 1 ; else send_computer_done <= 0 ; always@(posedge clk or negedge reset )// if (!reset) com_cnt <= 0 ; else if ( send_signal ) com_cnt <= 0 ; else if ( send_computer_en ) com_cnt <= com_cnt + 1 ; always@(*)//串口输出 时:分:秒 case(com_cnt) 0:uart_data = 0 ; 1:uart_data = dis_tim[23] ; 2:uart_data = dis_tim[22] ; 3:uart_data = dis_tim[21] ; 4:uart_data = dis_tim[20] ; 5:uart_data = dis_tim[19] ; 6:uart_data = dis_tim[18] ; 7:uart_data = dis_tim[17] ; 8:uart_data = dis_tim[16] ; 9:uart_data = 1 ; 10:uart_data = 0 ; 11:uart_data = dis_tim[15] ; 12:uart_data = dis_tim[14] ; 13:uart_data = dis_tim[13] ; 14:uart_data = dis_tim[12] ; 15:uart_data = dis_tim[11] ; 16:uart_data = dis_tim[10] ; 17:uart_data = dis_tim[9] ; 18:uart_data = dis_tim[8] ; 19:uart_data = 1 ; 20:uart_data = 0 ; 21:uart_data = dis_tim[7] ; 22:uart_data = dis_tim[6] ; 23:uart_data = dis_tim[5] ; 24:uart_data = dis_tim[4] ; 25:uart_data = dis_tim[3] ; 26:uart_data = dis_tim[2] ; 27:uart_data = dis_tim[1] ; 28:uart_data = dis_tim[0] ; 29:uart_data = 1 ; default:uart_data = 1 ; endcase endmodule
module digital_clk_complete(//连线 clk_wire, reset_wire, uart_tx_wire, baud_rate, dis_tim, send_signal, send_computer, uart_data ); input clk_wire ; input reset_wire ; input uart_tx_wire ; input [2:0]baud_rate ; output dis_tim ; output send_signal ; output send_computer ; output uart_data ; wire [7:0]data ; wire rx_done ; wire send_en ; uart_receive_1 part1( .clk(clk_wire) , .reset(reset_wire) , .baud_rate(baud_rate) , .uart_tx(uart_tx_wire), .data(data) , .rx_done(rx_done), .send_en(send_en) ); wire [23:0]dis_tim ; wire send_signal ; wire send_computer ; wire uart_data; digital_clk part2( .clk(clk_wire), .set_tim(data), .set_sig(send_en), .reset(reset_wire), .dis_tim(dis_tim), .send_signal(send_signal), .send_computer(send_computer), .uart_data(uart_data) ); endmodule
`timescale 1ns / 1ns module digital_clk_complete_tb(//测试激励文件 ); reg clk_wire ; reg reset_wire ; reg uart_tx_wire ; reg [8:0]baud_rate ; wire [23:0]dis_tim ; wire send_signal ; wire send_computer ; wire uart_data ; digital_clk_complete digital_clk_complete_sim( clk_wire, reset_wire, uart_tx_wire, baud_rate, dis_tim, send_signal, send_computer, uart_data ); initial clk_wire = 1 ; always #10 clk_wire = ! clk_wire ; initial begin reset_wire = 0 ; baud_rate = 0 ; uart_tx_wire = 1 ; #201 ; reset_wire = 1 ; baud_rate = 3'd5 ; #4500000; uart_input(8'b0001_0101) ; #1000000 ; uart_input(8'b0010_0000) ; #1000000 ; uart_input(8'b0011_0110) ; #1000000 ; $stop; end task uart_input ;//设定一个任务uart_inpt,有一个输入端uart_tx_data_stm 。在这个task里可以对task外的变量进行赋值 input [7:0]uart_tx_data_stm ;//不返回值,所以不能用x=uart_input。而是直接uart_input。 begin //结构简单的begin-end uart_tx_wire = 1 ; #20 ; uart_tx_wire = 0 ; #8640 ; uart_tx_wire = uart_tx_data_stm[0] ; #8640 ; uart_tx_wire = uart_tx_data_stm[1] ; #8640 ; uart_tx_wire = uart_tx_data_stm[2] ; #8640 ; uart_tx_wire = uart_tx_data_stm[3] ; #8640 ; uart_tx_wire = uart_tx_data_stm[4] ; #8640 ; uart_tx_wire = uart_tx_data_stm[5] ; #8640 ; uart_tx_wire = uart_tx_data_stm[6] ; #8640 ; uart_tx_wire = uart_tx_data_stm[7] ; #8640 ; uart_tx_wire = 1 ; #8640 ; end endtask endmodule