Maximalfrequenz an PINs ATMEGA8

Gast #305195
Lesenswert?

Hallo

Habe ein kleines Problem.
Ich will einen clock an einem Portpin des ATMEGA8 erzeugen. Diese
sollte 500kHz betragen. Mein Quarz hat 14Mhz. Am Ausgang kann ich
jedoch nur maximal ca 82 khz messen. Ist es möglich, dass es eine
Begrenzung in der Freuquenz an den Ausgängen gibt.

MfG
Markus
Gast #305200
Lesenswert?

@wie man fragen richtig stellt:
Wieder so'n unqualifizierter Kommentar. Traut sich noch nicht mal, nen
Namen zu nennen. Da gibts hier im Forum haufenweise Fragen zu denen so
was besser passen würde. Aber an dieser gibts eigentlich nicht viel
auszusetzen, zumindest nicht am zitierten Satz.
Gast #305201
Lesenswert?

ja sicher unqaulifiziert. denn das einzige was man als frag erkenne
könnte wäre  ob es so ist oder nicht. mehr musste daher auch nicht
gesagt werden. wieso fragen denn alle nach interruppts timern usw
wollte er das wissen ? nö er wollte wissen obs sowas gibt.

namen sidn auser bei angemeldeten eh schall und rauch

mfg ingo (oder doch robert) ach immer die gespaltenen persönlichkeiten
Gast #305207
Lesenswert?

Na dann isses ja klar. TCCR0 = 0x03 teilt die 14Mhz um den Faktor 64.
Der Timer nochmal um den Faktor 2. Macht ca 100 Khz.

Ich glaube, dass es etwas schwierig sein wird mit Timer0 einen 500kHz
Takt zu erzeugen. Das liegt daran, dass Timer0 nur ein sehr primitiver
8-bit counter ist, der beim overflow von 255 nach 0 einen interrupt
erzeugt. Die interrupt Routine muesste dann TCNT0 neu setzen und einen
I/O Pin toggeln. Um 500kHz Takt zu erzeugen musst der uC also timer
interrupts im 1MHz Takt abfackeln und kann sogut wie garnix anderes
mehr tun. Besser du nimmst ein Timer1 im CTC mode und laesst den einen
Pin automatisch togglen. Der Vorteil : keine interrupt Routine noetig
und der uC hat den Kopf fuer Wichtigeres frei.
Gast #305208
Lesenswert?

Wenn Du den Timer mit Taktteilung durch 64 betreibst, kriegste eh max.
218,75 kHz. Setz mal TCCR0 = 0x01;
Dann kriegste die Maximalfrequenz, die Du aber nicht berechnen kannst,
weil der Sprung in die ISR jedes mal einige Taktzyklen braucht. Höher
gehts nur, wenn Du mit Timer 1 oder 2 im Compare-Modus (CTC) arbeitest
und den OC1x bzw. OC2- Ausgang benutzt, weil Du dann keinen Interrupt
mehr brauchst.
Gast #305210
Lesenswert?

ausserdem mal schauen (listing), was der compiler so an Sachen rettet
und wiederherstellt.
In deinem Fall dürfte das minimal in etwas so aussehen:

push r16
in r16, sreg
push r16
ldi r16, 0xff
out tcnt0, r16
pop r16
out sreg, r16
pop r16
reti

Das ganze kann man aber deutlich schneller haben, wenn man ein Register
nur dafür reserviert, den Counter nachzuladen. Nehmen wir mal dafür R3.
Irgendwann am Programmanfang wird R3 mit 0xff geladen. DIe ISR sieht
dann nur noch so aus:

out tcnt0, r3
reti

Das ist schon ein Unterschied, oder? Eigentlich sollte es verboten
werden, MCs in C zu programmieren, wenn man von Assembler und der
Grundfunktion des MC keine Ahnung hat :-)
Gast #305211
Lesenswert?

Wenn Du wirklich nen 14MHz Quarz nimmst und den Ausgang (OC1 oder 2, je
nach verwendetem Timer) NICHT per Software toggelst (Also NICHT per
Interrupt oder so), dann müsste es aber funktionieren (also bis zu 7
MHz bei OCRn = 1 im CTC-Modus). C-Code hab ich jetzt grad keinen parat.
Ist aber ne reine Initialisierungssache...
Gast #305212
Lesenswert?

Der ImageCraft application builder generiert mir dafuer diesen code.
Aber besser nochmal nachpruefen.

//ICC-AVR application builder : 22.02.2006 16:08:58
// Target : M8
// Crystal: 14.0000Mhz

#include <iom8v.h>
#include <macros.h>

void port_init(void)
{
 PORTB = 0x00;
 DDRB  = 0x00;
 PORTC = 0x00; //m103 output only
 DDRC  = 0x00;
 PORTD = 0x00;
 DDRD  = 0x00;
}

//TIMER1 initialize - prescale:1
// WGM: 0) Normal, TOP=0xFFFF
// desired value: 500KHz
// actual value: 500,000KHz (0,0%)
void timer1_init(void)
{
 TCCR1B = 0x00; //stop
 TCNT1H = 0xFF; //setup
 TCNT1L = 0xE4;
 OCR1AH = 0x00;
 OCR1AL = 0x1C;
 OCR1BH = 0x00;
 OCR1BL = 0x1C;
 ICR1H  = 0x00;
 ICR1L  = 0x1C;
 TCCR1A = 0x40;
 TCCR1B = 0x01; //start Timer
}

//call this routine to initialize all peripherals
void init_devices(void)
{
 //stop errant interrupts until set up
 CLI(); //disable all interrupts
 port_init();
 timer1_init();

 MCUCR = 0x00;
 GICR  = 0x00;
 TIMSK = 0x00; //timer interrupt sources
 SEI(); //re-enable interrupts
 //all peripherals are now initialized
}

//
void main(void)
{
 init_devices();
 //insert your functional code here...
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren