基于FPGA的超声波测距

这篇具有很好参考价值的文章主要介绍了基于FPGA的超声波测距。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、项目框架

distance超声波测距模块负责数据的采集,vga、uart、beep、数码管根据采集到的数据分别进行vga的屏幕打点、串口输出到上位机、蜂鸣器根据数据大小进行鸣叫以及数码管显示采集到的数据。
基于FPGA的超声波测距

RTL视图

基于FPGA的超声波测距

二、超声波测距模块

基于FPGA的超声波测距
基于FPGA的超声波测距
代码

module distance_drive (
    input			wire						clk,
    input			wire						clk_1,
    input			wire						rst_n,

    input			wire						echo,
    output			reg						    trig,
    output			wire						data_out_vld,
    output			wire		[ 23:0 ]		distance_data
);
localparam	MAX_DISTANCE = 117647; //最大距离 4m

parameter	s_idle = 0;//空闲状态
parameter	s_send = 1;//发送触发信号
parameter	s_wait = 2;//等待内部发送脉冲
parameter	s_accept = 3;//检测回响信号
parameter	s_accept_wait = 4;//延时等待


reg								echo_r0			;
reg								echo_r1			;
reg			[ 2:0 ]			    s_current		;
reg			[ 2:0 ]			    s_next			;
reg			[ 22 :0 ]		    cnt				;
reg			[ 22:0 ]			cnt_wait		;
reg			[ 22:0 ]		    cnt_max			;
reg			[ 16:0 ]			cnt_distance	;
// reg			[ 25:0 ]			cnt_distance_r1			;
// reg			[ 19:0 ]			cnt_distance_r2			;

wire							accept_start_sig			;
wire							accept_stop_sig			;
wire							idle_sig			;
wire							send_sig			;
// wire							wait_sig			;
wire							flag_clear_cnt			;
wire							flag_clear_cnt_wait			;
reg			[ 19:0 ]			distance_data_r			;
wire			[ 23:0 ]			distance_data_r1			;

assign idle_sig = s_current == s_idle;
assign send_sig = s_current == s_send && flag_clear_cnt;
// assign wait_sig = s_current == s_wait && flag_clear_cnt_wait;
assign accept_wait_sig = s_current == s_accept_wait &&  flag_clear_cnt_wait;
assign accept_start_sig = s_current == s_wait && echo_r0 && ~echo_r1;
assign accept_stop_sig = s_current == s_accept && (~echo_r0 && echo_r1);


// always @(posedge clk or negedge rst_n) begin
//     if(!rst_n) begin
//         cnt_distance_r1 <= 0;
//         // cnt_distance_r2 <= 0;
//     end
//     else begin
//         cnt_distance_r1 <= cnt_distance * 340 / 100;
//         // cnt_distance_r2 <= cnt_distance_r1 >> 4;
//     end
// end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        echo_r0 <= 0;
        echo_r1 <= 0;
    end
    else begin
        echo_r0 <= echo;
        echo_r1 <= echo_r0;
    end
end
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        s_current <= s_idle;    
    end
    else begin
        s_current <= s_next;
    end
end

always @(*) begin
    case (s_current)
        s_idle : begin
            if(idle_sig) begin
                s_next = s_send;
            end
            else begin
                s_next = s_idle;
            end
        end
        s_send : begin
            if(send_sig) begin
                s_next = s_wait;
            end
            else begin
                s_next = s_send;
            end
        end
        s_wait : begin
            if(accept_start_sig) begin
                s_next = s_accept;
            end
            else begin
                s_next = s_wait;
            end
        end
        s_accept : begin
            if(accept_stop_sig) begin
                s_next = s_accept_wait;
            end
            else begin
                s_next = s_accept;
            end
        end
        s_accept_wait : begin
            if(accept_wait_sig) begin
                s_next <= s_idle;
            end
            else begin
                s_next <= s_accept_wait;
            end
        end
        default: s_next = s_idle;
    endcase
end

//距离
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        distance_data_r <= 0;
    end
    else if(accept_stop_sig) begin
        distance_data_r <= cnt_distance * 340 / 200;
    end
end

//转BCD码
assign     distance_data_r1[3:0]   = distance_data_r % 10;
assign     distance_data_r1[7:4]   = distance_data_r / 10 % 10;
assign     distance_data_r1[11:8]  = distance_data_r / 100 % 10;
assign     distance_data_r1[15:12] = distance_data_r / 1000 % 10;
assign     distance_data_r1[19:16] = distance_data_r / 10000 % 10;
assign     distance_data_r1[23:20] = distance_data_r / 100000 % 10;

assign data_out_vld = accept_wait_sig;
assign distance_data = distance_data_r1;

