C-Code im Sketch/TimerInterrupts

Hi,

ich bastel gerade an meinen Arduino Uno sowas wie einen Drehgeber ran. Ich habe als "Best-Practice" jetzt das hier gefunden: Drehgeber – Mikrocontroller.net und möchte das auch verwenden.

Den Code habe ich jetzt ein bisschen angepasst, allerdings scheitere ich hier an drei Zeilen:

TCCR0 = (1 << WGM01) | (1 << CS01) | (1 << CS00);   // CTC, prescaler 64
 OCR0 = (uint8_t)(XTAL / 64.0 * 1e-3 - 0.5);   // 1ms
 TIMSK |= 1 << OCIE0;

Gemeckert wird hier, dass TCCR0, OCR0, TIMSK und OCIE0 unbekannt sind ("Der Bezeichnier 'TCCR0' ist nicht definiert"). Das sind ja, wenn ich das richtig weiß Register des µC's und da hörts bei mir einfach auf. Evtl. kann mir da wer unter die Arme greifen.

Übrigens wird auch über XTAL gemeckert. Das ist der Takt in Hz. Gibt's dazu irgendwie eine Entsprechung, die ich verwenden kann um den Takt aus der Konfigurationsdatei herauszuziehen? Oder muss ich mir das definieren und dann aufpassen, wenn ich die Hardware wechsel?

VG
da_user

Die Register musst du auf deinen Controller anpassen. Das unterscheidet sich manchmal leicht. Vor allem zwischen Atmega8/16 und den späteren Atmegas oder den AtTiny. Siehe Datenblatt. Da ist alles aufgelistet.

TIMSK (timer interrupt mask) gibt es z.B nicht. Also ein Register für alle Timer. Auf den neueres Prozessoren hat jeder Timer sein eigenes Register dafür. Außerdem gibt es mehrere TCCR (timer counter control register) und OCR Register pro Timer. Da schaut man dann nach in welchem Register die Bits stehen die man ändern will.

Timer0 solltest du auf dem Arduino aber nicht verwenden. Der wird für millis() gebraucht. Timer1 oder Timer2 geht aber.

Controller ist der Uno, also AtMega328P.

Den Code habe ich jetzt mit deiner Hilfe schonmal soweit geändert:

	TCCR1A = (1 << WGM01) | (1 << CS01) | (1 << CS00);   // CTC, prescaler 64
	OCR1A = (uint8_t)(XTAL / 64.0 * 1e-3 - 0.5);   // 1ms
	TIMSK1 |= 1 << OCIE1A;

Ich bin halt gerade mobil unterwegs, da kann ich nicht testen und ein fettes Datenblatt will ich jetzt auch nicht ziehen. Sollte ich daheim mal machen und mir dann hier rüberschieben :wink:
Wenn das soweit funktionieren sollte, bräuchte ich nur noch idealerweise eine Möglichkeit den Takt (XTAL) aus der Konfigurationsdatei zu bekommen.
Hardwarewechsel ist bei mir nämlich meistens eher Taktwechsel, nämlich vom Uno-Board rüber auf den blanken Chip mit aktiviertem internen Takt.

Aber bis hierher schonmal vielen Dank!

VG
da_user

TCCR1A = (1 << WGM01) | (1 << CS01) | (1 << CS00);

Die Bit-Namen auch anpassen. CS11 und CS10

Und hier musst du dann wirklich ins Datenblatt schauen! Die Clock Select Bits sind bei Timer1 im TCCR1B Register.

Außerdem sind die Modi anders! Der Timer soll im CTC Modus laufen. Das ist dann WGM12. Das steht auch in TCCR1B. In TCCR1A sind nur WMG10 und WMG11

Die Timer funktionieren grundlegend gleich. Aber es gibt auch auf dem gleichen Prozessor kleine Unterschiede zwischen Timer0, Timer2 und Timer1/3/4/5 (3-5 nur auf dem Mega)

Den Takt bekommt du auf dem Arduino glaube ich mit F_CPU

Hallo,

