mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Impulse pro Minute


Autor: Bernd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen
Ich würde gerne mit einem AtMega8 die Zeit zwischen 2 Impulsen messen 
(zwischen 0,3 und 1,5 Sekunden)und anschließend die Anzahl der Impulse 
pro Minute ausgeben.
Dazu hatte ich vor Timer1 zu benutzen (Prescaler =1)und Input Capture zu 
aktivieren. Dann ist ja:
             Capturewert2 - Capturewert1 = Abstand in Timerschritten

diesen Abstand müsste ich dann mit der Zeit zwischen zwei Timerschritten 
multiplizieren und 60(Sekunden) durch diesen Wert teilen.

Allerdings hab ich das Problem, dass ich wenig Ahnung vom Programmieren 
habe und nicht weiß ob das so funktionieren kann oder vielleicht sogar 
einfacher geht. Außerdem weiß ich auch nach langem rumstöbern im 
Internet nicht wie ich die Multiplikation und die Division durchführe. 
Ich hoffe Ihr könnt mir da helfen.

Bernd

Autor: Kai Franke (kai-) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
die Grundidee ist schonmal gar nicht schlecht, allerdings steckt der 
Teufel im Detail...
Wenn du als Prescaler 1 nimmst und das ganze mit 8Mhz laufen lässt, wird 
der Timer1, der nur bis 65535 zählen kann in einer Sekunde genau 122 Mal 
überlaufen. Vergiss also nicht das overflow Interrupt, wo du die Anzahl 
der Overflows zählst und später mit 65536 * gespeicherter Wert wieder 
zurück rechnest

Solltest du in C programmieren wollen, kannst du eine Multiplikation mit 
* und eine Division mit / durchführen.

von der Art her sollte das Programm so aussehen:

                // Zeit ab hier stoppen
TCNT1 = 0;      // Timer 1 auf 0 setzen
overflow = 0;   // Variable zum Zählen der overflows zurücksetzen

// warten bis gestoppt wird

dummy = TCNT1   // wichtig, dass der Wert als erstes gespeichert wird,
                // dass keine Zeit verloren geht
dummy = dummy + 65536 * overflow
// dummy sollte mindestens als long definiert werden, da der Wert sehr
// groß werden kann
// mit dummy kann jetzt weiter gerechnet werden

Autor: Bernd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So vielen Dank für deine hilfreiche Antwort. Das mit dem Overflow hätte
mir eigentlich auffallen müssen, hab mich da wohl irgentwie verrechnet,
ist aber ja auch eigentlich kein großes Problem. Jetzt muss ich es nur
noch schaffen soweit mit C zurechtzukommen (hab sonst nur ein bisschen
mit Assembler rumbrobiert ), dass ich das Ganze auch programmieren kann.

Ich hätte da noch eine Frage: Wenn ich den Wert habe wie schaffe ich es
ihn auf 7-Segmentanzeigen oder einem LCD auszugeben?

Bernd

Autor: Christoph Kessler (db1uq) (christoph_kessler)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
http://www.mikrocontroller.net/articles/AVR_Arithmetik
eine ähnliche Aufgabe ist die Auswertung eines Geigerzählers, aber da 
reicht eine Messung nicht, da die Abstände zufällig sind.

Autor: Kai Franke (kai-) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Anzeige auf einem LCD ist relativ leicht, auf einem 7 Segment etwas 
komplizierter.
Wenn du CodevisionAVR benutzt, hast du ein LCD innerhalb weniger Minuten 
in Betrieb, bei dem C GNU Compiler sollte das aber auch recht leicht 
möglich sein, musst eben schauen wo du die LCD Routinen herbekommst, 
kenn mich da nicht so aus.

Wenn du 7-Segmente nehmen willst, musst du dir überlegen wie du die 
ansteuern willst. Direkt über den Mikrocontoller multiplexen oder doch 
einen MAX7921 (glaub das war der richtige) benutzen.
Außerdem ist der Anschluss von 7 Segmentern komplizierter, weil jede 
Ziffer 9 Anschlüsse braucht, bei einem LCD brauchst du nur 8 oder 9

