基于小梅哥的Xlinx FPGA开发视频的布置作业--用串口控制一个24小时数字钟

刚看完小梅哥的视频,花了几个钟头写成了作业,就两个功能,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

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值