Morgen!
Ich wollte mal rumhören, ob grundsätzliches Interesse an einem
Stoppuhr-Code bestehet. Es handelt sich dabei eher um ein
Anfängerprojekt. Ein bißchen mit Timer, Interrupts und so. Also nichts
mit I2C oder Flash oder so ;) ...
Wenn Ja kann ich heute mittag gern mal meinen Code und eine Beschreibung
posten...
Gruß,
Joachim
Ok, also hier hab ich mal mein Stoppuhr-Programm angehäng. Wie gesagt,
es ist ein Projekt von einen Anfänger für Anfänger.
Aber es funktioniert gut und zuverlässig.
Allgemeines:
Als Hardware verwende ich das Pollin-Evaluation-Board. Hier ist es so,
daß die vorhandenen Taster der PortPin auf high ziehen. Gefällt mir zwar
nicht, ist aber so. Darum sprechen die Interrupts auf "rising edges" an.
µC ist ein ATmega32, der mit nem externen 16 MHz-Quarz läuft.
Ursprünglich war es für einen mega8 gedacht, aber da hat mich das Board
etwas eingeschränkt, weil das dann mit den INT-Pins nicht mehr gepasst
hätte. Man könnte es zwar umschreiben, daß es auf nem mega8 läuft, aber
hmmm... wird das nächste Update =). Ja, PortA hab ich mal frei gelassen,
falls man den ADC mal noch braucht.
Die sechs 7-Segment-Anzeigen, auf denen die Ausgabe stattfindet, sind
wie im Multiplex-Tutorial auf dieser Seite angeschlossen, nur eben an
anderen Ports.
Die Stoppuhr hat eine Auflösung von 0,0001 Sekunden, oder 100 µs. Dafür
wird Timer2 verwendet weil.. oh, das weiß ich nicht mehr. Man könnte
auch einen anderen nehmen. Der Vorteiler steht auf 32. dabei ergibt sich
folgende Rechnung:
16000000/32 = 500000 -> in einer Sek wird also bis 500000 gezählt. D.h.
in 1/10000 Sek zählt er bis 50. Daher ist die OCR2 = 49. Warum das mit
50 nicht ging weiß ich nicht so genau. Aber mit 49 läuft das laut
Simulator 100%ig genau. Bei z.B. 4 MHz müßte der Vorteiler einfach auf 8
stehen.
Bei sechs Anzeigestellen kann man so Zeiten bis max 99,9999 Sek stoppen.
So, bei Fragen aber auch Anregungen immer raus damit. Weitere
Erläuterungen stehen als Comments im Code. Aber nicht sooo viel nörgeln,
ok? Wie gesagt, das Prog ist natürlich nicht perfekt (ISRs zu lang, ich
weiß... ;) ) und sooo lange mach ich das noch nicht.
So long,
Gruß,
Joachim
ACHTUNG: es ist ein verfluchtes Programm: 666 Bytes >:-]
Hell yeah!
sieht doch schonmal gar nicht so schlecht aus. Ich mache schon seit ein
paar Jahren mit avrs rum und hätte es fast nicht anders gemacht. Schön
ist es auch dass du für adresse und anzwert tabellen(array) genommen
hast. Kleiner Tipp noch zum eindämmen der Schreibarbeit:
Solchen statischen arrays würde ich so schreiben:
uint8_t anzwert[]={0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80,
0x90};
außerdem kann man bei adresse und anzwert das volatile weglassen. Das
spart enorm viel Code da sonst der optimierer nicht "loslegt"
Hallo Ulrich!
danke für die Antwort!
Das mit dem Füller der Arrays ist echt gut. Hab mich beim programmieren
auch öffters gefragt, ob ich die dinger nicht "in einem Rutsch" füllen
kann. Aber ok, so wirds gehn :) .
Muß auch gestehen, daß ich nicht ganz gecheckt habe, was volatile macht.
Ich wußte nur, daß es die Register für Hardware-Zugriffe freigibt. Und
da dachte ich, daß das ja nicht schädlich sein kann...
Ach ja: die Taster der Interrupts sind nicht entprellt, da die Schalter
hardwaremäßig schon entprellt sind und auch so recht wenig prellen. Habe
daher auf eine Software-Entprellung verzichtet. Es wurde also nicht
einfach "vergessen", m'kay?
Aber wenn ich das Programm änder... dann hab ich nicht mehr die coole
Größe von 666 Bytes ;) !
Gruß,
Joachim
Ulrich wrote:
> sieht doch schonmal gar nicht so schlecht aus. Ich mache schon seit ein> paar Jahren mit avrs rum und hätte es fast nicht anders gemacht.
Naja, Multiplexen in der Mainloop ohne Timerinterrupt ist schon ziemlich
strange, würde mir nie einfallen. Damit verbaut man sich gründlich das
Programmieren größerer Projekte.
Der Code erzeugt auch Geisterdigits, da das nächste Digit erst nach dem
Einschalten des Digits ausgeben wird.
Also erst PORTB ausschalten, PORTC ändern und PORTB wieder einschalten.
Zählen und Rechnen würde ich immer im Lieblings-Format der CPU, also
binär.
Nur zur Ausgabe würde ich dezimal wandeln. Damit ergibt sich kleinerer
Code und weniger CPU-Last.
Peter
5x (fast) der gleiche Code hintereinander schreit eigentlich nach einer
Funktion.
Du kannst auch (wie von Peter Dannegger bereits erwähnt) auch binär
rechnen und dann den Wert z.B. mit itoa/ltoa umwandeln.
Hi nochmal!
Danke für die Tipps.
@Peter:
es ist aber nenmal kein größeres Projekt. Denn wie mehrfach erwähnt kann
ich noch keine 10-jährige Programmiererfahrung ausweisen wie z.B.
Ulrich.
Geisterdigits werden nicht erzeugt. Zum einen, weil jeder Anzeigewert
1 ms gehalten wird (das wäre im Verhältnis zu einer Werteüberlappung
sehr lange). Aber die Werte überlappen sich nicht, da in Line 109 (glaub
ich) einmal 0xFF ausgegeben wird, was invertiert für "alles aus" steht.
Zu binär/dezimal: das versteh ich nicht ganz. Mir ist nicht aufgefallen,
daß ich überhaupt irgendwo in dezimal "rechne". Die Werte der Anzeige
werden doch allen in HEX übergeben. Mit Dezimal kann die Anzeige ja
nüscht anfangen grübel... ok, ich könnte den Grenzwert von 49 noch in
0x31 umändern. Aber obs was bringt?!
@Mike
du meinst sicher die ISR vom Timer2. Da, das fiel mir auch auf. Aber
irgendwie hatte ich keine zündende Idee, um das schlanker zu machen. Und
so fiel es mir leichter den Überblick zu behalten. Abr recht hast du. Es
mag zweifelsohne elegantere Lösungen geben. Ich üb' ja noch...
Gruß,
Joachim
Joachim wrote:
> es ist aber nenmal kein größeres Projekt. Denn wie mehrfach erwähnt kann> ich noch keine 10-jährige Programmiererfahrung ausweisen wie z.B.> Ulrich.
Willst Du jetzt etwa aufhören?
Oder willst Du auch mal größere Sachen machen?
Dann ist es durchaus sinnvoll, sich nicht erst Techniken anzugewöhnen,
die später hinderlich sind.
> Geisterdigits werden nicht erzeugt.
Mach einfach mal das Zimmer dunkel, dann siehst Du es.
> Zum einen, weil jeder Anzeigewert> 1 ms gehalten wird (das wäre im Verhältnis zu einer Werteüberlappung> sehr lange). Aber die Werte überlappen sich nicht, da in Line 109 (glaub> ich) einmal 0xFF ausgegeben wird, was invertiert für "alles aus" steht.
Aber Du schaltest wieder ein, bevor der neue Code ausgegeben wird.
Ausschalten nützt garnichts, wenn man es in der falschen Reihenfolge
macht.
> Zu binär/dezimal: das versteh ich nicht ganz. Mir ist nicht aufgefallen,> daß ich überhaupt irgendwo in dezimal "rechne".
Solltest Du Deinen eigenen Code nicht verstehen?
1
if(zeiger[0]>9)
2
{
3
zeiger[0]=0;
4
zeiger[1]++;
5
}
Du zählst nur von 0..9 und das nennt sich dezimal.
Binär heißt, ein Byte zählt von 0..255, 2 Byte von 0..65535 usw.
Peter
> Geisterdigits werden nicht erzeugt.
Es gibt sie ganz sicher und sie nerven...
Eine Variante für
1
if(zeiger[0]>9)
2
{
3
zeiger[0]=0;
4
zeiger[1]++;
5
}
6
7
(noch4x)
wäre auch:
1
for(i=0;i<6;i++){
2
if(zeiger[i]>9)
3
{
4
zeiger[i]=0;
5
zeiger[i+1]++;
6
}
7
}
Sieht so deutlich eleganter aus ;).
Gleich binär zu rechnen hätte den Vorteil das du nur einen Zähler
erhöhen musst. Du rechnest den Wert dann nur noch zur Anzeige um.
@Joachim:
Mit dieser Interrupt-Programmiertaktik wirst du recht bald auf der Nase
landen. Klar klappt das mit 2 Tastern und einem Timer noch recht
überschaubar.
Aber was passiert, wenn mitten im Timer-Interrupt noch der
Reset-Taster-Interrupt kommt? Oder der Start-Stop-Interrupt? Dürfen sich
die Interrupts gegenseitig unterbrechen? Oder stoppt die Start-Taste
auch die Interruptbearbeitung des Timers? Was passiert, wenn da noch ein
paar andere Eingangssignale dazukommen?
Machs doch wie in der SPS-Programmierung (oder wie Windows):
Durchlaufe dauernd eine Hauptschleife (so etwa wie die MUX-Schleife) mit
Vollgas, und schau dabei nach ob sich was getan hat (Taster, Timer...)
und reagiere dann darauf. Die Interrupt-Routinen setzen dann bestenfalls
nur Flags (z.B. der Timer ein 100us-Flag und ein 1ms-Flag), die dann in
der Hauptschleife abgefragt werden. Gerechnet wird in einem Interrupt
nichts! Auf diese Art und Weise kann ich einfach eine weitere Aufgabe
(neudeutsch: Task) mit in die Hauptschleife einbinden.
etwa so:
1
:
2
:
3
chartic100us;// Flags
4
charcnt100us;
5
chartic1ms;
6
charkeyStartStop;
7
charkeyStartStopOld;
8
charkeyReset;
9
charkeyResetOld;
10
charlauf;
11
:
12
:
13
main()
14
Init();// Timer, Ports...
15
lauf=0;
16
for(;;){
17
// Eingänge abholen
18
keyStartStopOld=keyStartStop;// merken für Flankenauswertung
@Mike:
ui, danke :)
das mit dem "zeiger[i+1]++;" war das Entscheidende, was mir bei meinen
Überlegungen gefehlt hat.
Das ist wirklich wesentlich hübschen. Hab das gleich mal umgesetzt.
das ganze sieht in der ISR jetzt also so aus:
1
ISR(TIMER2_COMP_vect)
2
{
3
zeiger[0]++;
4
5
for(i=0;i<6;i++)
6
{
7
if(zeiger[i]>9)
8
{
9
zeiger[i]=0;
10
zeiger[i+1]++;
11
12
if(zeiger[5]>9)
13
{
14
zeiger[0]=0;
15
zeiger[1]=0;
16
zeiger[2]=0;
17
zeiger[3]=0;
18
zeiger[4]=0;
19
zeiger[5]=0;
20
}
21
}
22
}
23
}
damit hat der code "nurnoch" 632 Byte... :(
Das geistern hab ich behoben, indem ich einfach nicht die Adressen,
sondern die Daten einmal aus gemacht habe. Wenn sich da nicht wieder ein
hinterhältiger Denkfehler eingeschlichen hat müßte das so richtig sein.
Eins noch: wenn ich da, wo "zeiger[0]++;" steht nen Breakpoint hinmache
und das Prog laufen lasse braucht der Simulator immer 100µs. Aber rund
alle 22 Klicks braucht er 160µs, weil er die main() von vorne beginnt
und nicht einfach in der while-Schleife bleibt. Wisst ihr warum?!
Danke nochmal und viel Spaß noch!
Joachim
@ lkmiller
klar, da hast du recht. Taktisch ausgereift war meine Lösung auch nicht.
Das habe ich aber oben weiter schon mehrfach erwähnt. Trotzdem danke für
den Tip. An diese ollen Sachen mit "Priorität hier" und
"zulassen/sperren da" muß ich mich noch etwas gewöhnen. Aber wie
gesagt... das mit der Übung, nech?
MfG
Joachim wrote:
> Das ist wirklich wesentlich hübschen. Hab das gleich mal umgesetzt.> das ganze sieht in der ISR jetzt also so aus:
Vorsicht!
Wenn du Indexberechnung in Arrays machst, dann überleg lieber
3 mal, ob der Index auch immer im erlaubten Bereich bleibt.
zeiger ist ein Array mit 6 Elementen: 0, 1, 2, 3, 4, 5
> ISR(TIMER2_COMP_vect)> {> zeiger[0]++;>> for(i=0; i<6; i++)
i nimmt nacheinander die Werte 0, 1, 2, 3, 4, 5 an, damit ...
> {> if(zeiger[i] > 9)> {> zeiger[i]=0;> zeiger[i+1]++;
ergibt i + 1 hier die Werte 1, 2, 3, 4, 5, 6
Autsch. Ein Arrayelement zeiger[6] existiert aber nicht!
> alle 22 Klicks braucht er 160µs, weil er die main() von vorne beginnt> und nicht einfach in der while-Schleife bleibt. Wisst ihr warum?!
Könnte eine fehlerhafte Spannungsversorgung sein, die einen
Reset auslöst.
@Joachim:
Das wird schon.
"Übung macht den Kleister" sagt der Malerlehrling.
Schon gar nicht ohne, wie du jetzt schon mit Pointern um dich wirfst ;-)
:
:
@Karl heinz Buchegger
jo, für einen Moment hab ich da auch drüber nachgedacht. Aber es
funktionierte dann doch letztendlich. Ich dachte wenn was nicht stimmt
wird der Compiler oder so schon nörgeln... ;)
Das mit der fehlerhaften Spannungsversorgung glaub ich nicht. Die hätte
ja mit dem Simulator nix zu tun. Und in real zählen die sechs Anzeigen
bei mir auf dem Schreibtisch ja von 000000 bis 999999. Aber nett, daß du
dir Gedanken gemacht hast.
@lkmiller
wie meinste das? Ist das dämlich? Ich hatte sowas schonmal etwas kleiner
in ASM gemacht. Da fand ich das mit den Pointern gar nicht so doof. Und
da fand ich das noch viel schlimmer mit indirekter Adressierung und so.
Ok, das war aber auch auf nem PIC.
Aber im nachhinein find ich es immer noch nicht doof, weil ich dann in
jedem "zeiger" den dezimal-wert der jeweiligen Anzeigenstelle stehen
hab. Das könnte ich dann nämlich gebrauchen, wenn das mal auf einem LCD
ausgegeben werden soll. Dann muß ich von zeiger[0-5] nurnoch nen String
oder so machen. also so war meine grobe Überlegung. wie das geht weiß
ich aber noch nicht... ;)
@kbuchegg
:
:> und das Prog laufen lasse braucht der Simulator immer 100µs. Aber
rund
:> alle 22 Klicks braucht er 160µs, weil er die main() von vorne beginnt
:> und nicht einfach in der while-Schleife bleibt. Wisst ihr warum?!
:
:Könnte eine fehlerhafte Spannungsversorgung sein, die einen
:Reset auslöst.
:
Wird der Simulator mit Spannung versorgt ;-)
@Joachim:
Was sind 22 Klicks??
Kommt da evtl. der Watchdog??
Joachim wrote:
> @Karl heinz Buchegger> jo, für einen Moment hab ich da auch drüber nachgedacht. Aber es> funktionierte dann doch letztendlich.
Vorsicht: Es scheint zu funktionieren.
Dein Problem ist, dass du eine Speicherstelle veränderst, die
nicht zum Array gehört. Wenn du Glück hast, ist das harmlos.
Wenn du Pech hast, liegt genau an dieser Stelle eine andere
Variable im Speicher, die dann plötzlich scheinbar von alleine
ihren Wert ändert.
> Ich dachte wenn was nicht stimmt> wird der Compiler oder so schon nörgeln... ;)
Der Compiler ist nur dafür zuständig, dass du die Grammatikregeln
einhältst. Die korrekte Logik ist dein Bier.
"Der Mann liest das Auto." ist auch ein grammatikalisch korrekter
deutscher Satz. Er besteht aus Subjekt Verb Objekt. Trotzdem ist
seine 'Logik' fehlerhaft indem er keinen Sinn ergibt. Der Compiler
prüft nur ob die Grammatik stimmt und wird diesen Satz als
deutschen Satz durchgehen lassen.
> Das mit der fehlerhaften Spannungsversorgung glaub ich nicht. Die hätte> ja mit dem Simulator nix zu tun.
Es gibt auch noch andere Möglichkeiten, die ich aber im Code nicht
kontrolliert habe.
Eine ist zb. wenn du einen Interrupt frei gibst für den es keine
ISR gibt.
> wie meinste das? Ist das dämlich?
anzwert[zeiger[a]];
Überhaupt nicht.
Ganz im Gegenteil. Du glaubst gar nicht, wie lange viele Neulinge
brauchen, bis sie so ein Konstrukt sich einzusetzen wagen.
> Aber im nachhinein find ich es immer noch nicht doof, weil ich dann in> jedem "zeiger" den dezimal-wert der jeweiligen Anzeigenstelle stehen> hab.
In deinem Fall, wenn du praktisch nichts mit der Zeit machst, ist
das schon ok. Du brauchst die 'Zeit' nur für Ausgabezwecke und dort
wiederrum benötigst du sie als einzelne Ziffern. Ergo ist diese
Repräsentierung dafür optimal.
Sobald du aber damit etwas rechnen musst, ändert sich das Blatt.
Dann wird diese Darstellung eher hinderlich.
Die einzelnen Ziffern aus einer Zahl zu extrahieren, ist kein
großes Problem. Und mit Zahlen im Bereich 0 bis 10000, die auch
tatsächlich Zahlen sind, rechnet es sich nun mal leichter, als
mit den einzelnen Ziffern.
@Joachim
Sorry wegen dem etwas zu hohem Index im Beispiel, aber da siehst du mal
wie leicht man mit der Indexzählerei in C auf die Nase fallen kann ;).
Das ist einer der Fehler bei denen sich das Programm sehr merkwürdig
verhält und die man dann ewig sucht...
Die meisten anderen Programmiersprachen hauen einem so etwas zur
Laufzeit um die Ohren.
@lkmiller
Ja, das mit den Klicks hätt ich n bissl genauer erklären können: Ich
habe bei der Stelle "zeiger[0]++;" einen Breakpoint gemacht und klicke
dann immer auf "Run", bis er da stehen bleibt. Da braucht er bei den
ersten 21 Durchgängen immer 100µs und beim 22. Mal dann 160µs. So war
das gemeint...
@Karl heinz Buchegger
dann fällt mir spontan als Lösung ein einfach das Array zeiger um 1
größer zu machen. Dann ist der Speicher reserviert und der Logik genüge
getan... dann "fährts" auch ;). Ich habs aber grad nicht vorliegen, war
nur ne spontane Idee.
Wo ich schonmal dabei bin: ich will das ganze nachher/irgendwann (oder
nächstes Jahr...) mal in Geschwindigkeit umrechnen. Dafür will ich alle
Werte in zeiger[0-5] in einem Variablen zusammenfassen, daß da dann zum
Beispiel ne Variable namens "zeit" ist, in der dann 846218 steht. Wie
kann ich das machen? Was muß ich beachten?
Und damit will/muß ich dann ja auch noch rechnen. Was wird alles schief
gehen?
Ich weiß, mir fehlen "etwas" die C-Grundlagen. Könnt ihr mir ein Buch
über µC-Programmierung in C empfehlen?
MfG
Joachim wrote:
> @Karl heinz Buchegger> dann fällt mir spontan als Lösung ein einfach das Array zeiger um 1> größer zu machen. Dann ist der Speicher reserviert und der Logik genüge> getan... dann "fährts" auch ;). Ich habs aber grad nicht vorliegen, war> nur ne spontane Idee.
Kannst du so machen.
Die Alternative dazu wäre mit einem if zu entscheiden ob es noch
eine nächste Stelle gibt und dann nur dann zu erhöhen, wenn 'links'
von der aktuellen Ziffer noch etwas ist.
Sprich: Das i abtesten, ob i+1 nicht größer als 5 wird.
> Wo ich schonmal dabei bin: ich will das ganze nachher/irgendwann (oder> nächstes Jahr...) mal in Geschwindigkeit umrechnen. Dafür will ich alle> Werte in zeiger[0-5] in einem Variablen zusammenfassen, daß da dann zum> Beispiel ne Variable namens "zeit" ist, in der dann 846218 steht. Wie> kann ich das machen? Was muß ich beachten?
Beobachtung:
Du hast die beiden Ziffern 1 5 (welche eine gedachte 15 ergeben)
Was ergibt dann 1 * 10 + 5?
In deinem Fall würde das dann lauten:
Ziffer[0]
+ Ziffer[1] * 10
+ Ziffer[2] * 100
+ Ziffer[3] * 1000
+ Ziffer[4] * 10000
+ Ziffer[5] * 100000
Beachten musst du lediglich, dass dir keine Berechnung überläuft.
Ein 16 Bit int zb. geht nur bis 32767 hoch. Im obigen sind alle
(bis auf eine) Multiplikationen und Additionen int Berechnungen.
Problematisch ist zb Ziffer[4] * 10000
Wenn Ziffer[4] den Wert 2 hat, dann ergibt 2 * 10000 = 20000
Das wäre noch im Bereich, den ein 16-Bit int abdecken kann
(Obergrenze: 32767). Aber wenn Ziffer[4] den Wert 7 hat, dann
hast du bereits einen Overflow, da ja 7 * 10000 = 70000 schon
über den maximal möglichen 32767 liegt.
Also musst du den Compiler zwingen, die Berechnugn nicht im
Zahlenraum int zu machen, sondern im Zahlenraum long (=32 Bit)
Der Compiler orientiert sich immer an den Operanden einer Operation.
Sind beide int, dann wird auch eine int-Berechnung gemacht. Ist
einer davon größer (zb. long), dann wird auch der andere zuvor
auf den größeren Datentyp hochgeholt und die Operation dann in
diesem Datentyp durchgeführt. Es reicht also, wenn einer der
beiden Operanden ein long ist, damit die Multiplikation als
32-Bit Multiplikation durchgeführt wird (und auch ein 32-Bit
Ergebnis liefert). Am einfachsten ist das bei den 10000. Einfach
ein L anhängen, und schon sind die 10000 als long-Zahl markiert.
Ziffer[0]
+ Ziffer[1] * 10
+ Ziffer[2] * 100
+ Ziffer[3] * 1000
+ Ziffer[4] * 10000L
+ Ziffer[5] * 100000L
Bei den 100000 wäre das theoretisch nicht notwendig. Denn 100000
sind für einen int sowieso zu groß und der Compiler muss als
Datentyp für die 100000 sowieso long annehmen. Aber zu Doku
Zwecken ist es immer gut explizit zu sein.
> Ich weiß, mir fehlen "etwas" die C-Grundlagen. Könnt ihr mir ein Buch> über µC-Programmierung in C empfehlen?
Über µc Programmierung an sich nicht. Aber das hat auch relativ
wenig mit µC an sich zu tun. Das sind Dinge, die auf allen Systemen
gleich sind, weil sie so in der Sprache C verankert sind.
Und dafür ist der Klassiker K&R immer noch ein empfehlenswertes
Buch:
Kernighan & Ritchie
Programmieren in C
Dass ein Anfänger hier seinen Code den Löwen zum Fraß vorwirft finde ich
mutig.
Dass es dann auch zu vielen Verbesserungsvorschlägen kommt war ja
abzusehen.
Aber dass Joachim dann die (ernst gemeinten) Kritiken, konstruktiv
aufgefasst hat, und nicht als persönlichen Angriff gewertet hat, hat mir
am meisten imponiert!
Dieser Thread ist das perfekte Beispiel dafür, dass es meist am
Threadersteller selbst hängt, wie sich die Diskussion entwickelt. In
diesem Falle macht es richtig Spass den Lernfortschritt mitzulesen.
Weiter so!
----, (QuadDash).
@ Karl heinz Buchegger
ja, sowas mit dem Bereich hab ich mir schon gedacht. Nur die
Vorgehensweise hab ich mir anders vorgestellt. Ich dachte eigentlich ich
könnte die Zahlen in den Zeigern einfach hintereinander reihen, quasi
4+6+3+8+7+1=463871 und das dann irgendwie als Zahl (long)
interpretieren. Aber deine Methode mit dem multipizieren und dem
aufsummieren ist auch gut. Und irgendwie auch einfach :). Manchmal hab
ich nen Brett vorm Kopp...
Jetzt muß ich "nurnoch" den UART programmieren, damit ich mir meine
Ergebnisse auch angucken kann. Mist, das hab ich ja noch nie gemacht...
;)
Hoffentlich kommt das LCD bald.
@QuadDash
jaaa, das ist ja so: ich hab ja nie den Anspruch gestellt, daß das Prog
fertig und perfekt ist. Es tat das, was es sollte und das wollte ich
nicht für mich behalten. Und wenn ich dann noch "erwarte", daß hier und
da Leute was anders/besser machen würden ist das ja ok, warum auch
nicht? Das hab ich ja auch an mehreren Stellen erwähnt. Darum ist jetzt
die ISR auch wesentlich kürzer und so. Und wenn sich Leute wie Karl
Heinz oder lkmiller schon Gedanken machen und Verbesserungsvorschläge
anständig rüberbringen gibt es ja keinen Grund aus zu rasten und zu
sagen "Ihr seid alle gegen mich!"... Zehn Jahre Jugendarbeit sollten
sich doch bemerkbar machen -> "Kritik üben und annehmen"
Insgesamt habt ihr mir bisher echt gut weiter geholfen. Danke nochmal.
Vielleicht findet sich ja wirklich wer, der denk "och, so eine stoppuhr
wollte ich immer schonmal haben..."
In nächster Zeit muß ich viel für Regelungstechnik lernen, darum werd
ich das Programmieren erstmal hinten anstellen (müssen). Aber wenn es
Updates gibt kann ich es ja wieder den Löwen zur Diskussion stellen ;)
...
MfG
Joachim wrote:
> aufsummieren ist auch gut. Und irgendwie auch einfach :). Manchmal hab> ich nen Brett vorm Kopp...
:-)
Viele Dinge sind eigentlich sehr einfach, wenn man sie erst mal
verstanden hat.
Konkret für diese Aufgabenstellung: Genau so ist unser Zahlensystem
aufgebaut. Das ist das Wesen unseres Stellensystems: Die jeweils
nächste Stelle links hat immer eine um einen bestimmten Faktor
größere Wertigkeit. Du bist gewohnt, daß dieser Faktor 10 ist
(daher nennen wir unser Zahlensystem auch Dezimalsystem). Der
muss nicht 10 sein. Im Binärsystem ist er 2, im Hexadezimalsystem
ist er 16. Aber das Prinzip ini all diesen Systemen ist immer
dasselbe: Aus den Einern werden Zehner, indem diselben Ziffern
mit 10 multipliziert werden. VOn den Zehnern zu den Hundertern ist
es wieder der Faktor 10. 100->1000 schon wieder der Faktor 10.
Das muss auch so sein, weil genau so das von uns verwendete
Zahlensystem funktioniert.
Geht es auch anders? Aber sicher doch! Schau dir mal die
römischen Zahlen an. Und dann überleg mal um wieviel einfacher
doch unsere Stellenwertsystem ist und um wieviel simpler es
sich damit rechnen lässt.
> jaaa, das ist ja so: ich hab ja nie den Anspruch gestellt, daß das Prog> fertig und perfekt ist.
Stell dein Licht nicht unter den Scheffel. Dein Programm ist gut.
Arbeiten kann man an allem und es werden sich immer irgendwelche
Dinge in einem Programm finden, die man besser machen kann.
Das ist ja die Krux am Programmieren. Es sieht zunächst so einfach
aus, entpuppt sich aber dann als eine harte Nuss. Nicht umsonst sagt
man, dass es ein paar Jährchen dauert, bis man das Zeug für ein
mittleres Industrieprojekt hat.
> Es tat das, was es sollte und das wollte ich> nicht für mich behalten. Und wenn ich dann noch "erwarte", daß hier und> da Leute was anders/besser machen würden ist das ja ok, warum auch> nicht?
Das ist die richtige Einstellung. Ich bin jetzt seit über 20 Jahren
im Geschäft und lerne immer noch dazu.
> Insgesamt habt ihr mir bisher echt gut weiter geholfen.
Freut mich wenn du die Anregungen annimmst und umsetzt. Sowas ist
immer das Salz in der Suppe. Vor allen Dingen wenn man merkt: "Jo,
jetzt hat er's verstanden und tippt nicht einfach nur stumpfsinnig
Code ab". Grade in der Programmierung ist das Verstehen des Prinzips
(das wir Algorithmus nennen) das Allerwichtigste. Eine Programmier-
sprache ist nur ein Werkzeug um die Algorithmen umzusetzen.
hallo leute kann mir jemand helfen
ich muss ein stopuhr mit atmega32 durch C programmieren
haber versucht aber zwecklos hoffe dass jemand mir hilfen kann
also ich will ihnen das programm beschreiben
1) Einfache Stopuhr
Unsere Stopuhr soll nun mit der Taste PA1 gestartet und mit PA2
angehalten werden( PA1 und PA2 stehen für den bit nummer 1 bzw nummer 2
von PINA)
können (Pause). PA3 dient zum Rücksetzen der Stopuhr.
Der Schleifendurchlauf soll nicht mehr als 250ms verzögert werden, damit
die Tastereingaben
auch bei kurzem Druck erkannt werden.
Die Anzeige soll am LCD Display in Sekunden erfolgen.
2) Zwischenzeit erfassen
PA4 soll die Anzeige anhalten und die Zwischenzeit anzeigen. Während der
Zwischenzeitanzeige
soll aber die Zeit weiter unsichtbar mitgezählt werden.
Damit man diesen Zustand vom Pausenzustand (mit PA2) unterscheiden kann,
soll
eine LED blinken.
Wenn die Start-Taste gedrückt wird, soll die Zeit wieder normal
angezeigt werden.
hallo
danke für deine schnelle Antwort.
hmm eigentlich ich was was du gemeint hast aber meine aufgabe ist :
ich soll der program in AVR studio ergänzen und genau diese punkt ist
mein problem
übersetzen und auf den bord hochladen kann ich schon
kannst du mir trozdem bitte hilfen?
Yasi Karmu wrote:
> ich soll der program in AVR studio ergänzen
'ergänzen' ist gut.
Da ist noch nicht mal ansatzweise eine Stoppuhr zu erkennen
und das ist mir dann doch zuwenig um dir die Arbeit abzunehmen.
Ausserdem hab ich im Code einen Kommentar gefunden, dass
das Ganze ein Praktikum der FH Regensburg ist. Von einem
FH Absolventen erwarte ich mir mehr (*), als ein lapidares: "Ich
wills noch nicht mal versuchen. Bitte macht mal!"
(*)
Speziell wenn man berücksichtigt, dass jetzt Semesterende ist
und du eigentlich dieses Semester so manche Übung gemacht
haben müsstest.
Aber einen Tipp gebe ich dir:
Eine Stoppuhr ist auch nichts anderes als ein etwas seltsamer
Zähler, der einfach nur ständig hochzählt. Dein erster Ansatz
könnte also sein, einfach mal eine Variable um 1 hochzuzählen
und diesen Zähler am LCD auszugeben. Das wird rasend schnell
gehen, daher ist der nächste Schritt: Der Zähler soll im Sekunden-
takt um 1 erhöht werden.
Eine Stoppuhr ist auch nur so ein Zähler. Nach 60 Sekunden ist
eine Minute rum (also wirst du wohl eine 2.te Variable für die
Minuten brauchen), und du setzt die Sekunden wieder auf 0 und
dafür die Minuten um 1 höher.
Yasi Karmu wrote:
> achsooo jetzt verstehe ich> und wie kann ich dieser zähler durch den AD wandler erzeugen??
Ähm. Du weißt schon, was ein AD-Wandler macht?
Du lange Antwort: gar nicht.
Stoppuhr und AD Wandler haben rein gar nichts miteinander zu tun.
(Es sei denn am AD-Wandler hängt eine Signal, welches die
Stoppuhr startet bzw. stoppt. Aber den Fall hast du ja nicht)
ja ja ich weiss was AD wandler macht aber hier steht , man erzeugt ein
wert mit einem potentiometer und der AD wandler wandelt den wert den
potentiometer ist im PIN0 verbunden.
du hast gesagt ich muss eine variabl für minuten und sekunden
deklarieren
und ich soll diese variable jedesmal inkrementieren wenn sie an 60
ankomment soll diese variable zurückgesetzt werden und wird die variable
von minuten incrementiert
meine frage wie kann ich die inkrenmentierte variable jedesmal am
bildschirm von den Bord zeigen?
danke schön
Kann es sein, dass du die Aufgaben nicht ganz verstanden hast?
Die ADC- und LCD-Sachen sind Vorübungen, um sich mit dem Board vertraut
zu machen. Für die eigentliche Stoppuhr werden die nur teilweise
(LCD-Ausgabe) gebraucht.
>wie kann ich die inkrenmentierte variable jedesmal am>bildschirm von den Bord zeigen?
Wenn sie geändert wurde, gibt man sie auf dem LCD aus.
Das kann / sollte man maximal jede Sekunde machen, weil der Mensch eh
nicht wesentlich schneller gucken kann.
Man lässt also einen Timer auf Tastendruck so laufen, dass er eine
sinnvolle Zeitbasis liefert (z.B. Interrupt alle 10ms).
In der Interrupt-Routine inkrmetiert man eine Variable und guckt nach,
ob es zu einem Überlauf kam (100*10ms = 1 Sekunde). Entweder tritt
dieser auf, was dann zu einem Sekunden-Inkrement und dem Zurücksetzen
der 10ms-Variable führt, oder eben nicht.
Genauso geht man dann mit den "nachfolgenden" Variabeln (Sekunden,
Minuten, Stunden...) um.
Man sollte dann auch noch abfragen, ob die Stopp-Taste gedrückt wurde.
Und bei einer entsprechenden Betätigung die aktuelle Zeit sichern bzw.
den Timer anhalten.
danke schöööööööööööön für deine Antowrt
hmm ich werde mal versuchen
( ich bin im 2. semester und habe noch nie ein bord programmiert deshalb
kann ich nicht ganz verstehen)
^^
Wie man den Timer benutzt siehst du im Beispielprogramm von Joachim
recht gut.
Wie er funktioniert und welche Register für was zuständig sind, steht im
Datenblatt des Conrtrollers
Auch im Tutorial sind einige Tips zu Timern. Eine Bibliothek time.h
brauchst du (vorerst) dafür nicht
Gruß
Roland
Ich denke nicht, das sein Lehrer auf einen Timer aus ist. Die
Aufgabenstellung liest sich für mich nach der Forderung nach
ganz banalen delays um die Uhr zum laufen zu bringen.
Das wird wohl ein Zugeständnis an die Kentnisse der Schüler
sein. Irgendwo muss man ja schliesslich auch anfangen.
Deshalb auch die Forderung, dass die Hauptschleife nicht länger
als 1/4 Sekunde verzögert werden soll um die Bedienung der Tasten
noch halbwegs angenehm zu machen.
Also in etwa so
also für die tasteneingabe habe ich so geschrieben
habe eine variable deklariert
pina
und der inhalt von porta wird auf pina zugewiesen
den zweiten bit entspricht das laufen von der stopuhr 3.bit anhalten und
4 reset
also
habe der 2 bit auf lauf gesetzt den 3. auf halt und 4 auf reset
und so schaut mein program aus?
unsigned short pina,halt, lauf, reset;
pina=~PINA ;
halt, lauf, reset
lauf=(pina>>1)&0x01;
halt(pina>>2)&0x01;
reset=(pina>>3)&0x01;
while (lauf==1)
{
while( 1 ) {
Zehntel ++;
if( Zehntel == 10 )
Zehntel = 0;
Sekunden++;
if( Sekunden == 60 ) {
Minuten++;
if( Minuten == 60 ) {
Minuten = 0;
}
}
// Minuten und Sekunden auf dem LCD ausgeben
sprintf( Buffer, "%02d:%02d", Minuten, Sekunden );
lcdPrint( 0, 0, Buffer );
}
delay_ms( 100 );
}
}
while(halt==1)
{
lauf=0;
}
while(reset==1)
{
lauf=1;
}
yassi karmu wrote:
> hmmm wieso denn was ist falsches ???
So ziemlich alles bis auf den Teil den du von mir übernommen
hast.
Das Teil sieht aus als ob du noch nie ein Programm geschrieben
hättest. Und ich meine überhaupt noch nie, nicht nur noch nieauf einem µC
Hallo,
ich bin dabei auch eine Stoppuhr aufzubauen. Leider bin ich in der
Programmierung blutiger Anfänger. Vielleicht ist ja jemand hier, der mir
etwas unter den Armen greifen kann.
Folgendes soll diese machen
Impuls am Eingang1 = Start der Uhr und gleichzeitig deaktivieren des
Eingangs für 5 sek.
Anzeige der Zeit in sek und 10.tel und 100.tel (1235,23 sek)
Erneuter Impuls am Eingang 1 stoppen der Uhr und wieder 5 sek den
Eingang deaktivieren.
Impuls am Eingang 2 die Anzeige auf 0,00 setzen und den Wert Speichern.
Maximale Speicherung - die letzten 5 Messungen
Impuls am Eingang 3 Durchblättern der letzten Werte.
Vor den letzten Wert soll dann 0-5 stehen 0 für aktuelle Messung und 5
für die älteste Messung
0- 125,36
1- 236,36
2- 456,36
3- 251,31
4- 452,14
5- 547,88
Wer kann helfen?
Frank schrieb:> gleichzeitig deaktivieren des> Eingangs für 5 sek.
Warum?
Es gibt ja nicht schon hunderte Stoppuhr-Projekte im Internet zu finden.
Frank schrieb:> Anzeige der Zeit in sek und 10.tel und 100.tel (1235,23 sek)
Bischen rechnen und fertig.