Forum: Compiler & IDEs Timer genaue Zeit und entprellen


von Christoph G. (booty3009)


Angehängte Dateien:

Lesenswert?

Hallo!

Ich möchte gerne eine Uhr programmieren. Dazu habe ich mir im Forum die
Routine von Peter Dannegger angeschaut. Ich nutze einen Atmega8535 und
das Programmierboard STK500. Ich habe diesen externen Quarz noch nicht,
sondern nutze den internen vom STK500 8Mhz. Kann ich das auch mit diesem
Programm machen? Ich will es ja erstmal testen! Die Entprellroutine von
Peter Dannegger nutze ich schon und die funktioniert auch sehr gut. Die
Uhr läuft aber auch mit dem Timer. Funktioniert das denn? Wenn ich zum
Beispiel einen Taster drücke und eine LED damit an und aus schalte, soll
sich ja an der Uhrzeit nichts ändern. Wie realisiere ich das? Später,
wenn ich die Uhr hinbekommen habe möchte ich eine Zeit als String vom PC
auf dem uC senden. Die Zeit soll dann mit der Uhrzeit des uC verglichen
werden. Wenn die Zeiten gleich sind, soll z.B. eine LED einegeschaltet
werden.
Jetzt möchte ich aber erstmal die Uhrzeit realisieren. Kann ich das im
Anhang aufgeführte Programm so übernehmen oder was muss ich noch
abändern? Bleibt die Berechnung gleich, wenn ich statt des externen
Quarzes den interne Frequenz des STK500 von 8Mhz einstelle?

von STK500-Besitzer (Gast)


Lesenswert?

>internen vom STK500 8Mhz

Der interne "Quarz" ist ein Oszillator, der mit 3,686 MHz läuft.
Aus dem STK-500-Userguide:
"The frequency of the software generated clock can be set from 0 to 
3.68Mhz. The default value is 3.68Mhz. Section "Oscillator" explains how 
to set the clock frequency from AVR Studio."

Wenn du 8KHz hast, dann sind die controllerintern per RC-Oszillator 
erzeugt, welcher relativ ungenau ist...
Die STK500-Frequenz ist da genauer...

Im Programm ist noch die von PeDa verwendete Quarzfrequenz angegeben.
Ansosnten könnte es funktionieren. Aber waum gibts du die Sekunden per 
DDR aus und nicht per PORT?

von Christoph G. (booty3009)


Lesenswert?

Wie schreibe ich den Code um damit eine LED am PORTA im Sekundentakt 
blinkt? Ich sehe bei dem Code noch nicht so richtig durch.

von xyz (Gast)


Lesenswert?

Wo liegt denn Dein Problem ?
Man nehme den TimerIRQ, zähle darin die Sekunden hoch und schalte die 
LED im main je nach Sekunde an oder aus:
1
for(;;){
2
    if( second == 60 )
3
      second = 0;
4
    if(second%2)
5
      PORTA &= ~(1<<PINA0); //LED aus
6
    else
7
      PORTA |= (1<<PINA0);  // LED an
8
  }
Also statt nun binär wie im Code acht LEDs gleichzeitig zu schalten, 
wird nur eine getoggelt.
Oder meinst Du etwas anderes ?

von Christoph G. (booty3009)


Lesenswert?

Danke für die Antwort. Ich habe es schon selber hinbekommen.
Ich möchte gerne noch über die RS232 Schnittstelle vom Rechner einen 
String senden z.B. eine "12". Wenn der String am uC ankomt dann soll die 
Sekunde auf 12 gestellt werden und weiterlaufen. Wie ich einen String 
mit dem uC empfange weiß ich, aber wie setze ich dann die Zeit?

von Fred S. (Gast)


Lesenswert?

Hi Christoph,
>... eine "12". Wenn der String am uC ankomt dann soll die
> Sekunde auf 12 gestellt werden und weiterlaufen. Wie ich einen String
> mit dem uC empfange weiß ich, aber wie setze ich dann die Zeit?
1
int8_t sekunde;
2
sekunde=atoi(string_mit_Sekundenwert);

Gruß

Fred

von Christoph G. (booty3009)


Lesenswert?

Die Variable Sekunde benötige ich aber als unsigned char und nicht als 
integer. Wie wandle ich das um?

von Karl H. (kbuchegg)


Lesenswert?

