IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

[FPGA] Créer un circuit logique pour piloter un télémètre à ultrasons (SRF05 / HC-SR04)
Un billet blog de f-leb

Le , par f-leb

0PARTAGES

Je vous présente aujourd'hui un contrôleur pour télémètre à ultrasons (de type SRF05 ou HC-SR04). La carte de développement est une carte FPGA Altera DE0-nano :

https://www.youtube.com/watch?v=F90JlWZx3VM

Le fonctionnement de ce type de capteurs est résumé sur les chronogrammes ci-dessous (Trigger et Echo séparés) :

624089

Une impulsion de 10μs minimum sur la broche Trigger du module va préparer l’envoi d’un train d’ultrasons. Quand le train d’ultrasons part, le signal Echo bascule à l’état haut (environ 750μs après l’impulsion du signal Trigger). Le signal Echo retourne à l’état bas au retour du train d’ultrasons après réflexion sur l’obstacle (ou après un timeout de 30ms si aucun obstacle n’est rencontré). La largeur du signal Echo représente le temps pris par le train d’ultrasons pour faire l’aller-retour entre le capteur et l’obstacle, et donc une image de la distance de l'obstacle (la vitesse du son étant connue, 345m/s environ).

Exemple : si la largeur du signal Echo relevée est de 20ms, alors la distance de l’obstacle est d = 345x0,02/2=3,45m environ (le facteur 1/2 s’explique car le train d’ultrasons parcourt deux fois la distance, aller et retour après réflexion, entre le capteur et l’obstacle).
Un contrôleur pour ce capteur doit donc être capable au minimum de produire un signal Trigger sur commande, et de récupérer finalement une donnée numérique qui sera l’image de la largeur du signal Echo.

Le module ultrasonic.v du contrôleur présente les entrées-sorties suivantes :

631157

