Hallo zusammen, ich versuche gerade eine einfache Uhr in C zu programmieren. Das ganze läuft über den Timer eines Mikrocontrollers. Mit dem TimerInterruptOverflow zähle ich eine Variable hoch. Diese wiederum zählt dann meine Schleifen hoch if(sek==59){ sek=0; min++; usw. funktioniert auch soweit und auch die Ausgabe auf das LCD. Als Variablen benutzte ich uint8_t. Das Problem ist das nach einer gewissen Zeit meine Zeilen auf dem Display mit irgendeinem Kram überschrieben werden. Es scheint mir so als ob die Variablen irgendwann überfüllt sind. Das verstehe ich nicht, da ich ja immer wieder bei 59 auf 0 setze usw. Hat jemand einen Tipp? Ich programmiere mit AVR-Studio 4
Anfänger schrieb: > Hat jemand einen Tipp? Ich würde zur Sicherheit auf >= 59 abfragen. Zeig mal ein bisschen mehr vom Code und verwende dabei die C-Code Formatierung
1 | [c]C-Code[/c] |
:
Bearbeitet durch User
Poste mal den gesamten Code (als anhang). In dem Codeausschnitt kann ich nichts sehen, was falsch wäre. Ich würde evtl. if(sek>=59) benützen, um sicher zu gehen, aber sollte eig. kein Problem sein.
>Das Problem ist das nach einer gewissen Zeit meine Zeilen auf dem >Display mit irgendeinem Kram überschrieben werden. Es scheint mir so als >ob die Variablen irgendwann überfüllt sind. Nö, ich denke das die Ausgabe auf das Display Müll ist. >Das verstehe ich nicht, da ich ja immer wieder bei 59 auf 0 setze usw. Wie gibst du die Zahlen aus? Mal ein einfaches Beispiel: Deine Minute war 59. Danach wird 0 ausgegeben. 59 -> 09. Sieht das ungefähr so aus?
Nein, kein Tipp. Aber wenn du uns den Sourcecode zeigst und ggf noch sagst welche Umgebung du nutzt und vielleicht sogar noch erwähnst welche Art Display, Library usw. dann könnte ein Tipp dabei rausspringen
holger schrieb: > Deine Minute war 59. Danach wird 0 ausgegeben. > 59 -> 09. Sieht das ungefähr so aus? kann sein wenn er nur 0 statt 00 ausgibt, beliebter Fehler :-) Wer sagt denn das die IF Abfrage zeitnah erfolgt? Anfänger schrieb: > if(sek==59){ > sek=0; > min++; was ist wenn sek schon bei 60 ist? Max H. schrieb: > Ich würde zur Sicherheit auf >= 59 eben usw.
also wie gesagt das flag wird in der Iterrupt Routine gezählt. Ja das Problem das beim umspringen von 59 auf 1 -> 19 steht hab ich auch noch ;-)
1 | static uint8_t sek=0; |
2 | static uint8_t min=0; |
3 | static uint8_t std=0; |
4 | |
5 | if(flag1>=61){ |
6 | sekunde++; |
7 | flag1=0; |
8 | lcd_set_cursor(7,1); |
9 | lcd_print_itoa(sekunde); |
10 | |
11 | if(sekunde>=59){ |
12 | sekunde=0; |
13 | minute++; |
14 | lcd_set_cursor(4,1); |
15 | lcd_print_itoa(minute); |
16 | if(minute>=59){ |
17 | minute=0; |
18 | stunde++; |
19 | lcd_set_cursor(1,1); |
20 | lcd_print_itoa(stunde); |
21 | if(stunde>=23){ |
22 | stunde=0; |
23 | }
|
24 | }
|
25 | }
|
26 | }
|
Anfänger schrieb: > beim umspringen von 59 auf 1 Eine Uhr sollte eigentlich von 59 auf 0 und nicht auf 1 springen. > lcd_print_itoa(sekunde); Die Funktion gibt keinen führenden Nullen aus, stimmt's? BTW: Die unteren if würde ich weiter einrücken, dann sieht man auf Anhieb, dass es verschachtelte if sind.
:
Bearbeitet durch User
die Funktion habe ich aus der vorhandenen lib und sieht so aus:
1 | The function itoa() converts the integer value from \c val into an |
2 | ASCII representation that will be stored under \c s. The caller |
3 | is responsible for providing sufficient storage in \c s. |
4 | |
5 | \note The minimal size of the buffer \c s depends on the choice of |
6 | radix. For example, if the radix is 2 (binary), you need to supply a buffer |
7 | with a minimal length of 8 * sizeof (int) + 1 characters, i.e. one |
8 | character for each bit plus one for the string terminator. Using a larger |
9 | radix will require a smaller minimal buffer size. |
10 | |
11 | \warning If the buffer is too small, you risk a buffer overflow. |
12 | |
13 | Conversion is done using the \c radix as base, which may be a |
14 | number between 2 (binary conversion) and up to 36. If \c radix |
15 | is greater than 10, the next digit after \c '9' will be the letter |
16 | \c 'a'. |
17 | |
18 | If radix is 10 and val is negative, a minus sign will be prepended. |
19 | |
20 | The itoa() function returns the pointer passed as \c s. |
21 | */
|
22 | extern char *itoa(int __val, char *__s, int __radix); |
Die Uhr springt ja jeweils durch rücksetzen sekunde=0; auf Null oder muss ich das anderst realisieren?
Anfänger schrieb: > die Funktion habe ich aus der vorhandenen lib und sieht so aus: Sieht nicht so aus als wäre eine führende null. > Die Uhr springt ja jeweils durch rücksetzen sekunde=0; auf Null oder > muss ich das anderst realisieren? Die if-Abfrage sollte auf >59 abfragen und das print sollte erst nach der Abfrage sein.
Max H. schrieb: > print sollte erst nach > der Abfrage sein. und immer 2-stellig erfolgen ! 00 statt 0 sprintf 02d oder per strcpy
:
Bearbeitet durch User
> Sieht nicht so aus als wäre eine führende null.
Jetzt muß ich doch mal fragen wo du das erkennst.
Der TO benutzt lcd_print_itoa,
zeigt uns aber die Beschreibung von itoa. Was lcd_print_itoa ist, das
wissen wir nicht.
Oder habe ich was übersehen ?
Ok ich verstehe schon was ihr meint. Ich versuche mal eine Lösung zu finden bzw. eine andere Funktion für die itoa Variante. Wie kann ich die Printfunktion beeinflussen damit immer 2-stellig geschrieben wird? Das Problem, dass mir irgendwann alles überschrieben wird habe ich aber immer noch nicht verstanden. Irgendeine Idee woher das kommen könnte?
Anfänger schrieb: > also wie gesagt das flag wird in der Iterrupt Routine gezählt. Das ewige und meist auch sinnvolle Dogma mit der möglichst kurzen ISR besagt nicht, dass man darin gar nichts machen darf. Zähl deine Uhr in der ISR hoch. Soviel Zeit muss sein. Und die ist auch vorhanden. Dann tritt auch das Problem, dass ein Inkrement verschluckt wird, gar nicht erst auf. Du zählst einfach bis 60 bzw. 24 und setzt dann auf 0. Nur Ausgabe auf das Display machst du natürlich nicht in der ISR. Sowas ist meist tödlich. mfg.
:
Bearbeitet durch User
Und wie sieht die lcd_print_itoa aus ? Wo kommt die her ? Was macht die ?
:
Bearbeitet durch User
Thomas Eckmann schrieb: > Zähl deine Uhr in > der ISR hoch. Soviel Zeit muss sein. Na, na, na, es reicht doch die Sekunden in der ISR zu inkrementieren. Der Rest ist doch für den µC lllllaaaaannnggsssaaammmmm, sehr llllllllllaaaaaaaannnnnnngggggsssssaaaaaaaammmmmmm.
ich inkrementiere nur ein Flag in der Interrupt Funktion und rufe hier drin die Funktion Uhrzeit auf, in der dann alles weitere abläuft! Sollte doch so richtig sein oder nicht?
Troll schrieb: > Na, na, na, es reicht doch die Sekunden in der ISR zu inkrementieren. Ja. Aber in einer Long-Variable. Das reicht für 136 Jahre. Die Uhrzeit rechnet man erst zur Ausgabe aus. mfg.
Anfänger schrieb: > in der Interrupt Funktion und rufe hier > drin die Funktion Uhrzeit auf, in der dann alles weitere abläuft Das ist nicht so gut. In der ISR solltest du nur das Flag und die Sekunden inkrementieren. Alles weitere machst du in der Hauptschleife.
Wenn das C ist, dann ist lcd_print_itoa eine Funktion. Die macht anscheinend irgendwas mit itoa und gibt was auf das LCD aus. Ob sie das mit/ohne 0 oder Leerzeichen macht, das wissen wir nicht. Wahrscheinlich/anscheinend nicht - aber wenn uns der TO nicht sagt welche Libraries er verwendet, dann ist alles nur geraten und stochern im Nebel. P.s. Die LCD Funktion solle nicht aus dem Interrupt sondern in der Hauptprogrammschleife aufgerufen werden. Aber das ist das 2.te Problem.
:
Bearbeitet durch User
1 | void lcd_data(unsigned char temp1) |
2 | {
|
3 | unsigned char temp2 = temp1; |
4 | |
5 | LCD_PORT |= (1<<LCD_RS); // RS auf 1 setzen |
6 | |
7 | temp1 = temp1 >> 4; |
8 | temp1 = temp1 & 0x0F; |
9 | LCD_PORT &= 0xF0; |
10 | LCD_PORT |= temp1; // setzen |
11 | lcd_enable(); |
12 | |
13 | temp2 = temp2 & 0x0F; |
14 | LCD_PORT &= 0xF0; |
15 | LCD_PORT |= temp2; // setzen |
16 | lcd_enable(); |
17 | |
18 | _delay_us(42); |
19 | }
|
20 | |
21 | void lcd_string(char *data) |
22 | {
|
23 | while(*data) { |
24 | lcd_data(*data); |
25 | data++; |
26 | }
|
27 | }
|
28 | |
29 | void lcd_print_itoa(unsigned int zahl) { |
30 | char buffer [1000]; |
31 | |
32 | itoa(zahl, buffer, 10); |
33 | lcd_string(buffer); |
34 | }
|
buffer[] habe ich eigentlich bei 20 und nicht bei 1000 war nur ein test
Anfänger schrieb: > char buffer [1000]; Ist das nicht ein bisschen übertreiben? Eine führende Null für eine eistellige Zahl könnte man so einbauen:
1 | itoa(zahl, buffer, 10); |
2 | if(buffer[1] == 0x00) |
3 | lcd_data('0'); |
4 | |
5 | lcd_string(buffer); |
:
Bearbeitet durch User
>Eine führende Null für eine eistellige Zahl könnte man so einbauen: > > itoa(zahl, buffer, 10); > if(buffer[1] == 0x00) > lcd_data('0'); OMG. if(zahl < 10) lcd_data('0'); Danach das andere Geraffel.
Du benutzt : lcd_print_itoa(); Du erklärst : itoa(); Du Antwortest : lcd_print ist nur die Funktion um etwas an das LCD zu senden Jetzt haben wir schon 3 unterschiedliche Funktionen im Spiel. Wenn das C ist, dann sind das 3 unterschiedliche Dinge. Aus lcd_print wird nicht plötzlich lcd_print_itoa nur weil man _itoa and den Namen dranhängt. Ich bin fast Sicher die Lösung wäre was in der Richtung
1 | if(flag1>=61){ |
2 | sekunde++; |
3 | flag1=0; |
4 | |
5 | lcd_set_cursor(7,1); |
6 | if ( sekunde < 10 ) |
7 | lcd_print("0"); |
8 | lcd_print_itoa(sekunde); |
9 | |
10 | if(sekunde>60){ |
11 | sekunde=0; |
12 | minute++; |
13 | lcd_set_cursor(4,1); |
14 | if ( minute < 10 ) |
15 | lcd_print("0"); |
16 | lcd_print_itoa(minute); |
17 | if(minute>=59){ |
18 | minute=0; |
19 | stunde++; |
20 | lcd_set_cursor(1,1); |
21 | if ( stunde < 10 ) |
22 | lcd_print("0"); |
23 | lcd_print_itoa(stunde); |
24 | if(stunde > 23){ |
25 | stunde=0; |
26 | }
|
27 | }
|
28 | }
|
29 | }
|
Und das im Hautprogramm aufgerufen. Aber halt nur geraten.
Warum immer so kompliziert?
1 | void lcd_print_time(void) |
2 | {
|
3 | char buffer [12]; |
4 | lcd_set_cursor(1,1); |
5 | sprintf( buffer, "%2u:%02u.%02u", |
6 | (uint16_t)hour, |
7 | (uint16_t)min, |
8 | (uint16_t)sec ); |
9 | lcd_string(buffer); |
10 | }
|
ok, erstmal vielen Dank für die ganzen Hilfestellungen. @Frank, deine Idee bringt mir aufjedenfall die führenden Nullen aber ich überschreibe mir tortzdem bei der Ausgabe auf dem LCD irgendwann meine weiteren Zeilen und Spalten mit irgendwelchen Zahlen. Was mich wundert, dass das manchmal sofort, manchmal erst nach 3 Minuten passiert.
Machst du die LCD Ausgabe mittlerweile in der Hauptprogrammschleife oder noch vom Interrupt aus ?
Troll schrieb: > Hoffentlich reicht der Speicher ... ;-) Auf nem ATtiny2313 könnts knapp werden. Es sollte schon ein ATmega88 sein.
Ich inkrementiere jetzt nur noch das Flag über den Interrup, der Rest läuft im Hauptprogramm. Es scheint jetzt zu funktionieren, keine komischen Zeichen mehr und nichts wird überschrieben. Hauptproblem war dann wohl meine Strukturierung. Vielen Dank für die ganzen Hilfen!!!
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.