Forum: Compiler & IDEs Umstieg zu Atmelstudio (hilfe beim Coden mit TimerInterrupt)


von Sören G. (xasir)


Lesenswert?

Hallo erstmal.

Ich bin gerade dabei von der gut vorgekauten Arduino-IDE auf Atmelstudio
umzusteigen.

Die ersten Hürden konnte ich noch gut überwinden und verstehen, doch nun 
die Erste die ich zwar überwunden habe aber nicht verstehe.

Da ich viel mit Arduino gemacht habe, laufen meine ersten schritte auf 
einem Arduino-uno (ATMega328).

Nun war nach den ersten timer und pwm versuchen der Wunsch geweckt auch 
ein LED blinken ohne delay zu bauen. Hier erstmal der Code der sogar 
funktioniert.
1
#define F_CPU 16000L
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <util/delay.h>
5
uint64_t millis = 0;
6
uint64_t last;
7
uint64_t micros;
8
uint64_t pos;
9
int main(void)
10
{
11
  DDRB = 0b00100000;
12
  PORTB = 0b00010000;
13
  DDRD = 255;
14
  PORTD = 0;
15
  TCCR0A = 0b10000011;
16
  TCCR0B = (1<<CS00);
17
  TIMSK0 = 0b00000001;
18
  sei();
19
  while (1)
20
  {
21
    OCR0A = 0;
22
    if(micros - last > 1000000){
23
      last = micros;
24
      PORTB ^= (1<<5);
25
    }
26
  }
27
}
28
ISR(TIMER0_OVF_vect){
29
  micros+=16;
30
}

Nun das Problem.
Wenn ich die Zeile mit "OCR0A = 0;" aus der while schleife schiebe oder 
lösche, blinkt PB5 nicht mehr. und trotz der 0 leuchtet die LED am Pin 
(PD6) an dem die Waveform ausgegeben wird ganz schwach.

Habe ich hier was falsch verstanden oder ist das die komplett falsche 
Herangehensweise?

von Carl D. (jcw2)


Lesenswert?

Da micros in der ISR geändert wird, muß volatile davor stehen:
1
volatile int64_t micros;

Edit: und offenbar reicht die eine Zeile genug Register zu brauchen, 
damit der Wert micros nachgeladen wird.

: Bearbeitet durch User
von Sören G. (xasir)


Lesenswert?

Ok danke klappt. und auch verstanden. :)

Das muss ich dann bei jeder anderen Variablen machen die ich außerhalb 
der main verändere und in der main verarbeiten möchte?
und gibt es in meinem Code groben Optimierungsbedarf?
und woher kommt das "Glimmen" der LED an PD6?

: Bearbeitet durch User
von Holger L. (max5v)


Lesenswert?

#define F_CPU 16000L scheint mir verkehrt zu sein, der Prozessor läuft 
wohl eher mit 16MHz.

Bei den Registerzuweisungen sollte man sich schon eine einheitliche 
Schreibweise angewöhnen, das bringt Übersichtlichkeit.

Die uint64_t Variablen könnte man sich sparen in dem man den Prescaler 
erhöht z.B. 64, und den CTC statt dem PWM Modus wählt.

Da die Led im Code selber geschaltet wird bietet sich CTC sowieso an.

PD6 ist der OC0A Pin der PWM...

: Bearbeitet durch User
von Sören G. (xasir)


Lesenswert?

Danke Für die Schreibweisentipps.
die LED will ich später noch in verschiedenen Dimmstufen leuchten 
lassen.
deswegen fast PWM.
mich wundert nur das wenn ich "OC0A = 0" mache die LED trotzdem etwas am 
"glimmen" ist.

: Bearbeitet durch User
von Karl M. (Gast)


Lesenswert?

Sören G. schrieb:
> while (1)
>   {
>     OCR0A = 0;
>     if(micros - last > 1000000){
>       last = micros;
>       PORTB ^= (1<<5);
>     }
>   }

Hallo, frage Dich bitte mit welcher Zahl die Differez (micros - last) 
verglichen wird.

Dass
1
PB5 = 5
 ist, weißt Du, es liest sich besser, dies umzuschreiben.
1
DDRB = 0b00100000; PORTB = 0b00010000;

Neu
1
DDRB = (1<<PB5); PORTB = (1<<PB5);

Ich nutze eine noch etwas andere Funktionalität, die Defines.
1
#define LED (1<<PB5)

Dadurch wird der Ausdruck noch leserlicher:
1
DDRB = LED; PORTB = LED;

Dass kann man weiter Abstrahieren, so dass dies möglich wird:
1
LED_DDR=1; LED=1;

von Holger L. (max5v)


Lesenswert?

Sören G. schrieb:
> mich wundert nur das wenn ich "OC0A = 0" mache die LED trotzdem etwas am
> "glimmen" ist.

Ich hoffe das ich mich nun nicht hineinsetze, aber ich meine des der Pin 
im nicht invertierten Modus für sehr kurze Zeit eingeschaltet wird.
Abhilfe sollte da der invertierte Modus schaffen, welcher (glaube dann 
allerdings keine maximale "helligkeit" mehr zuläßt)
1
TCCR0A = (1 << COM0A1) | (1 << COM0A0) | (1 << WGM01) | (1 << WGM00);

Set OC0A on Compare Match, clear OC0A at BOTTOM,
(inverting mode). Für Fast PWM Modus.

Die alte Initialisierung nur nochmal falls die obere unverständlich 
seien sollte
1
TCCR0A = 0b10000011;
  wäre das selbe wie
1
TCCR0A = (1 << COM0A1) | (1 << WGM01) | (1 << WGM00);

