PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Schonwieder - DREHZAHL erfassen



Kaiser-F
02.09.2005, 23:36
Hallo zusammen,

Ich möchte mit euch gerne mal eine optimale Lösung zum Thema Drehzahlerfassung austüfteln.

Das problem ist ja, dass je nach Programmgröße die Drehzahl nicht wirklich an einem Normalen PIN eines MCs erfasst werden kann.

Meine Idee dazu wäre:

Man steuert mit dem Drehzahlimpuls einen COUNTER an ( Externes IC ).
zB 8Bit Binärzähler.

Im MC programmiert man einen Counter, der nach jeder Sekunde einen Interrupt ausführt, welcher dann dazu genutzt wird den Binärzähler auszulesen.

ABER um nicht 8 BITs des MCs zu benutzen könnte man auch folgendes machen.

Den Counter umkehren ( count down ) und so lange Impulse an den Counter schicken bis er Leer ist. nach dem nächsten interrupt wird der Counter wieder in normalmodus versetzt und er zählt wieder die drehzahlimpulse.

Dadurch sind 0-255 Drehungen pro sekunde möglich. oder pro halbe sekunde, jenacdem wie man es machen will....



Was haltet Ihr davon?

Nur kenne ich kein COUNTER-IC, welches bei 0 ein signal gibt, und auch noch ein UP/DOWN counter ist.

Aber zusammen erreicht man mehr, wisst ihr da was?
Was habt Ihr für Ideen?

kater
03.09.2005, 06:48
Warum nicht einfach einen Counter vom MCU hochzaehlen und per INT auslesen. Ich mache das alle 65ms und regel somit 2 Motoren. Das funktioniert recht gut. Der Nachteil man braucht 2 Counter. Intresse an dem Code?

Kaiser-F
03.09.2005, 09:35
Hallo,

Danke für die Antwort.
Das st wohl die einfachste Lösung :-)....

Könntest mir den Code schicken? oder hier posten?

Danke!

Manf
03.09.2005, 11:33
Nur kenne ich kein COUNTER-IC, welches bei 0 ein signal gibt, und auch noch ein UP/DOWN counter ist.
Schön, wenn Du schon eine andere Lösung hast.

Wenn der Zähler kein up/down Zähler ist, dann kann man den Zähler auch bis zum Überlauf hochzählen.

Speist man dabei die Zählimpulse zum Auswerten über eine EXOR Verknüpfung in das Zählsignal ein, dann gehen die während der Auswertung eintreffenden Zählimpulse auch nicht verloren. (Nur mit sehr geringer Wahrscheinlichkeit.)

Das gesuchte Signal ist dann der Überlauf oder auch das MSB.
Manfred

PicNick
03.09.2005, 11:57
Ich müßte suchen, aber solche Preset-Counter gibt es fix und foxi, genau für diesen Zweck. (SN74160, 74161)

Manf
03.09.2005, 12:25
solche Preset-Counter gibt es fix und foxi, genau für diesen Zweck
Kannst Du noch ein bisschen dazu sagen welche Eigenschaften eines Zählers für diesen Zweck geeignt sind.
8bit, up/down, kombinierte clock Eingänge?
Manfred

Kaiser-F
03.09.2005, 14:19
Dazu könnte ich noch einen Ton abgeben,

Man könnte ja die 8 Ausgänge eines 8Bit Counters mit 8 Dioden auf einen Pin des MCs leiten, damit wüsste der MC immer wann der Counter 0 erreicht. Einen anderen PIN des Controllers müsste man mit Reset des Counters verbinden.


Ich bin aber trotz allem schon gespannt die Idee von "kater" zu testen.
Sein Code wäre noch der hit hier :-)

kater
03.09.2005, 15:30
Also mein Programm ist noch nicht ganz fertig. Ich hatte meine Drehzahl die ganze Zeit mit Digitalen Widerstaende gestellt, doch das ist zu bloede. Ich versucht heute mal PWM und passte mein Programm dann darauf an.
Das Grundgeruest kann ich aber schonmal freigeben _;)



