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.
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 :)
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
}
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.
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
Mach es dir zur Regel:
Der grundsätzliche Aufbau eines Programmes sieht so aus
1
voidmain()
2
{
3
4
// Initialisierung und Einstellung der beteiligten Hardware
5
// und µC-Komponenten
6
7
while(1){// das hier ist die Hauptschleife, in ihr wird
8
// gemacht ...
9
10
// die eigentliche Arbeit, die dein Programm erledigen soll
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
while(1){
2
TCNT2=0;
3
counter1=TCNT2;
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
charBuffer[5]=("U/min: ");
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!
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ß
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
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.
und wenn das dann zählt, dann änderst du fürs erste
1
while(1){
2
3
TCNT2=0;
4
_delay_ms(100);// 0.1 Sekunden warten
5
counter=TCNT2;
6
7
sprintf(buffer,"%3u",counter);
8
lcd_setcursor(10,2);
9
lcd_string(Buffer);
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.