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
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
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
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.
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
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?
> - 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?
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?
Also das mit der unsinnigen Berechnung: "zeit" muss Dummy heißen hab ich falsch abgeschrieben ... und hier jetzt das ganze (unfertige) Programm:
1 | #include <mega8.h> |
2 | |
3 | // Alphanumeric LCD Module functions
|
4 | #asm
|
5 | .equ __lcd_port=0x18 ;PORTB |
6 | #endasm
|
7 | #include <lcd.h> |
8 | |
9 | // Timer 1 overflow interrupt service routine
|
10 | interrupt [TIM1_OVF] void timer1_ovf_isr(void) |
11 | {
|
12 | Overflow = Overflow + 1; |
13 | }
|
14 | |
15 | // Timer 1 input capture interrupt service routine
|
16 | interrupt [TIM1_CAPT] void timer1_capt_isr(void) |
17 | {
|
18 | Dummy = TCNT1; |
19 | Dummy = Dummy + 65536 * Overflow; |
20 | Dummy = Dummy * 0,000000125; |
21 | Impulse = 60 / Dummy; |
22 | |
23 | }
|
24 | |
25 | // Declare your global variables here
|
26 | typedef unsigned char uint8_t Overflow ; |
27 | typedef unsigned long uint32_t Dummy ; |
28 | typedef unsigned char uint8_t Inmpulse ; |
29 | |
30 | void main(void) |
31 | {
|
32 | |
33 | PORTB=0x00; |
34 | DDRB=0x00; |
35 | |
36 | PORTC=0x00; |
37 | DDRC=0x00; |
38 | |
39 | PORTD=0x00; |
40 | DDRD=0x00; |
41 | |
42 | // Timer/Counter 0 initialization
|
43 | // Clock source: System Clock
|
44 | // Clock value: Timer 0 Stopped
|
45 | TCCR0=0x00; |
46 | TCNT0=0x00; |
47 | |
48 | // Timer/Counter 1 initialization
|
49 | // Clock source: System Clock
|
50 | // Clock value: 4000,000 kHz
|
51 | // Mode: Normal top=FFFFh
|
52 | // OC1A output: Discon.
|
53 | // OC1B output: Discon.
|
54 | // Noise Canceler: Off
|
55 | // Input Capture on Rising Edge
|
56 | // Timer 1 Overflow Interrupt: On
|
57 | // Input Capture Interrupt: On
|
58 | // Compare A Match Interrupt: Off
|
59 | // Compare B Match Interrupt: Off
|
60 | TCCR1A=0x00; |
61 | TCCR1B=0x41; |
62 | TCNT1H=0x00; |
63 | TCNT1L=0x00; |
64 | ICR1H=0x00; |
65 | ICR1L=0x00; |
66 | OCR1AH=0x00; |
67 | OCR1AL=0x00; |
68 | OCR1BH=0x00; |
69 | OCR1BL=0x00; |
70 | |
71 | // Timer/Counter 2 initialization
|
72 | // Clock source: System Clock
|
73 | // Clock value: Timer 2 Stopped
|
74 | // Mode: Normal top=FFh
|
75 | // OC2 output: Disconnected
|
76 | ASSR=0x00; |
77 | TCCR2=0x00; |
78 | TCNT2=0x00; |
79 | OCR2=0x00; |
80 | |
81 | // External Interrupt(s) initialization
|
82 | // INT0: Off
|
83 | // INT1: Off
|
84 | MCUCR=0x00; |
85 | |
86 | // Timer(s)/Counter(s) Interrupt(s) initialization
|
87 | TIMSK=0x24; |
88 | |
89 | // Analog Comparator initialization
|
90 | // Analog Comparator: Off
|
91 | // Analog Comparator Input Capture by Timer/Counter 1: Off
|
92 | ACSR=0x80; |
93 | SFIOR=0x00; |
94 | |
95 | Overflow = 0x00 |
96 | |
97 | // LCD module initialization
|
98 | lcd_init(16); |
99 | |
100 | // Global enable interrupts
|
101 | #asm("sei")
|
102 | |
103 | while (1) |
104 | {
|
105 | // Place your code here
|
106 | |
107 | };
|
108 | }
|
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.
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:
1 | // Timer 1 overflow interrupt service routine
|
2 | interrupt [TIM1_OVF] void timer1_ovf_isr(void) |
3 | {
|
4 | Overflow = Overflow + 1; |
5 | }
|
6 | |
7 | // Timer 1 input capture interrupt service routine
|
8 | interrupt [TIM1_CAPT] void timer1_capt_isr(void) |
9 | {
|
10 | Dummy = TCNT1; |
11 | Dummy = Dummy + 65536 * Overflow; |
12 | Dummy = Dummy * 0,000000125; |
13 | Impulse = 60 / Dummy; |
14 | |
15 | }
|
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
1 | // Declare your global variables here
|
2 | typedef unsigned char uint8_t Overflow ; |
3 | typedef unsigned long uint32_t Dummy ; |
4 | 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.
1 | // some data types to simplify typing
|
2 | typedef unsigned char uint8_t; |
3 | typedef unsigned long uint32_t; |
4 | typedef unsigned char uint8_t; |
5 | |
6 | // Declare your global variables here
|
7 | uint8_t Overflow; |
8 | uint32_t Dummy; |
9 | uint8_t Inmpulse; |
10 | |
11 | // Timer 1 overflow interrupt service routine
|
12 | interrupt [TIM1_OVF] void timer1_ovf_isr(void) |
13 | {
|
14 | Overflow = Overflow + 1; |
15 | }
|
16 | |
17 | // Timer 1 input capture interrupt service routine
|
18 | interrupt [TIM1_CAPT] void timer1_capt_isr(void) |
19 | {
|
20 | Dummy = TCNT1; |
21 | Dummy = Dummy + 65536 * Overflow; |
22 | Dummy = Dummy * 0.000000125; |
23 | Impulse = 60 / Dummy; |
24 | }
|
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;
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.