Les entrées :


  • clk : le signal d’horloge (paramètre CLK_MHZ à renseigner, 50MHz par défaut) ;
  • echo : à connecter sur la broche Echo du capteur (Attention, le capteur est alimenté en 5V, le signal Echo du capteur doit être abaissé à 3,3V à l’entrée de la carte FPGA (diviseur de tension) ;
  • start : démarre une mesure avec une impulsion synchronisée sur une période du signal d’horloge.


Les sorties :

  • trigger : à connecter à la broche Trigger du capteur. La paramètre TRIGGER_PULSE_US renseigne la durée de l’impulsion (12μs par défaut);
  • new_measure : signal de contrôle, où une impulsion est générée quand la mesure est complète (signal Echo redescendu ou timeout) ;
  • timeout : signal de contrôle, une impulsion si timeout (paramètre TIMEOUT_MS, 20ms par défaut) ;
  • distance_raw : donnée image de la largeur du signal Echo codée sur 21 bits. Il s’agit en fait d’un compteur 21 bits qui s’incrémente à la fréquence de l’horloge jusqu’au retour des ultrasons (ou timeout). La valeur est garantie si vous lisez la valeur du compteur au moment de l’impulsion du signal new_measure.
    Durée du signal Echo en microsecondes = distance_raw / CLK_MHZ


Le capteur SRF05 a un timeout de 30ms si aucun obstacle n'est rencontré. On peut simuler un timeout inférieur avec le paramètre TIMEOUT_MS. Si le signal Echo n'est pas redescendu après ce timeout, le contrôleur bloque distance_raw, délivre une impulsion sur la sortie new_measure et sur la sortie timeout.

Chronogrammes de simulation fonctionnelle :

624091

Le processus est décrit à la façon d’une machine à états finis (Finite State Machine) :

624092

Voici le code du module ultrasonic.v :

/*
* Un simple contrôleur pour les capteurs à ultrason
du type SRF05 ou HC-SR04

* Trigger et Echo séparés

/-----------------------------\
| ultrasonic sensor |
| controller |
| |
| trigger -->
| |
| new_measure -->
| timeout -->
--> echo |
| distance_raw[20:0] ==>
| |
--> start |
--> clk |
| |
\-----------------------------/

* clk : horloge (paramètre CLK_MHZ, 50 MHz par défaut)
* start : lance une mesure sur impulsion
* trigger : à connecter à la broche Trig du capteur
(paramètre TRIGGER_PULSE_US, 12 us par défaut)
* echo : à connecter sur la broche Echo du capteur
* new_measure : 1 impulsion si la mesure est complète
* timeout : 1 impulsion si timeout (paramètre TIMEOUT_MS, 20 ms par défaut
* distance_raw: à lire sur impulsion de new_measure
donnée image de la largeur du signal Echo codée sur 21 bits

duree du signal echo en microsecondes = distance_raw / CLK_MHZ

Le capteur SRF05 a un timeout de 30 ms si aucun obtacle n'est rencontré.
On peut simuler un timeout inférieur avec le paramètre TIMEOUT_MS
Si le signal Echo n'est pas redescendu après ce TIME_OUT, le contrôleur
bloque distance_raw, délivre une impulsion sur la sorte new_measure et sur la sortie timeout.
*/


module ultrasonic(clk, start, trigger, echo, distance_raw, new_measure, timeout);

input clk, start, echo;
output trigger, new_measure, timeout;
output reg [20:0] distance_raw;

parameter CLK_MHZ = 50, // fréquence horloge en MHz
TRIGGER_PULSE_US = 12, // durée impulsion trigger en microsecondes
TIMEOUT_MS = 25; // timeout en millisecondes

localparam COUNT_TRIGGER_PULSE = CLK_MHZ * TRIGGER_PULSE_US;
localparam COUNT_TIMEOUT = CLK_MHZ * TIMEOUT_MS * 1000;

reg [20:0] counter;

reg[2:0] state, state_next;
localparam IDLE = 0,
TRIG = 1,
WAIT_ECHO_UP = 2,
MEASUREMENT = 3,
MEASURE_OK = 4;

always @(posedge clk) state <= state_next;

wire measurement;
assign measurement = (state == MEASUREMENT);

assign new_measure = (state == MEASURE_OK);

wire counter_timeout;
assign counter_timeout = (counter >= COUNT_TIMEOUT);

assign timeout = new_measure && counter_timeout;
assign trigger = (state == TRIG);

wire enable_counter;
assign enable_counter = trigger || echo;

always @(posedge clk) begin
if (enable_counter)
counter <= counter + 21'b1;
else
counter <= 21'b0;
end

always @(posedge clk) begin
if (enable_counter && measurement)
distance_raw <= counter;
end

always @(*) begin
state_next <= state; // par défaut, état maintenu

case (state)
IDLE: begin // signal trigger sur impulsion start
if (start) state_next <= TRIG;
end

TRIG: begin // durée signal trig > 10us pour SRF05
if (counter >= COUNT_TRIGGER_PULSE) state_next <= WAIT_ECHO_UP;
end

WAIT_ECHO_UP: begin
// avec le SRF05, il y a un délai de 750us après le trig avant que le
// signal echo bascule à état haut.
if (echo) state_next <= MEASUREMENT;
end

MEASUREMENT: begin // attente echo qui redescend, ou timeout
if (counter_timeout || (~echo)) state_next <= MEASURE_OK;
end

MEASURE_OK: begin
state_next <= IDLE;
end

default: begin
state_next <= IDLE;
end
endcase

end


endmodule


Le code ci-dessous est une petite démonstration qui met en œuvre le télémètre à ultrasons SRF05 (voir la vidéo plus haut). Le bandeau de LED de la carte progresse en fonction de la distance de l'obstacle face au capteur :

module top(CLOCK_50, TRIG, ECHO, LED);

input CLOCK_50;
output TRIG;
input ECHO; // /!\ Alim. du capteur 5V, abaisser le signal ECHO à 3v3 (diviseur tension)
output [7:0] LED;

wire start, new_measure, timeout;
wire [20:0] distance_raw;

reg [24:0] counter_ping;

localparam CLK_MHZ = 50; // horloge 50MHz
localparam PERIOD_PING_MS = 60; // période des ping en ms

localparam COUNTER_MAX_PING = CLK_MHZ * PERIOD_PING_MS * 1000;

// avec horloge 50MHz et c=345m/s, distance_raw = 2900 * D(cm)
localparam D = 2900;


ultrasonic #( .CLK_MHZ(50),
.TRIGGER_PULSE_US(12),
.TIMEOUT_MS(3)
) U1
( .clk(CLOCK_50),
.trigger(TRIG),
.echo(ECHO),
.start(start),
.new_measure(new_measure),
.timeout(timeout),
.distance_raw(distance_raw)
);

assign LED = (distance_raw > 40*D); // distance > 40cm
assign LED = (distance_raw > 30*D);
assign LED = (distance_raw > 25*D);
assign LED = (distance_raw > 20*D);
assign LED = (distance_raw > 15*D);
assign LED = (distance_raw > 10*D);
assign LED = (distance_raw > 5*D); // distance > 5cm
assign LED = timeout; // avec timeout=3ms => distance > 52cm

assign start = (counter_ping == COUNTER_MAX_PING - 1);

always @(posedge CLOCK_50) begin
if (counter_ping == COUNTER_MAX_PING - 1)
counter_ping <= 25'd0;
else begin
counter_ping <= counter_ping + 25'd1;
end
end


endmodule

Vous avez lu gratuitement 44 216 articles depuis plus d'un an.
Soutenez le club developpez.com en souscrivant un abonnement pour que nous puissions continuer à vous proposer des publications.

Une erreur dans cette actualité ? Signalez-nous-la !