Hallo! Ich will eine Alarmsteuerung entwerfen. Die Steuerung hat 5 Sensoren (3x Chemie Alarm,2x Feuer Alarm). Das ganze soll über einen Zustandsautomat gebaut werden. Im Prinzip ist das kein Problem, ich wollte das so machen: Ich habe 2 getrennte Blöcke. Dieser Block... current_state=next_state; always@(posedge clock) begin case(current_state) ... end ...bearbeitet mir den aktuellen Zustand. Der zweite Block hier, berechnet mir den Folgezustand und reagiert auf Änderungen der Sensoren. always@(sens_f1,sens_f2,sens_c1,sens_c2,sens_c3) begin case({sens_f1,sens_f2,sens_c1,sens_c2,sens_c3}) .. end Nun ist für die Aufgabe gefordert, dass je nach Alarm unterschiedliche Dinge passieren sollen (z.B. soll die Firmenleitung gerufen werden und evakuiert werden) das wird über 8 Leds angezeigt. Eine davon simuliert eine Sirene und blinkt in einem bestimmten Takt. Hier kommt auch mein Problem: Ich habe gehört dass man wenn man zwei Blöcke baut wie oben, die ja parallel synthetisiert werden, man in beiden nicht auf gleiche Variablen zugreifen kann. Ohne das, weiß ich aber nicht wie ich die Aufgabe lösen kann, denn ich wollte das blinken so lösen: Ich gehe in Block 1 in den entsprechenden Zustand. Dort setze ich die led Leiste erstmal, z.B. so: leds = 'b0010_1100 (was das jetzt bedeutet ist egal). Das blinken wollte ich mit einer xor Verknüpfung realisieren z.B. so: leds = leds ^ 'b0000_0001 (lässt Led 8 blinken), dafür habe ich einen timer gebaut. Wenn ich aber jetzt nach einem Takt wieder in den Zustand komme, überschreibt mir ja leds = 'b0010_1100 wieder meine gerade gesetzte 1 bei Led 8. Also hatte ich mir überlegt ich baue einen lock und zwar so: if(lock==0) leds='b0010_1100; else begin lock=1; timer_32=timer_32-1; if(timer_32==0) begin leds = leds ^ 'b0000_0001; timer_32=40000000; (40.000.000 da 40 MHz und ich alle 1 Sekunde umschalten will) end end Damit ich das so machen kann, müsste ich aber in Block 2 lock auf 0 setzen. Somit würde ich aber lock in beiden Blöcken verändern. Geht das? Oder knallts dann in der Synthese? Ich hoffe ihr seht hier durch! Ich wäre für Hilfe sehr dankbar!
Nein, das geht nicht, Signale koennen nur in genau einem Block geschrieben werden, wie du richtig geschrieben hast. Setze doch in deiner Steuerung ein Bit, ob die LED blinken soll oder nicht. In einem weiteren Prozess (oder Block, ich kenne Verilog nicht) kannst du dann die LED ansteuern auf Basis dieses bits.
Hallo Jan! Danke für deine Antwort! :) Aber genau das wollte ich ja mit lock machen. lock ist nur was internes und wird nicht nach außen geführt (reg lock). Ich wollte lock im Steuerblock immer auf 0 setzen und im jeweiligen Zustand dann später auf 1.
Ich meinte das so: led_blink wird nur im ersten Block gesetzt, die led nur im zweiten Block geschaltet. Die anderen, nicht blinkenden LED kannst du ja weiterhin direkt in Block1 ansteuern. Block1: led_blink <= 0 if error_condition led2_blink <= 1 Block2: if led2_blink = 1 if counter = 40Mio led2 = not led2
Martin wrote: ... > Hier kommt auch mein Problem: > Ich habe gehört dass man wenn man zwei Blöcke baut wie oben, die ja > parallel synthetisiert werden, man in beiden nicht auf gleiche Variablen > zugreifen kann. Ohne das, weiß ich aber nicht wie ich die Aufgabe lösen > kann, denn ich wollte das blinken so lösen: > Der Ansatz mit den 2 Blöcken für die State Machine ist ganz gut. Dann mit dem Lock wird es sehr verzwickt. Aus der State Machine hast du ja schon den leds Vektor, bei dem ein Bit Anzeigt das die eine LED blinken soll. Mein Vorschlag währe einen dritten always block zu kreieren der immer den Takt für das Blinken erzeugt, unabhängig von der State Machine. Dann nimmst du einen kombinatorischen Konstrukt:
1 | assign led_blink = blink_takt & leds[x]; |
Das x spezifiziert das Bit für die blinkende LED im leds Vektor. Der blink_takt kommt von dem dritten always Block mit dem Takt. Jedes mal wenn deine State Machine jetzt sagt die LED soll blinke, dann wird das Signal mit dem Takt UND-verknüpft und schon blinkt deine LED. Damit musst du dir keine Gedanken über irgendwelche Locks machen. Gruß, Günter
@Jan Ich glaube ich hab zu der Aufgabenstellung was ausgelassen. Im Prinzip weiß ich schon wenn ich in Block2 bin, dass geblinkt werden soll, da das implizit durch den jeweiligen Zustand vorgegeben ist. Somit brauche ich in Block 1 nicht mehr zu sagen dass geblinkt werden soll. Bei mir sah das bis jetzt so aus: Block1: lock=0; next_state=tue_irgendwas_und_blinke; Block2: tue_irgendwas_und_blinke: begin if(lock==0) begin lock=1; leds='b0010_1100; end if(lock==1) begin timer_32=timer_32-1; if(timer_32==0) begin leds=leds^'b0000_0001; timer_32=40000000; end end Aber im Prinzip kann man den lock ja ganz weglassen und nur den Timer überprüfen, also so: Block1: next_state=tue_irgendwas_und_blinke; Block2: leds[0:7]='b0010_110; //Geht das? if(timer_32==40000000) leds[8]=0; if (timer_32>0) timer_32=timer_32-1; if(timer==0) begin leds[8]=leds[8]^1; timer_32=40000000; end Dann fällt zwar der lock raus, aber es gibt das Problem, dass ich wieder nur in Block 2 timer_32 setzen kann und ich habe das gleiche Problem wie ich es mit lock hätte. (Oder übersehe ich was?) @Günter Mit deiner Lösung müsste es gehen. Also würde ich einen dritten Block machen, der so aussieht always@(posedge clock) begin if(timer_32==40000000) blink_takt=0; if (timer_32>0) timer_32=timer_32-1; if(timer==0) begin blink_takt=1; timer_32=40000000; end end Block 2 würde dann so aussehen: always@(posedge clock) next_state=current_state; begin case(...) tue_irgendwas_und_blinke: begin leds[0:7]='b0010_110; //Geht das? leds[8] = blink_takt; end end Das sollte doch gehen?!
Martin wrote: ... > > @Günter > Mit deiner Lösung müsste es gehen. > Also würde ich einen dritten Block machen, der so aussieht > > always@(posedge clock) > begin > if(timer_32==40000000) > blink_takt=0; > if (timer_32>0) > timer_32=timer_32-1; > if(timer==0) > begin > blink_takt=1; > timer_32=40000000; > end > end > Dein blink_takt wird hier nur für eine clock Periode aktive sein. Da wirst du nicht viel von der LED sehen. Besser währe vielleicht den blink_takt aus dem always heraus zu nehmen und folgendes zu machen:
1 | assign blink_takt = (timer_32 < 20000000); |
Wenn jetzt timer_32 kleiner 20000000 ist, dann ist der Vergleich wahr und damit blink_takt 1. Wenn es größer/gleich 20000000 dann falsch und blink_takt ist 0. Damit erhälst du einen symmetrischen blink_takt.
Hallo! Das stimmt, dort müsste bei mir statt blink_led=1, blink_led = ~ blink_led stehen oder ich mach es so wie du. Jetzt verbleibt für mich aber noch ein Problem. Ich brauche noch einen Alarmnachlaufzeit. Auch wenn die Sensoren z.B. kein Feuer mehr melden, soll der Alarm 3 Minuten nachlaufen. Wie ich einen Timer für 3 Minuten mache ist kein Problem, ich mache zum 1s Timer einfach noch eine der bis 180 zählt. Aber wie kann ich den Timer überhaupt von außen zurücksetzen? Ich wollte das über ein zusätzliches Signal machen, z.b. timer_reset. Aber ich stosse wieder auf das gleiche Prolbem wie bei den LEDs: Wie kann ich timer_reset auslösen und dann wieder zurücksetzen? Das müsste ich ja im Steuerblock machen, der ist aber nur ereignisgesteuert (Ausschnit vom Steuerblock): always@(sens_f1, sens_f2, sens_c1, sens_c2, sens_c3) begin case({sens_f1,sens_f2,sens_c1,sens_c2,sens_c3}) ..... 'b1?1??: begin //beide Feuersensoren sind aktiv if(sens_f2) begin next_state=f2_chem_s3; end //nur ein Feuersensor ist aktiv else begin activate_sprinkler=1; next_state=f1_chem_s3; end end .... 'b00111: begin next_state=c3_s3; end .... endcase end Ich müsste ja aber dort irgendwo mein timer_reset Signal triggern (Ich kan n es zwar auf 1 setzen, ich bekomme es ja nicht mehr auf 0) Im Prinzip immer genau dann, wenn ich von einem Zustand mit Alarmsignal, in einen Zustand ohne Alarmsignal wechsel, dazu müsste ich ja nur current_state mit next_state vergleichen. Ich brauche dann auch 2 Timer für 3 Minuten, da einmal der Chemie- und einmal der Feueralarm nachlaufen kann.
Martin wrote: > Hallo! > > Das stimmt, dort müsste bei mir statt blink_led=1, blink_led = ~ > blink_led stehen oder ich mach es so wie du. > > Jetzt verbleibt für mich aber noch ein Problem. Ich brauche noch einen > Alarmnachlaufzeit. Auch wenn die Sensoren z.B. kein Feuer mehr melden, > soll der Alarm 3 Minuten nachlaufen. Wie ich einen Timer für 3 Minuten > mache ist kein Problem, ich mache zum 1s Timer einfach noch eine der bis > 180 zählt. > Aber wie kann ich den Timer überhaupt von außen zurücksetzen? > Ich wollte das über ein zusätzliches Signal machen, z.b. timer_reset. > Aber ich stosse wieder auf das gleiche Prolbem wie bei den LEDs: Du solltest die Steuerung von den LEDs, speziell der blinkenden nicht mit der State Machine verknüpfen. Die State Machine sollte dir nur ein Signal geben, dass der Alarm anliegt. Basierend auf diesem Signal kannst du jetzt extra Logik hinzufügen um die LED blinken zu lassen. Jedes mal wenn du das Blinken mit in die State Machine zurück bringst wird diese komplizierter. ... > > Ich müsste ja aber dort irgendwo mein timer_reset Signal triggern (Ich > kan n es zwar auf 1 setzen, ich bekomme es ja nicht mehr auf 0) Im > Prinzip immer genau dann, wenn ich von einem Zustand mit Alarmsignal, in > einen Zustand ohne Alarmsignal wechsel, dazu müsste ich ja nur > current_state mit next_state vergleichen. Ich brauche dann auch 2 Timer > für 3 Minuten, da einmal der Chemie- und einmal der Feueralarm > nachlaufen kann. Die State Machine signalisiert nur das der Alarm anliegt. Der Nachlauftimer wird von dem aktiven Alarm gehalten und hat einen aktiven Ausgang. Der Ausgang wird jetzt mit deinem Blink-Takt-Geber UND-Verknüpft. Sollte der Alarm abfallen, läuft der Nachlauftimer los und zählt die 3 Minuten runter. In der ganzen Zeit ist der Ausgang immer noch aktiv. Da du scheinbar mehrere Nachlauftimer benötigst, macht es vielleicht Sinn ein extra Modul davon zu machen und es entsprechend oft zu instanzieren.
Hallo! Ersteinmal Danke für deine Geduld und Hilfe! Entweder mir ist nicht ganz klar wie du das meinst oder ich habe einfach zu wenig Wissen in Sachen Verilog oder ich stelle mich einfach furchtbar dämlich an. Wenn ich also in einen Zustand gehe, wo es brennt, so führe ich folgende Anweisung im Zustand aus: melde_feuer=1; Wenn ich dann in einen Zustand wechsel, wo es nicht brennt, wir daraus: melde_feuer=0; Die Erkennung für die Negative Flanke von melde_feuer: always@(posedge melde_feuer, negedge melde_feuer) begin //negedge melde_feuer if (melde_feuer==0) nachlauf_feuer=1; //posedge melde_feuer if (melde_feuer==1) nachlauf_feuer=0; end Der Block für den Timer, das schalten der Ausgänge: alway@(clock) begin if(timer_init) begin timer_32=40000000; //für 40 MHz half_sec_blink=0; full_sec_blink=0; timer_init=0; end else begin if(timer_32>0) begin timer_32=timer_32-1; if(timer_32==20000000) //Hälfte der Zeit half_sec_blink=~half_sec_blink; end if(timer_32==0) begin half_sec_blink=~half_sec_blink; full_sec_blink=~full_sec_blink; timer_32=40000000; //Problemstelle: if(nachlauf_feuer==0) timer_8_feuer=180; if(nachlauf_feuer==1) begin if(timer_8_feuer==0) nachlauf_feuer=0; //Geht so ja nicht! else timer_8_feuer=timer_8_feuer-1; end end //Ausgänge schalten: //Sobald nachlauf_feuer==0 und melde_feuer=0 ist Ausgang Null //ansonsten blink Ausgang im Sekundentakt ausgang_feuer_sirene=(nachlauf_feuer||melde_feuer)&blink_takt_sekunde; end end Das Problem (Problemstelle ist gekennzeichnet): Hier schalte ich ja aber nachlauf_feuer wieder in 2 Blöcken. Also müsste es doch aber so hier gehen: (Ich habe nur das Gefühl es geht irgendwie einfacher und ich sehs einfach nicht) Die Erkennung für die Negative Flanke von melde_feuer: always@(posedge restart_timer,posedge melde_feuer, negedge melde_feuer) begin if (restart_timer_8_feuer==1) nachlauf_feuer=0; if (melde_feuer==1) nachlauf_feuer=1; if (melde_feuer==0) nachlauf_feuer=0; end Der Block für den Timer, das schalten der Ausgänge: alway@(clock) begin if(timer_init) begin timer_32=40000000; //für 40 MHz half_sec_blink=0; full_sec_blink=0; timer_init=0; end else begin if(timer_32>0) begin timer_32=timer_32-1; if(timer_32==20000000) //Hälfte der Zeit half_sec_blink=~half_sec_blink; end if(timer_32==0) begin half_sec_blink=~half_sec_blink; full_sec_blink=~full_sec_blink; timer_32=40000000; //Problemstelle: if(nachlauf_feuer==0) begin timer_8_feuer=180; restart_timer_8_feuer=0; end if(nachlauf_feuer==1) begin if(timer_8_feuer==0) restart_timer_8_feuer=1; else timer_8_feuer=timer_8_feuer-1; end end //Ausgänge schalten: //Sobald nachlauf_feuer==0 und melde_feuer=0 ist Ausgang Null //ansonsten blink Ausgang im Sekundentakt ausgang_feuer_sirene=(nachlauf_feuer||melde_feuer)&blink_takt_sekunde; end end
Martin wrote: ... > > Wenn ich also in einen Zustand gehe, wo es brennt, so führe ich folgende > Anweisung im Zustand aus: > > melde_feuer=1; > > Wenn ich dann in einen Zustand wechsel, wo es nicht brennt, wir daraus: > > melde_feuer=0; > > Die Erkennung für die Negative Flanke von melde_feuer: > > always@(posedge melde_feuer, negedge melde_feuer) Ich weiß nicht ob du das in synthesierbarer Logik machen kannst. Immer wenn du posedge oder negedge nimmst dann wird in der Logik ein Register genommen. Der Clock-Eingang eines Registers sollte aber immer mit dem synchronen Takt belegt werden. Was du hier also kreierst ist ein Latch, aber ich glaube nicht das es funktioniert den auf beide Flanken zu triggern. Schau dir den Synthesebericht bezüglich Warnungen mit den Signalen mal an. > begin > //negedge melde_feuer > if (melde_feuer==0) nachlauf_feuer=1; > //posedge melde_feuer > if (melde_feuer==1) nachlauf_feuer=0; > end Meiner Ansicht nach brauchst du das auch gar nicht. Mit melde_feuer hast du ja schon ein signal das den Alarm signalisiert. Das Signal nimmst du jetzt um den Nachlauftimer zu laden. Immer wenn melde_feuer aktiv ist, wird der Nachlauftimer mit den max Wert geladen. Wenn melde_feuer inaktive wird, fängt der Nachlauftimer an runter zu zählen. Das ganze sieht ungefähr so aus. Ziehe den timer_8_feuer aus den timer_32 heraus und packe ihn in einen neuen always block:
1 | always@(posedge clock) |
2 | if(melde_feuer) |
3 | timer_8_feuer = 180; |
4 | else
|
5 | if(timer_32 == 0 && timer_8_feuer > 0) |
6 | timer_8_feuer = timer_8_feuer - 1; |
Das eigentliche Signal wird jetzt aus kombinatorischer Logik gebildet:
1 | assign nachlauf_feuer = (timer_8_feuer > 0); |
2 | assign ausgang_feuer_sirene = machlauf_feuer & blink_takt_sekunde; |
Wenn timer_8_feuer > 0 ist dann ist das Ergebnis 1 und wird nachlauf_feuer zugewiesen. Wenn er 0 ist dann ist der Vergleich 0 und wird nachlauf_feuer zugewiesen. Um die LED blinken zu lassen wird das nachlauf_feuer mit dem blink_takt_sekunde UND verknüpft. Versuche sequentielle Blöcke, also always-Blöcke mit @(posedge clock) nur eine Funktion ausführen zu lassen. Dann verbinde solche sequentielle Blöcke mit kombinatorischer Logik.
@Günter So hats letzendlich funktioniert. :) Vielen Dank für deine Hilfe! Gruß, Martin
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.