Hi Leute, ich versuche mich an gcc ranzupirschen und stoße dabei auf einige kleine Hürden. Momentan versuche ich einen Frequenzzähler zu programmieren. Der Zählt auch schon ganz schön aber ich wollte eine automatische Umschaltung von Hz nach kHz. Das funktioniert auch gut. Aber ich wollte "mehr". Nämlich eine Kommastelle bei kHz 123.456kHz. Das funktiioniert mit der Funktion "dtostrf" nur "teilweise". Problem: Auf meinen LCD steht die eingespeiste Frequenz von zB. 1.500kHz und dann macht er manchmal 3.00kHz draus. Das wird schlimmer je höher ich in der Frequenz gehe. Manchmal verdoppelt er sogar mehrmals also erst z.B. 20.000kHz dann 40.000kHz dann 80.000kHz. Bei z.B. 500.000Hz passiert nichts da bleibt alles wie es soll. Ich hänge mal meinen Programmcode an.
Du machst IMHO viel zu viel in der Interruptroutine. Dadurch wird das Zeitfenster zu lang und du zählst zu lang Impulse. Dadurch wird der Frequenz zu hoch. Ich würde: 1/ Messung und Anzeige so streng wie möglich trennen. 2/ Statt den Signaleingang in main() zu pollen, würde ich das in einem 2. Interrupt machen lassen. 3/ Weshalb ist tmp vom Typ double, wenn du es doch ganzzahlig erhöhst? 4/ B und tmp werden von main() und ISR benutzt. Sie sollten volatile gekennzeichnet sein. 5/ Die Interrupts würde ich erst global einschalten, wenn alle Initialisierungen gelaufen sind (sei nach timer1_init) 6/ Einheit hat den falschen Typ (uint8_t statt uint8_t *). Da müsste der GCC gemosert haben.
Danke für die Antworten > 1/ Messung und Anzeige so streng wie möglich trennen. Ok. Ich versuchs > 2/ Statt den Signaleingang in main() zu pollen, würde ich das in einem > 2. Interrupt machen lassen. Ok. > 3/ Weshalb ist tmp vom Typ double, wenn du es doch ganzzahlig erhöhst? Ich dachte damit kann ich mehr als nur 65535 speichern. Weil uint32_t macht er nicht dann zeigt er keine Zahlen mehr an. > 4/ B und tmp werden von main() und ISR benutzt. Sie sollten volatile > gekennzeichnet sein. Was heißt das? ^^ > 5/ Die Interrupts würde ich erst global einschalten, wenn alle > Initialisierungen gelaufen sind (sei nach timer1_init) Ok. > 6/ Einheit hat den falschen Typ (uint8_t statt uint8_t *). Da müsste der > GCC gemosert haben. Hat nicht gemosert und angezeigt hat er Hz und kHz auch schön aber ich werds ändern.
uint32_t tmp 65535 ist die Grenze bei uint16_t. Wenn du uint32_t tmp benutzt, kannst du bis 4294967295 zählen, aber dtostrf nicht benutzen. Die passende Umwandlungsfunktion ist ultoa(). Wie die Funktion aufzurufen ist, kannst du in stdlib.h herausfinden - die Reihenfolge und Bedeutung der Argumente ist anders als bei dstrtof. Auch das Setzen des Kommas ist etwas anders (Rechnen mit Ganzzahldivision / und Modulo %) volatile http://www.mikrocontroller.net/articles/Interrupt#Steuersignale_zwischen_ISR_und_Hauptprogramm Nicht-Mosern Bei mir kommt an der Stelle
1 | ../Robin.c:30: warning: assignment makes integer from pointer without a cast |
2 | ../Robin.c:34: warning: assignment makes integer from pointer without a cast |
Wenn das bei deiner Toolchain nicht kommt, ist das ungünstig. Du verpasst Warnungen des GCC, die dir helfen, Programmierprobleme aufzudenken. Wenn du GCC aus AVR Studio heraus bedienst, weiss ich nicht, wie man es schafft, diese Warnung zu unterdrücken. Wenn du ohne AVR Studio mit einem Makefile arbeitst, solltest du das Makefile ändern. Wenn du das selbst nicht schaffst, zeig' das Makefile.
> ../Robin.c:30: warning: assignment makes integer from pointer without a > cast > ../Robin.c:34: warning: assignment makes integer from pointer without a > cast Ok das hat er gesagt aber ich dachte wäre net schlimm weils ja funktioniertz hat^^ ultoa kenne ich. Habe es aber nicht benutzt weil es keine Kommazahlen gibt. An Modula hab ich auch schon gedacht habe aber keinerlei Erfahrung damit und deshalb habe ich es bis jetzt gelassen. Werde es aber mal versuchen.
Das Rechnen mit Modulo (Rest der Ganzzahldivision) ist nicht schlimm. Beispiel:
1 | {
|
2 | uint32_t tmp = 2345; // Hz |
3 | uint32_t vorkomma = tmp / 1000; // 2345 / 1000 = 2 |
4 | uint32_t nachkomma = tmp % 1000; // 2345 % 1000 = 345; |
5 | uint8_t buffer[6]; |
6 | |
7 | if (vorkomma > 99999) |
8 | {
|
9 | // wg. Platz in buffer, ist anpassbar
|
10 | lcd_string(" OVERFLOW "); |
11 | }
|
12 | else
|
13 | {
|
14 | ultoa(vorkomma, buffer, 10); |
15 | lcd_string(buffer); |
16 | lcd_string(","); |
17 | ultoa(nachkomma, buffer, 10); |
18 | // Nullen ergänzen auf 3 Stellen hinterm Komma
|
19 | // Bsp. 2,5 => 2,500
|
20 | while(strlen(buffer) < 3) |
21 | strcat(buffer, "0"); |
22 | lcd_string(buffer); |
23 | lcd_string(" kHz"); |
24 | }
|
25 | }
|
Habs kaputt verbessert :( Hab mal ein paar Kommentare gemacht damit ich den Fehler dabei vlt. selbst finde aber nichts. Das LCD zeigt nichts mehr an bleibt einfach leer.
Vorab: Tja, den Einheit Fehler hast du nicht verbessert. Und bei der while-Schleife ist ein Klammerpaar nötig. Messung wird ohne das Klammerpaar nie aufgerufen! Ich bin dabei das in den Simulator einzupassen. Mehr demnächst...
Juhu. Dank deines Hinweises wegen der Klammern in der while Schliefe mißt er jetzt wieder und das auch noch bis über 100kHz. Leider fehlen jetzt noch die Kommazahlen. Und wegen der Variable Einheit. Ich habe leider nicht ganz verstanden was ich da ändern soll.
Habs jetzt hinbekommen das er bei der Variable "uint8_t Einheit" nicht mehr meckert. Hab sie in "static char* Einheit" geändert nd alles funktioniert.
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.