Forum: Mikrocontroller und Digitale Elektronik PWM mit ATtiny2313 an OCnx-Ausgang


von FoxAlpha (Gast)


Lesenswert?

Hallo zusammen,

ich bin frischer Einsteiger in die µC-Technik und habe folgendes 
Problemchen:

Ich möchte mit dem ATtiny2313 eine Hardware-PWM erzeugen bzw. auf einem 
Ausgang ausgeben, bin bisher aber erfolglos. Ich habe den Timer zwar zum 
laufen gebracht, der Ablauf stimmt auch (OCRnx als TOP, Intterupt flag 
bei compare match, etc.), die Interrupt Flags tauchen auch alle auf 
(Simulation mit AVR-Studio 4), aber an meinem Ausgang am PORTB tut sich 
nix... Das Setzen von prescaler, COMnx, WGM und dergleichen krieg ich ja 
alles hin, aber der Ausgang macht keinen Mucks...

Wenn ich das Datenblatt vom ATtiny2313 richtig verstanden habe, müsste 
ich eigentlich alles richtig gemacht haben (auch wenn ich stellenweise 
den Eindruck habe, dass das Datenblatt manches nicht vollständig 
erklärt). Das ganze müsste doch ohne Interrupt handler funktionieren, 
oder?

Ich liefere heut abend mal meinen sourcecode, vielleicht weiß jemand nen 
typischen Anfänger-Fallstrick?

Grüße

FoxAlpha

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ja das geht ohne ISR.
Hast du daran gedacht mit DDRx den Pin auf Ausgang zu setzen?

Hier ist ein Beispiel mit LED Fading:
http://www.mikrocontroller.net/articles/Pollin_Funk-AVR-Evaluationsboard#Blinky_Reloaded
Mode 5 non-inverted PWM on OC1A, 8 Bit Fast PWM

von FoxAlpha (Gast)


Lesenswert?

So, hier bin ich nochmal mit code... unschwer zu erkennen, möchte ich 
erstmal assemblerprogrammierung lernen/üben.
1
.include "tn2313def.inc"
2
3
init:
4
  ldi r16, RAMEND    ;stackinit (128byte RAM--> 8bit SP)
5
  out SPL, r16
6
  ldi r16, 0b11111111  ;portb als output
7
  out DDRB, r16
8
  ldi r16, 0      ;portb aus
9
  out PORTB, r16
10
  ldi r16, (1<<WGM00) | (1<<WGM01) | (1<<COM0A1) | (0<<COM0A0) | (1<<COM0B1) | (0<<COM0B0) 
11
            ;fast PWM ;set OC0A at top, clear on compare match fuer A und B
12
  out TCCR0A, r16
13
  ldi r16, 156    ;zwei werte fuer OCR0x
14
  out OCR0A, r16
15
  ldi r16, 12
16
  out OCR0B, r16
17
  ldi r16, (1<<CS00) | (0<<CS01) | (0<<CS02) | (1<<WGM02)  ;teiler 1, timer obergrenze OCR0A
18
  out TCCR0B, r16
19
  ldi r16, (1<<OCIE0A) | (1<<OCIE0B)  ;interrupt ein (braucht man das ueberhaupt?)
20
  out TIMSK, r16
21
22
main:
23
  ; einfach nixtun und den Timer arbeiten lassen ;)
24
  rjmp main

Portb setze ich als Ausgang und nulle den erstmal. Dann kommt der 
waveform generation mode als fast PWM mit OCR0A als TOP dran (und weil 
OCR0A = TOP, ist bei dem WGM OC0A immer gesetzt, OC0B dient als 
eigentliches Signal). OCR0x werden mit Zahlenwerten gefüttert, dann der 
Prescaler und der "Rest" vom WGM. Die Interrupts hab ich mal 
eingeschaltet, weiß der Geier, ob das notwendig ist...

Ziel des ganzen ist die Ansteuerung eines Modellbauservos. Zum 
Simulieren steht der Prescaler noch auf 1, später mit prescaler 1024 
kommt eine Frequenz von ca. 50Hz raus, an PB4 (OC0B) sollte dann ein 
PWM-Signal mit einem 20ms-Takt und rund 1,5ms "Ein"-Zeit rauskommen 
(Mittenstellung Servo). Mit dem 16bit Timer wäre das ganze etwas 
genauer, aber darauf kommts mir noch nicht an, ich muss erstmal lernen, 
mit dem Timer umzugehen.

Wenn jetzt jemandem was auffällt, was ich besser machen kann, kann er 
sich gerne dazu äußern.

Grüße

FoxAlpha

von FoxAlpha (Gast)


Lesenswert?

(irgendwie hat das mit dem posten das erste mal nicht geklappt, deswegen 
nochmal...)

So, hier bin ich nochmal mit code... unschwer zu erkennen, möchte ich 
erstmal assemblerprogrammierung lernen/üben.
1
.include "tn2313def.inc"
2
3
init:
4
  ldi r16, RAMEND    ;stackinit (128byte RAM--> 8bit SP)
5
  out SPL, r16
6
  ldi r16, 0b11111111  ;portb als output
7
  out DDRB, r16
8
  ldi r16, 0      ;portb aus