/*
* Motordrehzahlreglung, geschrieben fuer einen ATMega8 mit 8MHz.
* Das Programm ist fuer 2 Motoren geschrieben. Die Lichtschranken
* werden ueber eine Gatter Logig an Pin 6 (T0) angeschlossen. Es wechselt
* alle 62ms die Lichtschranke und vergleicht den Wert der in das Timer/Counter
* Register0 geschrieben wuerde mit einem Sollwert. Danch werden die Motoren langsamer
* oder schneller gestellt.
*
*/

#include <stdlib.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <stdint.h>

#define nop() asm volatile( "nop" );

#define MS PB0

#define NORMALSPEED 20


volatile uint16_t wayLeft = 0,
wayRight = 0,
wayLeftOld = 0,
wayLeftDiff = 0,
wayRightOld = 0,
wayRightDiff = 0;

volatile uint8_t impulseLeft = 0,
impulseRight = 0,
testLeftWheel = 1,
speedLeft = 0,
speedRight = 0,
geradeausFahren = 1;

// Timer1
SIGNAL(SIG_OVERFLOW1)
{


// Welches Rad ueberpruefen wir?
if (testLeftWheel == 1)
{

wayLeftOld = wayLeft;

// Die Lichtschranke sendet auch manchmal im Stillstand einen Wert von 1
if (TCNT0 <= 1) impulseLeft = 0;
else impulseLeft = TCNT0;

wayLeft += impulseLeft;

wayLeftDiff = wayLeft - wayLeftOld;

if (impulseLeft != speedLeft)
{

if (impulseLeft < speedLeft)
{

// Irgend etwas tun damit der linke Motor schneller dreht
nop();
}
else
{

// Irgend etwas tun damit der linke Motor langsamer dreht
nop();

}

}

testLeftWheel = 0;
// Rechter Motor auswaehlen
PORTB |= (1 << MS);

}
else
{

wayRightOld = wayRight;
if (TCNT0 <= 1) impulseRight = 0;
else impulseRight = TCNT0;

wayRight += impulseRight;

wayRightDiff = wayRight - wayRightOld;

if (impulseRight != speedRight)
{

if (impulseRight < speedRight)
{

// Irgendetwas tun damit der rechte Motor schneller dreht
nop();

}
else
{

// Irgendetwas tun damit der rechte Motor langsamer dreht
nop();

}

}

testLeftWheel = 1;
// Linker Motor auswaehlen
PORTB &=~ (1 << MS);

}


if (geradeausFahren == 1)
{

if (wayLeftDiff < wayRightDiff)
{

// Der rechte Motor hat eine groessere Strecke zurueckgelegt als der linke.
// Den rechten Motor langsamer fahren lassen

}
else if (wayLeftDiff > wayRightDiff)
{

// Der linke Motor hat eine groessere Strecke zurueckgelegt als der recht.
// Den linken Motor langsamer fahren lassen.

}

}


// Timer auf 0 setzten
TCNT0 = 0;

}


int main(void)
{

DDRB = 0xFF; // PORTB as Output
DDRD = 0x00; // PORTD as Input
PORTD = 0xff; // interne Pull-Ups an allen PortD-Pins aktivieren
TCCR0 |= (6<<CS00); // Ext. Clock, falling edge
TCCR1B |= (2<<CS10); // Clk/8
TIMSK |= (1 <<TOIE1); // Timer-1 Interrupt einschalten

speedLeft = 30;
speedRight = 30;

// Interrupts aktivieren
sei();

// Hauptschleife
while (1)
{

// Irgenwelche Befehler ueber z.B USART empfangen

}

}