Wenn es dir also egal ist wie die Zahl angezeigt wird, rate ich dir zu 
einem LCD

Autor: Bernd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So ich hab jetzt versucht mit Codevision ein Programm zu schreiben, das 
Problem dabei ist allerdings, dass ich von C wenig Ahnung hab und auch 
das GCC-Tutorial hilft mir da wenig.
ich habe nun Codevision das Programm soweit schreiben lassen und:

- In die Overflow Interrupt Routine
        Overflow = Overflow + 1;
  geschrieben.

- In die Input Capture Interrupt Routine
         Dummy = TCNT1;
         Dummy = Dummy + 65536 * Overflow;
         Dummy = Dummy * 0,000000125;
         Impulse = 60 / Zeit;

- Bei Declare your global variables
         typedef unsigned char uint8_t Overflow;
         typedef unsigned long uint32_t Dummy;
         typedef unsigned char uint8_t Impulse;

-Und im main Teil des Programms
         Overflow = 0x00

was ist daran jetzt falsch? Wie muss ich das ändern?
und wie gebe ich bei Codevision die Variable Impulse über das LCD aus?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> - In die Input Capture Interrupt Routine
>          Dummy = TCNT1;
>          Dummy = Dummy + 65536 * Overflow;
>          Dummy = Dummy * 0,000000125;
>          Impulse = 60 / Zeit;

Warum rechnest du da wie wild mit einer Variablen Dummy
herum, wenn du dann das Ergebnis der Rechnerei überhaupt
nicht benutzt?

Autor: rino (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vollständiges Programm zeigen, sonst kann man dir nicht gescheit helfen.

Autor: Kai Franke (kai-) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
lad doch einfach mal die C Datei hoch, sonst ist es wirklich schwer dir 
zu helfen.
Davon abgesehen, dass deine Rechnung keinen Sinn macht, weil du das 
Ergebnis nicht benutzt, ist sie sehr langsam und kompliziert! Lass den 
Controller nur so viel rechnen wie unbedingt sein muss.
Woran siehst du eigentlich, dass es nicht geht bzw was erwartest du zu 
sehen?

Autor: Bernd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also das mit der unsinnigen Berechnung: "zeit" muss Dummy heißen hab ich 
falsch abgeschrieben ...
und hier jetzt das ganze (unfertige) Programm:
#include <mega8.h>   

// Alphanumeric LCD Module functions
#asm
   .equ __lcd_port=0x18 ;PORTB
#endasm
#include <lcd.h>

// Timer 1 overflow interrupt service routine
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
  Overflow = Overflow + 1;
}

// Timer 1 input capture interrupt service routine
interrupt [TIM1_CAPT] void timer1_capt_isr(void)
{
  Dummy = TCNT1;
  Dummy = Dummy + 65536 * Overflow; 
  Dummy = Dummy * 0,000000125;
  Impulse = 60 / Dummy;
  
}

// Declare your global variables here   
typedef unsigned char uint8_t Overflow ;
typedef unsigned long uint32_t Dummy ;
typedef unsigned char uint8_t Inmpulse ; 
  
void main(void)
{
  
PORTB=0x00;
DDRB=0x00;

PORTC=0x00;
DDRC=0x00;

PORTD=0x00;
DDRD=0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
TCCR0=0x00;
TCNT0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 4000,000 kHz
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Rising Edge
// Timer 1 Overflow Interrupt: On
// Input Capture Interrupt: On
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x41;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
MCUCR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x24;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;  

Overflow = 0x00

// LCD module initialization
lcd_init(16);

// Global enable interrupts
#asm("sei")

while (1)
      {
      // Place your code here

      };
}  

Soll bis jetzt eben die Zeit zwischen zwei Impulsen berechnen und in 
Impulse pro Minute umrechnen. Was noch fehlt ist die Ausgabe der Impulse 
pro Minute über das LCD.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ui. Da fehlts aber an allen Ecken und Enden.
Du solltest dir dringend ein Buch über C zulegen. So ein
Wizard ist kein Ersatz für fehlende Kentnisse.

