Bonjour,
Ci-joint le code VHDL d'un correcteur PID en VHDL.
Il est plus ou moins fonctionnelle, je suis ouvert à tout critique afin de l'améliorer.
Code VHDL : 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
127
128
129
130
131
132
133
134
135
136
137
138 --###################################### --# Correcteur PID V.2.0 # --###################################### library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use IEEE.std_logic_signed.all; entity PID is generic ( Kp : integer range 0 to 32767:=1; Ki : integer range 0 to 32767:=1; Kd : integer range 0 to 32767:=1 ); port ( horloge_50Mhz, reset : in std_logic; erreur : in std_logic_vector(31 downto 0 ); -- consigne - erreure => comprise entre -32768 to 32767 consigne_fin : out std_logic:='0'; -- si consigne atteinte passe à 1 commande_position : out std_logic_vector(31 downto 0 ) -- consigne position comprise entre -32768 to 32767 ); end entity; architecture arch_PID of PID is constant precision : integer :=4; constant ecretage_seuille : integer := 500; --7000 commande max possible ( sécuritée) constant valeur_saturation : integer := 500; --6999 si commande max atteinte => valeur max de commande signal commande : integer range -2147483647 to 2147483647:=0; signal commande_distance : integer range -2147483647 to 2147483647:=0; signal ecart : integer range -2147483647 to 2147483647:=0; signal Sclk_temp_2 : std_logic:='1'; signal cpt : integer range -2147483647 to 2147483647:=0; signal cpt_int : integer range -2147483647 to 2147483647:=0; signal ecart_precedent : integer range -2147483647 to 2147483647:=0; begin calcul : process(Sclk_temp_2,reset) begin if rising_edge(Sclk_temp_2) then if reset = '0' then commande <= 0; else commande <= (( (ecart * Kp) + (cpt_int * Ki)+ ((ecart - ecart_precedent) * Kd) ))/4; --loi de commande PID end if; end if; end process; integrateur : process(Sclk_temp_2) begin if rising_edge(Sclk_temp_2) then if(ecart < precision and ecart > - precision) then cpt <= 0; else --cpt <= cpt + ecart; cpt_int <= cpt_int + ecart; end if; end if; end process; derivateur : process(Sclk_temp_2) begin if rising_edge(Sclk_temp_2) then ecart_precedent <= ecart; end if; end process; -- limiteur_int : process(cpt) -- variable cpt_temp : integer; -- begin -- cpt_temp := cpt; -- -- if cpt > 500 then -- cpt_temp := 500; -- end if; -- if cpt < -500 then -- cpt_temp := -500; -- end if; -- cpt_int <= cpt_temp; -- end process; commande_1 : process(Sclk_temp_2) variable tempo : integer range 0 to 30000000:=0; begin if rising_edge(Sclk_temp_2) then ---- Consigne atteinte ---- if ecart < precision and ecart > - precision then if tempo > 20000000 then commande_distance <= 0; consigne_fin <= '1'; else tempo := tempo + 1 ; end if; -- Ecretage + ---- elsif (commande) > ecretage_seuille then commande_distance <= valeur_saturation; consigne_fin <= '0'; tempo := 0 ; -- Ecretage - ---- elsif (commande) < -ecretage_seuille then commande_distance <=- valeur_saturation; consigne_fin <= '0'; tempo := 0 ; -- Regulation ---- else commande_distance <= commande ; consigne_fin <= '0'; tempo := 0 ; end if; end if; end process; horloge_2 : process(horloge_50Mhz) -- compteur pour l'integrateur et le derivateur variable cpt_2 : natural range 0 to 400000; --30 begin if rising_edge(horloge_50Mhz) then cpt_2 := cpt_2 +1; if (cpt_2=0)then Sclk_temp_2<=not(Sclk_temp_2); end if; end if; end process horloge_2; ecart <= to_integer(signed(erreur)); commande_position <= std_logic_vector(to_signed(commande_distance ,commande_position'length)); end arch_PID;
Partager