Forum: Mikrocontroller und Digitale Elektronik Timer1 im CTC Mode über ADC Frequenz einstellen


von verlorenes Schaf (Gast)


Lesenswert?

1
#include "config.h"
2
#include <avr/io.h>
3
//#include "lcd-routines.h"
4
//#include "usart.h"
5
#include <avr/interrupt.h>
6
7
volatile unsigned int timer_value;
8
9
//F_CPU = 16000000 , defined in config.h, no CLK Divider
10
11
void init (void)
12
{
13
//Init Timer1
14
  // toggle OC1A with 10Hz (see Prescaler = Clk/64).  
15
  OCR1A = (unsigned int)25000;
16
  // OC1A Pin is on
17
  TCCR1A = (1 << COM1A0);
18
  // timer1 running in CTC Mode (OCR) MCU clock/64  
19
  TCCR1B = (1 << WGM12)  | (1 << CS11) | (1 << CS10);
20
  // timer1 interrupt enable for Output compare match A unit
21
  TIMSK1 = (1 << OCIE1A);
22
23
//Init OC1A Pin = output
24
25
  DDRD |= (1 << DDD5);
26
  
27
//Init ADC
28
  // reference voltage = 5V (external)
29
  // ADC capture channel 4
30
  ADMUX =  (1 << MUX4);
31
  ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | (1 << ADIE) | (1 << ADPS2) | (0 << ADPS1) | (0 << ADPS0);
32
  ADCSRB = (1 << ADTS2) | (1 << ADTS1) | (1 << ADTS0); 
33
  DIDR0 = (1 << ADC4D);
34
}
35
ISR (ADC_vect)
36
{
37
38
timer_value = ADC;
39
40
//OCR1A = (timer_value << 6);
41
42
}
43
ISR (TIMER1_COMPA_vect)
44
{
45
//OCR1A++;
46
//timer_value = ADC;
47
OCR1A = (timer_value << 6);
48
49
}
50
51
52
int main(void)
53
54
{
55
  init();
56
  sei();
57
  while(1)
58
  {
59
    
60
  }
61
62
    return 0;
63
}


Hallo freundliche Helfer,

ich möchte gerne die Frequenz des 16Bit-Timer meines ATmega 1284p über 
den ADC -Spannungswert an Kanal 4 ändern können. Dazu habe ich den 
CTC-Mode mit toggelndem Bit bei OutputCompareMatch gewählt. Leider lässt 
sich die Frequenz jedoch innerhalb der ISR überhaupt nicht anpassen. Die 
Frequenz ändert sich nicht und entspricht auch nicht der initialisierten 
Frequenz von 10Hz. Selbst wenn ich den OCR1A -Wert nur inkrementiere 
(auskommentiert), geht die Freuqenz auf 62500Hz (entspricht 16Mhz / 256 
oder (16Mhz / 64) / 4). Der Timer scheint also dann schon in die ISR zu 
gehen und den Wert zu inkrementieren bis er überläuft und dann den Wert 
1 erreicht. Ab dann findet keine Freuqenzänderung mehr statt.

Was mache ich falsch?

Ich habe versucht mit beiden ISRs zu arbeiten und die Abpassung von 
OCR1A zu machen, sprich, die ISR des Timers und des ADCs. Beides geht 
nicht.

von Spess53 (Gast)


Lesenswert?

Hi

>ADMUX =  (1 << MUX4);

Wo kommt die Referenzspannung her?

MfG Spess

von verlorenes Schaf (Gast)


Lesenswert?

Referenz sind 5V über ein LC Filter des AVR-NET-IO Board von Pollin.

von verlorenes Schaf (Gast)


Lesenswert?

sorry. ich meinte ich wollte AVCC als Referenzspannung nehmen. Sprich

ADMUX =  (1 << REFS0) | (1 << MUX4);

Hab das korrigiert und teste jetzt nochmal. Ich mein ich hätte das aber 
vorher schon einmal gehabt.

Nichts desto trotz ragiert der Timer ja auf das automatische 
inkrementieren auch falsch. Warum?

von verlorenes Schaf (Gast)


Angehängte Dateien:

Lesenswert?

Getestet und immer noch gleiches Verhalten.

Hier mal ein Shot meines Oszis

von Spess53 (Gast)


Lesenswert?

Hi

>ADCSRB = (1 << ADTS2) | (1 << ADTS1) | (1 << ADTS0);

Das ist Autotrigger mit dem Timer/Counter1 Capture Event also einer 
Flanke am ICP-Eingang. Hast du das vor?

>OCR1A = (timer_value << 6);

Das Schieben kannst du dir ersparen, wenn du beim ADC ADLAR setzt.

>Hier mal ein Shot meines Oszis

Die ca. 1kHz entsprechen einem OCR-Wert von etwa 127. Wo kommen die her?

MfG Spess

von ICP? (Gast)


Lesenswert?

Wie wird die ISR (ADC_vect) angesprungen bzw ein Messen des ADC 
initiiert?
Ausgewählte Triggersource in ADCSRB ist Input Capture Event. Der ICP 
wird im Code sonst nirgendwo beachtet.

Könnte das Problem damit zusammenhängen?

von c-hater (Gast)


Lesenswert?

verlorenes Schaf schrieb:

> Getestet und immer noch gleiches Verhalten.
>
> Hier mal ein Shot meines Oszis

Bei solchen seltsamen Erscheinungen testet man sinnvollerweise 
schrittweise.