Christoph G. wrote:
> Die Variable Sekunde benötige ich aber als unsigned char und nicht als
> integer. Wie wandle ich das um?

du kannst genauso atoi dafür benutzen.

von Fred S. (Gast)


Lesenswert?

Hallo Christoph,
> Die Variable Sekunde benötige ich aber als unsigned char und nicht als
> integer. Wie wandle ich das um?

Karl Heinz hat Dir die Antwort schon gegeben. Denk mal nach: "Sekunde" 
kann maximal welchen Wert annehmen? Ja, 60. Wie viele Bits sind dafür in 
einer int8_t Variablen erforderlich? Wird dabei das Vorzeichen-Bit 
gesetzt? Nein? Dann gibt es auch keine Komplikationen bei der Umwandlung 
in unsigned! Falls Du dies nicht nachvollziehen kannst, empfielt sich 
ein Tutorial zu Datentypen.

Gruß

Fred

von Christoph G. (booty3009)


Angehängte Dateien:

Lesenswert?

Hallo!

Ich habe im Anhang meinen Quellcode geändert bereitgestellt. Beim 
compilieren kommen zwei Warnungen. Eine betrifft "atoi". Es kommt auch 
nichts an auf über RS232. Was habe ich falsch gemacht?

von Fred S. (Gast)


Lesenswert?

Hallo Christoph,

Du gibst die Sekunde an "LED_DIR" aus, und das ist DDRA. Wahrscheinlich 
willst Du aber an PORTA o.ä. ausgeben!

Der Befehl
1
  
2
  DDRA  |= (1 << PA6);
 im Anschluss an
1
  LED_DIR = 0xFF;

bewirkt auch nichts, da schon alle Bits gesetzt sind.

Welche Warnung gibt Dir denn der Compiler?

Gruß

Fred

von Christoph G. (booty3009)


Lesenswert?

Warnung:

avr-gcc.exe  -mmcu=atmega8535 -Wall -gdwarf-2 -O0 -MD -MP -MT uhr.o -MF 
dep/uhr.o.d  -c  ../uhr.c
../uhr.c: In function `main':
../uhr.c:130: warning: passing arg 1 of `uart_puts' makes pointer from 
integer without a cast
../uhr.c:139: warning: implicit declaration of function `atoi'
Build succeeded with 2 Warnings...


Ich habe oben einmal F_CPU definiert und dann XTAL. Darf man das 
überhaupt?

von Johannes M. (johnny-m)


Lesenswert?

Christoph G. wrote:
> ../uhr.c:130: warning: passing arg 1 of `uart_puts' makes pointer from
> integer without a cast
uart_puts will einen Pointer (und zwar genaugenommen einen Pointer auf 
ein Array von const char mit einem darin befindlichen nullterminierten 
String) übergeben bekommen, second ist aber eine einfache Variable und 
kein Pointer. Mit dem was Du da machst, kann alles Mögliche passieren, 
nur wahrscheinlich nicht das, was Du willst.

> ../uhr.c:139: warning: implicit declaration of function `atoi'
Du hast die stdlib.h nicht eingebunden.

> Ich habe oben einmal F_CPU definiert und dann XTAL. Darf man das
> überhaupt?
Du kannst definieren soviel Du willst. Ein "#define EINS 1" bedeutet 
nur, dass an allen Stellen im Code, an denen "EINS" steht, eine 1 
eingefügt wird. Wenn Du noch ein #define ONE 1 dahinterschreibst, werden 
eben alle "ONE"s auch durch 1en ersetzt...

von Rolf Magnus (Gast)


Lesenswert?

> ../uhr.c:130: warning: passing arg 1 of `uart_puts' makes pointer from
> integer without a cast

uart_puts erwartet einen Zeiger (auf den Anfang eines Arrays aus char). 
Stattdessen übergibst du ihm einen unsigned char. Das paßt überhaupt 
nicht.