//回响信号计数器
always @(posedge clk_1 or negedge rst_n) begin
    if(!rst_n) begin
        cnt_distance <= 0;
    end
    else if(accept_start_sig) begin
        cnt_distance <= 0;
    end
    else if(s_current == s_accept) begin
        cnt_distance <= cnt_distance + 1;
    end
    else begin
        cnt_distance <= 0;
    end
end

//发送触发信号
always @(posedge clk_1 or negedge rst_n) begin
    case (s_current)
        s_idle : begin
            trig <= 0;
        end
        s_send : begin
            trig <= 1;
        end
        s_wait : begin
            trig <= 0;
        end
        s_accept : begin
            trig <= 0;
        end
        s_accept_wait : begin
            trig <= 0;
        end
        default: begin
            trig <= 0;
        end
    endcase
end
//等待发送玩脉冲
always @( posedge clk_1 or negedge rst_n ) begin
    if ( !rst_n ) begin
        cnt <= 0;
    end
    else if ( s_current == s_send ) begin
        if ( flag_clear_cnt == 9 ) begin
            cnt <= 0;
        end
        else begin
            cnt <= cnt + 1;
        end
    end
    else begin
        cnt <= 0;
    end
end
assign flag_clear_cnt = cnt == 9;

//延时计数器
always @( posedge clk_1 or negedge rst_n ) begin
    if ( !rst_n ) begin
        cnt_wait <= 0;
    end
    else if ( s_current == s_accept_wait ) begin
        if ( flag_clear_cnt_wait ) begin
            cnt_wait <= 0;
        end
        else begin
            cnt_wait <= cnt_wait + 1;
        end
    end
    else begin
        cnt_wait <= 0;
    end
end
assign flag_clear_cnt_wait = cnt_wait == 250_000;
endmodule //distance

三、串口模块

基于FPGA的超声波测距

1.串口发送模块

module uart_tx(input			wire						clk,
               input			wire						rst_n,
               input			wire						tx_enable, // 发送使能
               input			wire		[ 07:0 ]		data_in, // 需要发送的数据
               input			wire		[ 19:0 ]		tx_bps, // 发送的波特率
               output			wire						data, // 发送的数据
               output			wire						tx_done);
    
    localparam MAX_BIT = 10;
    
    reg			[ 09:0 ]			data_r			; // 数据寄存器
    reg			[ 12:0 ]			cnt_bps			; // 波特率计数器
    reg			[ 03:0 ]			cnt_bit			; // 数据位计数器
    
    wire		[ 12:0 ]			max_bps			; // 波特率对应频率

    wire							flag_clear_cnt_bps			; // 计数器归零
    wire							flag_add_cnt_bit			; // 计数器+1
    wire							flag_clear_cnt_bit			; 
    reg								flag_send_data			    ; //发送数据标志
    
    //输入数据寄存
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            data_r <= 10'b0;
        end
        else if(tx_enable) begin
            data_r <={1'b1, data_in, 1'b0};
        end

    end
    
    // 波特率计数器
    always @( posedge clk or negedge rst_n ) begin
        if ( !rst_n ) begin
            cnt_bps <= 0;
        end
        else if ( flag_send_data ) begin
            if ( flag_clear_cnt_bps ) begin
                cnt_bps <= 0;
            end
            else begin
                cnt_bps <= cnt_bps + 1;
            end
        end
        else begin
            cnt_bps <= 0;
        end
        
    end

    assign flag_clear_cnt_bps  = cnt_bps >= max_bps -1;
    assign max_bps             = 50_000_000 / tx_bps;
    
    // 数据位计数器
    always @( posedge clk or negedge rst_n ) begin
        if ( !rst_n ) begin
            cnt_bit <= 0;
        end
        else if ( flag_send_data ) begin
            if ( flag_clear_cnt_bit ) begin
                cnt_bit <= 0;
            end
            else if ( flag_add_cnt_bit )begin
                cnt_bit <= cnt_bit + 1;
            end
            else begin
                cnt_bit <= cnt_bit;
            end
        end
        else begin
            cnt_bit <= 0;
        end
    end

    assign flag_add_cnt_bit   = flag_clear_cnt_bps;
    assign flag_clear_cnt_bit = cnt_bit >= MAX_BIT - 1 && flag_add_cnt_bit ;


    //发送数据标志
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            flag_send_data <= 0;
        end
        else if(tx_enable) begin
            flag_send_data <= 1;
        end
        else if(flag_clear_cnt_bit) begin
            flag_send_data <= 0;
        end
        else begin
            flag_send_data <= flag_send_data;
        end
    end
    //发送数据
    assign data = flag_send_data ? data_r[cnt_bit]:1;
    assign tx_done = ~flag_send_data  ;

endmodule

2.串口发送控制模块

