Hallo!
Ich versuche mich gerade an einem Projekt wo der µC Impulse zählen soll
und diese dann umrechnet in Meter und diese dann auf ein Display
ausgibt! jeder Impuls steht für 5,5cm! Könnte mir einer von euch
vieleicht ein paar Tips geben wie ich sowas programmieren kann?! Fange
gerade an mit dem Programieren!
Der Controller ist wie oben schon geschrieben ein ATEMGA 32 auf einen
Selbstegbauten programierboard! Ich Programmiere in C! Das mit dem
Display bekomm ich wohl hin... kann auch sachen auf Display schreiben
usw. Mir gehts eigentlich nur um die Rechnung. bei einem Impuls muss
5,5cm aufm Display stehn... bei 10 müssen halt 55cm usw... stehn!
sozusagen muss ich ja den einen Wert mal den anderen rechnen und diesen
wert dann ausgeben, aber geht das so einfach?
so einfach geht das? Da hätte ich auch selber drauf kommen können! :-D
Dann muss ich ja nur noch den Wert WegInM auf Display ausgeben und Meter
dahinter schreiben oder nicht?
Definiere eine "unsigned long"-Variable und jedes mal wenn Du einen
Impuls festellst addiere "55". Dann hast Du den Weg in mm und kannst bis
2^32 mm ~ 400.000 km messen. Für die Ausgabe musst Du nur noch das Komma
an die richtige Stelle setzen.
Hallo, ich bin wieder! Irgendwie bekomme ich das nicht hin mit der
Ausgabe!
Also nochmal: 1 Impuls sind 5,5cm, das muss umgerechnet und ausgeben
werden. Der Zähler sollte von 0 bis 500m Zählen können in 0,5m
Abschnitten ( oder was einfacher ist)
Hier ist mein C-Code... hoffe ihr versteht den^^
1
#include<avr/io.h> //einbinden der bibliotheken
2
#include<stdlib.h> //einbinden der bibliotheken
3
#include<stdio.h> //einbinden der bibliotheken
4
#include"lcd.h" //einbinden der bibliotheken
5
#include<util/delay.h> //einbinden der bibliotheken
6
#include<avr/interrupt.h> //einbinden der bibliotheken
7
#include<math.h> //einbinden der bibliotheken
8
#include<avr/iom32.h> //einbinden der bibliotheken
9
#include<avr/eeprom.h> //einbinden der bibliotheken
Hans schrieb:
> uint16_t buffer;> char Buffer[20];
Das ist böse fehlerträchtig. Und du bist unten elegant drüber gestolpert
(itoa verwendet buffer statt - wie wahrscheinlich gemeint - Buffer, ich
hätte nicht gedacht, dass das überhaupt kompiliert)
Außerdem hast du keine Flankenerkennung. Du musst den Wert von PINB0
speichern und erst bei einer Änderung den Impuls hochzählen. Nicht immer
dann, wenn der PINB0 negativ ist.
Und was sollen die delay-loops am Ende?
MfG, Heiko
Hans schrieb:
> DDRD = 0xFF; // D Ports als Ausgänge festlegen für LCD>> DDRB = 0xFF; // B Ports als Eingänge festlegen
Fifty-Fifty, aber vielleicht auch nur 50% ;)
avr
Das verstehe nun wer will mit den Ein bzw. ausgangsdefinition^^
Das LCD arbeitet richtig und die Taste am eingang des Ports werden auch
erkannt ( wenn ich drauf klick zählt er hoch).
Habe das mit dem Buffer geändert und nun zählt er, zwar nur ganzzahlig
aber er zähhlt!
Hier direkt:
Du speicherst einfach in jedem Programmdurchlauf den Zustand des
Schaltereingangs.
Wenn du nun die steigende Flanke abfragen möchtest vergleichst du den
Eingangszustand auf "größer als" mit dem gespeicherten Wert.
Für die negative Flanke dann halt ein "kleiner als" einsetzen.
Eine eventuelle Tastenentprellung kann ggf. auch nicht schaden aber dazu
gibt es hier ja viele schöne Dinge in der Codesammlung. (...sicher sogar
zur Flankenauswertung)
Da bin ich wieder ;-)
Habe das mit dem positiven Flanke hin bekommen! nur muss ich das nur
noch hin bekommen das er mir Kommazahlen ausdrückt, da ich nun 19 mal
aufm taster drücken musss um eine 1 aufm display zu haben! Wollte das
mit 0,1; 0,2 usw. aufm Display anzeigen lassen!
das mit der Taster entprellung brauche ich an sich nicht, da das Signal
nur aufm Prog board vom Taster kommt! Nacher kommt das Signal von einer
Lichtschranke!
hans schrieb:
> Da bin ich wieder ;-)> Habe das mit dem positiven Flanke hin bekommen! nur muss ich das nur> noch hin bekommen das er mir Kommazahlen ausdrückt, da ich nun 19 mal> aufm taster drücken musss um eine 1 aufm display zu haben! Wollte das> mit 0,1; 0,2 usw. aufm Display anzeigen lassen!
Denke mal über Folgendes nach:
1765 Millimeter sind 1 Meter (wenn man 1765 durch 1000 dividiert)
ABER
1765 / 1000 -> 1 UND
1765 % 1000 -> 765
1 und 765 kann man auf der Ausgabe leicht ausgeben. Wenn man dann noch
ein ',' dazwischenschreibt, steht dann auf dem LCD: 1,765
und 'zufällig' sind 1765 Millimeter auch 1,765 Meter :-)
% ist in C der Modulo-Operator (=Rest einer Division). So wie in: Eine
Mutter hat 8 Äpfel und 3 Kinder. Wieviele Äpfel bleiben der Mutter
übrig, wenn jedes Kind gleich viele Äpfel bekommt? (Wieviele Äpfel
bleiben übrig, wenn man von der Gesamtzahl die ganze Anzahl der
ausgegebenen Äpfel wegrechnet?)
Wieviele Millimeter bleiben übrig, wenn man von 1765 die ganze Anzahl an
Metern (=1000 Millimeter) wegrechnet?
und jetzt alles zusammengenommen
sprintf( buffer, "%d,%03d", WegInMm / 1000, WegInMm % 1000 );
lcd_goto( 1, 1 );
lcd_write_s(buffer );
Da heute Samstag ist, gehst du in die nächste Buchhandlung und besorgst
dir als allererstes ein C-Buch. Mit dem fängst du dann zu lernen an.
Und dann mistest du aus deinem Programm alle nicht benötigten Variablen
aus. Als nächstes gehst du dann her und stellst alle Einrückungen
richtig. All das sind nämlich auch Stolpersteine, mit denen du dir nur
selber das Leben schwer machst.
Du hast auch noch jede Menge Header Files includiert, die du in deinem
Projekt überhaupt nicht benötigst.
Auc solltest du dir überlegen, wie weit du wohl kommen wirst, wenn du
WegInMm als int definierst. Ein int geht (auf dem AVR) hoch bis 32767.
Da das bei dir Millimeter sind, ist daher bei ~32 Meter Schluss mit
lustig. Die Änderung von int nach etwas anderem erfordert aber ein paar
Anpassarbeiten .. aufpassen!
Wenn du ein neues Programm schreibst, dann schreib auch wirklich ein
neues Programm und fang nicht an, ein Vorhandenes abzuändern. Du kannst
einzelne Details aus einem vorhandenen Programm übernehmen. Aber gewöhn
dir an, immer mit einem leeren Source Code File zu beginnen. Zum einen
lernst du dann die Syntax viel schneller, irgendwann tippen die Finger
dann die ersten Schlüsselwörter von alleine, zum anderen schleppst du
dann nicht Unmengen von Altlasten immer mit dir rum über die du dann
stoplerst. Und mit ein klein wenig Übung ist das Umarbeiten von altem
Code auch nicht schneller als das Neuschreiben bzw. das Übernehmen und
Anpassen von altem Code in ein neues Projekt. Das ist einer der großen
Irrtümer, die Anfänger gerne machen: Ich lerne schneller, wenn ich mein
vorhandenes Programm zur Temperaturanzeige auf Sonnenscheindauer
umpfriemle. Das genau Gegenteil ist der Fall: beim Umpfriemeln geht man
nicht mehr systematisch vor, sondern es wird nur noch geraten. Anstatt
sich nach dem 3.-ten ';' Fehler die typische Fehlermeldungen des
Compilers zu merken lautet dann die Devise: Das alte Programm hat auch
compiliert, warum blos tuts das neue nicht mehr. etc. Gelernt wird
dabei nur wenig.
Programmieren erfordert viel Übung. Die kriegt man aber nur, indem man
übt und nicht indem man Vorhandenes nach dem Ratespielverfahren
umpfriemelt.
Lass mal dein Programm ansehen, wie es jetzt aussieht (nachdem du
aufgeräumt hast). Da kann man sicher noch mehr Tips geben. zb. benötigst
du die Anzahl der Impulse ja nicht wirklich. Es reicht daher auch völlig
aus, wenn du bei jedem erkannten Impuls zu WegInMm einfach 55 dazuzählst
anstelle einer Impulsvariable hochzählen und einer Multiplikation
danach. Ein LCD kommt leicht ins Flackern, wenn man ständig ausgibt. Man
macht daher die Ausgabe nur dann, wenn es tatsächlich eine Änderung an
den ausgegebenen Werten gibt. Um _delay_xxxx solltest du erst mal einen
großen Bogen machen. etc. etc.
So! habe das Programm mal so gut es ging aufgeräumt, hoffe ihr findet
euch nun besser zurecht!
Das mit der positiven Flanke ist nun eingebaut und das der Wert als
Kommazahl angezeigt wird!
Ich brauche aber an sich nur 1 Nachkommastelle, kann mir einer einen tip
geben wie ich diese Problem löse?
lcd_write_s(Buffer);// Ausgabe des "Buffer" Inhalts
62
63
lcd_goto(1,10);// Springe zu 1.10
64
lcd_write_s("Meter");// Schreibe "Meter"
65
66
}
67
}
Das Programm sieht immer noch ein wenig komisch geordnet aus, von der
Ordung! Aber irgendwie übernimmt das Forum meine Ordnung nicht wirklich,
bei mir im AVR Studio sieht es anders aus.
Ein Buch werde ich mir Montag auf jedenfall kaufen gehn!
Lothar hat doch schon einen gegeben...
Ich machs dir noch einmal vor:
Du hast bisher: WegInMm, zum Beispiel 1765.
Du willst ausgeben: 1,7 (oder 1,8?)
Die 1 bekommst du ganz einfach: 1765/1000 - steht ja schon oben.
Wie schafft man es jetzt, dass die 7 als zweite Zahl ausgegeben wird?
Naja, es gibt zwei Möglichkeiten:
1) 1765 % 1000 = 765, 765 / 100 = 7.
2) 1765 / 100 = 17, 17 % 10 = 7. (wahrscheinlich besser, weil kleinere
Divisoren -> könnte schneller sein)
Wenn du aufrunden willst, überleg einmal, wann eine 8 vorne stehen soll
- nämlich genau ab 750 und bis 849. Das kann man ganz einfach
realisieren, indem man vor der ganzen Rechnerei oben erstmal 50
draufaddiert - dann steht da statt 750...849 800...899 - also genau das,
was das Ziel war.
Man kann natürlich stattdessen auch noch eine if-Abfrage einbauen, oder
vielleicht gibt es auch schon fertige Funktionen dazu in der avr-libc?
Normale Rundungsfunktionen helfen aber nicht, die sind auf
Fließkommazahlen ausgelegt!
Mit einer geschickten Kombination von Klammern kann man so jede
beliebige Kombination von Ziffern einer Zahl ausgeben - probiers mal
aus.
MfG, Heiko
Super, vielen dank für den Tip! Habe nun nur eine Nachkommastelle! Nun
muss ich den gespeicherten wert nur anders ablegen, da int ja zu kurz
ist! WÜrde das mit unsigend long int gehn?
Wahrscheinlich. Der Standard definiert, dass unsigned long int größer
als oder genauso groß wie unsigned int ist. Es hat sich aber
eingebürgert, dass long int größer ist als int.
Sicherheitshalber würde ich stdint.h einbinden und uint32_t verwenden,
das ist garantiert 32Bit groß. Auch wenn du den Code später mal auf
einem PC oder einem anderen Mikrocontrollertyp verwendest.
MfG, Heiko
und aufpassen.
Wenn du den int auf long oder unsigned long umänderst, benötigst du auch
andere Formatierzeichen im sprintf-Steuerstring.
%d ist für int.
%u ist für unsigned int
%ld ist für long.
%lu ist für unsigned long
Und ja, klar kann man wieder zwischen den % und die Steuerbuchstaben
zusätzliche Steuerungen einbauen, wie die führende 0 bzw wieviele
Stellen angezeigt werden sollen.
Dein C-Buch weiß noch viel mehr zu berichten, was man im Formatstring
eines printf,sprintf alles angeben und machen kann.
Dein Code macht den Update auf das LCD bei jedem Schleifendurchlauf.
Aber eigentlich ist das unnötig. Denn solange WegInMm seinen Wert nicht
ändert, braucht auch die Anzeige nicht aktualisiert zu werden. Eine
Technik, mit der man so etwas angehen kann, sind Status Variablen. Eine
Status Variable sagt aus, dass ein bestimmter Zustand vorliegt. So ein
Zustand könnte zb sein: Das Display ist aktuell oder es ist eben nicht
aktuell. Ist das Display aktuell, dann braucht es nicht erneut
aktualisiert zu werden. Ist es nicht aktuell, dann macht man den Update
und setzt die Variable wieder auf 'aktuell' zurück. Wie kann das Display
'nicht aktuell' werden? Es ist ganz sicher am Anfang nicht aktuell, denn
dann steht ja noch gar nichts am LCD. Und es ist auch dann nicht mehr
aktuell, wenn sich WegInMm ändert. In beiden Fällen wird daher das LCD
auf 'nicht aktuell' gesetzt und es dem Abschnitt überlassen, der sich um
ein nicht aktuelles LCD kümmert, das LCD wieder auf den neuesten Stand
zu bringen.
lcd_write_s(Buffer);// Ausgabe des "Buffer" Inhalts
22
23
lcd_goto(1,10);// Springe zu 1.10
24
lcd_write_s("Meter");// Schreibe "Meter"
25
26
NeedUpdate=FALSE;
27
}
28
}
Zum Thema Kommentare.
Kommentiere das, was NICHT im Quelltext steht. Wenn du das Gefühl hast,
die eine Zeile Quelltext erzählt einem Leser nicht, was hier passiert,
dann versuch als Allererstes den Quelltext so umzuändern, dass er
aussagekräftig wird. Das kann zb bedeuten, dass man Funktionen einen
besseren Namen gibt oder Variablen einen aussagekräftigen Namen.
1
j=i*0.15;
erzählt einem Leser nun mal nicht dasselbe, wie
1
#define MehrwertSteuerSatz 0.15
2
3
BruttoPreis=NettoPreis*MehrwertSteuerSatz;
Sieh dir diesen Abschnitt an.
1
lcd_goto(1,10);// Springe zu 1.10
2
lcd_write_s("Meter");// Schreibe "Meter"
Jetzt lies den Quelltext und dann lies den Kommentar. Merkst du was? Da
steht, mehr oder weniger Wort für Wort, absolut das Gleiche. So ein
Kommentar ist sinnlos und man macht ihn besser nicht. So ein Kommentar
gibt keinerlei Hilfestellung und ist im schlechtesten Fall einfach nur
falsch. Im besten Fall erzählt er einem nichts, was nicht auch im
Quelltext steht. Und damit ist er überflüssig.
1
lcd_goto(1,10);
2
lcd_write_s("Meter");
ist genauso aussgaekräftig und man läuft nicht Gefahr, dass zb bei einer
Änderung der Spalte
1
lcd_goto(1,15);// Springe zu 1.10
2
lcd_write_s("Meter");// Schreibe "Meter"
der Kommentar nicht mehr mit dem Quelltext übereinstimmt. Denn da taucht
jetzt sofort die Frage auf: Was stimmt denn jetzt? Soll der LCD-Cursor
tatsächlich an die Spalte 10 und hat sich der Programmierer im Quelltext
vertippt, oder ist die Absicht wirklich nach Position 15 zu gehen und
der Kommentar wurde vergessen anzupassen?
Eine gute Faust-Regel für Kommentare lautet:
Ein Kommentar soll eine Aussage darüber treffen, WARUM etwas passiert
und nicht WIE es passiert (obwohl es da auch Ausnahmen gibt). Das WIE
steht im Quelltext, das WARUM kann ein Leser nicht wissen und das muss
man ihm erzählen, sofern es aus dem Code nicht hervorgeht.
In diesem Sinne solltest du zb darüber nachdenken, wie du das hier
1
WegInMm=WegInMm+55;// Zähle zu WegInMm 55 dazu
besser gestalten kannst. Das 55 zu WegInMm hinzugezählt wird, das sehe
ich im Quelltext. Aber WARUM wird das gemacht? WARUM sind das 55? WARUM
nicht 54 oder 56? Muss ich an dieser Stelle im Quellcode überhaupt
wissen, dass hier 55 dazugezählt werden oder könnte man den Zahlenwert
nicht an den Anfang des Codes, zb mit einem #define verfrachten und
dafür einen aussagekräftigen Namen vergeben, so dass an dieser Stelle
überhaupt kein Kommentar notwendig ist sondern mir der Code alles
notwendige erzählt?
Und noch ein PS: was macht eigentlich die Funktion, die den ADC
einschaltet, noch in deinem Code?