Hallo zusammen, ich möchte gerne von einer gabellichtschranke pulse zählen an einem Port z.B. Port D PD7 . Ich habe mir schon mal die Caounter/timer funktionen meines atmega 128 angeschaut werde da aber nicht richtig schlau draus gibts da noch eine einfachere möglichkeit zum Zählen von Zuständen. Ich denke mal das dürfte doch so sein als wenn ich eine taste betätige und da könnte ich ja zählen wie oft diese taste gedrückt wurde oder? bin über jede Hilfe glücklich. MfG
Am elegantesten ist es, wenn Du einen Hardware-Timer zählen lässt. Das kostet dann keine CPU-Zeit und geschieht im Hintergrund. Die meisten Mikrocontroller haben Eingänge, die als Clock-Source für einen Timer dienen können. Du musst dann nur noch periodisch die Zählvariable auslesen oder Dir beim gewünschten Zählerstand einen Interrupt generieren lassen.
Gast
#2085919
Jörg Roesberg schrieb: > Ich denke mal das dürfte doch so sein als wenn ich eine taste betätige > und da könnte ich ja zählen wie oft diese taste gedrückt wurde oder? Ja, eigentlich ist es das gleiche. Aber wo ist denn dein Problem? Du mußt doch eigentlich "nur" den Pin abfragen, ob sich der Zustand geändert hat. Wenn der neu eingelesene Zustand anders ist, als der alte, dann wurde gedrückt/hat die Lichtschranke einen Impuls gegeben. Das kannst du "manuell" machen (polling) oder Mit einem Timer. Bei der Timer-Methode kannst du dann noch unterscheiden, ob er die Zeit zwischen zwei Impulsen "stoppen" soll, oder ob er bei jedem Impuls einen hochzählen soll (Capture). Beschreib dein Problem mal etwas genauer. Aber eigentlich ist das nicht so schwer :)
Gast
#2085921
man kann das ganze ja auch zyklisch machen - die Länge des Zyklus hängt dann eben vom restlichen code ab, kommt noch viel (anderer) code, dauert es eben etwas länger. Eleganter ist es aber in der Tat mit einem Timer!
Danke schon mal für eure Antworten. Das ich das mit einem timer machen kann hab ich schon raus bekommen aber nur wie?? Also mein problem ist ich weis nicht wie ich anfangen soll das in C zu programmieren. Mit timern hab ich so quasi gar keine erfahrung. Ich habe in das Daten blatt von meinem atmeg128 reingeschaut und mir die register vom timer/counter angeschaut und raff das ned . gruß
hier mal ein versuch von mir bekomme aber folgende error meldung in AVR Studio gcc plug-in: Error: Object file not found on expected location E:.......default\LCDtest.elf #include <avr/io.h> #include <util/delay.h> #include "lcd-routines.h" // Header-File aus dem AVR-GCC-Tutorial // Header-File geändert (LCD sitzt an Port A) int main(void) { uint8_t bPortD; bPortD = PIND; int counter1=0; // deklaration Variable lcd_init(); // LCD Initialisierung // PORT D Bit 7 als Input while(1) { // Endlos-Schleife beginnt while(!(DDRD &= ~(1<<DDC7))){} ; // so lange PD7 Low --> nix tun (warten auf High) while(DDRD &= ~(1<<DDC7)){}; // so lange PD7 High --> nix tun (warten auf Low) while (!(DDRD &= ~(1<<DDC7))); // so lange PD7 Low --> counter1 jede ms um 1 hochzählen { _delay_ms(1); counter1++; } lcd_clear(); lcd_setcursor(0,1); // Gehe zu Pos. XY lcd_string("Drehzahl" ); // Ausgabe Maske lcd_setcursor(0,2); // Gehe zu Pos. XY lcd_string("U/min:" ); // Ausgabe Maske // lcd_setcursor(8,2); // Gehe an POS. XY // char Buffer [20]; // itoa( counter1, Buffer, 10 ); // Umwandlung // lcd_string( Buffer ); // Ausgabe der Drehzahl / Zeit counter1=0; // Zähler zurück auf 0 setzen } // Ende Endlos-Schleife }
Gast
#2086209
Da müssen vorher schon Fehlermeldungen schienen sein. Z.b. das er DDC7 nicht kennt.
Gast
#2086214
Völlig murks:
while(!(DDRD &= ~(1<<DDC7))){} ; // so lange PD7 Low --> nix
tun (warten auf High)
while(DDRD &= ~(1<<DDC7)){}; // so lange PD7 High --> nix
tun (warten auf Low)
while (!(DDRD &= ~(1<<DDC7))); // so lange PD7 Low -->
counter1 jede ms um 1 hochzählen
Pins liest Du über das PIND Register ein. Die Richtung, in deinem Fall
Eingang schaltet man über DDRD. Also:
DDRD &= ~(1<<PD7);
und dann:
while(!(PIND & (1<<PD7))){} ;
while( (PIND & (1<<PD7))){} ;
while(!(PIND & (1<<PD7))){} ;
ABER! Auch das ist Murks! Mach es mit dem Timer. Beispiele gibt es hier
im Tutorial.
Jörg Roesberg schrieb: Wie schon gesagt: Da muss es vorher noch andere Fehler gegeben haben Aber .... > while(1) { // Endlos-Schleife beginnt > > > while(!(DDRD &= ~(1<<DDC7))){} ; // so lange PD7 Low --> nix > tun (warten auf High) > ... lies bitte im AVR-GCC-Tutorial nach, wie man einen Eingangspin abfrägt. Da gibt es ein extra Kapitel dafür. Das ist das erste, bei dem es mit der AVR Programmierung richtig zur Sache geht und von dort weg folgen noch viele weitere. Mit anderen WOrten: Einen Pin abfragen zu können sind die absoluten Grundlagen. Ehe du die nicht sicher beherrscht hat es keinen Sinn in irgendeiner Form weiter zu machen.
Gast
#2086436
noch eine Möglichkeit: für einen Pin "Interrupt on change" setzen, der Interrupt setzt bei der pos/neg Flanke einen Zähler hoch, den main dann abfragen kann. Die Methode, einen Hardware-Timer zählen zu lassen, ist aber wesentlich eleganter.
Karl Heinz Buchegger schrieb: > Jörg Roesberg schrieb: > > Wie schon gesagt: Da muss es vorher noch andere Fehler gegeben haben > > Aber .... >> while(1) { // Endlos-Schleife beginnt >> >> >> while(!(DDRD &= ~(1<<DDC7))){} ; // so lange PD7 Low --> nix >> tun (warten auf High) >> > > > ... lies bitte im AVR-GCC-Tutorial nach, wie man einen Eingangspin > abfrägt. > Da gibt es ein extra Kapitel dafür. Das ist das erste, bei dem es mit > der AVR Programmierung richtig zur Sache geht und von dort weg folgen > noch viele weitere. Mit anderen WOrten: Einen Pin abfragen zu können > sind die absoluten Grundlagen. Ehe du die nicht sicher beherrscht hat es > keinen Sinn in irgendeiner Form weiter zu machen. hatte mich mit den eingangs ports verschrieben. So ich habs jetzt mal als timer geschrieben aber irgend wie kommt da nix. die periode ist 300ms f= 3Hz
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
Mach es dir zur Regel: Der grundsätzliche Aufbau eines Programmes sieht so aus
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
Die Richtung der Portpins einstellen, den Timer konfigurieren .... das alles fällt unter "Initialisieren und Einstellen der beteiligten Hardware" und hat daher als solches in der Hauptschleife nichts verloren, weil es nur EINMAL gemacht wird. Nämlich wenn das Programm startet. Damit bleibt vom Anfang deiner Hauptschleife übrig
1 | |
2 | |
3 | |
4 | |
5 | |
und wie erwartest du da jetzt, dass du jemals etwas anderes als 0 bekommen wirst (ok, ab und zu vielleicht einmal eine 1, wenn der Timer genau zwischen der Zuweisung der 0 und dem Abfragen von TCNT2 erhöht wird, was ziemlich unwahrscheinlich sein wird)?
Hatte dein Compiler dazu denn gar nichts zu sagen?
1 | |
Wie quetscht du den einen String das aus 17 Zeichen besteht in ein Array mit leidiglich 5 Elementen? Lass doch den Compiler das Array für dich dimensionieren!
1 | |
Karl Heinz Buchegger schrieb: > Damit bleibt vom Anfang deiner Hauptschleife übrig > > while( 1 ) { > TCNT2=0; > counter1= TCNT2; > > ... > > und wie erwartest du da jetzt, dass du jemals etwas anderes als 0 > bekommen wirst (ok, ab und zu vielleicht einmal eine 1, wenn der Timer > genau zwischen der Zuweisung der 0 und dem Abfragen von TCNT2 erhöht > wird, was ziemlich unwahrscheinlich sein wird)? so ich hab jetzt alle geändert aber das stimmt das der jetzt gar nicht zählt. Haste da einen tip wie ich das jetzt realisieren kann das der auch noch zählt. Das wäre super gut ich komm da einfach nicht weiter. Gruß
Jörg Roesberg schrieb: > Haste da einen tip wie ich das jetzt realisieren kann das der auch noch > zählt. Wenn du die Pulsfrequenz einer Lichtquelle bestimmen sollst und du machst das so: * Uhr starten * und gleich danach sofort auf die Uhr sehen dann wirst du wohl kaum irgendein anderes Ergebnis als 0 heraus bekommen. Du musst schon vom nach dem 0-Setzen des Timers eine gewisse Zeit verstreichen lassen, ehe du nachsiehst wieviele Pulse in dieser Zeiteinheit gezählt wurden. > Das wäre super gut ich komm da einfach nicht weiter. Logisch überlegen, dann geht das schon. Schon alleine die Einheit dessen, was du messen willst, U/min, sollte dir eigentlich sagen, dass da irgendwie die Zeit mit hineinkommen muss. Wie würdest du es denn händisch machen, wenn alles was du hast * eine Markierung an der zu messenden Welle * so ein Druckdingens ist, mit dem du jedesmal wenn die Markierung an einer bestimmten Position 1 ist, einen Zähler um 1 hochzählt (so ein Ding haben die Leute, wenn sie Personen zählen sollen. Hast du sicher schon gesehen. Dein Timer ist im Grunde auch nichts anderes) * eine Uhr ist. Wie misst du mit diesem 3 Zutaten eine Drehzahl?
Das ist mir so weit alles klar nur wie schreibe ich das jetzt in "C" ? mach ich das ganze mit ner or schleife ? ich bin echt mega verzweifelt und komm einfach nicht weiter. das ist jetzt erst mal die Zeit und die frequenz von dem takt. 300ms f= 3Hz gruß
Gast
#2097132
Hi Nun, die Frequenz allein ist nicht entscheidend. Normalerweise ist bei 300 mSek. Zeit genug, einen Eingang zu Pollen, aber es kommt auf die Signaldauer an. Angenommen, du hast auf deiner Scheibe nur ein Loch von 1/100 Durchmesser des Umfanges deiner Scheibe, dann ist dein Signal auch nur 1% von der Frequenz oder anders gesagt 3 mSek lang. Gut, entsprechend hoch getaktet und wenig Programm reicht das auch noch für's pollen, ansonsten, wenn du Zykluszeiten über 3 mSek. erwarten kannst, bist du nicht sicher, ob dein Programm jeden Impuls erfaßt. In einem solchen Fall ist es notwendig, auf einen interruptfähigen Eingang zu setzen und das Signal in einer ISR zu erfassen. Wichtig ist vielleicht auch noch, eine Flankernauswertung durchzuführen. Beim Interrupt legst du die Flanke ja fest, aber beim Polling nicht. Dann ist ein Zählen nur bei steigender oder fallender Signallage durchzuführen. IO einlesen mit altem IO Wert eine exclusiv Oder Verküpfung durchführen. Ergebnis sind gesetzte Bits bei unterschiedlicher Signallage zum alten Wert. Dieses Ergebnis mit neuem für steigende Flanke und mit altem Wert für fallende Flanke verunden. Anschließend die eingelesenen Bits für die nächste Prüfung abegen. So ein Flankenbit kannst du nun zum Zählen benutzen und danach zurücksetzen. Damit ist sichergestellt, das pro Signal auch nur ein Schritt gezählt wird. In Assembler hab ich das schon mehr wie einmal geschrieben, in C mußt du das selber umsetzen. Ach ja, eigentlich wollte ich mal in folgender Form antworten: dieantwortmußtdusebererarbeitendaduesnichthinbekommstgroßundkleinschrift anzuwendensowiesatzzeichenzusetzen.. aber du hast ja wenigstens noch Leerzeichen zwischenden Worten. Gruß oldmax
So hab noch mal etwas hier im forum nachgeschauft und hab nun folgenden Code geschrieben. Meint Ihr das geht so?
Jörg Roesberg schrieb: > So hab noch mal etwas hier im forum nachgeschauft und hab nun folgenden > Code geschrieben. > > Meint Ihr das geht so? Nein. Da ist noch nicht einmal ansatzweise zu erkennen, wie das jemals funktionieren könnte. * Du benutzt das TCNT2 Register, also das Zählregister vom Timer 2 um daraus irgendetwas auszurechnen. Du intialisierst aber Timer 2 nirgends * Dafür hast du den Timer 0 am Laufen um damit Overflow Interrupts auszulösen. Im Interrupt zählst du eine Variable hoch, verwendest diese Variable aber nicht weiter. Dein Problem besteht aus 2 Teilen * Du musst Pulse zählen * und zwar in einem bestimmten Zeitraum Für beides kann man Timer benutzen. Aber dazu müsstest du erst einmal festlegen, welcher Timer wofür zuständig sein soll. Und dann musst du den jeweiligen Timer für seine Aufgabe konfigurieren. Lass die Zeitsteuerung erst mal beiseite und sieh zu, dass du den Timer 2 soweit bringst, dass er dir an seinem zugeordneten Eingang die Pulse zählt. Der kann das. Einfach nur zählen, noch nicht in eine Drehzahl umrechnen. Und diese Pulszählung lässt du dir auf dem LCD ausgeben. Jedesmal wenn du die Lichtschranke (mit einem Blatt Papier) unterbrichst, muss der Timer um 1 weiterzählen und dein Programm den zugehörigen Zählerstand auf dem LCD ausgeben. Das könnte dein erstes Zwischenziel sein.
Sonst hampelst du noch 2 Wochen rum
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 | |
und wenn das dann zählt, dann änderst du fürs erste
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
in counter hast du dann die Anzahl der gemessenen Pulse in der letzten Zehntelsekunde. Und daraus kann man dann die Drehzahl ausrechnen. Bei langsamen Drehzahlen kann man auch länger warten, damit sich im Wartezeítraum genügend Pulse ansammeln. Und dann wisrt du irgendwann das relativ ungenaue _delay_ms durch eine Timerlösung ersetzen.
Super danke schon mal das läuft so weit jetzt! Karl Heinz Buchegger schrieb: > while(1) { > > TCNT2 = 0; > _delay_ms( 100 ); // 0.1 Sekunden warten > counter = TCNT2; > > sprintf( buffer, "%3u", counter ); > lcd_setcursor( 10, 2 ); > lcd_string( Buffer ); > } Wenn ich das aber ändere zählt der counter nicht mehr weiter sondern bleibt auf 0 . Mir ist schon klar wie das jetzt funktioniert, aber das versteh ich jetzz wider nicht
Jörg Roesberg schrieb: > Super danke schon mal das läuft so weit jetzt! > > Karl Heinz Buchegger schrieb: >> while(1) { >> >> TCNT2 = 0; >> _delay_ms( 100 ); // 0.1 Sekunden warten >> counter = TCNT2; >> >> sprintf( buffer, "%3u", counter ); >> lcd_setcursor( 10, 2 ); >> lcd_string( Buffer ); >> } > > Wenn ich das aber ändere zählt der counter nicht mehr weiter sondern > bleibt auf 0 . Dann hast du (für jetzt) zu wenig Pulse in 1 Zehntelsekunde. Lass den Timer halt mal 1 Sekunde lang Pulse zählen > Mir ist schon klar wie das jetzt funktioniert, aber das versteh ich > jetzz wider nicht Dann bezahl jemanden, dass er dir das programmiert. Es gibt Leute die leben davon, solche Dinge in 20 Sekunden zu verstehen. Diese Leute müssen auch von irgendetwas leben.
Ich verstehs ja nur bei machen sachen kommt man einfach nicht weiter( denke das geht jedem schon mal so und da ist man über jede hilfe froh) und dafür ist doch ein forum da oder? Karl Heinz Buchegger schrieb: > Dann hast du (für jetzt) zu wenig Pulse in 1 Zehntelsekunde. > Lass den Timer halt mal 1 Sekunde lang Pulse zählen hab den timer auf 1 sec gestellt geht aber nicht, macht auch nix ich werd jetzt weiter schauen bis das läuft. Ich danke auf jeden fall für die super hilfe.
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.