PicNick
04.09.2005, 09:55
Ich hab jetzt nachgesehen, 74160 ist BCD, 74161 wäre ein binärer Zähler. (4-Bit, beide sind aber kaskadierbar)
Muß allerdings revidieren: Diese beiden IC können nur "up" counten.
SN74192, 74193 (BCD, bin) wären die richtigen Burschen.
(Ich hoff', das Zeugs ist verfügbar)

Wie gesagt, man kann/muß zwei oder mehrere kaskadieren, jeder hat 4-Bit. Die Zählerstände sind parallel verfügbar
Man kann also wie bei der Maus arbeiten: Aus dem Encoder läßt man up/down zählen, und liest in bestimmten Intervallen aus (+clear)

oder man lädt eine Zahl und nimmt das Ripplecarry als interrupt beim Nulldurchgang (Das würde einem Zahlengleichstand entsprechen),

Up/down erfolgt durch zwei verschiedene Clock-Pins, das müßte man man Encode-design berücksichtigen.

SprinterSB
04.09.2005, 10:16
...oder man nimmt nen Tiny wie 2313 und programmiert den als Zähler, da braucht man nicht kaskadieren und lange runzusuchen ;-)
Und dürfte fast billiger sein als die selteten TTL-Chips und platzsparender als 2 kaskadierte Counter allemal.

PicNick
04.09.2005, 11:07
...oder man nimmt nen Tiny...
Hast sicher recht, wegen sowas gibt's ja auch Kontroller. Aus irgendeinem Grund scheut man sich viel zu oft, für irgendwelche Peripherie-Jobs ganz einfach sowas einzusetzen.
Vielleicht, weil die Controller-Controller Kommunikation immer noch ein bißchen Stiefkind ist ?

Edit : Allerdings zählt der IC oben mit max 17 MHZ, also schon recht flott.

Zarathustra
06.01.2008, 21:34
Meine Empfehlung wäre auch ein Kontrolleur, der einfach auf einen Pegelwechsel am Pin anspricht. Aus dem Grund habe ich einen Atmega168 für die Motoransteuerung; der hat INT0,1 und zusätzlich noch 3 PCINT's, die man auf (nahezu) alle Ports legen kann.

Gruß,
Markus

Kaiser-F
06.01.2008, 23:35
Hallo zusammen,

Verfasst am: Fr 02-09-2005, 23:36

Heute, gut zwei Jahre später, kann ich über meinen eigenen Eintrag nur lachen! :-)

Aber wie man sieht, fängt jeder mal klein an.

Heute würde ich es nach folgenden Methoden machen:

A:
Man benutzt einen externen Interrupt Eingang.
Bei jeder fallenden oder steigenden Flanke lässt man eine
Variable hochzählen. In regelmäßigen Zeitabständen frägt man den
Wert ab und setzt diesen zurück. z.B. jede Sekunde.
( eine s ist aber schonv erdammt lang...)

Wichtig hierbei: die Zeit nicht zu groß, oder die Variable nicht zu klein wählen (Überlaufgefahr)!

B:
Man benutzt einen Timer für das Hochzählen:
Im Grunde funktioniert das wie die obige Lösung,
nur dass das Hochzählen im Timer geschieht.
Dazu benutzt man bei ATMEL den Timer Eingang Tn.
Dieser zählt dann den Timer hoch. Mit einem anderen
Timer kann man dann wieder in gewählten Zeitabständen
den Wert im Timer abfragen und diesen dann wieder zurücksetzen.


Naja... waren das nicht noch Probleme früher :-).

Ich danke euch trotzdem für eure sehr geduldigen Antworten damals.
Ihr seid spitze!

Ohne Euch alle wäre ich nie so weit gekommen!

Ich hoffe ich kann auch anderen so helfen, wie mir geholfen wurde!

Zarathustra
07.01.2008, 08:31
Hab garnicht gesehen, dass der Eintrag schon 2 Jahre alt ist :-b
Das kommt davon, wenn man die Suche benutzt...

Kaiser: A:
Wieso denn hochzählen lassen und dann abfragen? Einfach bei jedem Interrupt die Zeit messen und die Drehzahlberechnung ausführen; dadurch gehen keine Informationen verloren und man hat die bestmöglichste Aktualisierungsgsrate,

Kaiser-F
07.01.2008, 09:07
Das geht natürlich auch.
Je nach Anwendungsfall... Bei hohen Drehzahlen ist wahrscheinlich
die von mir genannte Methode genauer.