9
  out PORTB, r16
10
  ldi r16, (1<<WGM00) | (1<<WGM01) | (1<<COM0A1) | (0<<COM0A0) | (1<<COM0B1) | (0<<COM0B0) 
11
            ;fast PWM ;set OC0A at top, clear on compare match fuer A und B
12
  out TCCR0A, r16
13
  ldi r16, 156    ;zwei werte fuer OCR0x
14
  out OCR0A, r16
15
  ldi r16, 12
16
  out OCR0B, r16
17
  ldi r16, (1<<CS00) | (0<<CS01) | (0<<CS02) | (1<<WGM02)  ;teiler 1, timer obergrenze OCR0A
18
  out TCCR0B, r16
19
  ldi r16, (1<<OCIE0A) | (1<<OCIE0B)  ;interrupt ein (braucht man das ueberhaupt?)
20
  out TIMSK, r16
21
22
main:
23
  ; einfach nixtun und den Timer arbeiten lassen ;)
24
  rjmp main

Portb setze ich als Ausgang und nulle den erstmal. Dann kommt der 
waveform generation mode als fast PWM mit OCR0A als TOP dran (und weil 
OCR0A = TOP, ist bei dem WGM OC0A immer gesetzt, OC0B dient als 
eigentliches Signal). OCR0x werden mit Zahlenwerten gefüttert, dann der 
Prescaler und der "Rest" vom WGM. Die Interrupts hab ich mal 
eingeschaltet, weiß der Geier, ob das notwendig ist...

Ziel des ganzen ist die Ansteuerung eines Modellbauservos. Zum 
Simulieren steht der Prescaler noch auf 1, später mit prescaler 1024 
kommt eine Frequenz von ca. 50Hz raus, an PB4 (OC0B) sollte dann ein 
PWM-Signal mit einem 20ms-Takt und rund 1,5ms "Ein"-Zeit rauskommen 
(Mittenstellung Servo). Mit dem 16bit Timer wäre das ganze etwas 
genauer, aber darauf kommts mir noch nicht an, ich muss erstmal lernen, 
mit dem Timer umzugehen.

Wenn jetzt jemandem was auffällt, was ich besser machen kann, kann er 
sich gerne dazu äußern.

Grüße

FoxAlpha

von FoxAlpha (Gast)


Angehängte Dateien:

Lesenswert?

So, hier bin ich nochmal mit code... unschwer zu erkennen, möchte ich 
erstmal assemblerprogrammierung lernen/üben.

Portb setze ich als Ausgang und nulle den erstmal. Dann kommt der 
waveform generation mode als fast PWM mit OCR0A als TOP dran (und weil 
OCR0A = TOP, ist bei dem WGM OC0A immer gesetzt, OC0B dient als 
eigentliches Signal). OCR0x werden mit Zahlenwerten gefüttert, dann der 
Prescaler und der "Rest" vom WGM. Die Interrupts hab ich mal 
eingeschaltet, weiß der Geier, ob das notwendig ist...

Ziel des ganzen ist die Ansteuerung eines Modellbauservos. Zum 
Simulieren steht der Prescaler noch auf 1, später mit prescaler 1024 
kommt eine Frequenz von ca. 50Hz raus, an PB4 (OC0B) sollte dann ein 
PWM-Signal mit einem 20ms-Takt und rund 1,5ms "Ein"-Zeit rauskommen 
(Mittenstellung Servo). Mit dem 16bit Timer wäre das ganze etwas 
genauer, aber darauf kommts mir noch nicht an, ich muss erstmal lernen, 
mit dem Timer umzugehen.

Wenn jetzt jemandem was auffällt, was ich besser machen kann, kann er 
sich gerne dazu äußern.

Grüße

FoxAlpha

von Stephan S. (foxalpha)


Lesenswert?

...mist, jetzt ist doch alles gepostet worden... die zwei überflüssigen 
posts (und den hier) darf jemand löschen, wer kann...

von Heiko (Gast)


Lesenswert?

Doofe Frage: Hast du schon Hardware oder schaust du im AVRStudio auf die 
Bits in PORTB? In PORTB tut sich nämlich nichts, der Pin wird "an PORTB 
vorbei" gesetzt bzw. gelöscht.

Siehe auch http://atmel.com/dyn/resources/prod_documents/doc8246.pdf 
Bild 11-4.

Zu deiner Frage bezüglich Interrupts: Braucht man nicht. Würde ich auch 
dafür nicht aktivieren, ist eine zusätzliche Fehlerquelle - denn ohne 
ISR macht der Controller unter Umständen dumme Sachen ;)

In deinem Programm ist das aber egal, denn du setzt das globale IRQ-Flag 
nicht.

MfG, Heiko

von Stephan S. (foxalpha)


Lesenswert?

Guten Morgen allerseits,

die richtige Frage wäre gewesen: "Schaust du auch auf die richtigen 
Ports?" Ich habe erst späääät festgestellt, dass OC0B ja in PORTD steckt 
und nicht in PortB... /*aua/*

Plötzlich funktioniert alles wie es soll. ;) Sorry für die blöden 
Fragen.

Grüße

FoxAlpha

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.