Forum: Mikrocontroller und Digitale Elektronik Atmega48 - Takt ausgeben


von Julian W. (julian-w) Benutzerseite


Lesenswert?

Hallo,
ich würde gerne am Pin B1 (OC1A) einen Takt von 204,8 kHz ausgeben (10 
Bit * 200 Hz ; für einen TLC5940).
Dazu habe ich folgenden C-Code auf den Atmega48 programmiert:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
#define sleep() asm volatile ("nop")
5
6
7
volatile uint8_t data[10];
8
9
int main(void)
10
{
11
12
    // --- TIMER1_COMPA irq ---
13
  // selected time = 204800 Hz (78 ticks)
14
  // prescaler = 1 (1 ticks ... 4.096 ms)
15
  TCCR1B = (1<<WGM12)|(1<<CS10);
16
  OCR1AH = 255;
17
  OCR1AL = 178;
18
  TIMSK1 |= (1<<OCIE1A);
19
20
  // --- main loop ---
21
  sei();
22
23
    for (;;) sleep();
24
25
  return 0;
26
}

Nur wenn ich jetzt mit dem Oszi messe, tut sich an Pin B1 gar nichts. 
Laut Datenblatt sollte das aber doch funktionieren!?
Der Atmega48 läuft mit einem 16Mhz Quarz und funktioniert auch korrekt 
(also LED blinken geht und Frequenz stimmt auch).

Könntet ihr mir da evtl. weiterhelfen, ich steht irgendwie auf dem 
Schlauch oder bin noch zu sehr dem Atmega8 gewöhent...

Viele Grüße
Julian

von Spess53 (Gast)


Lesenswert?

Hi

>ich steht irgendwie auf dem Schlauch oder bin noch zu sehr dem Atmega8
gewöhent...

Auch beim ATMega8 muss man das Pin auf Ausgang schalten.

MfG Spess

von Jean Payer (Gast)


Lesenswert?

Hi,

DDRB &= ~(1<<PB1);  //Richtung laut datasheet erst nach TCNT und OCRx 
setzen
TCNT1 = 0x00;       //clear
OCR1A = (F_CPU / (2*n*frequency)) - 1;  //Register laden, vorsicht n = 1 
!!!
DDRB |= (1<<PB1);   //Richtungsregister darf jetzt gesetzt werden
TCCR1A |= (1<<COM1A0);  //CTC Mode, mit Toggle PB1
TCCR1B |= (1<<CS10) | (1<<WGM12); //no prescaler, siehe oben, deswegen n 
= 1


und auf keinen TIMSK1 |= (1<<OCIE1A) setzen, ohne eine Interrupt 
Routine, da läuft dir das dingen ins Nirvana !

Gruß und hoffe das stimmt, nur auf die schnelle zusammen gesucht ausm 
DataS.

von Falk B. (falk)


Lesenswert?

@  Julian W. (julian-w) Benutzerseite

Besser so.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#define F_CPU 16e6
4
5
volatile uint8_t data[10];
6
7
int main(void)
8
{
9
10
  DDRB = (1<<PB1);
11
12
  // --- TIMER1 ---
13
  // 204800 Hz, CTC, WGM Mode 12
14
  
15
  TCCR1A = (1<<COM1A1);
16
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
17
  ICR1 = 77;
18
  OCR1A = 38;
19
20
  // --- main loop ---
21
22
   while(1);
23
24
  return 0;
25
}

>Nur wenn ich jetzt mit dem Oszi messe, tut sich an Pin B1 gar nichts.

Logisch, du hast es nicht als Ausgang geschaltet.

>Könntet ihr mir da evtl. weiterhelfen, ich steht irgendwie auf dem
>Schlauch oder bin noch zu sehr dem Atmega8 gewöhent...

Was wäre die Welt ohne dumme Ausreden. Der Timer 1 funktioniert in ALLEN 
AVRs gleich!

RTFM.

MFG
Falk

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Danke, funktioniert prima :)

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Upps, gar nicht gesehen, dass Falk noch was geschreiben hat. Aber leider 
funktioniert dein "Code-Schnipsel" nicht :/

von Falk B. (falk)


Lesenswert?

Mist, schon wieder den falschen PWM-Mode erwischt.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#define F_CPU 16e6
4
5
volatile uint8_t data[10];
6
7
int main(void)
8
{
9
10
  DDRB = (1<<PB1);
11
12
  // --- TIMER1 ---
13
  // 204800 Hz, CTC, WGM Mode 14
14
  
15
  TCCR1A = (1<<COM1A1) | (1<<WGM11);
16
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
17
  ICR1 = 77;
18
  OCR1A = 38;
19
20
  // --- main loop ---
21
22
   while(1);
23
24
  return 0;
25
}

von Julian W. (julian-w) Benutzerseite


Lesenswert?

So funktionierst, muss ich mich halt geschlagen geben ;)

Noch 'ne andere Frage:
Ist es auch möglich, dass ganze in einem Interrupt abzufangen. 
Eigentlich wäre für mich nur ein Interrupt alle 1024 Interrupts (10 Bit 
eben) interessant, aber notfalls muss ich halt per Software hochzählen, 
der μC hat eh nicht viel zu tun ;)

von I. L. (Gast)


Lesenswert?

