1.IDE:Quartus II
2.设备:Cyclone II EP2C8Q208C8N
3.实验:超声波测距-数码管显示
4.时序图:
5.步骤:
(1)FPGA乘除运算与单片机不同,特别需要注意位宽,同时尽量转换为位运算。
(2)注意计数器cnt不是无限制,0.5S已经足够。
(3)采用cnt计数,echo上升沿记下cnt,下降沿(一次捕获结束)则进行运算距离。
(4)数码管段码引脚对应
(5)实物运行图
6.代码:
smg.v
module smg
(
input wire clk,
input wire rst_n,
input wire [14:0] data,
output reg qw, //用于共阳极数码管控制数码管的开关(千位)
output reg bw, //用于共阳极数码管控制数码管的开关(百位)
output reg sw, //用于共阳极数码管控制数码管的开关(十位)
output reg gw, //用于共阳极数码管控制数码管的开关(个位)
output reg [7:0] smg //映射到真实引脚中
);
parameter show_zero = 8'b11000000;
parameter show_one = 8'b11111001;
parameter show_two = 8'b10100100;
parameter show_three = 8'b10110000;
parameter show_four = 8'b10011001;
parameter show_five = 8'b10010010;
parameter show_six = 8'b10000010;
parameter show_seven = 8'b11111000;
parameter show_eight = 8'b10000000;
parameter show_nine = 8'b10010000;
reg [25:0] cnt;
reg [13:0] counter; //数码管计数值
reg [3:0] qw_value; //数码管千位的值
reg [3:0] bw_value; //数码管百位的值
reg [3:0] sw_value; //数码管十位的值
reg [3:0] gw_value; //数码管个位的值
reg [1:0] scan_ws; //数码管扫描位数序列号(0 个位 1 百位 2 十位 3 千位)
reg [3:0] scan_value; //单个位扫描值
/*
*计数器(时基20ns 50MHz)
*/
always @ (posedge clk or negedge rst_n) begin
if(!rst_n)
cnt <= 26'd0;
else begin
if(cnt < 26'd50000000)
cnt <= cnt + 1'b1;
else
cnt <= 26'd0;
end
end
/*
*定时器(1s),用于数码管显示
*/
always @ (posedge clk or negedge rst_n) begin
if(!rst_n)
counter <= 14'd0;
else if(cnt == 26'd50000000) begin
if(counter < 14'd9999)
counter <= counter +1'b1;
else
counter <= 14'd0;
end
end
/*
*选择打开的数码管
*/
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
qw <= 1'b1;
bw <= 1'b1;
sw <= 1'b1;
gw <= 1'b1;
scan_value <= 4'd0;
end
else if(!(cnt % 26'd200000)) begin //4ms
bw <= 1'b1; //全关(因为程序执行中会打开部分数码管,每次单位数码管扫描前先关闭所有数码管)
sw <= 1'b1;
gw <= 1'b1;
qw <= 1'b1;
case(scan_ws) //决定打开哪个数码管
2'b00 : begin
scan_value <= gw_value;
gw <= 1'b0;
end
2'b01 : begin
scan_value <= sw_value;
sw <= 1'b0;
end
2'b10 : begin
scan_value <= bw_value;
bw <= 1'b0;
end
2'b11 : begin
scan_value <= qw_value;
qw <= 1'b0;
end
default : ;
endcase
end
end
/*
*向数码管写入数据
*/
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
smg <= show_zero;
end
else begin
case(scan_value)
4'd0 : smg <= show_zero;
4'd1 : smg <= show_one;
4'd2 : smg <= show_two;
4'd3 : smg <= show_three;
4'd4 : smg <= show_four;
4'd5 : smg <= show_five;
4'd6 : smg <= show_six;
4'd7 : smg <= show_seven;
4'd8 : smg <= show_eight;
4'd9 : smg <= show_nine;
default : ;
endcase
end
end
/*
*扫描位号赋值
*/
always @ (posedge clk or negedge rst_n) begin
if(!rst_n)
scan_ws <= 2'b00;
else if(!(cnt % 26'd200000)) begin //到达刷新时间
if(scan_ws == 2'b11)
scan_ws <= 2'b00;
else
scan_ws <= 2'b01 + scan_ws;
end
else
scan_ws <= scan_ws ;
end
/*
*向扫描值千百十个位赋值
*/
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
qw_value <= 4'd0;
bw_value <= 4'd0;
sw_value <= 4'd0;
gw_value <= 4'd0;
end
else begin
qw_value <= data/10'd1000;
bw_value <= data/7'd100%4'd10;
sw_value <= data/4'd10%4'd10;
gw_value <= data%4'd10;
end
end
endmodule
csbcj.v
/*
*超声波模块代码
*/
module csbcj(
input wire sys_clk ,
input wire sys_rst_n ,
input wire echo ,
output reg trig ,
output reg [29:0] distance
);
reg [24:0] cnt ;
reg [24:0] echo_rise_cnt ; //用于记录上升沿时刻
parameter half_second_cnt = 25'd25_000_000; //0.5s触发一次
parameter trig_max = 9'd500; //10us
/*
*触发控制
*/
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0)
trig <= 1'b0 ;
else if(cnt == 25'd0) //0.5s触发一次
trig <= 1'b1 ;
else if(cnt == trig_max || echo == 1'b1)
trig <= 1'b0 ;
else
trig <= trig ;
end
/*
*echo下降沿(完成一次接收)
*/
always @ (negedge echo) begin
distance <= (cnt-echo_rise_cnt)* 25'd34 / 25'd10_0000 ;
end
/*
*echo上升沿
*/
always @ (posedge echo) begin
echo_rise_cnt <= cnt ;
end
/*
*0.5秒计数器
*/
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0)
cnt <= 25'd0;
else if(cnt == half_second_cnt) //0.5s
cnt <= 25'd0;
else
cnt <= cnt + 1'b1;
end
endmodule
show_distance.v
module show_distance(
input wire sys_clk ,
input wire sys_rst_n ,
input wire echo ,
output wire trig ,
output wire qw ,
output wire bw ,
output wire sw ,
output wire gw ,
output wire [7:0] smg
);
wire [29:0] distance ;
csbcj csbcj_inst(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.echo (echo ),
.trig (trig ),
.distance (distance )
);
smg smg_inst
(
. clk (sys_clk ),
. rst_n (sys_rst_n ),
. data (distance ),
. qw (qw ),
. bw (bw ),
. sw (sw ),
. gw (gw ),
. smg (smg )
);
endmodule