Clear OC0A on Compare Match, set OC0A at BOTTOM,
(non-inverting mode) Für Fast PWM Modus.


So Pi mal Daumen, ist ungetestet. Es gibt bestimmt eine deutlich 
bessere, fachlich versiertere, Erklärung.

von Veit D. (devil-elec)


Lesenswert?

Sören G. schrieb:

>     if(micros - last > 1000000) {
>       last = micros;
>       ...
>       ...
>     }

Hallo,

nur so nebenbei. Den Codeausschnitt hättest du in der Arduino IDE auch 
mit micros() oder millis() erledigen können. Das nur zur reinen Info.

> Da ich viel mit Arduino gemacht habe, laufen meine ersten schritte auf
> einem Arduino-uno (ATMega328).
Korrektur: Atmega328P - "P" nicht das du das falsche Datenblatt 
verwendest

Weitermachen.  :-)

von Sören G. (xasir)


Lesenswert?

Karl M. schrieb:

> Ich nutze eine noch etwas andere Funktionalität, die Defines.
>
1
#define LED (1<<PB5)
>
> Dadurch wird der Ausdruck noch leserlicher:
>
1
DDRB = LED; PORTB = LED;

Bis hier hin komm ich noch mit.

> Dass kann man weiter Abstrahieren, so dass dies möglich wird:
>
1
LED_DDR=1; LED=1;

Da wirds für mich interessant, weil ich grad keine Ahnung hab wie ich 
das mit nem einfachen #define machen soll.


Veit D. schrieb:
>nur so nebenbei. Den Codeausschnitt hättest du in der Arduino IDE auch
>mit micros() oder millis() erledigen können. Das nur zur reinen Info.

Jap weiss ich, aber da ich die Arduinoumgebung gerade verlassen habe, 
steht mir diese nützliche Funktion leider nicht zur Verfügung und muss 
sie selbst bauen.

@ Holger
ich werds mal probieren.

von Wilhelm M. (wimalopaan)


Lesenswert?

Bei dem entlehnten Verb "coden" dreht sich mir immer der Magen um, weil 
ich da an was anderes denke. Steht zwar auch so im Wictionary, doch 
[ck]odieren oder coding erscheint mit irgendwie natürlicher, wobei koten 
(s.o.) natürlich auch ein natürlicher Vorgang ist ;-)

von Carl D. (jcw2)


Lesenswert?

Wilhelm M. schrieb:
> Bei dem entlehnten Verb "coden" dreht sich mir immer der Magen um, weil
> ich da an was anderes denke. Steht zwar auch so im Wictionary, doch
> [ck]odieren oder coding erscheint mit irgendwie natürlicher, wobei koten
> (s.o.) natürlich auch ein natürlicher Vorgang ist ;-)

Mit den Jahren und dank vieler junge Kollegen (jeder Bauart), hab ich 
eine gewisse Milde gegenüber Neuzeitsprech entwickelt. Sprachliche 
Korrektheit kann man ja immer noch in den Bereichen verlangen, in denen 
es wirklich wichtig ist. Z.B. weil Compiler nicht so rücksichtsvoll 
sind.

Wir waren schließlich auch nicht besser ;-)

von Sören G. (xasir)


Lesenswert?

Gut das wir alle einen Verstand haben und Wörter auch im Kontext 
verstehen...

Sören G. schrieb:
> Da wirds für mich interessant, weil ich grad keine Ahnung hab wie ich
> das mit nem einfachen #define machen soll.

Ok da sind wir stehen geblieben....

von Veit D. (devil-elec)


Lesenswert?

Sören G. schrieb:

>> Da wirds für mich interessant, weil ich grad keine Ahnung hab wie ich
>> das mit nem einfachen #define machen soll.

Du bemerkst jetzt dass das Arduino Framework gar nicht so blöd ist. Denn 
#define ist dafür ein klarer Rückschritt. In C scheinbar nicht anders 
möglich. Ich empfehle dir bleibe bei C++, baue dir Klassen usw., dann 
kannste das ähnlich wie mit dem Arduino Framework machen.

Wenn du unbedingt #define möchtest lese dir das AVR Tutorial hier im 
Forum durch. Als Einstieg ein Bsp. ...
1
#ifndef sbi
2
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))   
3
#endif
4
#ifndef cbi
5
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))  
6
#endif
7
8
#define P1_OUT  sbi (DDRA,3)  // PA3 Ausgang
9
#define P2_OUT  sbi (DDRA,4)  // PA4 Ausgang
10
11
#define P1_ON  sbi (PORTA,3)  // PA3 einschalten
12
#define P2_ON  sbi (PORTA,4)  // PA4 einschalten
13
14
#define P1_OFF  cbi (PORTA,3)  // PA3 ausschalten
15
#define P2_OFF  cbi (PORTA,4)  // PA4 ausschalten

Was du vielleicht auch machen kannst ist folgendes. Atmel Studio mit 
https://www.visualmicro.com/  Plugin. Du stehst damit nicht völlig auf 
verlorenen Posten. Kannst weiterhin das Arduino Framework nutzen und 
baust Stück für Stück eigenen Klassen bis du das Arduino Framework 
vielleicht nicht mehr benötigst, falls das dein Ziel sein sollte. Man 
kann aber auch weiterhin das Arduino Framework nutzen und nur das selbst 
neu schreiben was einem vielleicht stört. Das bleibt jeden selbst 
überlassen.

von Peter D. (peda)


Lesenswert?

Für den leserlichen Zugriff auf IO-Pins:

Beitrag "Re: Port als Variable"

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.