> ../uhr.c:139: warning: implicit declaration of function `atoi'

Dir fehlt der Header <stdlib.h>.

von Fred S. (Gast)


Lesenswert?

Hallo Christoph,

> Ich habe oben einmal F_CPU definiert und dann XTAL. Darf man das
> überhaupt?
Normalerweise wird F_CPU aus den voreingestellten Parametern (beim 
AVRStudio: "Project"|"Configuration Options") übernommen. Wie es bei 
reiner Verwendung eines "makefile" geht, weiß ich nicht. Welche 
"toolchain" benutzt Du?

Was Johannes zu uart_puts() sagt, stimmt. Wenn Du die Sekunde wieder in 
einen String zurückwandeln möchtest, könntest Du "itoa()" verwenden. 
Oder Du nimmst einfach Deinen "buffer" -- oder setzt Du atoi() auch ein, 
um führende Leerzeichen im übertragenen String zu unterdrücken?

"position" wird nicht so funktionieren, wie Du es Dir wünschst, denn es 
müsste mindestens als "volatile" deklariert sein. Da Du diese Variable 
nur innerhalb der ISR benötigst, wäre es noch besser, "position" 
innerhalb *der* ISR als "static" zu deklarieren und zu 
initialisieren:
1
static uint8_t position=0;

Ich habe nur ganz grob über Deinen Code geschaut, es können durchaus 
noch weitere Probleme drin sein. Versuche mal, die Vorschläge von 
Johannes und mir zu implementieren.

Viele Grüße

Fred

von Christoph G. (booty3009)


Lesenswert?

Ich habe jetzt die <stdlib.h> implementiert. Jetzt kommen keine 
Warnungen mehr.

Die Variablen "second" und "buffer" habe ich wie unten aufgeführt 
deklariert. Ist die aufgeführte Zuweisung so richtig?

unsigned char volatile second;
char buffer[10];

second = atoi(buffer);

Ich möchte es über RS232 wieder zurückschicken. Da habe ich folgende 
zusätzliche Variable deklariert:

char second2[10];

Das mit der Zuweisung stimmt glaube ich nicht, denn ich bekomme zwei 
Fehlermeldungen beim compilieren.

second2 = itoa(second);

Fehlermeldungen:
../uhr.c:133: error: too few arguments to function `itoa'
../uhr.c:133: error: incompatible types in assignment

Wie muss ich es richtig machen?

von Fred S. (Gast)


Lesenswert?

Hallo Christoph,

versuche doch erst einmal, ein Problem (das mit der Binärausgabe) zu 
lösen, ehe Du die serielle Ausgabe probierst. Sonst suchst Du immer 
Fehler an mehreren Stellen gleichzeitig. Das ist ein wichtiges Element 
jeder Fehlereingrenzung. Die serielle Eingabe (siehe Beitrag oben zu 
"position") muss zuerst noch in Ordnung gebracht werden.

Ich empfehle Dir dringlich, Dich mit den Bibliotheksfunktionen vertraut 
zu machen, damit Du Dir Fragen wie die zur Warnung bei Deiner itoa() 
selbst beantworten kannst. Hier eine gute Adresse: 
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html#g4f6b3dd51c1f8519d5b8fce1dbf7a665
Und das ganze als PDF: 
http://download.savannah.gnu.org/releases/avr-libc/avr-libc-user-manual-1.4.4.pdf

Viele Grüße

Fred

von Christoph G. (booty3009)


Angehängte Dateien:

Lesenswert?

Hallo!

Ich habe jetzt nochmal das Programm umgeschrieben. Nach 10 Sekunden soll 
die LED kurz angehen. Das macht sie auch. Wenn ich über RS232 vom 
Rechner z.B. eine 9 schicke geht sie nach einer Sekunde an. Die RS232 
Kommunikation funktioniert also auch. Jetzt möchte ich aber vom yC die 
Sekunde auf den Rechner ausgeben. Dazu muss ich die Variable "second", 
die als "unsigned char volatile second" deklariert ist in einen String 
umwandeln und dann in eine andere Variable z.B. "buffer" schreiben. Die 
Umwandlung soll glaub ich mit "itoa" funktionieren. Ich bekomme es aber 
nicht hin. Wie muss ich den Quelltext im Anhang abändern, dass auch das 
funktioniert?

von Fred S. (Gast)


Lesenswert?

Hi,
1
itoa((int)second, second2, 10);
2
uart_puts(second2);

Was genau hast Du daran nicht hinbekommen? Was ist an der Dokumentation, 
auf die ich Dich im letzten Posting hingewiesen habe, nicht zu 
verstehen?

Lies noch einmal nach, wie man Variable mit "volatile" deklariert.
"position" ist immer noch nicht richtig deklariert (siehe 2 Beiträge von 
mir weiter oben). Ich gebe es auf, Dir hier Tipps zu geben.

