www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Atmega48 - Takt ausgeben


Autor: Julian W. (julian-w) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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:
#include <avr/io.h>
#include <avr/interrupt.h>

#define sleep() asm volatile ("nop")


volatile uint8_t data[10];

int main(void)
{

    // --- TIMER1_COMPA irq ---
  // selected time = 204800 Hz (78 ticks)
  // prescaler = 1 (1 ticks ... 4.096 ms)
  TCCR1B = (1<<WGM12)|(1<<CS10);
  OCR1AH = 255;
  OCR1AL = 178;
  TIMSK1 |= (1<<OCIE1A);

  // --- main loop ---
  sei();

    for (;;) sleep();

  return 0;
}

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

Autor: Spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jean Payer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Julian W. (julian-w) Benutzerseite

Besser so.
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 16e6

volatile uint8_t data[10];

int main(void)
{

  DDRB = (1<<PB1);

  // --- TIMER1 ---
  // 204800 Hz, CTC, WGM Mode 12
  
  TCCR1A = (1<<COM1A1);
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
  ICR1 = 77;
  OCR1A = 38;

  // --- main loop ---

   while(1);

  return 0;
}

>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

Autor: Julian W. (julian-w) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke, funktioniert prima :)

Autor: Julian W. (julian-w) Benutzerseite
Datum:

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

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mist, schon wieder den falschen PWM-Mode erwischt.
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 16e6

volatile uint8_t data[10];

int main(void)
{

  DDRB = (1<<PB1);

  // --- TIMER1 ---
  // 204800 Hz, CTC, WGM Mode 14
  
  TCCR1A = (1<<COM1A1) | (1<<WGM11);
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
  ICR1 = 77;
  OCR1A = 38;

  // --- main loop ---

   while(1);

  return 0;
}

Autor: Julian W. (julian-w) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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 ;)

Autor: I. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Julian W. (julian-w) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Julian W. (julian-w) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: I. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: I. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Julian W. (julian-w) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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
TCCR1A &= ~(1<<COM1A1);   // OCR deaktivieren

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

MFG
Falk

Autor: I. L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Joachim B. (jojo84)
Datum:

Bewertung
0 lesenswert
nicht 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ß

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.