Directorio de artículos
prefacio
Entorno:
1. Quartus18.1
2. vscode
3. Modelo de placa: EP4CE6F17C8N
4. Módulo ultrasónico: HC_SR04
Requisitos:
utilice la placa de desarrollo EP4CE6F17C8 para controlar el módulo de detección ultrasónica (HC_SR04) y mostrar los datos medidos en el tubo digital en el desarrollo tablero superior
1. Introducción al módulo ultrasónico
1. Características del producto
El módulo de rango ultrasónico HC-SR04 puede proporcionar una función de detección de distancia sin contacto de 2 cm a 400 cm, y la precisión del rango puede alcanzar hasta 3 mm; el módulo incluye un transmisor ultrasónico, un receptor y un circuito de control.
Principio de funcionamiento básico:
(1) Use el puerto IO TRIG para activar el rango y proporcione una señal de alto nivel de al menos 10us.
(2) El módulo envía automáticamente 8 ondas cuadradas de 40 khz y detecta automáticamente si hay un retorno de señal;
(3) Si hay un retorno de señal, se emite un nivel alto a través del puerto IO ECHO y la duración del alto El nivel es el tiempo desde la transmisión hasta el regreso de la onda ultrasónica. Distancia de prueba = (tiempo de alto nivel * velocidad del sonido (340M/S))/2;
2. El diagrama de tiempo del módulo ultrasónico.
El diagrama de tiempo anterior muestra que solo necesita proporcionar una señal de disparo de pulso de más de 10uS, y el módulo enviará internamente 8 niveles periódicos de 40kHz y detectará ecos. Una vez que se detecta una señal de eco, se emite una señal de eco. El ancho de pulso de la señal de eco es proporcional a la distancia medida. Por lo tanto, la distancia se puede calcular a partir del intervalo de tiempo entre el envío de la señal y la recepción de la señal de eco.
2. Diseño del sistema
1. Diagrama de bloques del sistema
2. Código fuente
- Archivo de nivel superior HC_SR04_TOP:
module HC_SR04_TOP(
input clk ,
input rstn ,
input echo , // 距离信号
output trig , // 触发测距信号
output wire [5:0] sel ,
output wire [7:0] seg
);
wire [18:00] data_o ;
wire clk_us ;
seg_driver u_seg_driver(
.clk (clk ),
.rstn (rstn ),
.data_in (data_o ), //待显示数据
.sel (sel ), // 我这里是8位段选,可以换6位,但是要自己改代码
.seg (seg )
);
clk_div u_clk_div(
.clk (clk ),
.rstn (rstn ),
.clk_us (clk_us )
);
trig_driver u_trig_driver(
.clk_us (clk_us ),
.rstn (rstn ),
.trig (trig )
);
echo_driver u_echo_driver(
.clk (clk ),
.clk_us (clk_us ),
.rstn (rstn ),
.echo (echo ),
.data_o (data_o )
);
//Logic Description
endmodule
- Módulo de accionamiento ultrasónico trig_driver:
module trig_driver(
input wire clk_us ,
input wire rstn ,
output wire trig //触发测距信号
);
parameter CYCLE_MAX = 19'd29_9999;
reg [18:00] cnt ;
// 10毫秒持续电平输出
always @(posedge clk_us or negedge rstn) begin
if(!rstn) begin
cnt <= 19'd0;
end
else if(cnt == CYCLE_MAX) begin
cnt <= 19'd0;
end
else begin
cnt <= cnt + 19'd1;
end
end
assign trig = cnt < 15 ? 1'b1 : 1'b0;
endmodule
- módulo de rango echo_driver:
module echo_driver(
input wire clk ,
input wire clk_us ,
input wire rstn ,
input wire echo ,
output wire [18:00] data_o //检测距离,保留3位小数,*1000实现
);
parameter T_MAX = 16'd5_9999;//510cm 对应计数值
reg r1_echo,r2_echo; //边沿检测
wire echo_pos,echo_neg; //
reg [15:00] cnt ;
reg [18:00] data_r ;
//如果使用clk_us 检测边沿,延时2us,差值过大
always @(posedge clk or negedge rstn)begin
if(!rstn)begin
r1_echo <= 1'b0;
r2_echo <= 1'b0;
end
else begin
r1_echo <= echo;
r2_echo <= r1_echo;
end
end
assign echo_pos = r1_echo & ~r2_echo;
assign echo_neg = ~r1_echo & r2_echo;
always @(posedge clk_us or negedge rstn) begin
if(!rstn) begin
cnt <= 16'd0;
end
else if(echo) begin
if(cnt == T_MAX) begin
cnt <= 16'd0;
end
else begin
cnt <= cnt + 16'd1;
end
end
else begin
cnt <= 16'd0;
end
end
always @(posedge clk or negedge rstn)begin
if(!rstn)begin
data_r <= 'd2;
end
else if(echo_neg)begin
data_r <= (cnt << 4) + cnt;
end
else begin
data_r <= data_r;
end
end
assign data_o = data_r >> 1;
endmodule
- Módulo de división de frecuencia de reloj:
module clk_div(
input wire clk ,
input wire rstn ,
output wire clk_us //
);
parameter CNT_MAX = 19'd49;//1us的计数值为 50 * Tclk(20ns)
reg [5:0] cnt ;
wire add_cnt ;
wire end_cnt ;
// 时钟分频
always @(posedge clk or negedge rstn) begin
if(!rstn) begin
cnt <= 6'd0;
end
else if(cnt == CNT_MAX) begin
cnt <= 6'd0;
end
else begin
cnt <= cnt + 6'd1;
end
end
assign clk_us = cnt >= CNT_MAX ;
endmodule
- módulo controlador de tubo digital seg_driver:
module seg_driver(
input wire clk ,
input wire rstn ,
input wire [18:0] data_in , //待显示数据
output reg [5:0] sel , // 我这里是8位段选,可以换6位,但是要自己改代码
output reg [7:0] seg
);
//parameter define
localparam NUM_0 = 8'b1100_0000,
NUM_1 = 8'b1111_1001,
NUM_2 = 8'b1010_0100,
NUM_3 = 8'b1011_0000,
NUM_4 = 8'b1001_1001,
NUM_5 = 8'b1001_0010,
NUM_6 = 8'b1000_0010,
NUM_7 = 8'b1111_1000,
NUM_8 = 8'b1000_0000,
NUM_9 = 8'b1001_0000,
NUM_A = 8'b1000_1000,
NUM_B = 8'b1000_0011,
NUM_C = 8'b1100_0110,
NUM_D = 8'b1010_0001,
NUM_E = 8'b1000_0110,
NUM_F = 8'b1000_1110,
ALL_LIGHT = 8'b0000_0000,
LIT_OUT = 8'b1111_1111,
LINE = 8'b1011_1111;
localparam MAX_10us = 10'd999 ;
//reg 、wire define
reg [3:0] cm_hund ;//100cm
reg [3:0] cm_ten ;//10cm
reg [3:0] cm_unit ;//1cm
reg [3:0] point_1 ;//1mm
reg [3:0] point_2 ;//0.1mm
reg [3:0] point_3 ;//0.01mm
reg [9:0] cnt_10us ;
reg [7:0] num ;// 段选输出判断
always @(posedge clk or negedge rstn)begin
if(!rstn)begin
cm_hund <= 'd0;
cm_ten <= 'd0;
cm_unit <= 'd0;
point_1 <= 'd0;
point_2 <= 'd0;
point_3 <= 'd0;
end
else begin
cm_hund <= data_in / 10 ** 5;
cm_ten <= data_in / 10 ** 4 % 10;
cm_unit <= data_in / 10 ** 3 % 10;
point_1 <= data_in / 10 ** 2 % 10;
point_2 <= data_in / 10 ** 1 % 10;
point_3 <= data_in / 10 ** 0 % 10;
end
end
// 修改后 段选
always @(posedge clk or negedge rstn) begin
if(!rstn) begin
cnt_10us <= 10'd0;
end
else if(cnt_10us == MAX_10us) begin
cnt_10us <= 10'd0;
end
else begin
cnt_10us <= cnt_10us + 10'd1;
end
end
// 数码管位移
always @(posedge clk or negedge rstn) begin
if(!rstn) begin
sel <= 6'b111_110;
end
else if(cnt_10us == MAX_10us) begin
sel <= {
sel[0],sel[5:1]};
end
else begin
sel <= sel;
end
end
// 确定输出数字
always @(*) begin
case (sel)
6'b01_1111 : num = hex_data(point_3);
6'b10_1111 : num = hex_data(point_2);
6'b11_0111 : num = hex_data(point_1);
6'b11_1011 : num = hex_data(cm_unit);
6'b11_1101 : num = hex_data(cm_ten) ;
6'b11_1110 : num = hex_data(cm_hund);
// 6'b11_1111 : num = LINE;
// 6'b11_1111 : num = LIT_OUT;
default : num = NUM_0;
endcase
end
// 位选输出
always @(posedge clk or negedge rstn) begin
if(!rstn) begin
seg <= LINE;
end
else begin
case (num)
NUM_0 : seg <= NUM_0 ;
NUM_1 : seg <= NUM_1 ;
NUM_2 : seg <= NUM_2 ;
NUM_3 : seg <= NUM_3 ;
NUM_4 : seg <= NUM_4 ;
NUM_5 : seg <= NUM_5 ;
NUM_6 : seg <= NUM_6 ;
NUM_7 : seg <= NUM_7 ;
NUM_8 : seg <= NUM_8 ;
NUM_9 : seg <= NUM_9 ;
LINE : seg <= LINE ;
LIT_OUT : seg <= LIT_OUT ;
ALL_LIGHT : seg <= ALL_LIGHT;
endcase
end
end
// 函数,4位输入,7位输出,判断要输出的数字
function [7:0] hex_data; //函数不含时序逻辑相关
input [03:00] data_i;//至少一个输入
begin
case(data_i)
4'd0:hex_data = NUM_0;
4'd1:hex_data = NUM_1;
4'd2:hex_data = NUM_2;
4'd3:hex_data = NUM_3;
4'd4:hex_data = NUM_4;
4'd5:hex_data = NUM_5;
4'd6:hex_data = NUM_6;
4'd7:hex_data = NUM_7;
4'd8:hex_data = NUM_8;
4'd9:hex_data = NUM_9;
default:hex_data = ALL_LIGHT;
endcase
end
endfunction
endmodule
3. Vista RTL
4. Efecto
Alcance ultrasónico
3. Resumen
Los primeros tres dígitos del tubo nixie representan unidades centimétricas de cientos, decenas y centímetros, y los últimos tres dígitos son lugares decimales reservados. En términos generales, el módulo de medición de distancia es relativamente preciso. A través de esta operación, entiendo básicamente el principio de conducción del módulo ultrasónico y soy más competente en la operación del tubo digital.