Gruß

Fred

von Christoph G. (booty3009)


Lesenswert?

Danke für deine Auskunft.
Ich habe auch jetzt die Variable "position" geändert, dass hatte ich 
total vergessen.
Ich habe es ja vorhin so ausprobiert wie du es geschrieben hast, doch 
ich habe das int vor second vergessen. Trotzdem nochmal danke!

Wie mache ich es denn, das die Sekunde nur einmal zum Rechner geschickt 
wird und nicht viele male hintereinander?

von Fred S. (Gast)


Lesenswert?

Hi Christoph,

> Ich habe auch jetzt die Variable "position" geändert, dass hatte ich
> total vergessen.
OK

> Wie mache ich es denn, das die Sekunde nur einmal zum Rechner geschickt
> wird und nicht viele male hintereinander?
Die Daten sollten (wegen des Flags "habekommando") nur 1x für jeden 
empfangenen String gesendet werden.

Gruß

Fred

von Christoph G. (booty3009)


Angehängte Dateien:

Lesenswert?

Ja das ist richtig, aber das ist doch nur für den Empfang auf den yC.
Ich möchte ja vom yC zum PC die Zeit senden. Ich habe das Programm noch 
für Stunden, Minuten und Sekunden erweitert. Der yC sendet zwar die 
Sekunden raus aber immer zu hintereinander. Ich möchte das er die 
Stunden und Minuten in formatierter Uhrzeitform sendet. Wie mache ich 
das?
Im Anhang findest du das Programm.

von Fred S. (Gast)


Lesenswert?

Hi,

> Ich möchte das er die Stunden und Minuten in formatierter Uhrzeitform
> sendet. Wie mache ich das?
Dein Programm habe ich mir nicht noch einmal angesehen.
Du stellst eigentlich zwei Fragen. Dazu gleich. Die beste Vorgehensweise 
ist, sich so etwas genau zu überlegen, ehe man Code schreibt. Man 
fragt sich, was wie, wann, unter welchen Umständen, usw. passieren soll 
und welcher Prozess von welchen anderen Prozessen abhängig sein soll. 
Sind diese Fragen beantwortet, kann man ans Kodieren denken.

Erstens fragst Du, wie man die Zeit nur einmal sendet. Dafür schlage ich 
vor, Du detektierst, wann ein neuer Zeitwert (zu testen wäre ja nur der 
Sekundenwert!) vorliegt. Ist das gegeben, sendest Du die Zeit einmal.

Zweitens fragst Du, wie man die Zeit formatieren kann. Vermutlich denkst 
Du an etwas wie HH:MM:SS. Dazu musst Du lernen, wie man Strings 
formatiert. Alternativ kannst Du ja HH schicken, dann den Doppelpunkt, 
dann die Minuten, usw. Die "echten" Befehle zur String-Formatierung 
fressen manchmal viel Speicher (z.B. sprintf(), das mag aber trotzdem 
eine gute Lösung sein!). Da Deine Daten aber in einem festen Format 
(Stunden, Minuten und Sekunden zweistellig) vorliegen, kannst Du auch 
einfacher vorgehen: Du nimmst einen String (z.B.
1
 char Zeitstring[]="  :  :  ";
) und schreibst die Zeitwerte so in diesen String (Vorsicht, fiese 
Falle!):
1
itoa(stundeninteger, Zeitstring, 10);
2
itoa(minuteninteger, &Zeitstring[3], 10);
3
itoa(sekundeninteger,&Zeitstring[6], 10);
Jetzt habe ich Dich absichtlich aufs Glatteis geführt. Hast Du's 
gemerkt? Das geht zwar, aber es gibt einen Haken: itoa() schreibt '\0' 
an das Ende eines jeden Strings, überschreibt Dir also die Doppelpunkte! 
Die musst Du dann erneut setzen.

Wichtige Stringfunktionen, die Du lernen solltest, sind u.a.: strcpy(), 
strcat(), strlen(), strstr().

Das alles nur zur Anregung -- es gibt viele andere mögliche Wege. Die 
Implementierung bleibt "eine Öbung föör den Schööler".

Viel Erfolg,

Fred

von Christoph G. (booty3009)


Lesenswert?

Danke!
Ich werde es versuchen!

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
Noch kein Account? Hier anmelden.