Guten Morgen liebe Mikrocontroller,
ich bin dabei einen Ultraschallsensor (HC-SR04) mit Hilfe eines FPGA's
anzusteuern. Ich habe in VHDL ein periodisches Signal mit einer
Periodendauer von 100 ms und einer Pulsbreite von 10 us erzeugt um den
Sensor zu triggern. Mit einem Oszi konnte ich dann direkt am
Echo-Ausgang das Signal abgreifen und mir die Pulsbreite des
laufzeitverzögerten Signals anschauen und mit Hilfe der Formel
(Pulsbreite in us / 58 )die Distanz in cm ausrechnen.
Jetzt würde ich gerne das Echosignal als Input für den FPGA nehmen um
damit die Distanz von diesem berechnen lassen und anschließend das
Ergebnis auf der 7 Segment Anzeige ausgeben.
Um dies zu bewerkstelligen, würde ich einen Zähler, beispielsweise als
Integer, bauen, der, sobald der Echo-Eingang auf High switched, anfängt
die aufsteigenden Taktflanken meines 50 MHz Taktsignals zu zählen und
bei LOW-Switch wieder aufhört.
Meine Frage: Ginge es so, wie ich es beschrieben habe und falls ja, ob
ich auch mit arithmetischen Operationen in VHDL rechnen kann?
Ich würde nämlich dann den Wert meine Zählers durch einen konstanten
Integer mit dem Wert 50.000.000 teilen um somit die Pulsbreite in
Sekunden zu bekommen. Das Ganze könnte ich dann nochmal durch 1000
teilen, um die ms zu erhalten.
Oder müsste ich das Ganze statt der arithmetischen Operation mit einem
weiteren Zähler realisieren?
Wäre um Rat sehr dankbar,
viele Grüße,
pico
pico schrieb:> Meine Frage: Ginge es so, wie ich es beschrieben habe
Ja.
> und falls ja, ob> ich auch mit arithmetischen Operationen in VHDL rechnen kann?
Ja (abgesehen von der Division, die doch recht aufwendig ist)
ABER:
> Ich würde nämlich dann den Wert meine Zählers durch einen konstanten> Integer mit dem Wert 50.000.000 teilen um somit die Pulsbreite in> Sekunden zu bekommen. Das Ganze könnte ich dann nochmal durch 1000> teilen, um die ms zu erhalten.
Diese ganze Teilerei kannst du dir durch Nachdenken KOMPLETT sparen!
Und wie? Überleg dir, welche Zeit der Schall für einen cm braucht. Und
jetzt lass einen Zähler mit der passenden Frequenz laufen. Wenn du
diesen Zähler mit dem Startimpuls zurücksetzt und dann durchlaufen
lässt, hast du, wenn dein Schallimpuls zurückkommt, den Zählerstand
schon mal in cm im Zählerregister stehen. Das wär doch was, oder?
BTW:
> sobald der Echo-Eingang auf High switched
Ein guter deutscher Echo-Eingang schaltet (oder besser er /wird
geschaltet/, denn ein Eingang ist passiv). Warum nimmst du unnötig
Anglizismen? Wenn das deutsche Wort für "schwitched" so unglaublich
unsäglichlangwäredassessichlohnt, dann dürftest du gern auch das
passende englische Wort nehmen. Aber so hört sich das nur billig und
populistisch an...
Bei 20°C breitet sich der Schall durch das Medium Luft mit 343 m/s aus.
Dann würde der Schall für 1. Zentimeter Weg, 29,15 us benötigen. Da mich
aber das Reflektierte Signal interessiert, welches ja den selben Weg
wieder zurück legen muss, ergibt sich also aus einem ABSTAND zum Objekt
pro Zentimeter 58,3 also 58 us.
Nun müsste ich also einen Zähler bauen, der jede aktive Taktflanke
meines 50 MHz Signals bis 2900 zählt.
Denn wenn 50.000.000 Takte = 1 Sekunde beträgt, betragen 58 us 2900
Takte.
Sehe ich das so richtig?
Vielen Dank
pico schrieb:> Nun müsste ich also einen Zähler bauen, der jede aktive Taktflanke> meines 50 MHz Signals bis 2900 zählt.> Denn wenn 50.000.000 Takte = 1 Sekunde beträgt, betragen 58 us 2900> Takte.>> Sehe ich das so richtig?
Ja, ist aber ein wenig umständlich berechnet... ;-)
Ich würde einfach aus den 58,3us eine Frequenz errechnen und bekäme
17152 Hz. Damit muss also ein Vorteiler mit 50MHz/17152Hz = 2915 her.
Der erzeugt dann quasi einen "Zentimer-Impuls".
> pro Zentimeter 58,3 also 58 us.
Warum in so früh schon ungenau werden?
Ein kleines Problem habe ich noch. Und zwar benötigt der HC-SR04 eine
Betriebsspannung von 5 V. Meine Eingänge am FPGA Board vertragen laut
Betriebsanleitung aber nur 3.3 V. Womit oder wie kann ich am besten die
Spannung auf max. 3.3 V verkleinern? Mit einer Z-Diode, oder gäbe es
noch einen einfacheren Weg oder ein fertiges Bauteil als Pmod-Connector,
welches ich zwischen dem Pmod-Eingang und der 5 V Spannung
zwischenintegrieren kann?
Den richtigen Takt konnte ich erzeugen. Diesen habe ich mir auch mit
einem Logik-Analysator und dem Oszi angeschaut. Wenn ich nun das
Echosignal in den Input vom FPGA Board mit der Pulsbreite x einspeise,
steht auf der 7 Segmentanzeige nur der Wert, welcher unter "when others"
steht.
Nun habe ich mir eine Testbench erstellt und habe für die clk_periode 20
ns (50 MHz) und für das echo_in <= '0', '1' after 100 ms, '0' after 102
ms, '1' after 200 ms, '0' after 208 ms; vorgegeben.
Im ISIM fiel mir auf, das ab 100 ms, also ab dem Zeitpunkt, als echo_in
das erste mal auf 1 schaltet, meine Werte für die DIG_0 Anzeige von 1
bis 9 einmal komplett hintereinander ausgegeben wurden. Danach trifft
der "when others" Fall ein und blieb bei jeder neuen Periode ebenfalls
auf "when others".
Wie bekomme ich das hin, dass ich nur den Wert bekomme, der auch der
distance zugeordnet ist? Ich habe versucht am Ende des Prozesses die
distance wieder zurück zusetzen, jedoch gab es da immer einen
Synthetisierungsfehler.
Den Code habe ich mal angehangen:
1
libraryIEEE;
2
useIEEE.STD_LOGIC_1164.ALL;
3
useIEEE.numeric_std.all;
4
5
entityUltraschallis
6
Port(clk:inSTD_LOGIC;
7
-- reset : in STD_LOGIC;
8
echo_in:inSTD_LOGIC;
9
DIG_0:outSTD_LOGIC_VECTOR(6downto0);
10
ultra_takt:outSTD_LOGIC);
11
endUltraschall;
12
13
architectureBehavioralofUltraschallis
14
signalcounter:naturalrange4999999downto0;-- Zähler für die Periodendauer von 100 ms
15
signalcounter2:naturalrange2914downto0;-- Zähler für die Pulsbreite von 58 us, welche 1 Zentimeter Abstand beschreibt.
16
signaldistance:integer:=0;
17
18
begin
19
clock_gen:process(clk)
20
begin
21
if(clk'eventandclk='1')then
22
if(counter=4999999)then
23
counter<=0;
24
else
25
counter<=counter+1;
26
endif;
27
28
if(counter<500)then-- 500 entspricht 10 us
29
ultra_takt<='1';-- Asynchroner Takt mit Tp = 100 ms und Pulsweite von 10 us
30
else
31
ultra_takt<='0';
32
endif;
33
endif;
34
endprocess;
35
36
echo:process(clk)
37
begin
38
if(clk'eventandclk='1')then
39
if(echo_in='1')then
40
if(counter2=2914)then
41
counter2<=0;
42
distance<=distance+1;
43
else
44
counter2<=counter2+1;
45
endif;
46
endif;
47
endif;
48
endprocess;
49
50
segment:process(clk,distance)
51
begin
52
casedistanceis
53
when0=>DIG_0<="1111110";-- 0
54
when1=>DIG_0<="1111001";-- 1
55
when2=>DIG_0<="0010010";-- 2
56
when3=>DIG_0<="0000110";-- 3
57
when4=>DIG_0<="1001100";-- 4
58
when5=>DIG_0<="0100100";-- 5
59
when6=>DIG_0<="0100000";-- 6
60
when7=>DIG_0<="0001111";-- 7
61
when8=>DIG_0<="0000000";-- 8
62
when9=>DIG_0<="0001100";-- 9
63
--when others => DIG_0 <= "1111110"; -- -
64
whenothers=>DIG_0<="0000000";-- -
65
endcase;
66
endprocess;
67
endBehavioral;
Vielleicht kann mir ja einer einen Tipp geben, woran es liegen, bzw. wie
ich den Fehler beheben könnte.
Vielen Dank,
Ja, das stimmt.
Wenn ich nun distance vor dem Prozess auf 0 setze,
1
distance<=0;
2
echo:process(clk)
3
begin
4
if(clk'eventandclk='1')then
5
if(echo_in='1')then
6
if(counter2=2914)then
7
counter2<=0;
8
distance<=distance+1;
9
else
10
counter2<=counter2+1;
11
endif;
12
endif;
13
endif;
14
endprocess;
kommt folgende Fehlermeldung: "Line 80. Signal distance has a multi
source.
"
Wenn ich die distance innerhalb des Pozesses zurücksetze, würde ich doch
bei jedem Taktflankenwechsel distance zurück setzen, oder? Zumindest
kommt dann folgende Fehlermeldung:
1
echo:process(clk)
2
begin
3
distance<=0;
4
if(clk'eventandclk='1')then
5
if(echo_in='1')then
6
if(counter2=2914)then
7
counter2<=0;
8
distance<=distance+1;
9
else
10
counter2<=counter2+1;
11
endif;
12
endif;
13
endif;
14
endprocess;
"line 74: Signal distance cannot be synthesized, bad synchronous
description. The description style you are using to describe a
synchronous element (register, memory, etc.) is not supported in the
current software release."
pico schrieb:> signal counter: natural range 4999999 downto 0;
Wofür soll das downto gut sein?
Mach da mal besser einen aufsteigenden Wertebereich draus, ich weiß
nicht, ob das was hilft, aber "üblicher" ist es auf jeden Fall...
nun kann ein FF nur mit Takt laufen, also kann "distance"
nur im getakteten Teil eines Prozesses zugewiesen werden.
Was Fehlt ist eine Bedingung für das zurücksetzen von
"distance" also in etwa sowas:
> Was Fehlt ist eine Bedingung für das zurücksetzen von> "distance" also in etwa sowas:
1
if(clk'eventandclk='1')then
2
if(echo_in='1')then
3
if(counter2=2914)then
4
counter2<=0;
5
distance<=distance+1;
6
elsif(hiereinSignalalsBedingung='1')
7
distance<=0;
8
....
oder so:
1
if(clk'eventandclk='1')then
2
if(echo_in='1')then
3
if(counter2=2914)then
4
counter2<=0;
5
distance<=distance+1;
6
endif;
7
else
8
distance<=0;
9
10
...
d. h. immer wenn echo_in nicht '1' ist, wird distance auf '0' gesetzt.
Uebrigens brauchst du im letzten Process in der sensitivliste clk nicht
angeben, da dieses signal im process gar nicht auftauch.
der
Böse, böse...
Ich behaupte einfach mal frech, die Simulation passt da sicher nicht zur
Realität. In der Simulation zählt der Zähler distance fröhlich, in der
Realität ist der immer 0...
Das Problem: die Realität schert sich nicht um die Sensitivliste. Der
Prozess wird also "dauernd" ausgeführt. Und nur genau bei einer
Taktflanke (Dauer=0) ändert sich die distance möglicherweise auf 1, um
sofort wieder auf 0 zurückgesetzt zu werden. Der Zähler ist also
abgesehen von unendlich kurzen Zeitabschnitten immer 0.
Die Lösung: das "distance <= 0;" muss woanders hin.
bko schrieb:> das Signal "distance" wird wegen dieser Zeilen zu Flipflops> synthetisiert:
Oder eher: wegen dieser Zeile gleich komplett wegoptimiert...
distance <= 0;
So, jetzt funktioniert es und die Werte in cm werden auf der 7
Segmentanzeige angezeigt ;-) Habe einen distance_buffer eingefügt, der
meine Distanz zwischenspeichert. Und das Zurücksetzen der distance ist
nun Abhängig von dem low Pegel meines echo_in's .
pico schrieb:> Und das Zurücksetzen der distance ist nun Abhängig von> dem low Pegel meines echo_in's .
Ich hätte da eine Flankenerkennung gebastelt, und mit der Flanke den
Zählerstand übernommen. Den Zähler zurücksetzen würde ich mit dem
Aktivieren des Triggereingangs.