wenn du [u]delay()[/u], [u]millis()[/u] und [u]micros()[/u] verwendest, solltest du Timer 0 nicht selbst verwenden.
Dann eher Timer 2.
Und dann bitte immer beim setting vom Timer erstmal alle Timer-Register löschen beim Arduino, weil die sonst vorbelegt sind, anders wie man denkt.

Peter definiert XTAL, eigentlich ist F_CPU Standard.

Für ähnliche Zwecke habe ich mir letztens den Arduino Core verändert.

Jetzt habe ich eine Funktion die bei jedem Arduino Timer0 Interrupt aufgerufen wird.
Also ca im ms Takt, allerdings nicht genau.

Ein Blink.ino sieht dann so aus:

void SystemTick() // ISR
{
  static int Ticks = 0;
  Ticks++;
  if(Ticks > 500) 
  {
      Ticks = 0;
      PINB  = (1<<PB5);  //digitalWrite(13,!digitalRead(13));  
  }  
}



void setup() 
{ 
  DDRB |= (1<<PB5); //  pinMode(13,OUTPUT);
}

void loop() 
{
}

Interessiert, dann zeige ich auch gerne die Änderungen.

Interessiert immer, man wird nicht dümmer dadurch :wink:

Gruß Tommy

Tommy56:
Interessiert immer, man wird nicht dümmer dadurch :wink:

Gruß Tommy

Gerne doch!

Bei mir liegen die Dateien im Verzeichnis: E:\Programme\Arduino\hardware\arduino\avr\cores\arduino

Verändert wird wiring.c. hier ein Ausschnitt:

#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ISR(TIM0_OVF_vect)
#else
ISR(TIMER0_OVF_vect)
#endif
{
 // copy these to local variables so they can be stored in registers
 // (volatile variables must be read from memory on every access)
 unsigned long m = timer0_millis;
 unsigned char f = timer0_fract;

 m += MILLIS_INC;
 f += FRACT_INC;
 if (f >= FRACT_MAX) {
 f -= FRACT_MAX;
 m += 1;
 }

 timer0_fract = f;
 timer0_millis = m;
 timer0_overflow_count++;
  if(SystemTick) SystemTick(); //  // <<--------------
}

Und Arduino.h, auch ein Ausschnitt:

#include "binary.h"
#ifdef __cplusplus
extern "C"{
#endif


// ---------------

void SystemTick(void) __attribute__((weak));     // <<--------------

// ---------------

void yield(void);

#define HIGH 0x1
#define LOW  0x0

Die Veränderung begrenzt sich also auf je 1 Zeile in 2 Dateien.

Beachtenswert:
SystemTick() läuft im Kontext einer ISR.
Also immer schön schlank halten, volatile und atomic nicht da vergessen, wo es nötig ist, usw.

Danke.

Gruß Tommy

Hallo,

@ combie, dass ist also deine ATtiny Version von millis? :slight_smile:

Doc_Arduino:
Hallo,

@ combie, dass ist also deine ATtiny Version von millis? :slight_smile:

? ? ?

Nee...
Ja... (auf meinen Tiny85 tuts das unverändert)

Entstanden ist das, weil ich einen "Tick" brauchte, aber schon alle Timer mit irgendwas belegt waren. Und in loop() blockierende Dinge erledigt wurden. Seriell und I2C Gedöns.

aha :slight_smile:

Hi,

kurzes Feedback: ich hab der Einfachheit halber die TimerOne-Lib verwendet.

Mit dem Ergebnis, dass die gepostete Variante einfach nicht funktioniert hat. Und ja: ich habe mich da auf Fehlersuche begeben, die Hardware funktioniert, der Arduino bekommt die Signale, auch der Timer-Interrupt wird regelmässig aufgerufen. Zählt aber einfach nicht.

Ich hab's dann nach ein paar Stunden bleiben lassen und habe die klassische Variante "Wenn Pegelwechsel am Interrupt, guck was das andere Signal gerade für einen Wer hat" verwendet.
Funktioniert auch, und ich kann mich mit meinem eigentlichen Projekt beschäftigen.

Danke trotzdem!