Was willst du denn da abfagen? Der Timer is ne eigenständige Einheit.
Du kannst die aber im CTC-Modus Zeitintervalle generieren, die halt noch 
nebenbei laufen.



Gruß Knut

von Falk B. (falk)


Lesenswert?

@  Julian W. (julian-w) Benutzerseite

>Ist es auch möglich, dass ganze in einem Interrupt abzufangen.

Jain, ist hier aber nicht sinnvoll.

>Eigentlich wäre für mich nur ein Interrupt alle 1024 Interrupts (10 Bit
>eben) interessant, aber notfalls muss ich halt per Software hochzählen,
>der μC hat eh nicht viel zu tun ;)

Dann nimm Timer 0 und lass den dein Multiplexingintervall generieren. 
Fettig.

MFG
Falk

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Nunja, das ganze hat folgenden Hintergrund:
die 204,8 kHz sind der Takt einer 10 Bit PWM. Nach 1024 Takte ist die 
PWM also einmal durchgelaufen. Dieses "Ereignis" würde ich gerne 
abfangen.

Wie kann ich dass den am besten anstellen?

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Ach, Falk, sehe gerade, du hast ja schon was gepostet, während ich noch 
schieb.

Also du würdest mir empfehlen, Timer0 einfach mit 200Hz laufen zu 
lassen. Hört sich gar nicht so dumm an, hört sich sogar richtig gut an. 
Werd ich gleich mal testen...

von I. L. (Gast)


Lesenswert?

Julian W. schrieb:
> Nunja, das ganze hat folgenden Hintergrund:
> die 204,8 kHz sind der Takt einer 10 Bit PWM. Nach 1024 Takte ist die
> PWM also einmal durchgelaufen.

Ich versteh nicht ganz was du meinst?

von I. L. (Gast)


Lesenswert?

Julian W. schrieb:
> lso du würdest mir empfehlen, Timer0 einfach mit 200Hz laufen zu
> lassen. Hört sich gar nicht so dumm an, hört sich sogar richtig gut an.
> Werd ich gleich mal testen...

CTC-Modus halt...

Gruß Knut

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Ingo L. schrieb:
> Julian W. schrieb:
>> Nunja, das ganze hat folgenden Hintergrund:
>> die 204,8 kHz sind der Takt einer 10 Bit PWM. Nach 1024 Takte ist die
>> PWM also einmal durchgelaufen.
>
> Ich versteh nicht ganz was du meinst?

Ganz einfach: Ich nutze den TLC5940, diesem muss ich einen PWM-Takt 
seperat einspeißen. Das sind die 204,8 kHz (10bit = 1024; 200Hz PWM-FRQ 
=> 1024 * 200 = 204800). D.h., wenn der Timer1 1024 mal ausgelöst hat, 
ist eine PWM-Phase vorbei. Und dieses Ereignis würde ich gerne in 
Software abfangen.

von Falk B. (falk)


Lesenswert?

@  Julian W. (julian-w) Benutzerseite

>ist eine PWM-Phase vorbei. Und dieses Ereignis würde ich gerne in
>Software abfangen.

Mit Timer 0 im Overflow Interrupt. Dort kann man, wenn man will, 
einfach per
1
TCCR1A &= ~(1<<COM1A1);   // OCR deaktivieren

den TLC neu laden und dann mit
1
TCNT1 = 0;               //Timer reset
2
TCCR1A |= (1<<COM1A1);   // OCR aktivieren

MFG
Falk

von I. L. (Gast)


Lesenswert?

Falk Brunner schrieb:
> Mit Timer 0 im Overflow Interrupt

Ist nicht ein Compare-Match besser geeignet als ein Timeroverflow?
Nicht das deine Lösung nicht funktionieren würde...


Gruß Knut

von Falk B. (falk)


Lesenswert?

@  Ingo L. (knutinator)

>> Mit Timer 0 im Overflow Interrupt

>Ist nicht ein Compare-Match besser geeignet als ein Timeroverflow?

Ja, damit kann man die Interruptfrequenz viel genauer einstellen. Wenn 
das wirklich entscheidend ist.

MFG
Falk

von Joachim B. (jojo84)


Lesenswert?

Moin und Mahlzeit,

ich habe zu fast der gleichen Anwendung auch eine "Frage". Ich möchte 
eben auch einen Takt für einen TLC5940 generieren. Das könnte ich ja. 
z.B. mit Timer0 im fast PWM mode und OVF-Interrupt machen.

Jetzt muß ich ja aber beim "normalen" Grayscale-Mode des 5940 immer nach 
4095 Zählschritten (oder was ich auch immer für eine Auflösung haben 
will) den BLANK-Pin einmal toggeln.

Ich müßte also nach jedem PWM-Takt abfragen, ob das denn jetzt der 
4095ste war, oder nicht.
Da war meine Idee, ob ich den PWM-Pin nicht zusätzlich an den 
Capture-Pin von Timer1 anklemmen könnte. Da stelle ich den 
Vergleichswert dann auf 4095 und kann mir dann die Abfragen sparen, weil 
ich ja weiß, daß genau die gewünschte Anzahl von Takten durch ist.

Wäre das gut oder gibt es etwas schwerwiegendes, was dagegen spricht?

Gruß

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.