> hab ich falsch abgeschrieben ...
Du sollst überhaupt nicht abschreiben. Denn beim Abschreiben
entstehen Tippfehler. Und dann jagen 20 Leute Tippfehlern hinterher,
die so gar nicht in deinem Code enthalten sind. Cut&Paste ist
schon lange erfunden.

Aber zur Sache:
// Timer 1 overflow interrupt service routine
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
  Overflow = Overflow + 1;
}

// Timer 1 input capture interrupt service routine
interrupt [TIM1_CAPT] void timer1_capt_isr(void)
{
  Dummy = TCNT1;
  Dummy = Dummy + 65536 * Overflow; 
  Dummy = Dummy * 0,000000125;
  Impulse = 60 / Dummy;
  
}

Ein C Compiler arbeitet deinen Source Code von oben nach unten durch.
Variablen müssen definiert (oder deklariert) werden, bevor sie
das erste mal benutzt werden können.

In deiner Overflow ISR benutzt du zb. eine Variable namens 'Overflow'.
Wenn ich aber von dieser Codestelle in Richtung Anfang des Source
Codes durchschaue, dann findet sich keine Variable dieses Namens.
Selbiges für die Variable Dummy und Impulse in der zweiten ISR.

Und by the way. Das hier
// Declare your global variables here   
typedef unsigned char uint8_t Overflow ;
typedef unsigned long uint32_t Dummy ;
typedef unsigned char uint8_t Inmpulse ; 

sind keine Variablendefinitionen, sondern die Vereinbarungen für
neue Datentypen. Du definierst, dass der Datentyp 'Overflow' synonym
zu einem unsigned char uint8_t sein soll. Halt, Moment, das
ist insgesamt noch nicht mal ein korrekter typedef sondern
ein Syntax Error.

Von diversen fehlenden ; reden wir mal gar nicht.

In Programmiersprachen wird normalerweise meistens eine
Dezimalpunkt als . geschrieben und nicht als ,
, hat in C eine ganz spezielle Bedeutung.
// some data types to simplify typing
typedef unsigned char uint8_t;
typedef unsigned long uint32_t;
typedef unsigned char uint8_t;

// Declare your global variables here   
uint8_t Overflow;
uint32_t Dummy;
uint8_t Inmpulse;

// Timer 1 overflow interrupt service routine
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
  Overflow = Overflow + 1;
}

// Timer 1 input capture interrupt service routine
interrupt [TIM1_CAPT] void timer1_capt_isr(void)
{
  Dummy = TCNT1;
  Dummy = Dummy + 65536 * Overflow; 
  Dummy = Dummy * 0.000000125;
  Impulse = 60 / Dummy;
}

Ob bei der Multiplikation mit 0.000000125 jemals etwas anderes
als 0 herauskommen wird? Hängt wohl vom Wert für TCNT1 ab.
Mal nachrechnen. TCNT1 muss mindestens einen Wert von 8000000
haben, damit die Multiplikation etwas ergibt, was größer als 1
ist. Blöd ist nur, dass TCNT1 eine 16 Bit Variable ist und daher
niemals größer als 65535 werden kann. OK. Overflow könnte dich
noch retten und den Wert entsprechend hoch treiben. Dann mussten
aber pro Messung mindestens 123 Overflows anfallen.
In allen anderen Fällen ist Dummy dann einfach nur 0. Wodurch
sofort das nächste Problem entsteht

   Impulse = 60 / Dummy;

Da Dummy den Wert 0 haben wird, ergibt das eine Division durch 0.
Autsch!

Also so gehts nicht. Da musst du dir schon eine andere Berechnung
einfallen lassen, um aus dem Timerwert auf die Frequenz zurückzurechnen.
Und denk dran: Du hast nur ganze Zahlen! Keine Kommastellen, auch
nicht in Zwischenergebnissen.

Im Übrigen bezweifle ich mal die letzte Umrechnung auf Impulse/Minute.
Wenn du in 1 Sekunde 1 Impuls misst, dann misst du in 1 Minute
60 Impulse.
   Imulse = 60 * Dummy;

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.