Als erstes: Ein Oszillogramm ganz ohne ISRs. Wird dann überhaupt erstmal 
die gewünschte Frequenz erzeugt?

Als zweites: ISR für ADC und Testausgabe des ADC-Wertes z.B. per UART 
oder wenigstens der oberen acht Bits auf einen Port mit acht LEDs dran. 
Was gerade einfacher zu realisieren ist. Wird der Meßwert regelmäßig 
aktualisiert? Bewegt sich der Meßwert im erwarteten Wertebereich?

Spätestens bei diesem Test wärst du darauf gestoßen, daß was mit dem ADC 
nicht stimmt, denn

>  ADCSRB = (1 << ADTS2) | (1 << ADTS1) | (1 << ADTS0);

ist schlicht Blödsinn. Wo soll das Capture-Event herkommen, welches den 
ADC triggern könnte? D.h.: Der ADC wird genau eine Messung machen (weil 
du die erste manuell angestoßen hast) und dann ist Schicht im Schacht.

Sinn hätte vielleicht ergeben, die Messung durch den Overflow von Timer 
1 zu triggern, denn der tritt im CTC-Mode beim Compare-Match auf. Aber: 
damit das klappt, müssen zwei Bedingengen erfüllt sein, die bei dir 
beide nicht erfüllt sind:

1)
Der ADC zu diesem Zeitpunkt auch bereit sein zu einer Messung, d.h. die 
vorige muß abgeschlossen sein. Da der kleinstmögliche Meßwert 0 ist, 
damit die kleinstmögliche Einstellung für OCR1A ebenfalls 0, muß der ADC 
schneller messen als 20.000.000/64.
Die ADC-Messung dauert bei deiner Initialisierung aber schon im 
Normalfall 20.000.000/(13*16), im Falle der ersten Messung sogar 
20.000.000/(25*16).

2)
Damit der Trigger überhaupt triggert, muß das auslösende Flag zuvor 
zurückgesetzt sein. Das geschieht automatisch nur dann, wenn du eine ISR 
für das Triggerflag hast, ansonsten muß es von Hand gemacht werden. Du 
hast aber weder eine ISR für den Overflow, noch setzt du an irgendeiner 
Stelle das Overflow-Flag manuell zurück.

Ich würde in dieser Anwendung schlicht auf eine Hardwaretriggerung ganz 
verzichten und die ADC statt dessen im FreeRunning-Mode laufen lassen.

von Spess53 (Gast)


Lesenswert?

Hi

>Sinn hätte vielleicht ergeben, die Messung durch den Overflow von Timer
>1 zu triggern, denn der tritt im CTC-Mode beim Compare-Match auf.

Bei CTC werden je nach Top-Register OC1A- bzw IC-Interrupt ausgelöst, 
aber kein Overflow-Interrupt.

Besser Timer0 für Autotrigger oder Free Running Mode benutzen.

MfG Spess

von Stefan E. (sternst)


Lesenswert?

Und von den Trigger-Problemen mal abgesehen, ist das
1
ADMUX =  (1 << MUX4);
auch ganz sicher nicht das, was du unter "Kanal 4" verstehst.

von ICP? (Gast)


Lesenswert?

Spess53 schrieb:
> Besser Timer0 für Autotrigger oder Free Running Mode benutzen.

Da der ICP nicht initialisiert ist, dürfte das ICR1 auf 0 stehen und 
damit das ICP Flag immer bei Timerstand 0 gesetzt werden. Wenn es dann 
in der ISR (ADC_vect) "händisch" gelöscht würde, könnte es als Trigger 
mit minimaler Codeveränderung genutzt werden - wenn die MUX Bits auch 
noch passen.

von ICP? (Gast)


Lesenswert?

ICP? schrieb:
> Spess53 schrieb:
>> Besser Timer0 für Autotrigger oder Free Running Mode benutzen.
>
> Da der ICP nicht initialisiert ist, dürfte das ICR1 auf 0 stehen und
> damit das ICP Flag immer bei Timerstand 0 gesetzt werden. Wenn es dann
> in der ISR (ADC_vect) "händisch" gelöscht würde, könnte es als Trigger
> mit minimaler Codeveränderung genutzt werden - wenn die MUX Bits auch
> noch passen.

Bitte vergessen :(

von verlorenes Schaf (Gast)


Lesenswert?

Spess53 schrieb:
> Hi
>
>>ADCSRB = (1 << ADTS2) | (1 << ADTS1) | (1 << ADTS0);
>
> Das ist Autotrigger mit dem Timer/Counter1 Capture Event also einer
> Flanke am ICP-Eingang. Hast du das vor?

Korriegiert! War auch nicht so gewollt. Ändert aber nichts an der 
Veränderbarkeit der Frequenz, jedoch die Frequenz an sich. Ist noch 
etwas niedriger als in dem

>>OCR1A = (timer_value << 6);
>
> Das Schieben kannst du dir ersparen, wenn du beim ADC ADLAR setzt.

Im Prinzip schon, ja. Da vergisst man manchmal schon nützliche 
Funktionen des Atmegas :-(

>>Hier mal ein Shot meines Oszis
>
> Die ca. 1kHz entsprechen einem OCR-Wert von etwa 127. Wo kommen die her?

Keine Ahnung. Ist schon auffällig. Der OCR-Wert wird ja in der ISR 
gesetzt.
> MfG Spess

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.