串口控制模块把接受到的24位BCD码转换成ASSIC码,并且清除高位零位和添加单位和小数点。把处理好的数据加入FIFO中,再通过串口发送模块进行发送。

module uart_drive (
    input			wire						clk,
    input			wire						rst_n,
    input			wire		[ 23:0 ]		distance_data,
    input			wire						data_vld,
    output			wire						rx_data,
    output			wire						tx_data
);
reg			[ 23:0 ]			distance_data_r			;
reg			[ 7:0 ]				data		;
reg			[ 3:0 ]				cnt_byte		;
reg								send_flag			;
wire		[ 7:0 ]			    distance			;
wire							rdreq			;
wire							wrreq			;
wire							empty			;
wire							full			;
wire		[ 7:0 ]			    data_in			;

reg								flag			;
//串口
uart_tx u_uart_tx(
    .clk       ( clk       ),
    .rst_n     ( rst_n     ),
    .tx_enable ( rdreq      ),
    .data_in   ( data_in   ),
    .tx_bps    ( 115200    ),
    .data      ( tx_data      ),
    .tx_done   ( tx_done   )
);

assign rdreq = tx_done && ~empty;
assign wrreq = ~full && send_flag && (cnt_byte > 0) && flag;
assign distance = data;
tx_fifo	tx_fifo_inst (
	.aclr ( ~rst_n ),
	.clock ( clk ),
	.data ( distance ),
	.rdreq ( rdreq ),
	.wrreq ( wrreq ),
	.empty ( empty ),
	.full ( full ),
	.q ( data_in ),
	.usedw ( usedw_sig )
	);


always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        send_flag <= 0;
    end
    else if(cnt_byte == 9) begin
        send_flag <= 0;
    end
    else if(data_vld) begin
        send_flag <= 1;
    end

end
//数据计数器
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        cnt_byte <=0;
    end
    else if(cnt_byte == 9) begin
        cnt_byte <= 0;
    end
    else if(send_flag) begin
        cnt_byte <= cnt_byte + 1;
    end
end
//寄存数据
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        distance_data_r <=0;
    end
    else if(data_vld) begin
        distance_data_r <= distance_data;
    end
end

//去除前面的不必要的0
always @(*) begin
    if(!rst_n) begin
        flag = 0;
    end
    else if(!send_flag) begin
        flag <= 0;
    end
    else if(cnt_byte > 3 || data> 48) begin
        flag = 1;
    end
    else begin
        flag <= flag;
    end
end
//发送距离
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        data <=0;
    end
    else if(send_flag) begin
        case (cnt_byte)
            0 : data <= distance_data_r[23:20] + 48;
            1 : data <= distance_data_r[19:19] + 48;
            2 : data <= distance_data_r[15:12] + 48;
            3 : data <= distance_data_r[11:8 ] + 48;
            4 : data <= 46; // .
            5 : data <= distance_data_r[7 : 4] + 48;
            6 : data <= distance_data_r[3 : 0] + 48;
            7 : data <= 99 ; //c
            8 : data <= 109; //m
            default: data <=0;
        endcase
        // data <= distance_data_r[(4 * (6-cnt_byte) -1) -:4] + 48;
    end
end

endmodule //uart_drive

四、蜂鸣器模块

蜂鸣器模块把接受到的数据去掉低两位,也就是精度变成厘米级别。当处理完后的数据在MAX_DISTANCE和MIN_DISTANCE之间,则会根据数据的大小调整蜂鸣器鸣叫间隔,使得蜂鸣器的鸣叫频率随着距离的减少越来越高,当数据小于MIN_DISTANCE时则会一直处在鸣叫。

module beep_dirve (
    input			wire						clk,
    input			wire						rst_n,
    input			wire						beep_vld,
    input			wire						data_vld,
    input			wire		[ 23:0 ]		distance_data,
    output			reg						    beep
);

parameter	MAX_DISTANCE = 20;
parameter	MIN_DISTANCE = 10;
parameter	MAX_TIME = 50_000_000;
reg			[ 27:0 ]			cnt			        ;
wire		[ 27:0 ]			delay			    ;
wire		[ 19:0 ]			distance			;
reg			[ 23:0 ]			distance_data_r			;
// wire			[ 19:0 ]			distance_r			;

//寄存数据
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        distance_data_r <= 0;
    end
    else if(data_vld) begin
        distance_data_r <= distance_data;
    end
end
// 根据距离设置翻转频率
assign distance = distance_data_r[11:8] + distance_data_r[15:12] * 10 + distance_data_r[19:16] * 100 + distance_data_r[23:20] *1000;
assign delay =  ((distance ) + 1) * 200_000;

