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

f-leb

[Actualité] [FPGA] Créer un circuit logique pour piloter un télémètre à ultrasons (SRF05 / HC-SR04)

Noter ce billet
par , 24/08/2022 à 08h00 (24112 Affichages)
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) :

Nom : 8F8XF.gif
Affichages : 2723
Taille : 4,2 Ko

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 :

Nom : bloc_ultrasonic.png
Affichages : 1524
Taille : 9,3 Ko

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 :

Nom : simul-ultrasonic.png
Affichages : 1522
Taille : 18,1 Ko

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

Nom : state-machine-view.png
Affichages : 1519
Taille : 10,2 Ko

Voici le code du module ultrasonic.v :

Code verilog : Sélectionner tout - Visualiser dans une fenêtre à part
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 - Visualiser dans une fenêtre à part
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

Envoyer le billet « [FPGA] Créer un circuit logique pour piloter un télémètre à ultrasons (SRF05 /  HC-SR04) » dans le blog Viadeo Envoyer le billet « [FPGA] Créer un circuit logique pour piloter un télémètre à ultrasons (SRF05 /  HC-SR04) » dans le blog Twitter Envoyer le billet « [FPGA] Créer un circuit logique pour piloter un télémètre à ultrasons (SRF05 /  HC-SR04) » dans le blog Google Envoyer le billet « [FPGA] Créer un circuit logique pour piloter un télémètre à ultrasons (SRF05 /  HC-SR04) » dans le blog Facebook Envoyer le billet « [FPGA] Créer un circuit logique pour piloter un télémètre à ultrasons (SRF05 /  HC-SR04) » dans le blog Digg Envoyer le billet « [FPGA] Créer un circuit logique pour piloter un télémètre à ultrasons (SRF05 /  HC-SR04) » dans le blog Delicious Envoyer le billet « [FPGA] Créer un circuit logique pour piloter un télémètre à ultrasons (SRF05 /  HC-SR04) » dans le blog MySpace Envoyer le billet « [FPGA] Créer un circuit logique pour piloter un télémètre à ultrasons (SRF05 /  HC-SR04) » dans le blog Yahoo

Mis à jour 05/09/2022 à 22h44 par f-leb

Catégories
Programmation , FPGA

Commentaires