一、项目框架
distance超声波测距模块负责数据的采集,vga、uart、beep、数码管根据采集到的数据分别进行vga的屏幕打点、串口输出到上位机、蜂鸣器根据数据大小进行鸣叫以及数码管显示采集到的数据。
RTL视图
二、超声波测距模块
代码
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
三、串口模块
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显示模块
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
六、数码管
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分频得到对应的时钟。文章来源:https://www.toymoban.com/news/detail-469284.html
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模板网!