// // led
always @( posedge clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        cnt <= 0;
    end
    else if ( cnt >= delay  ) begin
        cnt <= 0;
    end
    else begin
        cnt <= cnt + 1; 
    end 
end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        beep <= 1;
    end
    else if(~beep_vld) begin
        beep <= 1;
    end
    else if(distance <= MAX_DISTANCE && distance >= MIN_DISTANCE && cnt == 1 && beep_vld) begin
        beep <= ~ beep;
    end
    else if(distance < MIN_DISTANCE && beep_vld) begin
        beep <= 0;
    end
    else if(distance > MAX_DISTANCE) begin
        beep <= 1;
    end
    else begin
        beep <= beep;
    end
end

endmodule //beep_dirve

五、vga显示模块

基于FPGA的超声波测距

1.vga协议驱动代码

    module vga_dirve (input			wire						clk,            //系统时钟
                    input			wire						rst_n,          //复位
                    input			wire		[ 15:0 ]		rgb_data,       //16位RGB对应值
                    output			wire						vga_clk,    //vga时钟 25M
                    output			reg							h_sync,     //行同步信号
                    output			reg							v_sync,     //场同步信号
                    output			reg		[ 11:0 ]				addr_h, //行地址
                    output			reg		[ 11:0 ]				addr_v,  //列地址
                    output			wire		[ 4:0 ]				rgb_r,  //红基色
                    output			wire		[ 5:0 ]				rgb_g,  //绿基色
                    output			wire		[ 4:0 ]				rgb_b  //蓝基色
    );

// 640 * 480 60HZ
localparam	 H_FRONT = 16; // 行同步前沿信号周期长
localparam	 H_SYNC  = 96; // 行同步信号周期长
localparam	 H_BLACK = 48; // 行同步后沿信号周期长
localparam	 H_ACT   = 640; // 行显示周期长
localparam	 V_FRONT = 11; // 场同步前沿信号周期长
localparam	 V_SYNC  = 2; // 场同步信号周期长
localparam	 V_BLACK = 31; // 场同步后沿信号周期长
localparam	 V_ACT   = 480; // 场显示周期长

// 800 * 600 72HZ
// localparam	 H_FRONT = 40; // 行同步前沿信号周期长
// localparam	 H_SYNC  = 120; // 行同步信号周期长
// localparam	 H_BLACK = 88; // 行同步后沿信号周期长
// localparam	 H_ACT   = 800; // 行显示周期长
// localparam	 V_FRONT = 37; // 场同步前沿信号周期长
// localparam	 V_SYNC  = 6; // 场同步信号周期长
// localparam	 V_BLACK = 23; // 场同步后沿信号周期长
// localparam	 V_ACT   = 600; // 场显示周期长


localparam	H_TOTAL = H_FRONT + H_SYNC + H_BLACK + H_ACT; // 行周期
localparam	V_TOTAL = V_FRONT + V_SYNC + V_BLACK + V_ACT; // 列周期

reg			[ 11:0 ]			cnt_h			; // 行计数器
reg			[ 11:0 ]			cnt_v			; // 场计数器
reg			[ 15:0 ]			rgb			; // 对应显示颜色值

// 对应计数器开始、结束、计数信号
wire							flag_enable_cnt_h			;
wire							flag_clear_cnt_h			;
wire							flag_enable_cnt_v			;
wire							flag_clear_cnt_v			;
wire							flag_add_cnt_v  			;
wire							valid_area      			;


// 25M时钟 行周期*场周期*刷新率 = 800 * 525 * 60
reg							clk_25			;
// 50M时钟 1040 * 666 * 72
wire							clk_50			;
//PLL
// pll	pll_inst (
// 	.areset ( ~rst_n ),
// 	.inclk0 ( clk ),
// 	.c0 ( clk_50 ), //50M
// 	.c1 ( clk_25 ) //25M
// 	);
//根据不同分配率选择不同频率时钟
assign vga_clk = clk;

always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        clk_25 <= 0;
    end
    else  begin
        clk_25 <= ~clk_25;
    end
end
// 行计数
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        cnt_h <= 0;
    end
    else if ( flag_enable_cnt_h ) begin
        if ( flag_clear_cnt_h ) begin
            cnt_h <= 0;
        end
        else begin
            cnt_h <= cnt_h + 1;
        end
    end
    else begin
        cnt_h <= 0;
    end
end
assign flag_enable_cnt_h = 1;
assign flag_clear_cnt_h  = cnt_h == H_TOTAL - 1;

// 行同步信号
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        h_sync <= 1;
    end
    else if ( cnt_h == H_SYNC - 1 ) begin // 同步周期时为1
        h_sync <= 0;
    end
    else if ( flag_clear_cnt_h ) begin // 其余为0
        h_sync <= 1;
    end
    else begin
        h_sync <= h_sync;
    end
end

// 场计数
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        cnt_v <= 0;
    end
    else if ( flag_enable_cnt_v ) begin
        if ( flag_clear_cnt_v ) begin
            cnt_v <= 0;
        end
        else if ( flag_add_cnt_v ) begin
            cnt_v <= cnt_v + 1;
        end
        else begin
            cnt_v <= cnt_v;
        end
    end
    else begin
        cnt_v <= 0;
    end
end
assign flag_enable_cnt_v = flag_enable_cnt_h;
assign flag_clear_cnt_v  = cnt_v == V_TOTAL - 1;
assign flag_add_cnt_v    = flag_clear_cnt_h;

// 场同步信号
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        v_sync <= 1;
    end
    else if ( cnt_v == V_SYNC - 1 ) begin
        v_sync <= 0;
    end
        else if ( flag_clear_cnt_v ) begin
        v_sync <= 1;
        end
    else begin
        v_sync <= v_sync;
    end
end

// 对应有效区域行地址 1-640
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        addr_h <= 0;
    end
    else if ( valid_area ) begin
        addr_h <= cnt_h - H_SYNC - H_BLACK + 1;
    end
    else begin
        addr_h <= 0;
    end
end
// 对应有效区域列地址 1-480
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        addr_v <= 0;
    end
    else if ( valid_area ) begin
        addr_v <= cnt_v -V_SYNC - V_BLACK + 1;
    end
    else begin
        addr_v <= 0;
    end
end
// 有效显示区域
assign valid_area = cnt_h >= H_SYNC + H_BLACK && cnt_h <= H_SYNC + H_BLACK + H_ACT && cnt_v >= V_SYNC + V_BLACK && cnt_v <= V_SYNC + V_BLACK + V_ACT;


// 显示颜色
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        rgb <= 16'h0;
    end
    else if ( valid_area ) begin
        rgb <= rgb_data;
    end
    else begin
        rgb <= 16'b0;
    end
end
assign rgb_r = rgb[ 15:11 ];
assign rgb_g = rgb[ 10:5 ];
assign rgb_b = rgb[ 4:0 ];

endmodule // vga_dirve

2.vga数据控制模块

横坐标为时间,纵坐标为距离大小。距离大小决定场坐标,第几个距离决定行坐标。

module data_drive (input			wire						clk,
                    input			wire						vga_clk,
                   input			wire						rst_n,
                   input			wire		[ 11:0 ]		addr_h,
                   input			wire		[ 11:0 ]		addr_v,
                   input			wire						data_vld,
                   input			wire		[ 23:0 ]		distance_data,
                   output			wire		[ 15:0 ]		rgb_data);

localparam	red    = 16'd63488;
localparam	orange = 16'd64384;
localparam	yellow = 16'd65472;
localparam	green  = 16'd1024;
localparam	blue   = 16'd31;
localparam	indigo = 16'd18448;
localparam	purple = 16'd32784;
localparam	white  = 16'd65503;
localparam	black  = 16'd0;

parameter	NUM = 100;
reg			[ 19:0 ]			distance_data_r			;
reg			[ 15:0 ]			rgb_data_r			;
reg			[ 10:0 ]			data_r[NUM -1:0]			;
integer j;
integer i;
//寄存数据
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        distance_data_r <= 0;
    end
    else if(data_vld) begin
        distance_data_r <=distance_data[7:4]+ distance_data[11:8]*10 + distance_data[15:12] * 100 ;
    end
end

//数据打拍
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        for (i = 0; i<NUM - 1;i=i+1 ) begin
            data_r[i] <= 0;
        end
    end
    else if(data_vld) begin
        data_r[0] <= distance_data_r;
        for (i = 1; i<NUM - 1;i=i+1 ) begin
            data_r[i] <= data_r[i-1];
        end
    end
end
reg			[ 10:0 ]			cnt			;
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        rgb_data_r = 0;
        cnt = 0;
    end
    else if(cnt == NUM) begin
        rgb_data_r = black;
        cnt = 0;
    end
    else if(addr_v > 470 && addr_v < 476 && addr_h >9 && addr_h < 625 ) begin //横坐标
        rgb_data_r = white;
        cnt = cnt;
    end
    else if(addr_h > 9 && addr_h <15 && addr_v >9 && addr_v <= 470) begin //纵坐标
        rgb_data_r = white;
        cnt = cnt;
    end
    else if(addr_h >20 && addr_h < 620 && addr_v >10 && addr_v < 470) begin  //打点
        if ( (cnt+1) * 3 == addr_h -20) begin
            if(data_r[cnt] == 470 - addr_v)begin
                rgb_data_r = red;
                cnt = cnt + 1;
            end
            else begin
                rgb_data_r = black;
                cnt = cnt + 1;
            end
        end
        else begin
            rgb_data_r = black;
            cnt = cnt;
        end
    end
    else begin
        rgb_data_r = black;
        cnt = cnt;
    end
end
assign rgb_data = rgb_data_r;
endmodule

六、数码管

基于FPGA的超声波测距

1.数码管段选控制

根据位选信号来显示对应位置的数字

module seg_drive(input			wire						clk,
                 input			wire						rst_n,
                 input			wire						data_vld,
                 input			wire		[ 23:0 ]		display_data,
                 input			wire		[ 5:0 ]		    sel,
                 output			reg		[ 7:0 ]				seg);
        

    localparam	ZERO  = 7'b100_0000;
    localparam	ONE   = 7'b111_1001;
    localparam	TWO   = 7'b010_0100;
    localparam	THREE = 7'b011_0000;
    localparam	FOUR  = 7'b001_1001;
    localparam	FIVE  = 7'b001_0010;
    localparam	SIX   = 7'b000_0010;
    localparam	SEVEN = 7'b111_1000;
    localparam	EIGHT = 7'b000_0000;
    localparam	NINE  = 7'b001_0000;
    localparam	N     = 7'b010_1011;
    localparam	P     = 7'b000_1111;

    reg			[ 23:0 ]			display_data_r			;
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            display_data_r <= 0;
        end
        else if(data_vld) begin
            display_data_r <= display_data;
        end
    end

    reg dot;
    reg [ 3:0 ] num;

    always@( * ) begin
        case( sel )
            6'b111_110: begin
                // num = display_data / 100000 % 10;
                num = display_data_r[23 :20];
                dot = 1;                
            end
            6'b111_101: begin
                // num = display_data / 10000 % 10;
                num = display_data_r[19 : 16];
                dot = 1;
            end
            6'b111_011: begin
                // num = display_data / 1000 % 10;
                num = display_data_r[15 : 12];
                dot = 1;
            end
            6'b110_111: begin
                // num = display_data / 100 % 10;
                num = display_data_r[11 :8];
                dot = 0;
            end
            6'b101_111: begin
                //num = display_data / 10 % 10;
                num = display_data_r[7 :4];
                dot = 1;
            end
            6'b011_111: begin
                //num = display_data % 10;
                num = display_data_r[3 :0];
                dot = 1;
            end
            default num = 4'hf; 
        endcase
    end
    
    always @ ( * ) begin
        case( num )
            4'd0:   seg = {dot,ZERO}; // 匹配到后参考共阳极真值表
            4'd1:   seg = {dot,ONE};
            4'd2:   seg = {dot,TWO};
            4'd3:   seg = {dot,THREE};
            4'd4:   seg = {dot,FOUR};
            4'd5:   seg = {dot,FIVE};
            4'd6:   seg = {dot,SIX};
            4'd7:   seg = {dot,SEVEN};
            4'd8:   seg = {dot,EIGHT};
            4'd9:   seg = {dot,NINE};
            default : seg = {1'b0,ZERO};
        endcase
    end
endmodule

2.数码管位选

每20000ns刷新一次数码管

module sel_drive(
	input clk,
	input rst_n,
	
	output reg [5:0] sel
);
localparam state0 = 3'd0;
localparam state1 = 3'd1;
localparam state2 = 3'd2;
localparam state3 = 3'd3;
localparam state4 = 3'd4;
localparam state5 = 3'd5;

parameter	MAX_NUM = 1_000;

reg [2:0] current_state;
reg [2:0] next_state;
reg    [20:0]	  cnt; //时钟分频计数器
reg              flag;

//计数器
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		flag <= 1'b0;
		cnt <= 0;
	end
	else if(cnt == 0)begin//一轮计数完毕
		flag <= 1'b1;
		cnt <= 1;
	end
	else	begin 
		flag <= 1'b0;
		cnt <= (cnt + 1'b1) % MAX_NUM;//循环+1
	end
end
// 状态跳转
always @(posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		current_state <= state0;
	end
	else if(flag) begin
		current_state <= next_state;
	end
end


//状态判断
always @(*) begin
	if(!rst_n) begin
		next_state <= state0;
	end
	else if(flag) begin
		case(current_state)
			state0: begin
				next_state <= state1;
			end
			state1: begin
				next_state <= state2;
			end
			state2: begin
				next_state <= state3;
			end
			state3: begin
				next_state <= state4;
			end
			state4: begin
				next_state <= state5;
			end
			state5: begin
				next_state <= state0;
			end
			default:begin
				next_state <= state0;
			end
		endcase
	end
	else begin
		next_state <= next_state;
	end
end


//状态输出
always@(current_state) begin
	case (current_state)
		state0: begin
			sel <= 6'b011111;
		end
		state1: begin
			sel <= 6'b101111;
		end
		state2: begin
			sel <= 6'b110111;
		end
		state3: begin
			sel <= 6'b111011;
		end
		state4: begin
			sel <= 6'b111101;
		end
		state5: begin
			sel <= 6'b111110;
		end
		default:begin
			sel <= 6'b111111;
		end
	endcase


end
endmodule

七、顶层文件

由于数码管需要25M时钟,超声波测距需要1M时钟,通过PLL分频得到对应的时钟。

module distance_top (
    input			wire						clk,
    input			wire						rst_n,
    input			wire						echo,
    
    output			wire						trig,
    output			wire		[ 5:0 ]			sel,
    output			wire		[ 7:0 ]			seg,
    output			reg		    [ 3:0 ]			led,
    output			wire						beep,
    input			wire						key,
    output			wire						h_sync,
    output			wire						v_sync,
    output			wire		[ 4:0 ]			rgb_r,
    output			wire		[ 5:0 ]			rgb_g,
    output			wire		[ 4:0 ]			rgb_b,
    input			wire						rx_data,
    output			wire						tx_data
);

wire							clk_50			;
wire							clk_1			;
wire							clk_25			;
wire		[ 23:0 ]			distance_data			;
wire							data_out_vld			;
reg							    beep_vld			;
wire							key_out			;
wire		[ 15:0 ]			rgb_data			;
wire		[ 11:0 ]		    addr_h;
wire		[ 11:0 ]		    addr_v;
pll	pll_inst (
	.areset ( ~rst_n ),
	.inclk0 ( clk ),
	.c0 ( clk_50 ),
	.c1 ( clk_1 ),
	.c2 ( clk_25 )
	);

//vga
vga_dirve u_vga_dirve(
    .clk      ( clk_25   ),
    .rst_n    ( rst_n    ),
    .rgb_data ( rgb_data ),
    .vga_clk  ( vga_clk  ),
    .h_sync   ( h_sync   ),
    .v_sync   ( v_sync   ),
    .addr_h   ( addr_h   ),
    .addr_v   ( addr_v   ),
    .rgb_r    ( rgb_r    ),
    .rgb_g    ( rgb_g    ),
    .rgb_b    ( rgb_b    )
);
//vag数据
data_drive u_data_drive(
    .clk           (clk),
    .vga_clk       ( vga_clk       ),
    .rst_n         ( rst_n         ),
    .addr_h        ( addr_h        ),
    .addr_v        ( addr_v        ),
    .data_vld      ( data_out_vld   ),
    .distance_data ( distance_data ),
    .rgb_data      ( rgb_data      )
);
//数码管
seg_drive u_seg_drive(
    .clk          ( clk          ),
    .rst_n        ( rst_n        ),
    .data_vld     ( data_out_vld ),
    .display_data ( distance_data),
    .sel          ( sel          ),
    .seg          ( seg          )
);
sel_drive u_sel_drive(
    .clk   ( clk_50   ),
    .rst_n ( rst_n ),
    .sel   ( sel   )
);
//测距
distance_drive u_distance(
    .clk           ( clk           ),
    .clk_1          (clk_1),
    .rst_n         ( rst_n         ),
    .echo          ( echo          ),
    .trig          ( trig          ),
    .data_out_vld  ( data_out_vld ),
    .distance_data ( distance_data )
);
//串口
uart_drive u_uart_drive(
    .clk           ( clk           ),
    .rst_n         ( rst_n         ),
    .distance_data ( distance_data ),
    .data_vld      ( data_out_vld   ),
    .rx_data       ( rx_data       ),
    .tx_data       ( tx_data       )
);

//蜂鸣器
beep_dirve u_beep_dirve(
    .clk           ( clk           ),
    .rst_n         ( rst_n         ),
    .beep_vld      ( beep_vld      ),
    .data_vld      ( data_out_vld      ),
    .distance_data ( distance_data ),
    .beep          ( beep          )
);
//按键消抖
key_debounce#(.KEY_W   ( 1 )) u_key_debounce(
    .clk     ( clk     ),
    .rst_n   ( rst_n   ),
    .key_in  ( key  ),
    .key_out  ( key_out  )
);

//控制蜂鸣器使能
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        beep_vld <= 0;
    end
    else if(key_out) begin
        beep_vld <= ~beep_vld;
    end
end
reg			[ 27:0 ]			cnt			        ;
// led
always @( posedge clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        cnt <= 0;
    end
    else if ( cnt == 50_000_000 - 1 ) begin
        cnt <= 0;
    end
    else begin
        cnt <= cnt + 1;
    end
end

always @( posedge clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        led <= 4'b0000;
    end
    else if ( cnt == 50_000_000 -1 )begin
        led <= ~led;
    end
    else begin
        led <= led;
    end
end
endmodule //distance_top

八、源代码

https://github.com/TangtangSix/distance文章来源地址https://www.toymoban.com/news/detail-469284.html

到了这里,关于基于FPGA的超声波测距的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【嵌入式系统应用开发】FPGA——基于HC-SR04超声波测距

    硬件 DE2-115 HC-SR04超声波传感器 软件 Quartus 18.1 使用DE2-115开发板驱动HC-SR04模块,并将所测得数据显示到开发板上的数码管。 HC-SR04 超声波测距模块可提供 2cm-400cm的非接触式距离感测功能,测距精度可达高到 3mm;模块包括超声波发射器、接收器与控制电路。图1为 HC-SR04 外观,

    2024年02月08日
    浏览(62)
  • FPGA一键测距仪之超声波模块篇

    FPGA一键测距仪之数码管篇 FPGA一键测距仪之[按键+控制+蜂鸣器]篇 FPGA一键测距仪之终篇 第一个FPGA小项目:基于BASYS3的超声波一键测距仪 本篇会对超声波测距模块进行详细的讲解,包括测距原理、各模块的时序图构思以及代码实现。 所用到的软件工具: Vivado 2019.1 Modelsim SE

    2024年02月02日
    浏览(51)
  • 基于STM32的超声波测距

    一、HC-SR04模块介绍 HC-SR04超声波测距模块可提供2cm-400cm的非接触式距离感测功能,测距精度可高达3mm;模块包括超声波发射器、接收器、与控制电路。 模块的基本工作原理为: (1)采用 IO口 TRIG触发测距,给最少 10us的高电平信呈。 (2)模块自动发送 8个 40khz的方波,自动检测是

    2024年02月13日
    浏览(47)
  • 基于单片机超声波测距语音播放

    一、系统方案 本设计采用52单片机作为主控器,HC-SR04测距,液晶1602显示,按键设置报警阀值,语音报警。 二、硬件设计 原理图如下: 三、单片机软件设计 1、首先是系统初始化 uint dist; // 保存超声波模块测量到的结果 2、液晶显示程序 / / // 1602液晶写命令函数,cmd就是要写

    2024年02月09日
    浏览(51)
  • 基于STM32超声波测距系统设计

    随着社会的发展和科技的进步,人们对测距的要求越来越高,特别是在一些要求实时测距的场合,传统的测距方式已经无法满足人们的需求,而超声波测距由于其非接触和实时反馈的特点在生活中得到广泛应用。 本系统硬件部分由电源模块、控制模块、显示模块、报警模块、

    2024年02月04日
    浏览(55)
  • 基于单片机的超声波语音测距系统

    一、系统方案 超声波具有指向性强,能量消耗缓慢,在介质中传播的距离较远,因而超声波经常用于距离的测量,如测距仪和物位测量仪等都可以通过超声波来实现。利用超声波检测往往比较迅速、方便、计算简单、易于做到实时控制,并且在测量精度方面能达到工业实用的

    2024年02月10日
    浏览(54)
  • 基于STM32_HAL库实现超声波测距

    核心板               : STM32F103C8T6。 超声波测距模块 : HC-SR04超声波测距模块 实验目的            : 利用超声波测距,将测量的距离打印在串口并输出。 HC-SR04超声波测距模块介绍         接口定义:Vcc、 Trig(控制端——PA2)、 Echo(接收端——PA11)、 Gnd        

    2024年02月16日
    浏览(52)
  • 基于51单片机的超声波测距及温度显示

    (仿真+程序+PCB+原理图+设计报告) 功能介绍 具体功能: 1.超声波测距传感器HC-SR04、温度传感器DS18B20将检测的数据传给51单片机; 2.LCD1602实时显示测得的距离和温度; 3.按键可以设置距离的上下限; 4.距离超过设定范围,蜂鸣器+LED产生声光报警; ​演示视频: 基于5

    2024年04月24日
    浏览(51)
  • 基于c51单片机超声波测距仪

            整个系统由AT89C51,超声波电路,显示电路和报警电路,按键控制组成,系统复位后,首先对各模块进行初始化,初始化后根据超声波模块返回的回波进行数据计算,把数据显示到LMO16L液晶显示器上,并与设定的报警值相比较,小于报警值则蜂鸣器响起、指示灯亮

    2024年02月04日
    浏览(54)
  • 基于Arduino单片机超声波测距仪设计

    文章目录 摘  要 1.课程设计任务 1.1课程设计题目 1.2设计的要求 2.设计总体方案 2.1初步设计方案 2.2各个单元电路的设计要求 2.3主要性能指标 2.4总体方案 3.单元模块设计 3.1显示模块 3.2超声波测距模块 3.3蜂鸣器模块 3.4电机模块 3.5 LED二极管模块 4.软件流程图 5.设计代码 5.1核

    2024年02月11日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包