Habe mal alles in eine Datei im Anhang zu sehen gepackt.
Ich bekomme jedoch diese Fehlermeldung :
In file included from C:\Users\Ich\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.6\cores\arduino/Arduino.h:30:0,
from G:\AVR-Projekte\Arduino\MEGA2560 Board\GLCD_ST 7920\Entprellen\GLCD_entprellen\GLCD_entprellen.ino:1:
G:\AVR-Projekte\Arduino\MEGA2560 Board\GLCD_ST 7920\Entprellen\GLCD_entprellen\GLCD_entprellen.ino: In function 'void loop()':
GLCD_entprellen:76:1: error: expected unqualified-id before string constant
ISR( TIMER1_COMPA_vect ) { // every 10ms
^
GLCD_entprellen:76:26: error: a function-definition is not allowed here before '{' token
ISR( TIMER1_COMPA_vect ) { // every 10ms
^
GLCD_entprellen:96:26: error: a function-definition is not allowed here before '{' token
void init_entprell(void) {
^
GLCD_entprellen:112:43: error: a function-definition is not allowed here before '{' token
uint8_t get_key_press( uint8_t key_mask ) {
^
GLCD_entprellen:128:41: error: a function-definition is not allowed here before '{' token
Und immer schön hierdrann denken, so wie in diesem Fall, an Punkt 4.
"Die fünf universellen Forenregeln ;-)"
Threadüberschrift lesen
Evtl. Datum beachten
Posting verstehen
Falls nicht drittens, dann nachfragen oder Klappe halten.
Auf die Fragen eingehen und / oder Alternativen bzw. Verbesserungen
nennen.
Die Punkte kann man an einer Hand abzählen, man sollte also in der Lage
sein, bis fünf zählen zu können.
Deshalb sind sie evtl. gut zu merken, falls nicht dann nur Punkt 3 und
Punkt 4 merken.
Ich hab es so wie hier gelöst, aber danke für deine Hilfestellung die
ich nicht verstehe, aber egal ich hab ja eine Lösung.
Du hast keine Lösung, du hast auch keine Ahnung. Und daran wird sich auch zu deinen Lebzeiten nichts mehr ändern. Du stolperst nur vollkommen planlos durch die Gegend in der irrigen Annahme, auch nur ansatzweise was Sinnvolles zu programmieren.
Nei, in deiner originalen Abfrage testet du ob eine Variable gleich einem Wert ist und gleichzeitig (logisches &&) ob das Ergebnis einer Schiebeoperation ungleich Null ist. Letzteres ist bei dir immer der Fall.
Im zitierten Beitrag wird getestet ob zwei Bits einer Variable (binär 'ver-und-tete'(&) mit Bitmaske) gleichzeitig (logisches &&) gesetzt sind.
bei mir lese ich die Key Pins in der Arduino TIMER0 ISR mit einem Huckepack Compare A Interrupt.
Dazu habe ich diese ISR hinzugefügt die im Hintergrund (Schmarotzerisch) mit der Arduino TIMER0 ISR mitläuft:
ISR(TIMER0_COMPA_vect)
{
_keyreg = ....
}
// Der TIMER0 ist schon fuer millis() gebraucht. Man triggert den Interrupt // einfach in der Mitte des T0 Timers und ruft die COMPARE A Funktion auf/
OCR0A = 0xAF;
TIMSK0 |= _BV(OCIE0A);
Der Rest ist der normale Einsatz des Standard Beispiels von Peter.
_keyregs ist natuerlich Global deklariert und übermittelt den Portzustand der KEYS in Peters Code .
Das ganze hat den Vorteil den AVR kaum zu belasten und die Keys werden bequem von der schon existierenden ARDUINO TIMER0 ISR mitgezogen. die rund 1ms T0 Rate lässt sich mit einem Zähler wie gewünscht anpassen. Bei mir werden die Pins dann alle 10ms abgetastet.
Im konkreten Fall eigentlich über einen PCF8575 IO Expander. Aber das tut nichts zur Sache.
Jedenfalls funktioniert es bei mir so ausgezeichnet. Läuft wie ein Uhrwerk.
Ich habe einen Hand-Encoder der 20 Rastungen hat.
Pro Rastung werden 4 Signaländerungen erzeugt, also der typische
2-Bit-Graycode => 00; 01; 11; 10
Könnte jemand mal den Code im Anhang mit so wenig Codezeilen wie möglich ändern, damit pro Klick bzw. Rastung nur eine Zahl ausgegeben wird und nicht 4 ?
Aber bitte nicht gleich die Universallösung für 1, 2, 4 Rastungen.
Könnte jemand mal den Code im Anhang mit so wenig Codezeilen wie möglich
ändern, damit pro Klick bzw. Rastung nur eine Zahl ausgegeben wird und
nicht 4 ?
Die Anpassung ans Raster pro Änderung kann man über das Shiften des Zählerwertes machen.
Die Anpassung ans Raster pro Änderung kann man über das Shiften des
Zählerwertes machen.
Ich vermute durch 2 maliges Rechtsschieben, was ja einer Teilung durch 4 entspricht.
Verstehe leider nur nicht, warum dies nicht klappt.
Packe ich enc_delta >>= 2; an die eine Stelle, passiert das Eine und ein weiterdrehen bewirkt nichts mehr.
Genauso, wenn ich es an die andere Stelle kopiere ( siehe Screenshots ).
du brauchst jetzt noch einen Absolutenzähler. Datentyp für deine Anwendung passend. Auf diesen wird immer der Wert von enc_delta aufaddiert. enc_delta gibt jetzt pro Rastung nur noch +1 oder -1 oder 0 raus.
bei uns in der Ausbildung hieß das MUP. Methode des unbekümmerten Probierens. Kann man durchaus einmal machen. :-) Ich kann Bernd nicht einschätzen. Es fällt ihm scheinbar sehr schwer und er quält sich durch.
val entfernt, dafür struct Counter erstellt, kannste auch umbenennen.
Immer wenn alt ungleich neu ist wird das verarbeitet.
Einfaches Prinzip um ständige Wiederholungen ohne Änderung zu unterdrücken.
val entfernt, dafür struct Counter erstellt, kannste auch umbenennen.
Vielen dank für deinen Code, der auch funktioniert, den ich aber leider nicht nachvollziehen konnte.
Vielleicht kann mir ja jemand erklären warum meine Lösung auch funktioniert.
Selbst meine Lösung verstehe ich nicht. Habe sie durch Zufall gefunden, als ich wenigstens nur einen Wert, nämlich die 1 ausgeben wollte. Beim weiterdrehen kam dann 2 usw. Die Gegenrichtung funktionierte nicht, da hab ich einfach mal ...
1
voidloop()
2
{
3
if(enc_delta==4|enc_delta==-4){
4
val+=encode_read(4);// 4 Signaländerungen pro Rastung
5
6
Serial.print("val = ");
7
Serial.println(val,DEC);
8
9
}
10
LEDS=val;
11
}// Ende void loop()
Ach, anbei noch eine gute Erklärung zu PeDa's Hand-Encoder-Lösung.
Ab Kapitel 5, Seite 11 bzw. 20.
Kleiner Tipp: *.txt ist kein guter Name für einen Dateianhang mit Code.
Wenn ihr statt dessen *.cpp verwendet, kriegt ihr auch das "Syntax-Highlighting). Ob das MC-net auch *.ino kann, weiß ich nicht.
Es geht ja nur im den Variablennamen new, in C++ ist das ein
Schlüsselwort.
Du kannst den Text auch ändern, das ist ein Wiki.
Echt? War mir noch gar nicht aufgefallen ;-)
Ich zitier' mich mal selbst:
Niemand hält Dich davon ab, es zu tun. Bring' Dich ein!
Die Frage ist, ob es überhaupt Sinn macht. Zwar bin ich davon überzeugt, dass meine Lösung tatsächlich die flexibelste und effektivste ist, jedoch scheitert es ja regelmäßig daran, dass die Leute hier sich beschweren, dass bspw. für avr-g++ keine libstdc++ verfügbar ist, und dass deswegen kein std::array<> oder std::make_index_sequence<>, ... verfügbar sei. Aber auf die Idee, das selbst zu erstellen, kommt irgendwie keiner. Und wenn man die Sachen hinzufügt, dann kommt die Beschwerde, es sei zu umfangreich. Obwohl das natürlich Bestandteil einer Bibliothek ist, damit gar keine Rolle spielt und der eigentliche Code zur Lösung der Aufgabe recht kurz. Weil er so kurz ist, kommt die Beschwerde, dass zu viel hinter Bibliotheken versteckt sei und man deswegen nichts verstehe bzw. Meta-Programmierung, funktionale Ansätze und Closures nicht geeignet seien. Für die meisten größeren Controller (etwa STM) macht es dann auch wieder wenig Sinn, weil die ja oft einen Quadratur-Encoder als interne Peripherie dabei haben. Daher verspüre ich wenig Drang dazu, das in das Wiki zu schreiben.
Die Frage ist, ob es überhaupt Sinn macht. Zwar bin ich davon überzeugt,
dass meine Lösung tatsächlich die flexibelste und effektivste ist,
Kann sein, ist beim Thema Arduino und seiner großen Zielgruppe aber nicht das wesentliche Kriterium. Es muss einfach anwendbar und robust sein. Das reicht. Selbst Einschränkungen in der Funktionalität sind in vielen Fällen akzeptabel und werden teileise sogar aktiv betrieben, um die Einfachheit zu erreichen. Der Wurm muss dem Fisch schmecken und nicht dem Angler!
Wie du siehst, bindet == stärker sowohl als | (bitwise OR) als auch als || (logical OR). Du führst also eine bitweise Veroderung zweier Vergleichsresultate aus. Vergleichsresultate sind immer entweder 0 oder 1. Und deren bitweise Veroderung ergibt dasselbe Resultat wie deren logische Veroderung.
Dennoch solltest du dir natürlich angewöhnen, in logischen Ausdrücken die logischen Operatoren zu verwenden, und nicht die Bitoperatoren.
Dennoch solltest du dir natürlich angewöhnen, in logischen Ausdrücken
die logischen Operatoren zu verwenden, und nicht die Bitoperatoren.
Ich versuch es ja.
Ich versteh es trotzdem nicht.
Wenn ich beispielsweise 5 habe ist dies weder == 4 noch == -4.
Jetzt was anderes. Habe schon sämtliche Datentypen durch und weiß nicht wie ich es schaffen soll, dass wenn der Wert von val < 0 wird, val = 0 gesetzt wird. Oder wenn val >= 65535 wird val auf 65535 begrenzt wird (siehe Screenshot ).
Kann val denn überhaupt größer als 65535 werden? Wenn es ein uint16 ist, dann wird dieser Wert nie erreicht. Der Zähler wenn er immer um 4 inkrementiert wird) erreicht erst den Wert 65.532 und läuft dann über und steht auf dem Wert 1 anstatt 65.536 zu erreichen.
Konkret sieht es so aus:
val wird um 4 inkrementiert und hat den Wert 65.532. Dies erfüllt deine Bedinungung noch nicht. Nächster Durchlauf, val wird wieder um 4 inkrementiert und anstatt 65536 zu erreichen, hat val den Wert 1. Und vergleicht man, ob 1 >= 65535 ist, kommt man zu dem Schluss, dass dies nicht der Fall ist.
Was aber außerhalb deines Schnipsels mit val passiert liegt wieder im Dunkeln...
Die Frage ist, ob es überhaupt Sinn macht. Zwar bin ich davon überzeugt,
dass meine Lösung tatsächlich die flexibelste und effektivste ist,
jedoch scheitert es ja regelmäßig daran, dass die Leute hier sich
beschweren, dass bspw. für avr-g++ keine libstdc++ verfügbar ist, und
dass deswegen kein std::array<> oder std::make_index_sequence<>, ...
verfügbar sei. Aber auf die Idee, das selbst zu erstellen, kommt
irgendwie keiner. Und wenn man die Sachen hinzufügt, dann kommt die
Beschwerde, es sei zu umfangreich. Obwohl das natürlich Bestandteil
einer Bibliothek ist, damit gar keine Rolle spielt und der eigentliche
Code zur Lösung der Aufgabe recht kurz. Weil er so kurz ist, kommt die
Beschwerde, dass zu viel hinter Bibliotheken versteckt sei und man
deswegen nichts verstehe bzw. Meta-Programmierung, funktionale Ansätze
und Closures nicht geeignet seien. Für die meisten größeren Controller
(etwa STM) macht es dann auch wieder wenig Sinn, weil die ja oft einen
Quadratur-Encoder als interne Peripherie dabei haben. Daher verspüre ich
wenig Drang dazu, das in das Wiki zu schreiben.
Das liest sich alles nach Ausrede. Man muss ja nicht immer mit der größten Keule jedes Problem erschlagen. Wenn man die libstdc++ nicht hat, löst man das Problem eben ohne. Da finden sich immer Wege. Und wenn du jemanden eine praktische Lösung vorschlagen möchtest ist es irgendwie vermessen und gar komisch, von den gleichen Leuten denen man mit einer Lösung ihres Problems helfen möchte gleichzeitig zu verlangen das die gefälligst vorher sich ihre libstdc++ selbst schreiben. Das passt ja nun nicht zusammen. Wer in der Lage ist seine libstdc++ zu schreiben, der benötigt sicherlich keine fremde Hilfe mehr für irgendwas anderes. Für diese Encoderauswertung hier benötigt man zudem keine libstdc++. Ich wüßte nicht wofür. Der nächste Gedanke ist, wenn jeder seine libstdc++ schreibt ist das bestimmt nie zu 100% zur echten libstdc++ kompatibel. Da gibt es zu viele Fallstricke der Umsetzung, nehme ich an. Du wirst deine sicherlich auch immer mal wieder anpassen müssen, weil irgendwo ein Problem auftauchte.
Wenn du wirklich helfen möchtest, dann kannst du den Leuten hier helfen ihre libstdc++ aktuell zu halten. https://github.com/modm-io/avr-libstdcpp
Das ist die Beste die ich kenne, läuft aber manchmal noch nicht "ganz rund".
Ich formuliere es einmal anders. Du musst nicht jeden Tag den Leuten unter die Nase reiben das du deine libstdc++ hast und sie alle gefälligst nachprogrammieren sollen. Die meisten werden davon noch nie etwas gehört haben und kamen auch ohne gut klar. Viele Dinge der libstdc++ kann man auf dem AVR sowieso nicht nutzen wegen Speicherallokationen. Da muss man sowieso wissen was man tut. Von daher ist die komplette libstdc++ in meinen Augen witzlos.
Laut meines Wissens wird die libstdc++ für C++23 in größerem Umfang "umgebaut". Um das Problem zu bekämpfen das man eigentlich gar nicht weiß welche Bibliothek man einbinden muss um irgendwas passendes anwenden zu können. Die ist also wie der gcc selbst nie fertig. Der Pflegeaufwand muss sehr hoch sein. Das ist in meinen Augen noch ein Grund warum ich mir bis jetzt nur paar Type Traits davon nachgebaut habe aber nie wirklich angefangen habe mich mit der libstdc++ als solches zu befassen. Ich will ja meine Aufgaben lösen und mir nicht künstlich neue Probleme schaffen. Das Ding heißt ja nicht umsonst Standard STL und nicht Wilhelm-STL oder Veit-STL. Die ist ja nur einfachen Nutzung da und nichts anderes und ausgiebig getestet.
Wenn du für den Encoder eine praktische Lösung hast ohne libstdc++ kannste die zeigen. Vielleicht haste ja eine bessere Lösung als meine für meinen Nano Every. Aber deine ständige Wiederholung nach dem Motto "warum habt ihr Idioten keine eigene libstdc++" geht mir langsam aber sicher auf den Zeiger. Weil das hilft niemanden weiter. Denn wenn ich was habe was ich sowieso niemanden anderem zeige, dann erzähle ich davon erst gar nicht.
Für
diese Encoderauswertung hier benötigt man zudem keine libstdc++. Ich
wüßte nicht wofür.
Wenn man etwas mit TMP macht, so benötigt man eigentlich immer std::index_sequence<>, std::integral_constant<>, std::make_index_sequence<>. Und für integrierte Test oder LUTs dann auch std::array<>.
Na, das ist ja großartig. Es ist schon wirklich Jahre her, dass ich mir das Projekt mal angesehen hatte. Aber der Hinweis ist natürlich sehr wichtig, als es nun gar keinen Grund mehr gibt, Dinge abzulehnen, die für AVR auch die stdlibc++ benutzen.
Viele Dinge der
libstdc++ kann man auf dem AVR sowieso nicht nutzen wegen
Speicherallokationen. Da muss man sowieso wissen was man tut. Von daher
ist die komplette libstdc++ in meinen Augen witzlos.
Wenn die o.g. Realisierung nun tatsächlich einen std::vector<> oder std::string<> mit Heap-Alloc anbietet, dann ist das natürlich Murks. Vielleicht doch nicht so gut, was Du da erwähnst. Entweder man hat so etwas wie FixedVector<> oder man benutzt einen static-pool-allocator.
Für
diese Encoderauswertung hier benötigt man zudem keine libstdc++. Ich
wüßte nicht wofür.
Wenn man etwas mit TMP macht, so benötigt man eigentlich immer
std::index_sequence<>, std::integral_constant<>,
std::make_index_sequence<>. Und für integrierte Test oder LUTs dann auch
std::array<>.
Viele Dinge der
libstdc++ kann man auf dem AVR sowieso nicht nutzen wegen
Speicherallokationen. Da muss man sowieso wissen was man tut. Von daher
ist die komplette libstdc++ in meinen Augen witzlos.
Wenn die o.g. Realisierung nun tatsächlich einen std::vector<> oder
std::string<> mit Heap-Alloc anbietet, dann ist das natürlich Murks.
Vielleicht doch nicht so gut, was Du da erwähnst. Entweder man hat so
etwas wie FixedVector<> oder man benutzt einen static-pool-allocator.
Ist es nicht der Sinn eines Standards das Standardverhalten für alle zu haben? Ich kann doch niemanden einen Vorwurf machen wenn er das Standardverhalten für AVR nachbaut. Der es dann nutzt muss wissen was er auf einem AVR sinnvoll einsetzen kann und was nicht. Soweit muss man da gar nicht schauen. Das fängt schon mit der String Lib an, ohne zu wissen was man tut kann die nach hinten losgehen. Das Problem mit dem Speicher ist auch nicht zwingend auf AVR begrenzt. Alle die µC programmieren und die libstdc++ verwenden müssen wissen was sie ihrem stark begrenzten Speicher im Vergleich zur Desktop CPU/RAM zumuten können und was nicht.
Kann val denn überhaupt größer als 65535 werden? Wenn es ein uint16 ist,
dann wird dieser Wert nie erreicht.
...
Auch int32_t brachte kein Erfolg, aber jetzt mal ganz von Anfang.
val wurde in Einer Schritten gezählt. Zuerst vorwärts bis 2, dann rückwärts um die Bedingung val < 0 zu prüfen. Hierbei erwartete ich -1, aber stattdessen wird die Bedingung val >= 65535 erfüllt ( siehe Screenshot im Link ).
Das Programm ist im Anhang ( ..._Original ) und die Folge für val ist " *2 + 102 ", was eigentlich 164346 ergeben müsste. Jetzt dürfen wir raten, warum 38810 herauskommt ( siehe Screenshot ).
Jaja, programmieren mit Unlogik . . .
Ich weiß zwar nicht warum ich das hier mache, ich mach's trotzdem. Siehe Anhang.
1
volatileint8_tenc_delta;
2
staticuint8_tlast;
Diese beiden Variabelen sind TABU!!! Die faßt man an Anwender NIE an! Die einzige Funktion, die man benutzt, ist
int8_t encode_read( uint8_t klicks );
Die liefert die Anzahl der Schritte seit dem letzten Aufruf mit Vorzeichen! Nur DAMIT arbeitet man.
Dann ist es auch leicht, zu erkennen, wann am Rad gedreht wurde. Nämlich dann, wenn der Rückgabewert ungleich 0 ist! WOW! Der Rest ist trivial^2. Oder doch nicht? Naja, man sollte schon VOR der Benutzung einer Variablen deren Grenzen prüfen und nicht DANACH! Du hast es genau anders herum gemacht! (Sind wir überrascht? Nicht wirklich)
Und interen Pull-Ups schaltet man auch anders ein.
cli( );
OCR3A = val; // An Rechteckgenerator Wert
übergeben
sei( );
Bin mir gar nicht mehr sicher ob das mit cli und sei überhaupt nötig
ist.
Und wenn nein - warum ?
Weil das Register durch den Compiler schon richtig beschrieben wird und in deinem Programm kein Zugriff darauf in einem Interrupt passiert.
Wahrscheinlich, weil du es kannst ;-)
case 4: enc_delta = val & 3; val >>>= 2; break;
Diese Logik verstehe ich nicht. val ist zu Begin = enc_delta.
Man maskiert Bit 0 & 1 aus, dann schiebt diese so, dass enc_delta immer
Null ergibt.
Das muss du gar nicht verstehen, denn du willst den Drehgeber nur benutzen. Fertig.
////////////////////////////////////////////////////////////////////////////////
void loop()
{
int8_t delta;
delta = encode_read(4); // 4 Signaländerungen pro Rastung
if( delta != 0 ) {
pwm_wert += delta;
if( pwm_wert > 65535 ) pwm_wert = 65535;
if( pwm_wert < 0 ) pwm_wert = 0;
OCR3A = pwm_wert; // An Rechteckgenerator Wert
übergeben
Warum erzeugt man zwei weitere Variablen ( delta, pwm_wert ) und
arbeitet nicht einfach mit val weiter ?
Weil es so besser ist. Klar kann man sich auch den alten Wert merken und prüfen, ob eine Änderung vorliegt. Ist aber doppelt gemoppelt. Außerdem ist delta eine kleine 8 Bit Zahl, pwm_wert ja nach Anwendung 16 oder 32 Bit. Mehr Speicher, mehr CPU-Last, mehr Aufwand für einen Vergleich.
Das muss du gar nicht verstehen, denn du willst den Drehgeber nur
benutzen. Fertig.
1
case4:h_encoder_delta=val&3;val>>=2;break;
Wär aber schön, denn ich verstehe auch nicht, wieso h_encoder_delta in der ISR nur bis 4 bzw. -4 zählt. Der Ausdruck rechts vom Gleichheitszeichen ergibt ja entweder 1 oder -1. Also wird doch eigentlich h_encoder_delta bis zum Überlauf hoch,- bzw. runtergezählt
Was sorgt dafür, dass h_encoder_delta nur bis 4 hochzählt, wenn doch immer 1 addiert wird ?
1
volatileint8_th_encoder_delta;
2
3
h_encoder_delta+=(diff&2)-1;// bit 1 = direction (+/-)
Das muss du gar nicht verstehen, denn du willst den Drehgeber nur
benutzen. Fertig.
case 4: h_encoder_delta = val & 3; val >>= 2; break;
Wär aber schön, denn ich verstehe auch nicht, wieso h_encoder_delta in
der ISR nur bis 4 bzw. -4 zählt.
Bei jedem Aufruf der Funktion passiert folgendes
h_encoder_delta = val & 3;
nur die unteren 2 Bit von h_encoder_delta bleiben übrig, die oberen Bits werden gelöscht. 3 = 0b00000011, siehe Bitmanipulation.
val >>= 2; break;
Die Variable val, welche den Wert von h_encoder_delta enthält, wird um 2 Bits nach rechts geschoben. Damit werden die unteren 2 Bits rausgeschoben und die Variable praktisch durch 4 dividiert. Denn genau das will man bei einem Encoder, der 4 elektrische Pulse / mechanischer Raststufe besitzt.
Der Ausdruck rechts vom
Gleichheitszeichen ergibt ja entweder 1 oder -1. Also wird doch
eigentlich h_encoder_delta bis zum Überlauf hoch,- bzw. runtergezählt
Nö.
Was sorgt dafür, dass h_encoder_delta nur bis 4 hochzählt, wenn doch
immer 1 addiert wird ?
Die Tatsache, daß dein Programm die Funktion encode_read(4) sehr oft aufruft, mit mehreren Dutzend kHz. In der Zeit kann sich die Variable gar nicht schneller ändern, denn die ISR, welche die Variable verändert, läuft nur mit 1kHz. In einem richtigen Programm wird die Funktion deutlich langsamer aufgerufen, vielleicht mit 1-10 Hz. In der Zeit kann der Drehgeber aber mehrere Schritte machen. Die werden alle korrekt gezählt.
Bei jedem Aufruf der Funktion passiert folgendes
...
Danke, dass du es mir doch noch erklärt hast.
Die einfachsten Dinge bereiten mir Probleme, es ist schon fast verflucht.
In der rechteckgenerator_init, weise ich OCR3A den Wert 10.000 zu.
Es hat aber seltsamerweise den Wert 16. Mache ich dies an einer anderen Stelle, so stimmt alles.
10.000 scheint nicht in ein 8 Bit Register zu passen. 10.000 modulo 256 ergibt 16.
Du musst mit den Grundlagen vom ersten Kapitel an anfangen.
Edit:
Ok, es ist ein 16 Bit Register. Das ist es nicht.
Der Wert steht vermutlich richtig im Register, aber im PrintLn wird der Zugriff nicht richtig gemacht. Auslesen über 16 Bit Hilfsvariable könnte gehen.
Ich stelle fest: Arduino Mega
Also werden alle Timer für 8 Bit PWM vorbereitet und Timer0 ist zusätzlich für millis() und Freunde vorbereitet.
Das kann die lustigsten Fallen stellen!
Darum grundsätzlich die Timer Control Register erst zurücksetzen, bevor man irgend etwas anderes damit anstellt.
(Ausnahme Timer0)
Es gab mal einen Thread hier, über das sonst entstehende undokumentierte Durcheinander.
Denn, entweder hat der Timer einen Bug, oder das Datenblatt ist unvollständig.
man kann nicht einfach wahllos irgendein Register ändern und danach den gesamten Timer neu konfigurieren. Bei Arduino sind die Timer mit PWM Einstellungen für analogWrite vorkonfiguriert. Wenn man noch nicht ganz genau weiß was macht macht, immer erstmal alle relevanten Timer Register reseten. Zuerst TCCRnB, damit steht der Timer und kann keinen Unsinn mehr machen. Dann den Rest reseten, dann neu einstellen und zum Schluss den Prescaler setzen. Dann läuft der Timer sauber an. Wenn der vorher schon läuft und die Konfig noch nicht fertig, kann und wird er Mist machen, auch wenn es ggf. nur kurzeitig ist.