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 :Le fonctionnement de ce type de capteurs est résumé sur les chronogrammes ci-dessous (Trigger et Echo séparés) :
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 :
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 :
Le processus est décrit à la façon d’une machine à états finis (Finite State Machine) :
Voici le code du module ultrasonic.v :
| Code verilog : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | /*
* 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 :
| Code verilog : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | 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[6] = (distance_raw > 40*D); // distance > 40cm
assign LED[5] = (distance_raw > 30*D);
assign LED[4] = (distance_raw > 25*D);
assign LED[3] = (distance_raw > 20*D);
assign LED[2] = (distance_raw > 15*D);
assign LED[1] = (distance_raw > 10*D);
assign LED[0] = (distance_raw > 5*D); // distance > 5cm
assign LED[7] = 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 2 838 articles depuis plus d'un an.
Soutenez le club developpez.com en souscrivant un abonnement pour que nous puissions continuer à vous proposer des publications.
Soutenez le club developpez.com en souscrivant un abonnement pour que nous puissions continuer à vous proposer des publications.