Augus

你好,FPGA之Uart-数码管显示

0
阅读(2896)

功能实现:

1.按键控制串口数据接收

2.数码管显示串口接收的数据

工具: in - system sources and probes editor 的使用

代码:

module uart_tx_top(clk,rst_n,rs232_tx,key_in0,sel,seg,led); input clk; input rst_n; input key_in0; wire [32:0]disp_data; output rs232_tx; output led; output [7:0] sel;//数码管位选(选择当前要显示的数码管) output [6:0] seg;//数码管段选(当前要显示的内容) wire send_en; wire [7:0]data_byte; wire key_flag0; wire key_state0; assign send_en = key_flag0 & !key_state0; uart_tx uart_tx( .clk(clk), .rst_n(rst_n), .data_byte(data_byte), .send_en(send_en), .baud_set(4'd4), .rs232_tx(rs232_tx), .tx_done(), .uart_state(led) ); key_filter key_filter0( .clk(clk), .rst_n(rst_n), .key_in(key_in0), .key_flag(key_flag0), .key_state(key_state0) ); HEX8 HEX8( .clk(clk), .rst_n(rst_n), .En(1'b1), .disp_data(data_byte), .sel(sel), .seg(seg) ); issp issp ( .source (data_byte) // sources.source ); endmodule module uart_tx( clk, rst_n, data_byte, send_en, baud_set, rs232_tx, tx_done, uart_state ); input clk,rst_n; input [7:0]data_byte; //发送字节 input send_en;//发送控制 input [3:0]baud_set;//波特率选择 output reg rs232_tx;//数据发送 output reg tx_done;//发送完成 output reg uart_state;//是否处于空闲状态 //查找表--比特率选择 reg [15:0]bps_max;//分频计数最大值 always @(posedge clk or negedge rst_n) if(!rst_n) bps_max <= 16'd5207; else begin case (baud_set) 0: bps_max <= 16'd5207;//9600 1: bps_max <= 16'd2603;//19200 2: bps_max <= 16'd1301;//38400 3: bps_max <= 16'd867;//57600 4: bps_max <= 16'd433;//115200 default:bps_max <= 16'd5207; endcase end reg [15:0]div_cnt; always @(posedge clk or negedge rst_n) if(!rst_n) div_cnt <= 16'd0; else if(uart_state)begin if(div_cnt == bps_max) div_cnt <= 16'd0; else div_cnt <= div_cnt +1'b1; end else div_cnt <= 16'd0; reg bps_clk;//波特率时钟 always @(posedge clk or negedge rst_n) if(!rst_n) bps_clk <= 1'b0; else if(div_cnt == 16'd1) bps_clk <= 1'b1; else bps_clk <= 1'b0; reg [3:0]bps_cnt; //计数到11,波特率时钟计数器 always @(posedge clk or negedge rst_n) if(!rst_n) bps_cnt <= 4'd0; else if(bps_clk) bps_cnt <= bps_cnt + 1'b1; else if(bps_cnt == 4'd11) //原tx_done 错 bps_cnt <= 4'd0; else bps_cnt <= bps_cnt; always@(posedge clk or negedge rst_n) if(!rst_n) tx_done <= 1'b0; else if(bps_cnt == 4'd11) tx_done <= 1'b1; else tx_done <= 1'b0; always @(posedge clk or negedge rst_n) if(!rst_n) uart_state <= 1'b0; else if(send_en) uart_state <= 1'b1; else if(bps_cnt == 4'd11)//原tx_done uart_state <= 1'b0; else uart_state <= uart_state; reg [7:0]r_data_byte; always @(posedge clk or negedge rst_n) if(!rst_n) r_data_byte <= 8'd0; else if(send_en) r_data_byte <= data_byte; else r_data_byte <= r_data_byte; localparam START_BIT = 1'b0; localparam STOP_BIT = 1'b1; always@(posedge clk or negedge rst_n) if(!rst_n) rs232_tx <= 1'b1; else begin case(bps_cnt) 0 : rs232_tx <= 1'b1; 1 : rs232_tx <= START_BIT; 2 : rs232_tx <= r_data_byte[0]; 3 : rs232_tx <= r_data_byte[1]; 4 : rs232_tx <= r_data_byte[2]; 5 : rs232_tx <= r_data_byte[3]; 6 : rs232_tx <= r_data_byte[4]; 7 : rs232_tx <= r_data_byte[5]; 8 : rs232_tx <= r_data_byte[6]; 9 : rs232_tx <= r_data_byte[7]; 10 : rs232_tx <= STOP_BIT; default:rs232_tx <= 1'b1; endcase end endmodule module key_filter(clk,rst_n,key_in,key_flag,key_state); input clk; input rst_n; input key_in; output reg key_flag; output reg key_state; localparam IDEL = 4'b0001, FILTER0 = 4'b0010, DOWN = 4'b0100, FILTER1 = 4'b1000; reg [3:0]state; reg [19:0]cnt; reg en_cnt; //使能计数寄存器 //对外部输入的异步信号进行同步处理 reg key_in_sa,key_in_sb; always@(posedge clk or negedge rst_n) if(!rst_n)begin key_in_sa <= 1'b0; key_in_sb <= 1'b0; end else begin key_in_sa <= key_in; key_in_sb <= key_in_sa; end reg key_tmpa,key_tmpb; wire pedge,nedge; reg cnt_full;//计数满标志信号 //使用D触发器存储两个相邻时钟上升沿时外部输入信号(已经同步到系统时钟域中)的电平状态 always@(posedge clk or negedge rst_n) if(!rst_n)begin key_tmpa <= 1'b0; key_tmpb <= 1'b0; end else begin key_tmpa <= key_in_sb; key_tmpb <= key_tmpa; end //产生跳变沿信号 assign nedge = !key_tmpa & key_tmpb; assign pedge = key_tmpa & (!key_tmpb); always@(posedge clk or negedge rst_n) if(!rst_n)begin en_cnt <= 1'b0; state <= IDEL; key_flag <= 1'b0; key_state <= 1'b1; end else begin case(state) IDEL : begin key_flag <= 1'b0; if(nedge)begin state <= FILTER0; en_cnt <= 1'b1; end else state <= IDEL; end FILTER0: if(cnt_full)begin key_flag <= 1'b1; key_state <= 1'b0; en_cnt <= 1'b0; state <= DOWN; end else if(pedge)begin state <= IDEL; en_cnt <= 1'b0; end else state <= FILTER0; DOWN: begin key_flag <= 1'b0; if(pedge)begin state <= FILTER1; en_cnt <= 1'b1; end else state <= DOWN; end FILTER1: if(cnt_full)begin key_flag <= 1'b1; key_state <= 1'b1; state <= IDEL; end else if(nedge)begin en_cnt <= 1'b0; state <= DOWN; end else state <= FILTER1; default: begin state <= IDEL; en_cnt <= 1'b0; key_flag <= 1'b0; key_state <= 1'b1; end endcase end always@(posedge clk or negedge rst_n) if(!rst_n) cnt <= 20'd0; else if(en_cnt) cnt <= cnt + 1'b1; else cnt <= 20'd0; always@(posedge clk or negedge rst_n) if(!rst_n) cnt_full <= 1'b0; else if(cnt == 999_999) cnt_full <= 1'b1; else cnt_full <= 1'b0; endmodule module HEX8(clk,rst_n,En,disp_data,sel,seg); input clk; //50M input rst_n; input En; //数码管显示使能,1使能,0关闭 input [31:0]disp_data; output [7:0] sel;//数码管位选(选择当前要显示的数码管) output reg [6:0] seg;//数码管段选(当前要显示的内容) reg [14:0]divider_cnt;//25000-1 reg clk_1K; reg [7:0]sel_r; reg [3:0]data_tmp;//数据缓存 // 分频计数器计数模块 always@(posedge clk or negedge rst_n) if(!rst_n) divider_cnt <= 15'd0; else if(!En) divider_cnt <= 15'd0; else if(divider_cnt == 24999) divider_cnt <= 15'd0; else divider_cnt <= divider_cnt + 1'b1; //1K扫描时钟生成模块 always@(posedge clk or negedge rst_n) if(!rst_n) clk_1K <= 1'b0; else if(divider_cnt == 24999) clk_1K <= ~clk_1K; else clk_1K <= clk_1K; //8位循环移位寄存器 always@(posedge clk_1K or negedge rst_n) if(!rst_n) sel_r <= 8'b0000_0001; else if(sel_r == 8'b1000_0000) sel_r <= 8'b0000_0001; else sel_r <= sel_r << 1; always@(*) case(sel_r) 8'b0000_0001:data_tmp = disp_data[3:0]; 8'b0000_0010:data_tmp = disp_data[7:4]; 8'b0000_0100:data_tmp = disp_data[11:8]; 8'b0000_1000:data_tmp = disp_data[15:12]; 8'b0001_0000:data_tmp = disp_data[19:16]; 8'b0010_0000:data_tmp = disp_data[23:20]; 8'b0100_0000:data_tmp = disp_data[27:24]; 8'b1000_0000:data_tmp = disp_data[31:28]; default:data_tmp = 4'b0000; endcase always@(*) case(data_tmp) 4'h0:seg = 7'b1000000; 4'h1:seg = 7'b1111001; 4'h2:seg = 7'b0100100; 4'h3:seg = 7'b0110000; 4'h4:seg = 7'b0011001; 4'h5:seg = 7'b0010010; 4'h6:seg = 7'b0000010; 4'h7:seg = 7'b1111000; 4'h8:seg = 7'b0000000; 4'h9:seg = 7'b0010000; 4'ha:seg = 7'b0001000; 4'hb:seg = 7'b0000011; 4'hc:seg = 7'b1000110; 4'hd:seg = 7'b0100001; 4'he:seg = 7'b0000110; 4'hf:seg = 7'b0001110; endcase assign sel = (En)?sel_r:8'b0000_0000; endmodule `timescale 1ns/1ns `define clk_period 20 module uart_tx_tb; reg clk; reg rst_n; reg send_en; reg [3:0]baud_set; reg [7:0]data_byte; wire rs232_tx; wire tx_done; wire uart_state; uart_tx uart_tx( .clk(clk), .rst_n(rst_n), .data_byte(data_byte), .send_en(send_en), .baud_set(baud_set), .rs232_tx(rs232_tx), .tx_done(tx_done), .uart_state(uart_state) ); initial clk = 1; always#(`clk_period/2)clk = ~clk; initial begin rst_n = 1'b0; //key_in0 = 1'b1; data_byte = 8'd0; send_en = 1'd0; baud_set = 3'd4; #(`clk_period*20 + 1 ) rst_n = 1'b1; //key_in0 = 1'b1; #(`clk_period*50); data_byte = 8'haa; send_en = 1'd1; #`clk_period; send_en = 1'd0; @(posedge tx_done) #(`clk_period*5000); data_byte = 8'h55; send_en = 1'd1; #`clk_period; send_en = 1'd0; @(posedge tx_done) #(`clk_period*5000); $stop; end endmodule

仿真:

效果:

2016-04-17_000122.jpg

更多资料请参考:

发烧友小梅哥专版


Baidu
map