Es wurden ja schon öfters Entprellroutinen vorgestellt, aber diese hat
den Vorteil, besonders kurz und schnell zu sein.
Außerdem werden alle 8 Tasten gleichzeitig bearbeitet, es können also
alle exakt zur selben Zeit gedrückt werden.
Andere Routinen können z.B. nur eine Taste verarbeiten, d.h. die zuerst
oder zuletzt gedrückte gewinnt oder es kommt Unsinn heraus.
Die eigentliche Einlese- und Entprellroutine ist nur 8 Instruktionen
kurz. Der entprellte Tastenzustand ist im Register "key_state".
Mit nur 2 weiteren Instruktionen wird dann der Wechsel von Taste offen
zu Taste gedrückt erkannt und im Register "key_press" abgelegt.
Im Beispielcode werden dann damit 8 LEDs ein- und ausgeschaltet.
Jede Taste entspricht einem Bit in den Registern, d.h. die Verarbeitung
erfolgt bitweise mit logischen Operationen.
Zum Verständnig empfiehlt es sich daher, die Logikgleichungen mit
Gattern für ein Bit = eine Taste aufzumahlen.
Die Register kan man sich als Flip-Flops denken, die mit der
Entprellzeit als Takt arbeiten. D.h. man kann das auch so z.B. in einem
GAL22V10 realisieren.
Als Kommentar sind neben den einzelnen Instruktionen alle 8 möglichen
Kombinationen der 3 Signale dargestellt.
Peter
Hallo Peter,
Dein Programm ist zwar besser als - wie anderswo erwähnt - Monoflops
einzusetzen; es funktioniert aber nur auf dem Papier, da es ideale
Taster voraussetzt.
Reale Taster prellen aus Erfahrung mehr, als das ideale Datenblatt
angibt: insbesondere im Laufe der Zeit und bei Feuchtigkeit. Ein typisch
schlechter Taster ist z.B. einer, wie man ihn bei der
Hausinstallationstechnik findet. Die Kontakte sind für hohe Ströme
ausgelegt und nicht für geringes Prellen.
Für eine sauberes Entprellen kommt man nicht umhin, den Tastenzustand
wiederholt auf Gleichheit zu überprüfen und danach auszuwerten.
Hallo Michael,
ich habs aber nicht nur auf dem Papier (Bildschirm) getestet.
Ich habe das Program auf dem AVR Testboard ausprobiert und dabei keine
einzige Fehlfunktion feststellen können.
Wenn man das Entprellen testweise rausnimmt, sieht man auch wunderschön,
wie diese kleinen Taster prellen können.
Allein durch das Abtasten in einem festen Zeitrahmen ergibt sich schon
eine gewisse Entprellwirkung. Der anschließende Vergleich gibt dem
Preller dann entgültig den Rest.
Ich habe bei allen meinen Projekten bisher immer nur 1-mal auf
Gleichheit mit dem vorherigen Zustand geprüft und dananch keine Preller
mehr entdeckt.
Es würde mich aber freuen, wenn Du es mal testen könntest. Vielleicht
hast Du ja einen Taster, der so miserabel ist, daß wirklich mal 1
Preller auf 1000 Betätigungen durchkommt.
Dann kann der Kode kann nach dem gleichen Prinzip leicht auf den
Vergleich von 3 Registern erweitert werden.
Spätestens dann sollte die Prellsicherheit über 1/1000000 liegen.
Also, wenn Du da mal praktische Statistiken hättest, statt nur zu
behaupten, es ginge nicht, das würde mich wirklich freuen.
Dann würde ich auch gerne den Vergleich auf 3-fach erweitern.
Damit sollte man dann sogar die Kontakte in einem Airbus zuverlässig
entprellen können.
Peter
Hallo Peter,
ich sagte doch, Deine Routine ist immerhin besser als Monoflops,
zumindest für Bastelanwendungen. Baue ein Gerät, teste es durch, und es
wird immer funktionieren. Verkaufe dieses schöne Gerät nach z.B. Mexico,
und da funktioniert es dann nicht mehr. So ist das Leben !
Vielleicht ist es doch besser, ein paar mehr Byte zu programmieren ?
Schade, Du bleibst also auf dem "Immer-Schlechtmachen-Trip" :-(
Beweisen oder Testen hätte mir besser gefallen.
Warum sollen denn die AVRs in Mexico nicht mehr funktionieren ???
Ich baue Geräte, die intern viele Hochspannungen erzeugen müssen (bis
15kV), d.h. die machen sich ihre Störungen selber.
Wenn da die Tasten spinnen würden, könnte das lebensgefährlich sein.
Nach Mexico haben wir, glaube ich, noch nichts verkauft, nur USA, Japan,
Indien usw.
Peter
Nun gut, ich wollte Dir gerne wie immer das letzte Wort lassen; nun habe
ich doch mein AVR-Starterkit (4-5 Jahre alt) ausgepackt.
Je nach Taste habe ich Preller alle 5-6 Mal. Entweder geht die LED ganz
aus oder flackert aus-ein (je nach Taste). Habe ich doch gleich gesagt!
@Michael,
ich hab mir gestern die Finger wund gedrückt (>1000) und keinen einzigen
Preller gesehen.
Ich habe noch das alte STK von 1997 und die Taster machen auch keinen
labrigen Eindruck (deutlicher Druckpunkt).
Den 1200 betreibe ich mit 11.0592MHz.
Wie gesagt, in nun schon über 12 Jahren Praxis verwende ich diese
Prinzip auf 8051-ern und bisher ist weder mir noch den Kunden ein derart
massives Prellen bei nur 5-6 Betätigungen aufgefallen.
Ich habe also absolut keine Erklärung dafür, warum es bei Dir nicht
funktioniert.
Peter
Sorry, jetzt habe ich's begriffen: Dein AVR-Programm ist eine Falle !
Du bist ja der Fan von dem ollen 8051, dem Prozessor mit dem 8-Bit
Stackpointer, der bei rekursiver Programmierung meist das Handtuch
wirft. Wenn dann das obige Programm auf einem AVR scheinbar anfängt zu
spinnen, ist es wieder ein trefflicher Grund, über die hervorragenden
AVR-Prozessoren zu schimpfen.
Ganz schön clever !
Scherz beiseite: warum zierst Du Dich so, auch 'mal die Erfahrungen
anderer Leute anzunehmen ? Deine 'quick and dirty'-Programmierung ist
mir schon öfter aufgefallen. Im Laufe der Zeit relativiert sich das
'quick'; übrig bleibt dann nur 'dirty'.
Hallo Peter,
ich finde Deinen Code super!
Habe mich bloß gewundert, warum der achte Taster nicht funktioniert.
Fälschlicherweise hatte ich das STK verdächtigt. Es ist aber unschuldig.
Der At1200 hat nur die Pins PD0 -> PD6.
Grüße
Oliver
@Michael,
wenn einer Grund hat, auf den AVR zu schimpfen, dann bist das doch
alleine Du.
Bei mir läuft es doch einwandfrei und bei Oliver auch.
Nur Du meldest laufend Probleme an.
Und dann wieder diese Beschimpfungen.
Der Code ist doch klar, knapp und logisch:
- Das SREG wird gesichert.
- Die Arbeitsregister (IWR0, IWR1) sind exclusiv den Interrupts
zugeordnet, so daß sie nicht gepusht werden müssen.
- Das Rückgaberegister auslesen und löschen ist schön mit CLI/SEI
geklammert.
Sämtliche AVR-Fallgruben sind also gesichert.
Der Code ist somit ohne jegliche Problem in größere Projekte
einzubinden.
Es mag ja sein, daß ich, der mit TTL groß geworden ist, logische
Operationen (EOR, AND, COM, OR) etwas leichter verstehe als andere.
Ich weiß wirklich nicht was Dir für eine Laus über die Leber gelaufen
ist, andere immer so zu beschimpfen.
Dein Entprellcode, der nur eine Taste gleichzeitig kann, ist dagegen
wirklich 'quick and dirty'.
Peter
Nach dem Lesen der Diskussion habe ich noch eine andere
Frage:
Muß man Tasten eigentlich entprellen?
Wenn man davon ausgeht, das Tasten nicht länger als 100ms prellen (eher
viel kürzer) reicht es aus die Taste(n) alle
110 ms abzufragen.
Was sagt Ihr dazu ?
@Dirk,
nein es reicht nicht,.. da du ja wenn du zb. keinen IRQ verwendest nicht
weist ob die taste wirklich gedrückt wurde oder nicht,.. das, was da an
dem eingang als zustand anliegt kann ja das resultat des tastenprellens
sein.
am besten die taste mehrere male abfragen und wenn du immer das gleiche
ergebniss hast is es schon richtig, wenn nicht wiederhole die abfrage
bis du mal was richtiges einliest.
das is schnell einfach zu implementieren, verbraucht keine irqs und es
funktioniert,.. jedenfalls bei allen tasten die ich bis jetzt verwendet
habe.
MfG
Sebastian
@Dirk
Versuchs damit: Für jede Taste richtest Du einen Zähler ein. Alle 10ms
Taste abfragen. Wenn Taste gedrückt dann Zähler um 1 erhöhen, wenn nicht
Zähler löschen. Wenn Zähler = 5 dann gewünschte Aktion durchführen. Dann
kannst Du ja bei Bedarf auch noch abfragen ob der Zähler z.B. > 50 ist
und damit eine verzögerte Repeat-Funktion realisieren. Hab ich schon
vielfach und ohne Probleme so gemacht, Codebeispiel gibts auf Wunsch.
Fino
Bei Anwendungen mit einer Tastatur zur Zifferneingabe ist es dem
Anwender (in den meisten Fällen) eigentlich egal ob 20 oder 200ms
vergehen, bis auf den Tastendruck reagiert wird. Also reicht eine
Abfrage alle 100ms aus. Dann kann es max. passieren, das die Taste bei
der ersten Abfrage noch prellt und nicht erkannt wird. Bei der nächsten
Abfrage wird der Tastendruck aber auf jeden Fall erkannt.
Das funktioniert allerings nicht, wenn eine schnelle Reaktion auf die
Betätigung einer Taste benötigt wird. Dann zählt aber schon der erste
Impuls um eine Reaktion auszulösen (evtl. zweite Abfrage zur Absicherung
gegen kurze Störimpulse)und alle nachfolgenden müssen dann durch die
Software abgeblockt werden bis die Prellzeit vorbei ist bzw. ein
sauberer (nicht mehr wechselnder) Pegel anliegt.
Es kommt immer auf die konkrete Anwendung an ob und wie entprellt werden
muss.
MfG
Steffen
@Florian,
z.B. bei einer Matrixtastatur geht das nicht.
Wenn die Tasten jede einen einzelnen Portpin und der MC
Schmitt-Trigger-Eingänge hat, dann ginge das.
Bloß Du brauchst dann für jede Taste und für jedes Board die
Kondensatoren.
Die paar Zeilen Code mußt du dagegen nur einmal erstellen oder kopieren
und kannst sie dann ganz ohne Löten in beliebig vielen Projekten für
beliebig viele Tasten verwenden. Kostet Dich dann keinen Pfennig mehr.
Peter
Hallo,
ich enprelle die Tasten folgendermaßen:
1. Überprüfung ist Tastenpin auf high (Tastendruck, Preller ausgelöst
durch Tastendruck) und temoräre Variable auf low.
2. Wenn ja Aktion auführen und temp-var=high setzen.
3. in einer Timer-ISR wird die temp-var alle 100ms zurückgesetzt wenn
der Tasenpin low und die temp_var high ist.
Bis jetzt hat das immer sehr gut funkioniert und die Schaltung reagiert
im selben Moment in dem die Taste gedrückt wird.
MfG
Rainer
@Rainer,
niemand hat behauptet, daß es nur eine Möglichkeit gibt.
Ich habe nur gesagt, daß dieser Algorithmus besonders wenig Rechenzeit
und Speicherplatz benötigt. Außerdem kann er bis zu 8 Tasten und merkt
sich die Betätigung, auch wenn das Hauptprogramm gerade mal nicht
sofort die Taste abfragen kann.
Außerdem belegt er keinen Interrupt, d.h. der Timer kann immer noch
weitere Sachen machen, da er frei durchläuft.
Das ich auch beim Drücken verzögere, hat den Sinn, daß ich nicht
jedesmal, wenn sich einer mit elektrostastisch geladenen Pullover den
Tasten nähert, diese dann sofort verrückt spielen.
Der Mensch reagiert eh nicht schneller als etwa 300ms, da ist eine
Verzögerung um weitere 20ms völlig bedeutungslos.
D.h. für einen Menschen betrachtet, reagiert meine Routine auch im
selben Moment.
Peter
Hallo Peter,
ich wollte nur mal posten wie ich meine Tasten entprelle....
Meine Routine belegt auch keinen Interrupt. der Timer ist auf immer für
andere Zwecke zu benuzten ich schreib nur am Schluß dieser Timer ISR
eine Schleife rein die obengenanntes überprüft...
Na ja was heißt wenn das Hauptprogramm mal keine Zeit hat? Wenn ich
davon ausgehe das der Taster mindestens 100ms gedrückt ist laufen bei
einem mit 4MHz getakteten AVR 400'000 Befehle drüber....ich hab noch
kein Programm verbrochen das soviel Rechenoperationen benötigt. Bei
Warteschleifen im Quellcode - sorry - da ist die Programmierung nicht
gerade die beste......
Und was die Rechenzeit angeht, die betrachte ich erst gar nicht wenn
ich eh von vorherein schon sage das 20ms nicht ins Gewicht fallen,
Das entspricht wieder 80'000 Instructions @4MHz :-). Aber wir
programmieren hier ja schließlich keine Airbag-Steuerung :-) .....
IHMO sind 99% der Themen die hier im Forum behandelt werden (meine
Projekte eingeschlossen) für die MCUs sowieso Schlaftabletten.
:-)
MfG
Rainer
"Bei Warteschleifen im Quellcode - sorry - da ist die Programmierung
nicht gerade die beste......"
Du sprichst mir voll aus dem Herzen. Leider sieht man immer wieder
Programme, wo eine ganze Sekunde oder noch länger nutzlos verpulvert
wird und dann die Klagen kommen, die CPU ist zu lahm.
Das schärfste, was ich gesehen habe, war eine DCF77-Routine, die
geschlagene 2 Minuten dauerte, also absolut völlig praxisfern.
Ich benutze immer die Main-Loop Methode und wenn ein Prozeß mal warten
muß, dann aber schleunigst zurück zu Main und den nächsten Prozeß an
die Reihe gelassen.
Bisher habe ich immer Durchlaufzeiten von nicht über 500ms erreicht,
d.h. meine Geräte reagieren auf jeden Tastendruck quasi sofort.
Leider ist das bei industriellen Heimgeräten (Videorekorder, TV, HiFi,
Waschmaschine) nie der Fall, sowas programmieren wohl ausschließlich
Stümper :-(
Schlimmer noch, die puffern nicht mal !
Wenn ich also für das Erhöhen der Helligkeit beim TV 5 Tastendrücke
brauche, muß ich immer ewig warten, bis das Menü jede einzelne Taste
auch angezeigt hat.
Und moderne HiFi Anlagen haben längere Bootzeiten, als früher die
Röhrengeräte zum Aufheizen brauchten, völlig indiskutabel.
Muß mir meine nächste HiFi-Anlage wohl doch wieder selber bauen :-(
So, nun genug Frust abgelassen, muß ja auch mal sein.
Peter
Hallo,
für "Warteschleifen" hab ich in jedem größeren AVR mind. 2 Timer ...
aber das ist anscheinend schwer sich vorzustellen das man ein Programm
zu großen Teilen (die kleinen bei mir ganz) in die ISRs reinschreiben
kann. Das finde ich das ist eigenlich am "schwierigsten" am MC
Programmieren... ne Struktur zu finden in der keine Warteschleifen
benötigt werden. Wenn ich mir die (meisten) LCD Librarys z.B. anschau
.... schüttel graus ... da läufts mir kalt den Rücken runter. Da werden
doch mal eben >10k Taktzyklen vernichtet - das ist eigentlich wertvolle
Zeit um Strom zu sparen oder etwas anderes zu machen und nicht nur
verschachtelte char variablen zu erhöhen....
g Ein wenig größer betrachtet: Deßhalb brauch ich nun schon einen
>2GHz (besser 3GHz) PC um schnell Surfen zu können g. Mit einem <=1
GHz Teil wird ja mein Modem/ISDN sooooo stark runtergebremst....
MfG
Rainer
Zwar Off-Topic:
@Peter: Meinst Du mit DCF77 zufällig die ELV Lösung von vor ca. 10
Jahren ? Da war aber nicht nur die Synch Zeit von 2 Minuten störend :)
Gruß,
Andreas
Hallo Peter!
Beistrich sagt man bei uns in Österreich!
Ich weiß nicht ob ihr auch Semicolon sagt, wir nennen's jedenfalls
Strichpunkt :)
MfG,
Thomas K
PS.: Vielleicht sollte man gewissen Leuten hier die Unfähigkeit einen
Knopf zu drücken unterstellen :P
hallo peter dannegger
bin neu im internet forum chat deshalb mich bitte
korrigieren wenn ich unsinn mache.
spreche Sie an,weil mir Ihre wortbeiträge und stil gut gefallen haben;
auch ich habe in chats "experten" erleben dürfen (wurde verarscht,da
neu)
seit 4 jahren mit 8515 auf assembler (stk200 alt).
einstieg als autodidakt mit stk200 Buch:S.Volpe: AVR yC
und atmel-datenblättern.
wesentliche subsysteme des 8515 durchprobiert (timer/irq/aco)
projekte: LED-Laufschrift (512LEDS),
4x7segment LED decoder in assembler (leds direkt an ports/muxen der 4
segmente).etc etc
suche hilfe von profi bei detailproblemen (habe eins mit ACO und
int, das auch atmel nicht lösen kann).
andere frage:kann man an den 8515 2 16bit parallel-audio-wandler
(A-D D-A)
an die ports anschließen,um ein digitales audio subwoofer filter
(parameter: 6 12 18 24dB/okt // grenzfrequenz 20 - 200 Hz
Bessel Butterworth) zu realisieren ?
hat der 8515 genug rechenleistung ? (für stereo werden 2 Stück
mit identischem programm eingesetzt --> mono signal pro 8515)
welche algorithmen kommen zum einsatz (FIR oder IIR - Filtermodell
und wie funktionieren sie?)(es geht um multiply-befehle).
Idee:alle datenwörter durch 2 geteilt (rechtsschieben 1bit)/ror
und schon ist es halb so laut (wenn doch alles so einfach wäre...).
las schon einige bücher zum thema aber die mathe ist grausam.
deshalb einstieg schwierig.
antwort wäre nett.
ich kann auch verstehen,das Sie vielleicht keine lust haben,
"die welt schlauer zu machen".
nett,wenn sie mir auch dies kurz mailen an:
bukongahelas0815@netscape.net
oder tel
02741/935248
danke
@Ulrich,
Als Neuling in Foren das hier beachten:
http://www.lugbz.org/documents/smart-questions_de.html
Dann wird man auch nicht mehr freundlich darauf hingewiesen, daß man in
mehrere große Fettnäpfchen getreten ist (was Du als "verarscht"
empfunden haben magst).
Deine gröbsten Fehler sind:
- falsche Rubrik (Überschrift der Rubrik nicht gelesen)
- neue Frage nicht als neuen Beitrag gestellt
- für persönliche Beiträge gibts E-Mail
Peter
Ich weiss gar nicht was diese ständigen Diskussionen über Tasten
entprellen sollen. Und die ganzen entprellkods aus dem Forum finde ich
doof. Ich progge es folgender maassen: wenn einer der Tasten betätigt
wird läuft eine Zeit ab (frei ein zu stellen,je nach Anwendung) erst
dann wird das Hauptprogramm abgearbeitet. Und wenn mitten im Programm
in einer Schleife meinentwegen,wieder Eingänge abgefragt werden
müssen,dann wird davor wieder eine verzögerung programmiert.
Also total easy und garantiert kein prellen!!!
Gruss.
Vitali.
Uwe,wenn du möchtetst kann ich dir genauer erklären was prellen ist.
Jeder der probleme mit Tasten prellen hat, wird für sich schon eine
Lösung finden.Ich habe meine eigene Lösung dafür, die sich bei meinen
Projekten bewärt hat.
MfG.
Vitali.
danke peter für antwort aber ich weis leider nicht welche
rubrik wo gemeint ist.der begriff ist klar,
aber in diesem zusammenhang ?
werde die empfohlene hilfeseite besuchen und hausaufgaben machen.
oder problem:wie stelle ich einen neuen beitrag ?
diese fragen sind rhetorisch und harren keiner beantwortung.
erst mal selber lesen.und nur noch zum konkreten thema schreiben.
klar.danke.uli
Hi Peter,
wenn Dir was an meiner DCF77-Routine nicht passt, dann kanst Du sie ja
mal verbessern. Unter der Vorraussetzung, dass diese in einem recht
gestörtem Umfeld läuft und der DCF77 keine sauberen Bit-Werte liefert.
Ich habe bis jetzt nur diese eine Lösung. Die eigentliche Applikation
mißt Daten. Die Abspeicherung der Zeiten muß über DCF77 ohne Ausfälle
abgeglichen werden. Es darf maximal ein DCF77-Ausfall (1 min) erlaubt
werden. Ansonsten muß eine Störmeldung per SMS gesendet werden. Am
Anfang war das der reinste SMS-Generator !!
Viel Spaß beim tüfteln !!
@Michael
"wenn Dir was an meiner DCF77-Routine nicht passt"
ich meinte konkret diesen Code:
// Modulname: $Source:
C:/c51_buecher/Teil2/software/Peripherie/DCF77/rcs/DCF77_lib.c $
// User: $Author: MEBA $
// Version: $Name: $ $Revision: 1.1 $
// Datum: $Date: 2001/02/03 11:03:35Z $
Er ist doch sehr aufwendig und dadurch schwer zu verstehen.
Wenn ich das richtig sehe, wartet es 512/3 Pegelwechsel, d.h. die CPU
ist quasi 85 Sekunden tot.
Wenn man noch Pech hat, liegt die Minutenpause gerade in der Mitte,
d.h. man hat 42 alte Bits und 42 neue, die gesamte Zeit- und
Datumsinformation ist dann fürn Arsch.
Auch so völlig ohne jede Notwendig 1024kB SRAM zu verschwenden, um
wahnsinnsschnelle 1Bit/Sekunde zu puffern ist auch nicht gerade die
feine Englische.
Meinen Code findest Du z.B. hier:
http://www.specs.de/users/danni/appl/soft/c51/thclock/index.htm
Die Impulszeitmessung erfolgt im Timer-Interrupt und die Auswertung
ganz nebenbei im Main.
Im Beispiel erfolgen noch mehrere Temperaturmessungen, ohne daß sich
beides ins Gehege kommt.
Ausgelastet ist der 2051 damit aber noch lange nicht, viele weitere
Funktion könnten also noch mit eingebaut werden.
Es ist auch ein exzellentes Beispiel, wie man Tabellengesteuert mehrere
ähnliche Aktionen (einen bestimmten Wert zu einer bestimmten Adresse
addieren) extrem Code sparend ausführen kann anstelle einer riesigen
Statemaschine (switch).
Durch die Überprüfung der Pulsanzahl, der Pulsdauer, der Pulspausen und
schließlich der Parität ergibt sich auch eine exzellente
Fehlererkennung, da ja Störungen asynchron und nicht Pegelgleich sind.
"Es darf maximal ein DCF77-Ausfall (1 min) erlaubt
werden."
Warum ?
Was machst Du dann bei Gewitter oder Wartungsarbeiten am Sender ?
Es reicht doch, wenn einmal am Tag eine fehlerfreie Information
empfangen wurde und die dann den internen Takt synchronisiert.
Ich mache es jedenfalls so und habe die Uhr in der Nähe des PCs stehen.
D.h. sobald der Monitor an ist und stört, läuft sie einfach intern
weiter.
Peter
Hi Peter,
wenn der DCF77-Empfang gestört ist, kann es zwei Möglichkeiten geben:
1. Es ist bekannt, dass durch eine Wetterlage oder durch
Wartungsarbeiten das DCF77 zur Zeit nicht arbeitet. Dann kann dies der
eigentlichen Meßstation mitgeteilt werden.
2. Oder es gibt Probleme an der Stelle, wo die Meßeinrichtung steht. In
diesem Fall muß sofort weitergemeldet werden, dass unter anderm das
DCF77 Signal nicht mehr empfangen werden kann. Es hat sich
herausgestellt, dass eine "statische Luftaufladung im großen Stil",
den Empfang stört. Da die Meßstation nichts weiter macht als eine
Luftsäuremessung, und eine Temperturmessung pro Minute, wollte ich
keine Interrupts einführen. Der Sensor für die Luftsäuremessung ist
zudem sehr träge, sodas eine häufigere Abfrage sich nicht lohnt.
Das DCF77-Signal ist zu einem weiteren Indikator geworden für die
Messstation, nicht mehr und nicht weniger :-)
"Da die Meßstation nichts weiter macht als eine
Luftsäuremessung, und eine Temperturmessung pro Minute, wollte ich
keine Interrupts einführen."
Ich habe absolut keine Idee, warum diese Sachen gegen den Einsatz eines
Interrupts sprechen sollen ?
Ich benutze Interrupts sehr gerne.
Und wenn dadurch der Code einfacher wird, dann ist daß auf alle Fälle
ein gutes Argument für den Interrupt.
Interrupts sind ja quasi eine 2.CPU, die parallel zu den anderen
Routinen arbeitet.
D.h. um eine Aufgabe, die der Interrupt erledigt, brauch ich mich dann
nicht mehr im Main kümmern.
Und ich brauche auch kein Nebenwirkungen mehr zu befürchten, die Länge
des Durchlaufs des Main behindert ja nicht den Interrupt.
Peter
P.S.:
Habe ich nun irgendwas übersehen, oder stimmt das oben wirklich, also
CPU 85s tot und 1024Byte RAM-Verschwendung.
Ich komme ja fast immer mit den 128Byte des 2051 aus.
Hi
@Peter, ich habe mir erlaubt deine Routine als erstes Projekt für mein
neues AVR Hobby zu benutzen, bin also Einsteiger. Allerdings
programmiere ich professionell schon über 15 Jahre. Deine Methode ist
super gut und macht genau das was Software meiner Meinung nach machen
soll, Hardwarekosten senken. Man denke nur mal an ein 8x8
Matrixkeyboard. Beim Testen konnten keine Preller festgestellt werden
obwohl bei meinem STK500 der SW3 ab&zu klemmt. D.h. gerade solche
Taster fangen öfters an zu prellen.
Ich habe den Code für das STK500 Board angepasst. Die jetzige Routine
demonstriert das Entprellen von Tasten, Tastenwiederholungen mit
Zeitverzögerung und das Ansteuern einer LED per Pulsweiten Modulation.
Die Taktfrequenz/Inversion/Pulsweite der PWM kann über die entprellten
Taster eingestellt werden. Den Code poste ich hier weil ich selber als
Anfänger nicht viele gute und einfach zu verstehende Beispiele gefunden
habe. Achso, wichtig am Source war es für mich den Sleep Mode der MCU
zu nutzen !
Da es mein erstes AVR Projekt ist würde ich mich über Feedback von euch
freuen, eg. Was habe ich falsch gemacht bzw. was geht zu verbessern.
Allerdings soweit ich das verstanden habe ist PWM auf den meisten
AVR's ziemlich ineffizient wenn man die Basisfrequenz der PWM fleißend
einstellen will, richtig ?
Gruß Hagen
...hallo Hagen,
ich bin beim MC Programmieren absoluter Neuling.
Wo finde ich PE2 ?
Hab jetzt mal alle LED's auf Bort B angeklemmt.
Sieht ja lustig aus, wie das flackert.
Was mache ich denn, wenn ich einzelne Ports anderweitig benötige ?
Ich würde gerne Port D für ein LCD und eine UART-Verbindung nutzen.
Ich versuche das mal zu verstehen, was Du in Deinem Proggi tust aber da
Du immer mit dem Ganzen Port arbeitest, ist es wahrscheinlich recht
aufwändig, das auf einzelne Ports umzubauen.
Da wäre es doch bestimmt einfacher die Pins einzeln abzufragen, oder ?
@Hagen
Hast Du mal die Taster abgeklemmt,
Ziemlich wildes Verhalten.
Da man bei Überwachungsaufgaben meistens nur einen Öffner oder einen
Schließer hat, ist das nicht wirklich sicher.
Bei undefiniertem Zustand spinnt mein STK 500 zumindest völlig.
@Peter:
Sag mal, was bedeutet eigentlich diese Zeile ?
ldi wr0, 1<<CS02^1<<CS00
ldi ist klar. wr0 auch aber das mit den '<' Zeichen habe ich schon
mehrfach gesehen aber keine wirkliche Erklärung dazu.
heisst das Du schiebst hier eine 1 nach bit 0...7 ?
Dann schiebst Du aber nicht sondern setzt das entsprechende Bit auf
eins.
Würde 0<<1 bedeuten bit 1 ist 0 ?
Was beduten diese Zeilen dann genau ?
init:
ldi wr0, 0xFF
out ddrb, wr0
ldi wr0, 1<<CS02 ;divide by 256 * 256
out TCCR0, wr0
ldi wr0, 1<<TOIE0 ;enable timer interrupt
out TIMSK, wr0
wird hier wr0 auf 00000100 gesetzt ? (CS02 ist Bit2 von TCCR0, wenn ich
nicht irre).
wird wr0 vorher komplett gelöscht ?
wr0 = 4 oder 0b00000100 wäre doch viel einfacher nachvollziehbar.
@Carsten
Ich würde z.B. "1<<6" mit "eine 1 um 6 Bitpositionen nach links
verschoben" übersetzen. Das Ergebnis ist genau wie Du sagts, dass das
entsprechnede Bit gesetzt ist. Der Vorteil des Schiebeoperators
gegenüber z.B. einer direkten binären Darstelleung ("0b01000000")ist,
dass ich den Schiebeoprator z.B. auch mit definierten Pinnummern
verwenden kann und damit beim Quelltextschreiben nicht so viel denken
muss. Das ganze funktioniert auch mit einer 0 (z.B."0<<7" = "eine 0
um 7 Bitpositionen nach links verschoben"), was aber zumindest im
Zusammenhang mit einem ldi nicht allzuviel Sinn macht. Ich verwende es
trotzdem im Zusammenhang mit der Portinitialisierung. Dann kann ich
ohne die Pinnummer oder deren Namen zu schreiben oder zu löschen
entscheiden, ob der Ausgang 1 oder 0 sein soll usw.
z.B.
ldi RG0,1<<pSpiEn|1<<pSCK|0<<pMOSI|1<<pMISO|1<<pLed1|1<<pLed2
Ist zwar einmal etwas Schreibarbeit, aber aus meiner Sicht recht
flexibel und gleich einigermaßen dokumentiert.
Jörg
Also ich habe mir mal die debounce_keys.c angeschaut von Peter Fleury,
wobei im Header steht:
"based on algorithm of Peter Dannegger", daher hier die Frage..
Was ich nicht verstehe ist, wie ich diese Port(8PIN) Entprellung in
meinem Programm nutzen kann...
Ich möchte nicht, dass die Tastenabfrage in dieser for(;;)
Endosschleife läuft, da kann cih ja nebenbei mein Programm nicht mehr
abarbeiten....
Wenn ich diese for Schleife aber weglasse, dann funzt das Programm ja
net richtig(wegen den Timern..?!)...?
Danke
Verprellter wrote:
> Wie kann man über so ne Trivialaufgabe eigentlich so lange öffentlich> labern...?
Es gibt reichlich Geräte, die zeigen, daß das Thema nicht trivial ist
bzw. nicht verstanden wird.
Ständig muß man sich über prellende Tasten oder verlorene Tastendrücke
ärgern.
Oft denken die Leute, daß der Kunde bei einfachen Geräten keine
funktionierende Entprellung haben will.
Die internen Ablaufzeiten werden schon irgendwie mehr schlecht als recht
ne rein zufällige Entprellung ergeben.
Dabei paßt eine funktionierende Entprellung selbst in nen kleinen
6-Pinner PIC.
Aber auch bei Fahrstuhlsteuerungen habe ich schon prellende Tasten
erlebt.
Peter
rapeur wrote:
> Hallo zusammen,> ich habe alle ihre Beitrage über Tasten entprellen gelesen und probiert> aber immer noch nicht geschaft.
Was soll der Code machen?
Wo ist das Main?
Längeren Code als Dateianhang.
Was ist "unsigned float"?
Wird Dein Code ohne Fehler und Warnungen übersetzt?
Entscheide Dich für einen Entprellcode, 2 verschiedene zusammen zu
pappen ist unsinnig und kann nicht funktionieren.
Alle Compiler kennen Bytevariablen und logische Operationen mit
Bitmasken.
Manche Compiler unterstützen aber auch Bitvariablen.
Finde heraus, was Dein Compiler kann und entscheide Dich für eines
davon. Beides zu mischen ist verboten (zumindest für Anfänger).
Peter
Hallo Peter,
ich bin letzte Woche in das Thema µC eingestiegen und habe mir erst mal
die kompletten Tutorials zu diesem Thema durchgelesen.
Um erst einmal ein paar grundlegende Sachen zu verstehen und
auszuprobieren, habe ich unter anderem auch deinen Algorithmus zum
Entprellen von Tastern verwendet. Ich habe allerdings etliche Male
versucht mir klar zu machen, wie dein Algorithmus funktioniert, aber ich
habe es nicht geschafft. Könntest du mir vielleicht deine Vorgehensweise
erklären?
Konkret habe ich folgende Fragen: Welche Bedeutung haben iwr0, iwr1 und
key_state? Welchen Zweck erfüllen die einzelnen boolschen Operationen,
z.B. wozu invertierst du key_old? Wieso heißt es in der Beschreibung,
die Tasten werden 4 mal abgetastet? Ich habe das ganze mal mit einem Bit
simuliert und erst nachem 2mal hintereinander eine 1 und 2mal
hintereinander eine 0 anlagen, wird der Tastendruck als solcher
gewertet. Wie speichert aber dein Algorithmus "2mal 1 und 2mal 0
hintereinander"? Ich finde es erstaunlich, dass das ganze nur mit
boolschen Operationen funktioniert, aber wie gesagt, verstehen tue ich
es noch nicht ganz.
Danke schon mal.
Mir gehts genauso wie Dir, ist wohl nix für Anfänger...
Ich hab jetzt auch einige Zeit dran geknabbert und stelle mir die
gleichen Fragen. Jetzt hab ich mal versucht, das mit AVM-Studio
nachzuvollziehen aber so wie es da steht, funktioniert es scheinbar
garnicht. Egal was eingelesen wird, key_press bleibt bei mir am Ende
immer 0x00.
Leyna S. wrote:
> Konkret habe ich folgende Fragen: Welche Bedeutung haben iwr0, iwr1
Interrupt-Working-Register 0, 1 usw.
Da der AVR ja viele Register hat, ist es effizient, einige davon für
Interrupts zu reservieren, spart viel PUSH/POP ein.
> key_state?
Merkt sich den entprellten Tastenstatus.
> Welchen Zweck erfüllen die einzelnen boolschen Operationen,> z.B. wozu invertierst du key_old?
Weil die Tasten low-aktiv sind, aber ich dann später in der
Tastenauswertung lieber ne 1 für Gedrückt haben will.
> Wieso heißt es in der Beschreibung,> die Tasten werden 4 mal abgetastet?
Ist bei dem obigen Code auch nicht der Fall
Der mit der 4-fach Abtastung ist der hier:
Beitrag "Tasten entprellen - Bulletproof"> Ich habe das ganze mal mit einem Bit> simuliert und erst nachem 2mal hintereinander eine 1 und 2mal> hintereinander eine 0 anlagen, wird der Tastendruck als solcher> gewertet.
Ja, stimmt.
Wie speichert aber dein Algorithmus "2mal 1 und 2mal 0
> hintereinander"?
Mit Hilfe von "key_old".
> Ich finde es erstaunlich, dass das ganze nur mit> boolschen Operationen funktioniert
Ich habs mit Gattern erstmal für nur 1 Bit entwickelt.
Peter
Kann mir denn jemand verraten, warum das bei mir nicht funktioniert? Ich
meine doch, ich hätte den Code 1:1 übernommen (ergänzt um
Stackpointer-Initialisierung), von pind werden auch Werte eingelesen,
aber am Ende der Verknüpfungs-Orgie bleibt key_press irgendwie immer
ohne Wert. Was mach ich denn falsch?
DeppchenDoof wrote:
> Kann mir denn jemand verraten, warum das bei mir nicht funktioniert?
Nein.
Ich hab Deinen Code auf mein STK500 gebrannt, er läuft wie dumm.
Ich hab zwar keinen Mega8515, sondern nen Mega162, aber die sind ja
kompatibel.
Anbei mal das Hex aus Deinem Code für den Mega8515.
Peter
Jesses, ich doof, kaum macht mans richtig, schon gehts. Hätte ich nur
mal aufmerksam gelesen ("Ich habe das ganze mal mit einem Bit
simuliert und erst nachem 2mal hintereinander eine 1 und 2mal
hintereinander eine 0 anlagen, wird der Tastendruck als solcher
gewertet.") oder wahlweise einfach schonmal selbst mitgedacht... =)
Brennen wollte ich das ja nur, wenn ichs auch verstehe, deswegen bin ich
noch mit dem Simulator zugange. Aber den sollte man dann vielleicht auch
richtig bedienen...
Vielen Dank für Deinen Beistand!
Hallo Peter,
jetzt, wo ich die Funktionsweise deines Algorithmus endlich kapiert
habe, muss ich sagen, dass dieser echt genial ist! Er ist, wie beworben,
kurz und schnell.
Probleme hatte ich hauptsächlich deswegen, weil die Funktionsweise unter
http://www.mikrocontroller.net/articles/AVR-Tutorial:_Tasten schlicht
falsch beschrieben ist. Gemeldet wird die Flanke dann, wenn zwei Mal die
Taste gedrückt war und davor zumindest zwei Mal nicht gedrückt war,
richtig?
Ich würde das auch selber ändern, fühle mich hier aber noch nicht so
heimisch. Das ist mein erster Post, mit Mikrokontrollern arbeite ich
seit gestern :)
Und was in diesem Thread geschimpft wurde ... da dreht's einem ja fast
den Magen um. Danke, dass du deine Routine trotzdem veröffentlicht hast.
LG,
Christian
Hallo Peter,
zunächst mal herzlichen Dank für Deine Beiträge und den Code zum Thema
Tastenentprellung.
Ich habe Deine IRQ-Routine eine ganze Weile nicht verstanden, daher habe
ich das Ganze mal in Excel simuliert. Dabei ist mir (durch Zufall)
aufgefallen, dass die Routine bei verschiedenen Sequenz von
"Verprellern" (also h/l-Folgen) in einen Status fällt, der den
Tastendruck komplett ignoriert.
Ich habe das Excelsheet mal im Anhang dazugepackt. Ich habe es mehrfach
überprüft und glaube nicht, einen Fehler gemacht zu haben. Wenn Du
magst, kannst Du ja mal reinschauen. Ich habe zuerst gedacht, es ist ein
Excel-Problem, aber das hat sich nicht bestätigt. Habe dann auf Deinem
Ansatz (mit Interstates) aufgesetzt die Routine verändert. Das
Codestückchen habe ich interessehalber dazu gepackt.
Übrigens, da ich viel mit Tinys (wenig Pins) mache, diese
Tastenentprellung funktioniert auch für Eingänge, die gleichzeitig auch
als Ausgang genutzt werden. Daher am Anfang die Abfrage auf DDR-Status.
So kann man eine Einknopfbedienung bauen, bei der nur ein Pin benutzt
wird. Auch bei "schnell, also zwischen 10-500ms" blinkenden LEDs
funktioniert die Tastenerkennung super.
Beste Grüße
Magnus
Magnus C. schrieb:
> Ich habe Deine IRQ-Routine eine ganze Weile nicht verstanden, daher habe> ich das Ganze mal in Excel simuliert. Dabei ist mir (durch Zufall)> aufgefallen, dass die Routine bei verschiedenen Sequenz von> "Verprellern" (also h/l-Folgen) in einen Status fällt, der den> Tastendruck komplett ignoriert.
Um einen Zustandswechsel zu akzeptieren, erwartet die Routine viermal
aufeinanderfolgend low bzw. high.
Kürzere Wechsel werden ignoriert. Du kannst z.B. 3 low und 3 high
ständig im Wechsel senden, es ändert sich nichts.
> Ich habe das Excelsheet mal im Anhang dazugepackt.
Ich hab kein Excel.
Ich hab aber gesehen, daß Du den Code völlig umgestellt hast.
Das könnte natürlich eine andere Funktion bewirken.
Warum nimmst Du nicht den funktionierenden Code?
http://www.mikrocontroller.net/articles/Entprellung#Komfortroutine_.28C_f.C3.BCr_AVR.29> Übrigens, da ich viel mit Tinys (wenig Pins) mache, diese> Tastenentprellung funktioniert auch für Eingänge, die gleichzeitig auch> als Ausgang genutzt werden.
Das macht nichts.
Die Pins werden unabhängig entprellt, man muß auf Ausgänge keine
Rücksicht nehmen.
Peter
Hallo Peter,
danke für die schnelle Antwort.
1) Ich betrachtete bei der Simulation nur einen Pin. Mir ist klar, dass
bei Deiner Programmierung jeder Pin einzeln betrachtet wird. Das mit dem
Zustandswechsel kann man in der Simulation sehr schön sehen. Daher
behaupte ich, dass bei bestimmten Prellsituationen (L-H-H-H-H-L-L-H...H)
die einzelne Taste nicht erkannt wird. Der Code ist damit ein bisschen
buggy. Daher habe ich ihn umgestellt. In der Simulation funktioniert
"meine" Änderung ohne die Effekte.
Die Fehlersituation ist im Testfeld so gut wie nicht zu simulieren. Es
könnte einfach nur so sein, dass man hin und wieder die Taste drückt und
nix passiert.
Schade, dass Du kein Excel hast, sollte Dich das Ergebnis aber
interessieren, kann ich versuchen es auch anders auszugeben, dann kann
man nur nicht so schön spielen, denn das Excel-Sheet rechnet.
2) Ich meine nicht unterschiedliche Pins, sondern den gleichen Pin zur
Ausgabe einer LED und Tastereingabe. Man benutzt Taster gegen Masse, LED
gegen Plus, PORTnx=0 gesetzt -> Schalten der LED mit DDRnx, in den
Dunkelphasen der LED kann man den Taster abfragen (und der User sieht
seinen Tastendruck durch LED-Leuchten). Ich gebe dann das Feedback über
unterschiedliche Blinkfrequenzen. Funktioniert super!
LG
Magnus
Magnus C. schrieb:
> Daher> behaupte ich, dass bei bestimmten Prellsituationen (L-H-H-H-H-L-L-H...H)> die einzelne Taste nicht erkannt wird. Der Code ist damit ein bisschen> buggy.
Mit dieser schwammige Behauptung kann bloß niemand was anfangen.
Warum schreibst Du nicht einfach die magische Kombination auf, die
Deiner Meinung nach buggy sein soll?
> Daher habe ich ihn umgestellt. In der Simulation funktioniert> "meine" Änderung ohne die Effekte.
Er ist zumindest deutlich aufwendiger (2 zusätzliche if-Anweisungen).
Aber solange ich nicht weiß, wogegen er helfen soll, kann ich ihn nicht
beurteilen.
Dazu brauchts auch kein Excel, schreib einfach die Sequenz hin
(0-0-1-1-..) und gut is.
Anbei noch ein Testprogramm, womit man schön auf STK500 simulieren kann,
da mit 1s entprellt wird, d.h. man muß >4s drücken oder loslassen.
> Die Fehlersituation ist im Testfeld so gut wie nicht zu simulieren.
Was soll denn das nun wieder heißen?
Wie hast Du dann den Fehler festgestellt?
Ist es denn wirklich so schwer, einen aussagekräftigen Fehlerreport zu
verfassen?
Peter
Magnus C. schrieb:
> 2) Ich meine nicht unterschiedliche Pins, sondern den gleichen Pin zur> Ausgabe einer LED und Tastereingabe. Man benutzt Taster gegen Masse, LED> gegen Plus
Daran stört mich, daß die LED nicht reagiert, solange die Taste gedrückt
ist.
Daher benutze ich folgende Lösung:
Beitrag "Taster + LED am selben Draht (4*)"
Peter
Hallo Peter,
mach Dich locker!
Ich will Dich bestimmt nicht ärgern. Trotzdem befürchte ich, habe ich
recht. Ich habe den Fehler in einer Simulation bemerkt!!
Eine logische Folge hatte ich oben genannt. Es gibt mehrere.
Danke für die STK500-Routine, ich werde meine logische Folge mit Deinem
Code testen und dann berichten.
Grüße
Magnus
Magnus C. schrieb:
> mach Dich locker!
Naja, Du behauptest, da wäre ein Fehler, kannst ihn aber in keinster
Weise belegen.
Der Code wird auch von vielen anderen benutzt und verstanden, da sollte
ein Fehler schon längst aufgefallen sein.
Da er nur logische Operationen benutzt, ist er fehlerfrei. Ansonsten
müßte man AND/OR/XOR/NOT und Zähler mit D-FF neu definieren. Ich hab ihn
nämlich erst als Logik-Schaltplan entwickelt mit nem GAL.
Viel warscheinlicher ist daher, daß der Fehler in dem Code liegt, den Du
nicht gezeigt hast und Deine Änderung nur die Symptome bekämpft, nicht
aber die Ursache.
Sehr häufig gemachte Fehler sind Atomic- und Volatile-Fehler.
Wichtig ist natürlich, genau die Reihenfolge der Operationen
einzuhalten, sonst funktioniert der Zähler nicht richtig.
> Ich will Dich bestimmt nicht ärgern. Trotzdem befürchte ich, habe ich> recht. Ich habe den Fehler in einer Simulation bemerkt!!
Dann müßtest Du ihn ja auch reproduzieren können. Und dann auch
beschreiben.
Bisher hast Du aber nicht mal ein kleinstes Pfitzelchen konkretes
gesagt.
Kommt mir so vor, wie die vielen, die eine Bug im C-Compiler finden und
dann später feststellen, das der Fehler doch auf der anderen Seite des
Bildschirms lag.
> Eine logische Folge hatte ich oben genannt. Es gibt mehrere.
Wo denn bitte.
Wenn der Fehler in Excel auftritt, ist das nur ein Beweis, daß die
Umsetzung in Excel fehlerhaft ist. Oder kann man in Excel etwa direkt
C-Code eingeben?
Wenn Du etwas simulieren willst, nimm besser den Simulator im AVRStudio.
Der ist deutlich näher an der Realität als Excel.
Peter
Trotzdem befürchte ich, habe ich
> recht. Ich habe den Fehler in einer Simulation bemerkt!!
....sorry, ich hatte unrecht!!
Ich habe mit Deiner Routine meine Sequenzen getestet und habe einen
Fehler in der Simulation gefunden. Deine Routine funktioniert
einwandfrei. Ich werde Deinen Code zukünftig in meinen Tastenabfragen
einbauen.
Danke nochmals für die Unterstützung!
Beste Grüße
Magnus
Hallo Peter,
du hast oben geschrieben, dass Du die Routine schon längere Zeit für
8051er verwendest. Könntest du vielleicht auch eine 8051er adaptierte
Version des Sourcecodes online stellen?
Wäre super.
Hallo,
ich möchte an dieser Stelle mal einen großen Dank an Peter Dannegger
aussprechen. Ich benutze die "C-Komfortroutine" inzwischen in einigen
Projekten und die ist wirklich klasse. Einfach und Zuverlässig.
Vielen Dank & viele Grüße,
Alex
peter dannegger schrieb:>...> Die eigentliche Einlese- und Entprellroutine ist nur 8 Instruktionen> kurz.>...
Hallo,
gehe ich richtig in der Annahme das es sich dabei um die beiden letzten
Zeilen handelt die wegfallen könnten ?
and iwr1, iwr0 ; 00000010
or key_press, iwr1 ;store key press detect
>...>> Zum Verständnig empfiehlt es sich daher, die Logikgleichungen mit> Gattern für ein Bit = eine Taste aufzumahlen.>> Die Register kan man sich als Flip-Flops denken, die mit der> Entprellzeit als Takt arbeiten.>...>
Das habe ich gemacht, weil ich dachte dann würde ich die Routine
verstehen.
Aber ehrlich gesagt hat das nur alles verschlimmert. Nun versteh ich
noch weniger.
Irgendwie habe ich auch das Programm nicht richtig in Logikgatter
umgewandelt, denn beim Exklusiv Oder-Gatter ( 8 ) Ausgang ( key_state )
ist mir beim durchspielen ein Fehler aufgefallen.
Danach dann ganz deutlich das beim Oder-Gatter ( 10 ) Ausgang
( key_press ) erst recht etwas nicht stimmt, denn key_press bleibt ja,
wenn einmal auf eins immer auf eins.
Wo sind meine Fehler oder besser wie sieht der Logik-Gatter-Plan richtig
aus ?
Anbei noch meine Umwandlung vom Programm in eine Logik-Gatter-Schaltung.
Bernd_Stein
ich gehe in dem Fall so vor, erstmal mit dem Oszi oder zur Not mit dem
LA das Prellen des Tastern feststellen, danach mache ich meine
Entprellroutine mit entsprechenden Sicherheitsabstand da die Tastern
auch mal altern.
Beispiel 1: Bei Flankenwechsel High/Low, Aktion auslösen, Interrupt
sperren und Interrupt erst wieder nach z.B. 5 mSek per Timer aktivieren.
Beispiel 2: Nach Flankenwechsel und Verzögerungszeit, wird mehrmals der
Zustand eingelesen und mit den letzen beiden malen verglichen.
Beispiel 3: Ware eine zusätzlich Plausibilität, man vergleicht also ob
es sein kann das jemand den Taster nur 2mSek lange gedruckt hat und
ignoriert das dann z.B. komplett.
Wahrscheinlich weil ich ein AVR+Assembler-Neuling bin:
Ich komm' einfach nicht dahinter wozu der Label "get8key:" in der
einfachen Entprellroutine von Peter gut ist?
Gibt's jemand der mich aufklärt?
Aber in Wien würde man zu der Entprellroutine - anerkennend! - sagen:
"Der Beda is a Hund!", was hierorts durchaus als Kompliment gilt!
Servus aus Wien
Harald
Harald Fuckar schrieb:> Ich komm' einfach nicht dahinter wozu der Label "get8key:" in der> einfachen Entprellroutine von Peter gut ist?
Ich bin jetzt auch kein Asm Crack, aber das Label hat m.E. keine
Funktion (mehr):
Man dürfte es auch nicht von ausserhalb anspringen (oder planen so etwas
zu tun), weil dann Register zurückgesichert werden, deren Absichern man
übersprungen hat. Und das beim Anspringen zu berücksichtigen - da wird
es m.E. etwas zu hacky.
Man könnte es als descriptiven Funktionsnamen verstehen oder es ist ein
Relikt aus dem Originalcode wovon Peter abstrahiert und hier eingestellt
hat.
Ansonsten: wer kann sich ein nutzloses Label schon leisten! Man muss
zeigen, was man hat :-)
Harald Fuckar schrieb:
> Ich komm' einfach nicht dahinter wozu der Label "get8key:" in der> einfachen Entprellroutine von Peter gut ist?
Tja, das kommt davon, wenn man schlecht geschriebenen/dokumentierten
Code verwendet. Hier recht es sich, dass nicht sauber programmiert
wurde.
lg Heiner
Hallo @conny_g!
Ja, das hab' ich auch vermutet, dass dieser Label ein "Überbleibsel"
ist. Na, dann sind wir ja schon zwei, die das denken.
Heiner schrieb:> Tja, das kommt davon, wenn man schlecht geschriebenen/dokumentierten> Code verwendet. Hier recht es sich, dass nicht sauber programmiert> wurde.
Lieber Heiner.
Dein Kommentar ist leider nicht sehr konstruktiv und hilft überhaupt
nicht. Wenn Du Kritik äußerst, bitte konkret werden, damit auch andere
davon profitieren können.
Im übrigen: Wenn die mit "recht" das Wort gemeint hast, dass sich von
"Rache" ableitet, dann solltest Du in Zukunft "rächt" schreiben.
Ich vermute mal, dass "Rächtschreiben" nicht Deine Sterke ist ;-)
Aber unsachlich kritisieren ...
Jetzt, nachdem ich mir nochmals die Peter-Danegger-Entprellung zugeführt
habe, habe ich doch noch folgende Fragen:
1. Ich möchte eine Taste drücken und eine Zeitlang halten. Und solange
die Taste gedrückt ist, möchte ich vom uC eine Aktion ausführen lassen
(z.B. Klingeln). Erst wenn die Taste wieder losgelassen wird, möchte ich
auch die Aktion beenden. Bei diesem Beispiel gibt es zwei Flanken
LOW>HIGH=TasteIstGedrücktWorden und HIGH>LOW=TasteIstLosgelassenWorden.
Über Betrachtungsweisen bzgl. PullUp vs PullDown habe ich mich hier
bereits informiert - sie sind aber nicht ggst. Thema.
Wenn ich Peter Danegger's "Einfache Tastenentprellung und Abfrage"
richtig verstanden habe, bekomme ich aber bei der Methode nur gemeldet,
dass eine Taste (im ActiveLowMode) gedrückt wurde. Das Loslassen der
Taste, also die gegenteilige Flankenänderung krieg ich damit aber nicht
mit - oder?
Die erweitere Funktion "Tastenentprellung, Abfrage und Autorepeat" ist
aber für meine Aufgabenstellung auch nicht geeignet, da sie ja das
wiederholte Drücken einer Taste simuliert. Das entspricht aber nicht der
(meiner Beispiel-) Realität. Ich möchte gerne erkennen, dass eine Taste
gedrückt oder losgelassen wurde UND sie dabei ordentlich entprellen.
Mein erster Ansatz war ja mit einer Interrupt-Logik (Interrupt, wenn
Tastenpin sich ändert). Dann bin ich über's Entprellen ins Grübeln
gekommen und hab' hier im Forum gelesen, dass eine Interrupt-Lösung für
Tastendrücke "PfuiGack" ist.
Und jetzt steh' ich schön da und weiß nicht wie ich's möglichst
ordentlich mach', das Entprellen. Denn wenn's das nicht geben würde, wär
die Elektronikwelt aber sowas von einfach und sonnig ;-)
Kann mir wer raten?
Harald Fuckar schrieb:> Kann mir wer raten?
Ich weiss jetzt nicht, ob Du die ASM oder die C-Version anschaust, aber
muss man nicht einfach in dieser Routine:
Danke @conny_g für Deine Antwort!
Ich glaub' ich hab' die Lösung - für mich - gefunden:
Kostet mich ein Register:
Ich merk' mir den "alten" key_state-Wert im Register key_stalt.
Und wo bisher temp1 auf 0 abgefragt wurde, vergleiche ich die beiden
Register. Hat sich bei einer oder mehreren der betrachteten Tasten was
geändert, dann muss ich nur die entsprchende Aktion starten: Also z.B.:
LED1 aus wenn Status der Taste1 "nicht gedrückt", LED1 ein wenn Status
der Taste1 "gedrückt", usw.
Und dann muß ich mir natürlich den aktuellen key_state-Inhalt für den
nächsten Vergleich in key_stalt holen.
Auf diese Art kann ich die Vorteile der Peter-Danegger-Entprellung
nutzen und hab' dazu die von mir gewünschte Lösung - PRIMA!
Na der Peter Danegger wird "Schnackerl" (Schluckauf) haben.
(Sagt man in Wien, wenn von einem gesprochen oder an einen gedacht wird
;-)
>(Sagt man in Wien, wenn von einem gesprochen oder an einen gedacht wird>;-)
Also in den letzten 100 Jahren ist nicht viel sinnvolles aus
Oesterreich gekommen. Und das oben stehende wird daran nichts aendern.
lg Heiner
Über das int16_t wird erreicht, dass recht 16 Bit signed gerechnet wird,
mit dem Minus negiert und über das uint8_t werden die unteren 8 But
genommen und als unsigned deklariert.
Achim schrieb:> Der hintere Ausdruck berechnet sich für einen Atmega8L mit 8MHz> zu:8000000 / 1024 * 0.01 + 0.5 = 78.7
Das hast ja schon ausgerechnet.
Ah, halt 10^-3 ist 0.001 bzw. :1000
1
Also 8000000 / 1024 / 1000 + 0.5 = 8.3
Als "int" ist das 8.
Da steht jetzt noch ein Minus davor: (int16_t)-...
d.h. der Ausdruck rechts soll als "signed" gerechnet werden und negativ
gemacht werden, also -8.3 oder in bits 0b1111 1111 1111 1000.
Wenn Du das jetzt nochmal von (int16_t) in (uint8_t) konvertierst, dann
wird einfach das LSB genommen und es bleibt 0b1111 1000 übrig.
Hallo Peter,
mal was anderes. :-)
Warum prüfst du das Tastersignal 4x?
Würde es nicht ausreichend sein eine erste Betätigung/Änderung
festzustellen, sich dieses Zustand zumerken und nach der Entprellzeit
nochmal das Signal mit dem gespeicherten vergleichen. Wenn gleich wurde
der Taster wirklich gedrückt. Sind nur 2 Prüfungen auf den
gedrückten/geänderten Zustand. Wo lauert die Falle wenn es eine gibt?
Mario schrieb:> Hallo Peter,>> mal was anderes. :-)>> Warum prüfst du das Tastersignal 4x?> Würde es nicht ausreichend sein eine erste Betätigung/Änderung> festzustellen, sich dieses Zustand zumerken und nach der Entprellzeit> nochmal das Signal mit dem gespeicherten vergleichen. Wenn gleich wurde> der Taster wirklich gedrückt. Sind nur 2 Prüfungen auf den> gedrückten/geänderten Zustand. Wo lauert die Falle wenn es eine gibt?
Volatilität.
Durchschnitt aus 2 ist anfälliger für Störungen/Unklarheit als
Durchschnitt aus 4.
Und Du meinst nichtmal Durchschnitt, sondern, dass das 2. Sample
entscheidet.
Aber das ist noch anfälliger. Deshalb wird zum Entprellen gerne der
gleitende Durchschnitt über mehrere Samples genommen (ein RC Glied ist
nix anderes). Und 4 ist ein Punkt wo langsam eine Stabilität einkehrt,
es aber wenig Zeitversatz kostet.
Aber „0“ beim ersten Mal und „1“ beim zweiten Mal ergibt 0,5 = und dann?
Ab dem dritten kristallisiert sich eine Richtung heraus, ab dem 4.
stabilisiert sie sich. Wenn die Samplezeit zur Entprellzeit passt.
Mario schrieb:> Warum prüfst du das Tastersignal 4x?
Weil die wahre Prellzeit nicht bekannt ist, sich im laufe der Zeit auch
ändern kann und Störimpulse ausfiltern...
Damit kann man einen Taster, wehrend er noch prellt, recht sicher
auswerten.
Mal wieder eine Frage/Ergänzung zu der Entprellroutine... ich verwende
die C-Version mit folgendem Code (für insgesamt 12 Taster über zwei
Ports verteilt, die ich aber gern mit einer gemeinsamen Maske abfragen
möchte, daher die Union):
1
typedefunion
2
{
3
uint16_tdata;
4
uint8_tbyte[2];
5
}keyInfo;
6
7
/**
8
* Variable to save current key status
9
*/
10
volatilekeyInfokeyState;
11
12
/**
13
* Variable to save key press detections
14
*/
15
volatilekeyInfokeyPress;
16
17
/**
18
* Variable to save key release detections
19
*/
20
volatilekeyInfokeyRelease;
21
22
/**
23
* To be called every 10ms from ISR - handle key input
Habe ich die Flankenerkennung richtig verstanden - in i sind am Ende der
Routine diejenigen Bits gesetzt, die sich geändert haben - und korrekt
um die "Taste-Losgelassen"-Erkennung ergänzt?
Vielen Dank Peter für die Vorlage, ich verknote mir zwar jedes Mal
wieder das Hirn, wenn ich es nachvollziehen will, aber die Funktion ist
großartig!
MfG, Arno
Okay, ich kann mir die Frage selbst beantworten, nachdem ich die
Hardware überredet habe, doch zu funktionieren: Ja, so funktioniert es,
es wird sowohl "Drücken" als auch "Loslassen" erkannt :)
Nur sollte man im CTC-Modus des Timers nicht auf den Overflow-IRQ
warten...
MfG, Arno
Ja, da hat sich ein Schreibfehler eingeschlichen. Das EXOR ist Unsinn,
2
muß ein AND sein.
3
Hier mal ein funktionierender Code:
Ich blick dort in diesem Thread nicht mehr durch.
Welchen Schreibfehler meint er dort ?
Wo wurde das EXOR durch ein AND ersetzt ?
Beitrag "Re: Universelle Tastenabfrage"
Bernd_Stein
Bernd S. schrieb:> Ich blick dort in diesem Thread nicht mehr durch.
Kannst Du bitte davon absehen, auf diese absonderliche Art und Weise zu
zitieren? Code-Tags sind für etwas anderes gedacht als für Zitate.
Markiere bitte - wie alle anderen User das hier auch machen - die zu
zitierende Stelle mit der Maus und klicke dann auf "Markierten Text
zitieren".
Peter D. schrieb:> Ja, da hat sich ein Schreibfehler eingeschlichen. Das EXOR ist Unsinn,> muß ein AND sein.> Hier mal ein funktionierender Code:>Bernd S. schrieb:> Ich blick dort in diesem Thread nicht mehr durch.>> Welchen Schreibfehler meint er dort ?> Wo wurde das EXOR durch ein AND ersetzt ?>> Beitrag "Re: Universelle Tastenabfrage">> Bernd_Stein>Beitrag "Re: Universelle Tastenabfrage"
Bernd_Stein
Arno schrieb:> für insgesamt 12 Taster über zwei> Ports verteilt, die ich aber gern mit einer gemeinsamen Maske abfragen> möchte, daher die Union
Das sieht recht umständlich aus.
Nimm doch für alles uint16_t:
Da ich PeDa´s AVR8ASM-Grundroutine zur Entprellung vollständig
verstanden habe und auch Hannes Lux seine Variante mit nur 4 Tastern und
der zusätzlichen Loslasserkennung, versuche ich nun die C-Komfortroutine
zu verstehen und habe natürlich einige Fragen dazu.
Ich habe mal die C-Komfortroutine angehangen, damit man eine
einheitliche Grundlage zur Diskussion hat.
Es geht noch mal um den Vorladewert für den 8-Bit Timer/Counter0.
Ich lasse den ATmega 2560 auf dem Arduino-Board mit seinen voll
möglichen 16MHz takten.
Der T/C0 wird ja durch 1024 heruntergeteilt, was 15625 Hz bedeutet und
ein Timertakt somit 64µs dauert.
Ein T/C0 Überlauf würde somit bei 256 * 64µs = 16384µs oder 16,384ms
erfolgen.
Jetzt müsste ich ja den T/C0 Wert auf 6,384ms setzen, damit noch 10ms
bis zum T/C0 Interrupt-Überlauf bleiben.
Dies wiederum würde bedeuten dass im TCNT0-Register der Wert 6384µs/64µs
= 99,75 also 100 stehen müsste.
Der Simulator sagt aber dass 240 errechnet wurde.
Im Prozessor Status Fenster des Simulators habe ich auch die Frequency
auf 16,000 MHz gestellt und bemerkt, dass die IRQ ca. alle 1,0x ms
auftritt.
Wo ist der Fehler ?
1
TCNT0=(uint8_t)(int16_t)-(F_CPU/1024*10e-3+0.5);// preload for 10ms
Nachdem mir bisher niemand zu meinem vorherigen Posting geantwortet hat,
habe ich generell mal überlegt. Eine Verzögerung von 100ms wird von
einigen Menschen schon bemerkt.
Wenn alles gut läuft, ist der Taster nach 40ms entprellt und man kann
mit ihm weiterarbeiten, alles in Ordnung.
Alles was sich im Bereich von 50ms tut, wird quasi als Echtzeit
wahrgenommen. Taster prellen meistens so um die 10ms, falls also mal
einer etwas länger prellt und dies von der Routine erkannt wird, erhöht
sich die
Entprellzeit um weitere 10ms, auf 50ms. Das ein Taster viel länger als
10ms prellt kommt sicherlich auch vor, aber nach 20ms ist da wohl
wirklich meistens Schluß, so dass eine Entprellzeit von 50ms wohl auch
realistisch ist. Also wahrscheinlich immer noch alles tuti. Die meisten
Tastendrücke können praktisch nach 40ms weiterverarbeitet werden.
Ich habe mir aber trotzem überlegt, den unbearbeiteten Timer/Counter0
Überlauf zu nutzen, der bei einem Teiler von 256 eine Zeitbasis von
4,1ms erzeugt, was einer Entprellzeit von ca. 16ms entpricht, wenn alles
gut läuft und sich halt im 4ms Abstand erhöht, falls ein Preller erkannt
wird.
Ich weiß eine 4,1ms Zeitbasis ist nich so dolle für die meisten
Anwendungen, deshalb wäre es toll, wenn Jemand mal eine Formel aufstellt
die mit verschiedenen CPU-Takten bzw. Frequenzen klarkommt.
Bernd S. schrieb:> In der Zwischenzeit schaue ich mir mal ein paar YT-Videos zur> C-Programmierung an, da C++ für µC nicht alles kann, C schon mehr und> ASM eben alles, nur nicht als Inline-Assembler wegen dem blöden ABI vom> Compiler ;-)
Genau diese Geisteshaltung ist dein Problem. Woher hast du das? um sich
mit einer Sprache auseindanderzusetzen braucht es einen offenen Geist
oder wie FZ immer betonte...
A mind is like a parachute. It doesn't work until its open.
Hallo,
Bernd S. schrieb:> ...da C++ für µC nicht alles kann, C schon mehr...
Also das interessiert mich jetzt aber, was kann denn C in der
µC-Programmierung mehr als C++?
rhf
Erklärungen zu sowas, habe ich leider bisher nicht gefunden :
1
if(get_key_short(1<<KEY1))
Erstens, wo ist der Vergleichsoperator ?
Ich beziehe mich auf die erste if-Anweisung nach :
1
while(1){
Man springt also zur FUNKTION get_key_short, dort passiert im
wesentlichen :
1
returnget_key_press(~key_state&key_mask);
Es wird also weiter zur FUNKTION get_key_press gesprungen, dort
passiert im wesentlichen:
1
returnkey_mask;
Nun landet man wieder in der FUNKTION get_key_short, wo man nach der
if-Anweisung gestartet ist, aber halt am Ende.
1
}
Um wieder am " Anfang " zu enden :
1
if(get_key_short(1<<KEY1))
Die if-Anweisung interessiert wahrscheinlich nur, ob in ihrer Klammer
eine 0 oder 1 bzw. false oder true, herauskommt. Dies ist wahrscheinlich
in der Variablen key_mask enthalten, von der ich gar nicht sagen kann,
ob diese jetzt global, lokal oder sonst irgendwie zu sehen ist.
Der Simulator ist leider bis zur dieser Sequenz im Screenshot nicht klug
genug mir zu zeigen, welche Variable ich beoachten soll (Auto).
Dies ist mir als Arduino-Anfänger jetzt erstmal viel zu undurchsichtig.
Falls es mir niemand erklären möchte, dann bitte wenigstens Literatur
nennen, die solche Praxisbeispiele haben und auch für Anfänger erklären.
Obwohl ich denke, dass dies leider kein Anfängerlevel mehr ist.
Bernd_Stein
Bernd S. schrieb:> Erklärungen zu sowas, habe ich leider bisher nicht gefunden :
also wie ein if() in C funktioniert steht in jedem Lehrbuch.
Bernd S. schrieb:> Erstens, wo ist der Vergleichsoperator ?
braucht man nicht, der Ausdruck in den Klammern wird ausgewertet und
wenn er true ist, dann ist die Bedingung erfüllt. Man könnte einen
Vergleich hinschreiben, braucht man aber nicht unbedingt.
Die kurzen Funktionen wird der Compiler 'inlinen', also keinen
Funktionsaufruf einsetzen weil der Aufruf mehr kostet als den Code
direkt einzubauen. Das kann man meist unterbinden wenn man mit Debug
Einstellungen kompiliert, das macht das Verfolgen einfacher. Für die
Ausführung macht die Optimierung Sinn, und das können die Compiler sehr
gut.
Bernd S. schrieb:> Es wird also weiter zur FUNKTION get_key_press gesprungen, dort> passiert im wesentlichen:> return key_mask;
Nö.
Die wichtigste Operation hast Du unterschlagen:
1
key_mask&=key_press;// read key(s)
Das ist die Maskierung des Dich interessierenden Bits.
Du brauchst erstmal ein Verständnis, wie man in C einzelne Bits
behandelt.
C prüft bei Bedingungen, ob ein Ausdruck 0 oder nicht 0 ist.
Die einfachste Möglichkeit, um uninteressante Bits auszublenden, ist
daher, sie mit 0 zu verunden.
Man verundet dazu mit einer Maske, wo nur das interessante Bit gesetzt
ist, eben mit (1<< KEY1). KEY1 ist dabei im Bereich 0..7 zu definieren.
Bernd S. schrieb:> nur nicht als Inline-Assembler wegen dem blöden ABI vom Compiler
Es ist ja in Ordnung, das Constraint Management von GCC nicht in einer
halben Stunde zu begreifen. Aber nur, weil du etwas nicht aus dem
Stegreif begreifst, es als "blöd" zu bezeichnen, wird dich gewiss nicht
weiterbringen.
Man kann das Zeug unhandlich finden, aber ich habe auch andere
Inline-Assembler gesehen (bspw. von IAR), und ich kann dir versichern,
dass das, was GCC hier anbietet, sehr viel besser und durchdachter ist.
Es gestattet, Inline-Assembler-Code zu schreiben, der erstens der
Optimierung des Compilers nicht im Weg herum liegt und der zweitens
zukunftssicher ist, weil er sich in die Internals des Compilers
integriert statt irgendwelche impliziten Annahmen über selbige machen zu
müssen (bspw. in welchen Registern er bestimmte Sachen hinterlegt), die
schon in der übernächsten Version nicht mehr stimmen müssen.
Peter D. schrieb:> Nö.> Die wichtigste Operation hast Du unterschlagen:key_mask &= key_press;> // read key(s)> Das ist die Maskierung des Dich interessierenden Bits.>
Also, solche eine if-Abfrage, habe bisher in noch keinem Buch gefunden.
1
if(get_key_short(1<<KEY1))
Und die von dort startende Springerei, um nur wieder genau hier zu
landen ist sehr verwirrend für mich. Ich vermute ja nur, dass key_mask
eine Schlüssefunktion hat, weil diese Variabele immer wieder als
Return-Wert weitergereicht wird.
Wann zeigt mir also der Simulator welchen Wert diese Variable hat ?
KEY1 hat ja 1, so wie es halt in #define angebeben ist.
Ich raff es einfach nicht. KEY1 wird ja bei dieser Springerei nie ein
anderer Wert zugewiesen und trotzdem frage ich KEY1 irgendwie als
FUNKTION ab.
Jörg W. schrieb:> Es ist ja in Ordnung, das Constraint Management von GCC nicht in einer> halben Stunde zu begreifen. Aber nur, weil du etwas nicht aus dem> Stegreif begreifst, es als "blöd" zu bezeichnen, wird dich gewiss nicht> weiterbringen.>
Dass gerade ein Moderator nicht vollständig zitiert. Aber vielleicht war
es auch Copy&Paste Fehler.
Am Ende ist ein Simlie !
Es ist also nicht so biederernst gemeint.
Als ich festgestellt habe, dass man ziemlich nahe mit dem
Inline-Assembler an die ASM-Syntax kommt mit, war ich halt enttäuscht,
dass es leider doch keine 1:1 Übersetzung ist, weil man nicht
zuverlässig, feste GPR zuweisen kann.
Bernd S. schrieb:> ... , C schon mehr und ASM eben alles, nur nicht als Inline-Assembler> wegen dem blöden ABI vom Compiler ;-)>
Bernd_Stein
Bernd S. schrieb:> Am Ende ist ein Simlie !
Ja, nur klang der Text nicht so.
> … war ich halt enttäuscht,> dass es leider doch keine 1:1 Übersetzung ist, weil man nicht> zuverlässig, feste GPR zuweisen kann.
Kannst du, solltest du aber besser nicht tun. Dann machst du nämlich
genau das, was die Constraint-Syntax eigentlich vermeiden helfen soll:
du stehst dem Compiler bei der Optimierung im Weg herum, weil du deinen
Kopf durchsetzen willst.
Stattdessen sollst du halt dem Compiler beschreiben, was du brauchst:
"Ich brauche ein beliebiges CPU-Register", oder "ich brauche ein
Register oberhalb R16" usw usf. Dann kann der Compiler den restlichen
Code so organisieren, dass er möglichst wenige Daten "umschichten" muss,
was dir bei einer festen Zuordnung schnell passieren könnte.
> Also, solche eine if-Abfrage, habe bisher in noch keinem Buch gefunden.
Dann hast du schlechte Bücher gelesen. ;-)
Auch, wenn es seit C99 in C einen Typ "boolean" gibt: die Bedingungen
erwarten einfach einen Typ "int", und eine Bedingung ist wahr, wenn der
Wert verschieden von 0 ist. Daher kann man hinter if (oder while oder
so) natürlich genauso gut eine Funktion aufrufen, die ein "int"
zurückgibt (oder einen damit kompatiblen Typ). Genau das wird hier
getan.
Bernd S. schrieb:> Erklärungen zu sowas, habe ich leider bisher nicht gefunden :> if( get_key_short (1<< KEY1))>> Erstens, wo ist der Vergleichsoperator ?
Denn braucht es ja nicht.
Anscheinend hast Du noch nie in einer prozeduralen Sprache programmiert.
Nimm doch einfach mal ein C-Buch und suche das Kapitel "Funktionen" und
dann noch das Kapitel "Kontrollstrukturen" sowie ein Kapitel über
"Ausdrücke". Das könnte Dich weiter bringen.
Im obigen Fall wird innerhalb der if()-Klammer die Funktion
get_key_short() aufgerufen und gibt einen Wert vom Typ "uint8_t" zurück.
Ist dieser Wert ungleich 0, wird in die nachfolgende {}-Klammer
verzweigt, ist er 0 werden die Anweisungen innerhalb der {}-Klammer
nicht ausgeführt.
Vielleicht ist es für dich etwas klarer wenn man die Zeile ein wenig
aufbröselt, aber C-Programmierer mögen es nun mal kurz.
1
uint8_tresult;
2
...
3
result=get_key_short(1<<KEY1);
4
if(result!=0)
5
{
6
...
7
}
Bernd S. schrieb:> Also, solche eine if-Abfrage, habe bisher in noch keinem Buch gefunden.
So was ist in fast jedem C-Quelltext zu finden.
rhf
P.S.
Wie viele andere hier kann auch ich dir nur dringend raten mal ein
C-Lehrbuch in die Hand zu nehmen und ein paar Stunden in das Erlernen
(zumindest der Grundbegriffe) zu investieren. Der Versuch an Hand eines
Assemblerlistings C-Quellcode zu verstehen wird nicht funktionieren.
Roland F. schrieb:> Wie viele andere hier kann auch ich dir nur dringend raten mal ein> C-Lehrbuch in die Hand zu nehmen und ein paar Stunden in das Erlernen> (zumindest der Grundbegriffe) zu investieren.
Ja, ohne das wird's nicht abgehen können.
> Der Versuch an Hand eines> Assemblerlistings C-Quellcode zu verstehen wird nicht funktionieren.
Sowas kann durchaus mal hilfreich sein. Aber nicht für ihn. Der hat es
in >10 Jahren nicht geschafft, den überaus simplen AVR8-Assembler zu
beherrschen. Also wird er wohl mindestens 100 Jahre brauchen, bis er das
sehr viel komplexere C beherrscht. Selbst wenn man das mal auf avr-gcc
runterbricht...
Bernd S. schrieb:> Ich habe wirklich alle meine Bücher nach einem ähnlichem Konstrukt> durchsucht, aber nur if-Abragen gefunden, die Operatoren benutzen.
Dann solltest du beim Großvater der C-Bücher anfangen, dem K&R. Da gibt
es beispielsweise:
Bernd S. schrieb:> Ich habe wirklich alle meine Bücher nach einem ähnlichem Konstrukt> durchsucht, aber nur if-Abragen gefunden, die Operatoren benutzen.
Deswegen sagte ich Dir ja, dass Du mal schauen sollst, was ein
"Ausdruck" in C seien kann. Es gibt einfach bestimmte Dinge, die man
einmal klären sollte. Dieses Wissen hilft Dir dann ungemein, C-ähnliche
Sprachen zu verstehen (e.g. Java, C#, ...).
Programmiersprachen wie C operieren auf einer abstrakten (C)-Maschine.
Da hilft es ein klein wenig, wenn man sich vom sehr konkreten
(materialisierten) Assembler löst, und versucht in anderen Kategorien zu
denken: Datentypen, Werte, Variablen, Ausdrücke, ... Und dazu gibt es
tonnenweise Literatur, die man hier im Forum wirklich nicht wiederholen
muss. Wer mich kennt, weiß, dass ich dazu Stepanovs "Elements of
Programming" empfehle ;-)
Hallo,
Bernd S. schrieb:> Ich habe wirklich alle meine Bücher nach einem ähnlichem Konstrukt> durchsucht, aber nur if-Abragen gefunden, die Operatoren benutzen.
Nochmal:
1
if(get_key_short(1<<KEY1))
ist die Kurzform von
1
if(get_key_short(1<<KEY1)!=0)
> Vielleicht kann ja mal jemand eine Seite verlinken, die obige Konstrukte> erklärt.
Und das sagt die C-Bibel(1) im Kapitel "3.2 if-else" dazu:
------------------------------------------------------------------------
--
Da bei if einfach der numerische Wert eines Ausdrucks getestet wird,
sind bestimmte Abkürzungen möglich. Am offensichtlichsten ist dabei
Bernd S. schrieb:> if( get_key_short (1<< KEY1))> Ich habe wirklich alle meine Bücher nach einem ähnlichem Konstrukt> durchsucht, aber nur if-Abragen gefunden, die Operatoren benutzen.
Kann es sein, daß Dich das "1 << KEY1" durcheinanderbringt?
Das ist einfach nur eine Konstante. KEY1 ist, wie Du selbst schriebst,
als 1 definiert, und 1 << 1 ist 2.
Also steht da
1
if(get_key_short(2))
Gibt die Funktion get_key_short einen Wert ungleich 0 zurück, trifft die
Bedingung zu.
Hallo,
Harald K. schrieb:
> Das ist einfach nur eine Konstante. KEY1 ist, wie Du selbst schriebst,> als 1 definiert, und 1 << 1 ist 2.>> Also steht da>> if (get_key_short(2))
Ergänzend wäre vielleicht noch hinzuzufügen, das der Compiler erkennt
das das Argument für get_key_short() in diesem Fall eine Konstante ist
und erst
gar keinen Code für die Schiebeoperation erzeugt:
Bernd S. schrieb:> Ich habe wirklich alle meine Bücher nach einem ähnlichem Konstrukt> durchsucht, aber nur if-Abragen gefunden, die Operatoren benutzen.
Wirklich alle Deine Bücher und nichts gefunden? Dann taugen sie nichts.
Hier eines von hunderten Beispielen im Netz:
https://www.c-howto.de/tutorial/verzweigungen/vergleichsoperatoren/
Direkt am Anfang der Seite steht:
1
if(1)printf("1 ist wahr\n");
2
if(0)printf("0 ist wahr\n");
3
if(4711)printf("4711 ist wahr\n");
4
if(1-1)printf("1-1 ist wahr\n");
Denksportaufgabe für Dich: Welche von den 4 printf-Statements werden
ausgeführt?
Regel: Das Ergebnis einer Bedingung mit Vergleichsoperator wie z.B. "a <
b" ist in C auch nur eine Zahl (genauer: ein Integer), nämlich konkret 0
oder 1.
Kannst Du leicht prüfen:
1
printf("%d\n",3<11);
2
printf("%d\n",3>11);
Denksportaufgabe: Was wird ausgegeben?
Hinweis für Dich:
Aus obiger Regel folgt implizit, das heißt ohne weitere notwendige
Erklärung, dass man in if(), while() und for() auch einfach eine Zahl
oder das Ergebnis einer Funktion eintragen kann wie z.B. "if (33)" oder
auch "if (func(42))".
Wilhelm M. schrieb:> Programmiersprachen wie C operieren auf einer abstrakten (C)-Maschine.> Da hilft es ein klein wenig, wenn man sich vom sehr konkreten> (materialisierten) Assembler löst, und versucht in anderen Kategorien zu> denken: Datentypen, Werte, Variablen, Ausdrücke, ...
Der eigentliche Witz ist: wer kompetent in Asm programmiert, macht das
natürlich ebenfalls. Ständig. Zwangsweise. Er sieht nur jederzeit die
Wahrheit: z.B.: eine Variable ist nicht wirklich eine Variable. Das ist
nur ein verschissener Name für eine Speicheradresse mit automagischer
eingebauter Derefenzierung für Zugriffe darauf. In Asm ist das schlicht
ein Label. Und ja: in Asm muß man "von Hand" derefenzieren.
Aber, bezogen auf das konkrete Problem hilft das nicht wirklich weiter.
Da hilft nur eins weiter: sich zu vergegenwärtigen, das die Erfinder von
C eine spezielle Eigenschaft von int (nämlich 0 oder was anderes sein zu
können) dazu missbraucht haben, boolesche Logik abzubilden, das aber
wiederum nicht konsequent, denn für echte boolsche logik mussten sie
dann doch wieder zusätzliche Operatoren erfinden, weil die völlig
zweckentfremdete Binärlogik hier dann falsche Ergebnisse liefern würde.
Sprich: C ist konzeptionell äußerst schmutzig. Ungefähr genauso
schmutzig wie Asm. Asm hängt da nur kein Mäntelchen mehr oder weniger
abstruser Syntax drum, das ist eigentlich der einzige Unterschied...
Es ist für einen richtigen Asm-Programierer natürlich nicht schwer, zu
erkennen, was dahinter steckt. Nur der TO ist eben keiner. Hat's mehr
als 10 Jahre versucht, aber bis heute nicht geschafft...
C-hater schrieb:> Wilhelm M. schrieb:>>> Programmiersprachen wie C operieren auf einer abstrakten (C)-Maschine.>> Da hilft es ein klein wenig, wenn man sich vom sehr konkreten>> (materialisierten) Assembler löst, und versucht in anderen Kategorien zu>> denken: Datentypen, Werte, Variablen, Ausdrücke, ...>> Der eigentliche Witz ist: wer kompetent in Asm programmiert, macht das> natürlich ebenfalls. Ständig. Zwangsweise.
Ich halte es für ungewöhnlich, dass Assemblerprogrammierer tatsächlich
in Datentypen denken wie z.B. ComplexNumber, double, Transaction oder
Velocity. Und natürlich unterstützt sie niemand bei der Entdeckung von
Fehlern aufgrund z.B. nicht definierter Operationen auf oder zwischen
Datentypen, etc...
> Er sieht nur jederzeit die> Wahrheit: z.B.: eine Variable ist nicht wirklich eine Variable. Das ist> nur ein verschissener Name für eine Speicheradresse mit automagischer> eingebauter Derefenzierung für Zugriffe darauf. In Asm ist das schlicht> ein Label.
Nun, eine Variable ist ein "benanntes Objekt" (in den meisten Sprachen),
Objekte haben einen Typ und einen Wert., ...
> Und ja: in Asm muß man "von Hand" derefenzieren.
Das tut mir leid.
> Aber, bezogen auf das konkrete Problem hilft das nicht wirklich weiter.> Da hilft nur eins weiter: sich zu vergegenwärtigen, das die Erfinder von> C eine spezielle Eigenschaft von int (nämlich 0 oder was anderes sein zu> können) dazu missbraucht haben, boolesche Logik abzubilden, das aber> wiederum nicht konsequent, denn für echte boolsche logik mussten sie> dann doch wieder zusätzliche Operatoren erfinden, weil die völlig> zweckentfremdete Binärlogik hier dann falsche Ergebnisse liefern würde.
Und wenn es kein C wäre (wo es auch __Bool aka bool gibt), sondern eine
Sprache mit einem DT bool, so würde dem TO das auch nicht helfen. Denn
er versteht nicht, was ein Ausdruck ist.
> Sprich: C ist konzeptionell äußerst schmutzig. Ungefähr genauso> schmutzig wie Asm. Asm hängt da nur kein Mäntelchen mehr oder weniger> abstruser Syntax drum, das ist eigentlich der einzige Unterschied...
Das kann man sicher so betrachten, aber auch das hilft dem TO nicht,
weil er an einer Stelle hängt, an der dies keine Rolle spielt.
>> Es ist für einen richtigen Asm-Programierer natürlich nicht schwer, zu> erkennen, was dahinter steckt.
Einem 0815-C-Programmierer ist das auch sofort klar ;-)
>Nur der TO ist eben keiner. Hat's mehr> als 10 Jahre versucht, aber bis heute nicht geschafft...
Mag sein.
C-hater schrieb:> Sprich: C ist konzeptionell äußerst schmutzig.
Du bist nicht "moby", schreibst aber den gleichen Unfug.
> Ungefähr genauso schmutzig wie Asm.
C ist portierbar und wartbar. Assembler nicht.
Harald K. schrieb:> Du bist nicht "moby", schreibst aber den gleichen Unfug.
Das ist kein Unfug. Wenn du wirklich C kannst, solltest du das wissen.
Oder andersrum: wenn du es nicht weißt, kannst du nicht wirklich C.
> C ist portierbar und wartbar. Assembler nicht.
Wartbar ist Asm ziemlich genauso wie C. Man muß einfach nur die Leute
haben, die die Sprache wirklich beherrschen. Und natürlich gut
kommentierten Quelltext. Nicht so'n schwachsinnigen Scheiß wie die
automagisch erzeugten "Dokumentationen" á la Doxygen. Das ist völlig
hirnloser Bullshit, da steht typisch effektiv nur drin, was auch in der
Deklaration der dadurch "dokumentierten" Entität steht.
Portierbarkeit ist für Asm innerhalb einer Ziel-Architektur ziemlich
genauso wie für C. Geht einfach, nur bei der Peripherie muss ggf. was
angepaßt werden.
Der einzige Vorteil von C ist, dass damit (zuindest in gewissem Umfang)
auch Portabilität über Architekturgrenzen hinaus möglich wird. Alles
hardwarenahe ist dabei genauso gearscht wie in Asm. Muß ebenfalls mit
hohem Aufwand manuell "portiert" (also effektiv: neu geschrieben)
werden.
Wilhelm M. schrieb:> Ich halte es für ungewöhnlich, dass Assemblerprogrammierer tatsächlich> in Datentypen denken wie z.B. ComplexNumber, double, Transaction oder> Velocity.
ComplexNumber: ja. double: ja.
Transaction aber ist für mich kein Datentyp, genausowenig wie Velicity.
Was sollen denn das für schwachsinnige Datentypen sein?
> Und natürlich unterstützt sie niemand bei der Entdeckung von> Fehlern aufgrund z.B. nicht definierter Operationen auf oder zwischen> Datentypen, etc...
Natürlich nicht. Ist halt Asm. Allerdings ist bei C die Unterstützung
auch äußerst eingeschränkt. Eigentlich kaum mehr als reine Makulatur.
Du meinst wohl eher C++. Das hat ja immerhin tatsächlich ein striktes
Typsystem (welches allerdings eben wegen der Unterstützung für den
Stammvater C viel zu leicht zu umgehen ist, um eine wirklich sichere
Sprache zu sein). All die Sicherheitslücken in aktueller Software können
wohl nicht lügen...
Die Wurzel allen Übels ist halt das unsägliche C. Wie ich nicht müde
werde, immer wieder zu betonen.
C-hater schrieb:> Der einzige Vorteil von C ist, dass damit (zuindest in gewissem Umfang)> auch Portabilität über Architekturgrenzen hinaus möglich wird. Alles> hardwarenahe ist dabei genauso gearscht wie in Asm. Muß ebenfalls mit> hohem Aufwand manuell "portiert" (also effektiv: neu geschrieben)> werden.
Kleiner Ausflug:
Bei PC-Betriebssystemen wie z.B. Linux ist das gerade eine große Stärke
von C: Linux läuft auf zig verschiedenen Architekturen - eben weil die
hardwarenahen Teile minimal sind. Und selbst bei der Programmierung der
Hardware kann die Programmierung der Logik, wie die HW zu bedienen ist,
unverändert übernommen werden. Bei Assembler fängst Du hier bei jeder
Architektur wieder bei 0 an, denn Du musst dann eine neue Sprache
lernen. Und ich wette, dass Du hier im Forum unter einem Betriebssystem
schreibst, wo der Assembler-Anteil minimal ist.
Aber zurück zu den Mikrocontrollern, um die es hier geht:
Genau genommen wurde C nicht für Mikrocontroller konzipiert, sondern
ursprünglich für damalige "Großrechner", sprich Multi-User-Server. Für
die Programmierung eines 8-Bit-AVR war C urspünglich nie vorgesehen.
Dass hier irgendwann die Möglichkeit geschaffen wurde, einen AVR in C zu
programmieren, bei der schon ein Integer nicht der "natürlichen
Bit-Breite" des Prozessors entspricht, ist eigentlich ein Unding, aber
trotzdem sinnvoll für Leute, die mit Assembler nichts am Hut haben
wollen.
Diese Leute müssen dann halt mit den Schwächen von C, von denen Du hier
genügend aufgezählt hast, auf einem 8-Bit-System leben. Und tatsächlich
finden sie sich mit diesen Schwächen deshalb ab, weil sie mit Assembler
eine viel größere A*karte ziehen würden. Sie müssten nämlich für alle
Mikrocontroller-Familien, die sie bedienen, jeweils eine neue
Assembler-Sprache lernen. Das wäre bei mir ca. ein gutes Dutzend - und
das akzeptiere ich keinesfalls.
Ausguck über den Tellerrand von 8-Bit:
Ich bin schon vor einigen Jahren von den AVRs zu den STM32 gewechselt
und bin froh, dass ich meine C-Programme mit sehr geringem Aufwand von
AVR zu den STM32 portieren konnte. Lediglich die hardwarenahe
Programmierung musste ersetzt werden - und die ist viel weniger, als man
denkt! So läuft zum Beispiel IRMP auf ATmegas, ATtinys, Xmegas,
ESP8266, STM32, STM8 und diversen anderen Cortex-Mikrocontrollern. In
Assembler müsste man IRMP jedes Mal komplett neu programmieren.
Bei 32-Bit-Controllern kann C seine Stärken richtig ausspielen und die
meisten Deiner Argumente, wie schlecht C für einen Mikrocontroller ist,
treffen da überhaupt nicht mehr zu. Ich bitte Dich daher, Dich
ausdrücklich auf 8-Bit-Mikrocontroller zu beziehen, wenn Du dich mal
wieder über C auskotzen musst. Leider kommen einige Deiner
Formulierungen bzgl. C allgemeiner rüber, als Du es tatsächlich meinst.
Und als letztes: 8-Bit-Mikrocontroller sind auf dem sterbenden Ast. Du
bewegst Dich also in einer bald obsoleten Welt mit obsoleten Argumenten.
Oder willst Du mir hier erzählen, dass Du Dir noch die
Assembler-Programmierung auf einem fortschrittlichen Mikrocontroller wie
einen STM32 tatsächlich noch antust? Nein natürlich nicht, Du schwärmst
von Assembler-Programmierung für ein obsoletes System - und damit bist
Du klar in der Minderheit.
Ich kenne nur zwei, die sich tatsächlich so vehement für
Assembler-Progammierung auf Mikrocontrollern einsetzen und alles
drumherum abgrundtief hassen: Du und Moby. Aber damit lebt Ihr beide in
einer obsoleten Welt. Auf STM32 und anderen
32-Bit-Mikrocontroller-Systemen seid ihr angesichts der größeren
Komplexität mit Programmierung in Assembler schlicht aufgeschmissen,
d.h. Eure Kompetenz bzgl. Assembler wird irrelevant.
Und solange Du hier im Forum auf einem Betriebssystem schreibst, dass
nicht zu 100% in Assembler programmiert ist, keimt bei mir auch noch der
Gedanke der Scheinhheiligkeit auf. Aber das ist ein anderes Thema.
Frank M. schrieb:> C-hater schrieb:>> Der einzige Vorteil von C ist, dass damit (zuindest in gewissem Umfang)>> auch Portabilität über Architekturgrenzen hinaus möglich wird. Alles
[snip]
> Und als letztes: 8-Bit-Mikrocontroller sind auf dem sterbenden Ast. Du> bewegst Dich also in einer bald obsoleten Welt mit obsoleten Argumenten.
Vor einigen Jahren waren die Acht-Bitter CPU stromsparender als die 16-
oder 32-Bit CPUs. Die Welt hat sich aber weiter gedreht und mittlerweile
sind die aktuelle Modelle von z.B. ST sehr leistungsstark und auch
stromsparend.
Und so ein Quatsch wie Time to market oder Kosten
Firmware-Programmierung ist natuerlich im Hobbybereich irrelevant, aber
im Profi-Bereich sehr wichtig. Und der Hobby-Markt ist nicht relevant.
Es ist schon beeindruckend was sich in den letzten 30 Jahren geaendert
hat. Ich moechte unter keinen Umstaenden zurueck zu einer PDP11 mit
Assemblerprogrammierung oder eine Z80 oder 6502 mit ganzen 64kB
Speicherraum.
Gruesse
Th.
Thomas W. schrieb:> Ich moechte unter keinen Umstaenden zurueck zu einer PDP11 mit> Assemblerprogrammierung
Soviel ich weiß, wurde der erste C-Compiler für eine PDP-11 entwickelt,
um damit den UNIX-Kernel dafür zu schreiben ;-)
> oder eine Z80 oder 6502 mit ganzen 64kB Speicherraum.
Z80-Emulator auf einem STM32: STECCY. Natürlich in C geschrieben und
um einige Faktoren schneller als der damalige Z80.
Frank M. schrieb:> Thomas W. schrieb:>> Ich moechte unter keinen Umstaenden zurueck zu einer PDP11 mit>> Assemblerprogrammierung>> Soviel ich weiß, wurde der erste C-Compiler für eine PDP-11 entwickelt,> um damit den UNIX-Kernel dafür zu schreiben ;-)
Ja, weil der Aufwand um einen Betriebssystem-Kernel in Assembler zu
schreiben selbst bei einer CISC-Architektur zu gross ist. Daher baute
K&R einen C-Compiler.
Zum Teil sind die alten Quellen noch verfuegbar: Assembler fuer etwas
Glue (z.B. Task-Wechsel), ansonst C (ich habe noch Tanenbaum, Operating
Systems von 1991 im Regal [ist aber fuer einen PC])
>> oder eine Z80 oder 6502 mit ganzen 64kB Speicherraum.>> Z80-Emulator auf einem STM32: STECCY. Natürlich in C geschrieben und> um einige Faktoren schneller als der damalige Z80.
Das ist ein geniales Stueck SW.
Viele Gruesse
Th.
Thomas W. schrieb:> Ich moechte unter keinen Umstaenden zurueck zu einer PDP11 mit> Assemblerprogrammierung
Es ist ja so, daß viele Ältere erstmal mit Assembler angefangen haben
und später zu C gewechselt sind. Alle haben gemerkt, daß sie dadurch
viel produktiver wurden, viel weniger Fehler machten und auf keinen Fall
wieder zu Assembler zurück wollen.
Ich hab mir auch erstmal das Listing des C-Compilers angeschaut. Und
mußte dabei viele Tricks entdecken, auf die ich nie selber gekommen
wäre. Meine alten Assemblerprogramme waren also nichtmal schneller oder
kleiner gegenüber dem Compiler.
Peter D. schrieb:> Thomas W. schrieb:>> Ich moechte unter keinen Umstaenden zurueck zu einer PDP11 mit>> Assemblerprogrammierung>> Es ist ja so, daß viele Ältere erstmal mit Assembler angefangen haben> und später zu C gewechselt sind.
Die Assembler war meistens billig, richtige Compiler kosteten richtiges
Geld. Das aenderte sich mit Borland (Turbo Pascal, Turbo C) fuer CP/M
und DOS.
> Alle haben gemerkt, daß sie dadurch> viel produktiver wurden, viel weniger Fehler machten und auf keinen Fall> wieder zu Assembler zurück wollen.
Es gab damals (TM) Metriken ueber correct lines of Code, und da hatte
der Compiler unglaubliche Vorteile. Es gibt aktuelle Forschung ueber den
Einfluss von Backus ("Erfinder" von FORTRAN): ca. 1954(!) fing die
Diskussion ueber Assembler <-> Compiler an, offensichtlich ist das
siebzig Jahre spaeter immer noch nicht ausgestanden.
> Ich hab mir auch erstmal das Listing des C-Compilers angeschaut. Und> mußte dabei viele Tricks entdecken, auf die ich nie selber gekommen> wäre. Meine alten Assemblerprogramme waren also nichtmal schneller oder> kleiner gegenüber dem Compiler.
Da musst Du natuerlich auch die Art der CPU beruecksichtigen: Es gibt
schon einen kleinen Unterschied zwischen z.B. einer VAX (CISC) und einer
MIPS-CPU.
Und Du darfst nicht vergessen: Auch die Entwicklung der Compiler ist
nicht stehengeblieben, selbst bei konstant gebliebenem Sprachumfang. Die
Optimierung des Codes ist deutlich besser geworden.
Genug ueber die guten alten Zeitem (TM)
Gruesse
Th.
Wilhelm M. schrieb:> ...> Wer mich kennt, weiß, dass ich dazu Stepanovs "Elements of> Programming" empfehle ;-)>
Sorry, zum Lernen ist englische Literatur nichts für mich.
Roland F. schrieb:> (1) "Programmieren in C", Kernighan/Ritchie, 2.Ausgabe, ANSI-C, Hanser> 1990>
Hat ziemlich viele gute Bewertungen, aber für Anfänger die nur AVR8-µc
per Arduino-Style programmieren wollen zu heftig.
Wie ich bereits geschrieben hatte, verstehe ich das die if-Abfrage
erfüllt ist, wenn der Ausdruck "!=0" bzw. true ergibt, aber bei 1<< KEY1
ist es druch die ganze Springerei schwierig zu erkennen, wo jetzt
bestimmt wird 0 oder != 0.
Harald K. schrieb:> Kann es sein, daß Dich das "1 << KEY1" durcheinanderbringt?>
Ja, aber nicht so wie du es denkst, sondern so wie ich es nachfolgend
versuche zu erklären.
Peter D. schrieb:> Natürlich findet Google sowas, z.B.:https://www.badprog.com/c-general-programming-return-value-of-a-if-statement-without-any-condition>
Ja, da ist der Grundgedanke zu erkennen.
Ich erkenne halt im übertragenen Sinne nicht wo die Zuweisung
1
KEY1=get_key_short();
2
if(KEY1)
geschieht.
Roland F. schrieb:> Ergänzend wäre vielleicht noch hinzuzufügen, das der Compiler erkennt> das das Argument für get_key_short() in diesem Fall eine Konstante ist> und erst> gar keinen Code für die Schiebeoperation erzeugt:>
Der Disassembler ist natürlich eine Möglichkeit zu erkennen, was da
passiert, aber gerade deswegen will ich ja mit dem Arduino arbeiten, um
mich nicht weiter mit AVR8ASM herrumzuquälen und schon gar nicht mit vom
Compiler erzeugten Code.
Bernd_Stein
Bernd S. schrieb:> Wilhelm M. schrieb:>> ...>> Wer mich kennt, weiß, dass ich dazu Stepanovs "Elements of>> Programming" empfehle ;-)>>> Sorry, zum Lernen ist englische Literatur nichts für mich.
Mmh, unten listest Du aber was englisches auf!
>> Roland F. schrieb:>> (1) "Programmieren in C", Kernighan/Ritchie, 2.Ausgabe, ANSI-C, Hanser>> 1990>>> Hat ziemlich viele gute Bewertungen, aber für Anfänger die nur AVR8-µc> per Arduino-Style programmieren wollen zu heftig.
Arduino-Style ist im wesentlichen eben C++ und nicht C.
> Wie ich bereits geschrieben hatte, verstehe ich das die if-Abfrage> erfüllt ist, wenn der Ausdruck "!=0" bzw. true ergibt, aber bei 1<< KEY1> ist es druch die ganze Springerei schwierig zu erkennen, wo jetzt> bestimmt wird 0 oder != 0.
Was denn für eine Springerei: es taucht kein goto auf.
> Ja, da ist der Grundgedanke zu erkennen.> Ich erkenne halt im übertragenen Sinne nicht wo die Zuweisung>
1
>KEY1=get_key_short();
2
>if(KEY1)
3
>
> geschieht.
Was denn für eine Zuweisung?
Versuche doch mal abstrakt zu denken: get_key_short() liefert einen
Wert, genau wie (die Dereferenzierung) einer Variablen einen Wert
liefert. Dieser Wert wird dann im Bedingungsteil des if-statements
verwendet.
Wenn Du immer noch in der Assembler-Denke mit Sprüngen verhaftet
bleibst, dann wirst Du nie C++ lernen (oder eine andere Hochsprache).
Wilhelm M. schrieb:>> Sorry, zum Lernen ist englische Literatur nichts für mich.>> Mmh, unten listest Du aber was englisches auf!>
Hier ganz konkret die deutsche Übersetzung :
https://www.amazon.de/Programmieren-C-Reference-Manual-deutscher-Sprache/dp/3446154973>> Was denn für eine Springerei: es taucht kein goto auf.>
Ich spreche vom Programm im Anhang. Man muss es halt im AS7, mit dem
Simulator durchgehen, dann weiß man was ich meine.
>> Was denn für eine Zuweisung?>
1
KEY1=get_key_short();
Dies ist für mich eine Zuweisung, da mein schlaues Arduino-Buch
schreibt, dass " = " ein Zuweisungsoperator ist.
Bernd_Stein
Bernd S. schrieb:> KEY1 = get_key_short();> Dies ist für mich eine Zuweisung, da mein schlaues Arduino-Buch> schreibt, dass " = " ein Zuweisungsoperator ist.
stimmt ja auch
get_key_short(); ist eine Funktion die einen Wert an die Variable KEY1
liefert.
hör auf die Leute zu vera*schen, du kennst doch sicher auch noch aus der
Schule Formeln wie a² + b² = c²
Joachim B. schrieb:> hör auf die Leute zu vera*schen, du kennst doch sicher auch noch aus der> Schule Formeln wie a² + b² = c²>
Sorry, sehe ich etwas anders.
Was auf der linken Seite steht ist = dem was auf der rechten Seite
steht.
Hierbei ist es zum Beispiel nicht gleich, da ct0 zuerst einen anderen
Wert hat. Und erst nach der Abarbeitung dieser Zeile, evtl. verändert
wird. Wobei es hier natürlich nur um 0 oder 1 geht.
1
ct0=~(ct0&i);// reset or count ct0
Außerdem verarsche ich hier niemanden, sondern versuche begreiflich zu
machen, dass das mir aus den Büchern vermittelte Grundwissen, in der
Realität, mit seiner Komplexität, nicht wieder erkenne.
Dies ist bzw. soll ja im Prinzip
1
number=checkIt();
2
if(number)
dies hier sein :
1
if(get_key_short(1<<KEY1));
Ich könnte mich verarscht fühlen, da mir niemand zeigen kann, wo im Code
KEY1 einen anderen Wert erhält, als bei #define. Es Also niemals eine
Änderung gibt, es aber trotzdem funktioniert.
Nur der Vollständigkeit halber, wieder etwas was mich wahnsinnig macht.
Warum wird a durch a = a++; nicht inkrementiert ?
Bernd S. schrieb:> Joachim B. schrieb:>> hör auf die Leute zu vera*schen, du kennst doch sicher auch noch aus der>> Schule Formeln wie a² + b² = c²
Auch wenn in der Mathematik das "=" ähnlich aussieht wie der
Kopierzuweisungsoperator "=" in C++, so ist beides doch was ganz
anderes.
> Außerdem verarsche ich hier niemanden, sondern versuche begreiflich zu> machen, dass das mir aus den Büchern vermittelte Grundwissen, in der> Realität, mit seiner Komplexität, nicht wieder erkenne.
Weil Du offenbar nicht wirklich etwas liest oder verstehen willst.
>> Dies ist bzw. soll ja im Prinzip>
1
>number=checkIt();
2
>if(number)
3
>
>> dies hier sein :>
1
>if(get_key_short(1<<KEY1));
2
>
Was haben die beiden Code-Schnipsel miteinander zu tun?
> Ich könnte mich verarscht fühlen, da mir niemand zeigen kann, wo im Code> KEY1 einen anderen Wert erhält, als bei #define. Es Also niemals eine> Änderung gibt, es aber trotzdem funktioniert.
Du kannst
1
if(get_key_short(1<<KEY1)){...}
auch als
1
if(autox=get_key_short(1<<KEY1);x){...}
Auch wenn das im init-Teil des if-statements keine Zuweisung ist sondern
eine Definition mit Initialisierung, hilft es ggf.
> Nur der Vollständigkeit halber, wieder etwas was mich wahnsinnig macht.> Warum wird a durch a = a++; nicht inkrementiert ?
Du solltest dabei eine Warnung bekommen, dass das undefiniert ist.
Und Du solltest Dir klar machen, was ein post-increment Operator ist.
Wilhelm M. schrieb:> Du solltest dabei eine Warnung bekommen, dass das undefiniert ist.>
Nur wenn ich a++; schreibe. a = a++; macht keine Warnung.
>> Und Du solltest Dir klar machen, was ein post-increment Operator ist.>
Ja genau dass wollte ich erreichen, dass a erstmal Null bleibt und erst
bei jedem weiteren aufrufen, der FUNKTION a inkrementiert wird.
Ich denke ich arbeite erstmal dass Buch komplett durch, bevor ich hier
wahnsinnig werde.
Bernd_Stein
Bernd S. schrieb:> Ja genau dass wollte ich erreichen, dass a erstmal Null bleibt und erst> bei jedem weiteren aufrufen, der FUNKTION a inkrementiert wird.
Das hat mit einer Funktion nicht wirklich etwas zu tun. In einem
Programm gibt es einen Kontrollfluss (Thread, Aktivitätsträger). Und
wenn die Anweisung a++; erreicht wird, wird die ausgeführt. In diesem
Fall ein post-increment.
Die post-increment-Operator ist ein besonderer Operator, weil er nicht
nur einen Wert liefert (und zwar den ursprünglichen Wert von a), sondern
auch einen Seiteneffekt auf a ausübt (das Inkrement).
In sofern ist a = a++; vollkommen unsinnig. Was Du willst, ist einfach
a++. Und warum a = a++; unsinnig ist und Du eine Warnung (-Wall)
bekommst, kannst Du ggf. Stand jetzt noch nicht verstehen.
Vielleicht solltest Du besser a = a + 1; schreiben. Da hast Du das + als
reinen Operator drin (= ist wieder ein Operator mit Seiteneffekt).
Bitte lies erstmal Dein C-Buch zuende. Und bedenke, dass Dein
Arduino-Krams eigentlich C++ ist.
>> liefert>> [c]> a.c: In function 'main':> a.c:8:5: warning: operation on 'a' may be undefined [-Wsequence-point]> 8 | a = a++;> | ~~^~~~~> [\c]
Aber eben auch nur wenn "-Wall" eingeschaltet ist. Wer weiß wie Bernds
AS7 konfiguriert ist.
rhf
Frank M. schrieb:> Genau genommen wurde C nicht für Mikrocontroller konzipiert, sondern> ursprünglich für damalige "Großrechner", sprich Multi-User-Server. Für> die Programmierung eines 8-Bit-AVR war C urspünglich nie vorgesehen.
Aber dafür chars mit != 8Bit und Zahlendarstellungen != two's
complement. Welch ein Wahnsinn. Schon zur Zeit der Entstehung dieser
unsäglich schlecht designten Sprache...
> Sie müssten nämlich für alle> Mikrocontroller-Familien, die sie bedienen, jeweils eine neue> Assembler-Sprache lernen.
So what? Ich beherrsche "fließend" derzeit vier, mehr oder weniger
"broken" ungefähr 40. Über den gesamten Bereich von winzigsten µC bis
hin zu den aktuellen x86(x64)-High-End-Boliden.
(Hinweis: "fließend" bedeutet: gut genug, um besser sein zu können als
ein aktueller Compiler für die relevante Architektur. "broken" bedeutet:
gut genug, um noch Fehler in Compilern finden zu können.)
Bin ich ein Genie? Nein, sicher nicht. Es ist nur schlicht sehr viel
einfacher, eine Assemblersprache zu lernen als solche aufgeblähten
Syntax-Monster wie C oder gar C++.
> Ich bin schon vor einigen Jahren von den AVRs zu den STM32 gewechselt
Ich "wechsele" nicht. Ich mache alles, was nötig ist und bezahlt wird.
Und zwar so lange es nötig ist und bezahlt wird.
> Bei 32-Bit-Controllern kann C seine Stärken richtig ausspielen und die> meisten Deiner Argumente, wie schlecht C für einen Mikrocontroller ist,> treffen da überhaupt nicht mehr zu.
Doch, leider treffen viele davon auch auf 32Bit-MCU/CPUs zu. Das ist
eine direkte Folge dieser unsäglichen Integer-Propagation. Diese sorgt
zwar dank des Taschenspielertricks, int einfach breiter zu machen dafür,
dass eine Portierung von einer 16Bit-Architektur auf eine
32-Bit-Architektur recht leicht (oder, bei sauberem Code sogar nichtmal
nötig) ist, aber beileibe nicht bei der Portierung von 8Bit-Code auf
32Bit, weil hier typisch eben schon an der Quelle oft exzessiv Casting
auf Typen aus stdint.h verwendet wurde (werden musste).
> Ich bitte Dich daher, Dich> ausdrücklich auf 8-Bit-Mikrocontroller zu beziehen
Das kannste vergessen. Was wahr ist, muss wahr bleiben.
> Und als letztes: 8-Bit-Mikrocontroller sind auf dem sterbenden Ast.
Alles klar. Du hast keine Ahnung. Ich hingegen bin absolut sicher, dass
die 8Bitter länger überleben werden als du und ich. Die wird es noch
geben, wenn von unseren sterblichen Überresten nur noch ein Häuflein
Asche oder ein Skelett über sind.
> Auf STM32 und anderen> 32-Bit-Mikrocontroller-Systemen seid ihr angesichts der größeren> Komplexität mit Programmierung in Assembler schlicht aufgeschmissenARM-Thumb ist einer der vier Assembler, dich ich fließend beherrsche...
Hallo,
Wilhelm M. schrieb:> Bitte lies erstmal Dein C-Buch zuende.
Genau das sollte Bernd auch machen. Der Hinweis das
> Arduino-Krams eigentlich C++ ist.
ist ja richtig, bei den konkreten Problemen von Bernd im Moment aber
nicht relevant. Ich fürchte eher das ihn dein Hinweis noch mehr
verwirrt.
rhf
Roland F. schrieb:> Wilhelm M. schrieb:>> Bitte lies erstmal Dein C-Buch zuende.>> Genau das sollte Bernd auch machen. Der Hinweis das>>> Arduino-Krams eigentlich C++ ist.
Wo bei ich sagen muss, der K&R ist (zumindest auf Deutsch) die pessimale
Wahl. Ich hatte auf die Schnelle
https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/ noch gefunden.
Wer hat denn ein logisch aufgebautes C-Lehrbuch?
Gruesse
Th.
P.S.: Der K&R ist (zumindest in der deutschen 1.Auflage) eins der
wenigen "Fachbuecher" die ich in die thermische Verwertung gepackt
hatte.
>> Ich könnte mich verarscht fühlen, da mir niemand zeigen kann, wo im Code> KEY1 einen anderen Wert erhält, als bei #define. Es Also niemals eine> Änderung gibt, es aber trotzdem funktioniert.>
Doch, es gibt eine Änderung!
KEY1 ist die PIN-Nummer in PINB (siehe #define). Der Zustand des Ports
wird in der ISR abgefragt und in den Funktionen zum Abrufen des
'Tastenzustandes' in diversen key_xxx-Variablen zwischengespeichert. In
diesem Fall oben willst du wissen, ob die Taste mit Namen 'KEY1' mal
kurz gedrückt wurde.
> Nur der Vollständigkeit halber, wieder etwas was mich wahnsinnig macht.> Warum wird a durch a = a++; nicht inkrementiert ?
Das ist eine Konstruktion, die 'per Definition' nicht zulässig ist.
Hallo,
Thomas W. schrieb:>>> Arduino-Krams eigentlich C++ ist.
Das Zitat ist nicht von mir, sondern von Wilhelm.
> Ich hatte auf die Schnelle> https://openbook.rheinwerk-verlag.de/c_von_a_bis_z/ noch gefunden.
Ich kann Bücher von Jürgen Wolf nicht empfehlen, alle Bücher die ich
kenne sind schludrig und unvollständig.
> Wer hat denn ein logisch aufgebautes C-Lehrbuch?
K&R, 2 Ausgabe ANSI C. Leider auf dem Stand von 1990, aber für den
Anfang immer noch gut geeignet. Und die speziellen Probleme von Bernd
werden dort erschöpfend behandelt.
rhf
C-hater schrieb:> Das ist> eine direkte Folge dieser unsäglichen Integer-Propagation. Diese sorgt> zwar dank des Taschenspielertricks, int einfach breiter zu machen dafür,> dass eine Portierung von einer 16Bit-Architektur auf eine> 32-Bit-Architektur recht leicht (oder, bei sauberem Code sogar nichtmal> nötig) ist,
Eben, C-Code konnte dank Integer-Propagation ohne signifikante
Änderungen einfach mit den Architekturen (16 -> 32 -> 64) mitwachsen,
Assembler-Code jedoch nicht. Deshalb gibts auch keine Betriebssysteme,
die in Assember geschrieben sind. Soviel Lebenszeit will keiner
verschwenden.
> aber beileibe nicht bei der Portierung von 8Bit-Code auf> 32Bit,
Portierung von "8Bit-Code"? 8-Bit-Code in C? Was soll das denn sein?
Gabs noch nicht mal auf der PDP-11, der C-Ur-Maschine.
8-Bit-Code-C-Compiler sind keine C-Compiler, sondern irgendwelche
Micky-Maus-Konstrukte. Ein Integer in C war damals schon per Definition
mindestens 16 Bit breit.
Es gibt also keine Notwendigkeit, sog. "8Bit-Code" auf 32Bit zu
portieren. Wer sich sowas angetan hat, ist selber schuld. C-Code für den
AVR ist kein 8Bit-Code, sondern 16Bit-Code. Ja, passt nicht zur
Architektur, da gebe ich Dir recht. Trotzdem geht es - mit minimalen
Einschränkungen, die Du zwar als die großen "Katastrophen" ansiehst,
trotzdem aber beherrschbar sind. Von daher kann Dein andauerndes
Lamentieren getrost als "nicht sooo wichtig" zur Seite gelegt werden.
Gönn doch einfach jedem seine Vorlieben. Ich respektiere durchaus, dass
Du Assembler vorziehst. Ich mag halt lieber C, so what?
Roland F. schrieb:> Aber eben auch nur wenn "-Wall" eingeschaltet ist. Wer weiß wie Bernds> AS7 konfiguriert ist.
Falls er nicht -Wall und -Wextra setzt, hat er als Anfänger schon wieder
den nächsten Fehler gemacht.
Thomas W. schrieb:> P.S.: Der K&R ist (zumindest in der deutschen 1.Auflage) eins der> wenigen "Fachbuecher" die ich in die thermische Verwertung gepackt> hatte.
Tja, ich habe ihn aus Nostalgiegründen behalten :-)
Pass mal auf, in 20 Jahren stelle ich den bei Bares für Rares ein. Ich
habe eines der allerersten Bücher ...
Bernd S. schrieb:>KEY1 = get_key_short();
Ich verstehe nur Bahnhof.
Wie kommst Du auf diese Zeile?
KEY1 ist als die Bitnummer einer Taste definiert.
Eine Zuweisung sollte daher eine Fehlermeldung werfen.
Peter D. schrieb:> Bernd S. schrieb:>>KEY1 = get_key_short();>> Ich verstehe nur Bahnhof.> Wie kommst Du auf diese Zeile?
ich sag doch er trollt und saugt sich Probleme aus den Fingern die es
nicht gibt.
Mir kam die Zeile in cap letters sowieso merkwürdig vor, hatte aber auch
nicht in deinen Quellcode geschaut, weil es deinerseits keine
Notwendigkeit gab, dein Code ist perfekt!
Bernd S. schrieb:> KEY1 = get_key_short();
wo soll denn die stehen?
In PeDas code jedenfalls nicht!
er weiss halt immer noch nicht das
#define KEY1 1
eine reine Textersetzung macht, überall wo KEY1 steht wird eine 1 in den
Text eingesetzt und deswegen kann
KEY1 = get_key_short();
mit TEXTERSETZUNG
zu
1 = get_key_short();
nicht funktionieren!
Damit gilt weiterhin er ist lernresistent oder trollt!
Joachim B. schrieb:> er weiss halt immer noch nicht das> #define KEY1 1> eine reine Textersetzung macht,
Es weiß nicht nur das nicht, er ist mit allem komplett überfordert. Mich
wundert, dass er überhaupt irgendetwas zustande bekommt.
Hallo,
Joachim B. schrieb:> ich sag doch er trollt und saugt sich Probleme aus den Fingern die es> nicht gibt.
Komm mal von deiner Troll-Phobie runter, die Wahrheit ist eher die hier:
Wilhelm M. schrieb:> Es weiß nicht nur das nicht, er ist mit allem komplett überfordert.
rhf
Roland F. schrieb:> Hallo,> Joachim B. schrieb:>> ich sag doch er trollt und saugt sich Probleme aus den Fingern die es>> nicht gibt.>> Komm mal von deiner Troll-Phobie runter, die Wahrheit ist eher die hier:>> Wilhelm M. schrieb:>> Es weiß nicht nur das nicht, er ist mit allem komplett überfordert.>
Es ist wohl alles gesagt, und nun ist es Zeit, dass Moby den Thread
übernimmt.
Frank M. schrieb:> Portierung von "8Bit-Code"? 8-Bit-Code in C? Was soll das denn sein?
Effizent. Not more and not less. Nur halt nicht portabel. Wenn man aber
die Wahl hat zwischen "geht" (aber nicht portabel) und "geht nicht"
(aber portabel), dann würden wohl nur wirkliche Vollidioten die zweite
Lösung wählen...
> Gabs noch nicht mal auf der PDP-11, der C-Ur-Maschine.
Eben das ist die Crux. Eine konkrete Maschine als Ausgangspunkt hat zu
einer ziemlich beschissenen Sprach-Definition geführt. Nunja,
angereichert mit noch einigem anderen Kram aus der damaligen Zeit, aber
eben nicht unbedingt mit dem, was damals auch aktuell war. Der Witz
ist: die Sprachdesigner konnten sich einfach nicht vorstellen, dass man
kleine 4 oder 8-Bitter auch in C programmieren könnte oder sollte. Und
zumindest in diesem Punkt hatten sie schlicht 100% Recht...
Der Anspruch der Portabilität kam übrigens eigentlich auch erst später.
Und ist so wie C als Ganzes: ganz viele Versprechen, die in vielen
Fällen halt nicht eigehalten werden können.
Hallo,
C-hater schrieb:> ...aber eben nicht unbedingt mit dem, was damals auch aktuell war
Was war denn damals "auch" aktuell?
C-hater schrieb:> Und ist so wie C als Ganzes: ganz viele Versprechen, die in vielen> Fällen halt nicht eigehalten werden können.
Der Fehler ist zu glauben, das die Erfinder von C, ähnlich wie die
Erfinder von Algol oder Nachfolgesprachen wie Pascal, vorhatten eine
saubere und perfekte Programmiersprache zu entwickeln.
In erster Linie ging es um die Entwicklung eines Betriebssystems, das
für die damals neuartigen Arbeitsplatzrechner geeignet war. Die
vorhandenen Sprachen waren dazu aus Sicht der C-Entwickler ungeeignet,
also haben sie über einige Zwischenschritte letztlich C entwickelt. Und
man kann C an vielen Ecken ansehen das da Pragmatismus vorherrschte.
Man muss das alles auch in Hinblick auf die zur Verfügung stehenden
Hardware sehen. Die Hauptspeichergrößen lagen im ein- bis zweistelligen
Kilobytebereich, der Massenspeicher war ein Kartenleser oder ein
Magnetband und die Eingabe erfolgte mit Terminals ähnlich
Fernschreibern. Es ging eben nicht um die perfekte Sprache, sondern um
eine Werkzeug, das klein, kompakt und schnell war.
Vor diesem Hintergrund ist es kein Wunder, das es in C so viele Stellen
gibt an denen man sehen kann das es nicht um Perfektion ging, sondern um
ein Werkzeug, das auf möglichst vielen Rechnern eingesetzt werden konnte
um eben ein Betriebssystem wie UNIX ausführen zu können.
Und das ist bis heute so geblieben, die Sprache ist nach wie vor so
klein, das sie auf nahezu jeder Hardware in kurzer Zeit zu Laufen
gebracht werden kann. Man hat also mit dem Erscheinen eines neuen
Prozessors praktisch sofort eine bekannte Programmiersprache zur
Verfügung und muss sich nicht mit den immer komplizierteren Assemblern
beschäftigen.
Sicherlich ist C in die Jahre gekommen und der Zwang zur Kompatibilität
steht wichtigen Verbesserung von C im Wege. Aber ich finde das C bei
aller gerechtfertigten Kritik ein überaus gelungenen Spagat zwischen
Hardwarenähe auf der eine Seite und Hardwareabstraktion auf der anderen
Seite darstellt, die von anderen Sprachen so nicht erreicht wird.
Zumindest müssen sich andere Sprachen am Erfolg von C messen lassen.
rhf