Forum: Mikrocontroller und Digitale Elektronik Problem mit unterschiedlichen Prescalern


von Christian B. (chbalnuweit)


Lesenswert?

Hallo und ein frohes neues Jahr!

ich benutze den AT90USB1287 (16 MHz)und habe Timer 1 2 und 3 laufen mit 
einem Prescaler von 64. Die Timer funktionieren auch wie sie sollen.
Nun benötige ich noch einen Timer (Timer 0), der eine sehr viel höhere 
Frequenz erzeugen soll, und daher ohne Prescaler (Prescaler = 1) laufen 
soll.
Schreibe ich das Programm nur mit Timer 0 funktioniert alles wie es 
soll.
Integriere ich den Timer in mein bestehendes Programm mit den drei 
anderen Timern so scheint es nicht mehr zu funktionieren.

Laut Datenblatt nutzen zwar Timer 0 1 und 3 das selbe Prescaler-Modul, 
aber dennoch soll es möglich sein, verschiedene Faktoren zu nutzen:

> 12. Timer/Counter0, Timer/Counter1, and Timer/Counter3 Prescalers
>
> Timer/Counter0, 1, and 3 share the same prescaler module, but the
> Timer/Counters can have different prescaler settings. The description
> below applies to all Timer/Counters. Tn is used as a general name, n = 0,
> 1 or 3

Die Timer sind wie folgt konfiguriert:
1
void timer_init()
2
{
3
  sei();                      // Aktiviere Interrupts global
4
  
5
  // 16Bit-Timer1
6
  TCCR1A = (1<<COM1A0);                         // Toggle Pin on Compare Match, siehe Datenblatt Tabelle 14-1
7
  TCCR1B = (1<<WGM12) | (1<<CS10) | (1<<CS11);  // Aktiviere CTC Mode non PWM, siehe Datenblatt Tabelle 14-4
8
  TCCR1C = (1<<FOC1A);                          // Aktiviere Output Compare für Channel A
9
  TIMSK1 = (1<<OCIE1A);                         // Aktiviere Interrupt, siehe Datenblatt S.147
10
  OCR1A = 0x7D00;
11
  
12
  // 16Bit-Timer3 (Initialisierung wie Timer1)
13
  TCCR3A = (1<<COM3A0);
14
  TCCR3B = (1<<WGM32) | (1<<CS30) | (1<<CS31);
15
  TCCR3C = (1<<FOC3A);
16
  TIMSK3 = (1<<OCIE3A);  
17
  OCR3A = 0x7D00;
18
    
19
  // 8Bit-Timer2 PWM
20
  TCCR2A = (0<<COM2B0) | (1<<COM2B1) | (0<<COM2A0) | (0<<COM2A1) | (1<<WGM20)  | (1<<WGM21);
21
  TCCR2B = (1<<WGM22)  | (1<<CS22)   | (0<<CS21) | (0<<CS20)   | (1<<FOC2A);
22
  TIMSK2 = (1<<TOIE2);
23
  OCR2A = 255;
24
  OCR2B = 95;  
25
  
26
  // 8Bit-Timer0 PWM
27
  TCCR0A = (0<<COM0B0) | (1<<COM0B1) | (0<<COM0A0) | (0<<COM0A1) | (1<<WGM00)  | (1<<WGM01);
28
  TCCR0B = (1<<WGM02)  | (0<<CS02)   | (0<<CS01) | (1<<CS00)   | (1<<FOC0A);
29
  TIMSK0 = (1<<TOIE0);
30
  OCR0A = 160;
31
  OCR0B = 5;
32
}

Hat jemand eine Idee woran es liegen kann?

Viele Grüße

Christian

von Krapao (Gast)


Lesenswert?

Wieviel % der Gesamtrechenzeit verbrät dein sehr schnell laufender 
Timer0?

Wieviele Timer1,2,3 Interrupts gehen durch den häufig auftretenden 
Timer0 IRQ verloren?

Wenn du ein Oszi hast kannst du beides durch geschicktes Togglen von 
Pins in den jeweiligen ISRs heraus finden.

von Noname (Gast)


Lesenswert?

>scheint es nicht mehr zu funktionieren.
>Hat jemand eine Idee woran es liegen kann?

Was soll woran liegen? Was ist denn der Fehler?

von Christian B. (chbalnuweit)


Lesenswert?

Noname schrieb:
>>scheint es nicht mehr zu funktionieren.
>>Hat jemand eine Idee woran es liegen kann?
>
> Was soll woran liegen? Was ist denn der Fehler?

Also ich sende die 8-Bit Werte für die PWM-Pulsbreite über UART an den 
µC. Lasse ich ein Programm laufen, in dem ich nur Timer0 eingerichtet 
habe, dann kann ich über UART Pulsbreiten vorgeben und der Schrittmotor 
dreht auf die richtige Position.
Nun habe ich den Timer0 in ein anderes Programm integriert und er 
scheint die Frequenzen nicht richtig zu erzeugen. Ich kann das 
allerdings nicht genau nachverfolgen, denn mein 
"Soundkarten-Oszilloskop" kann die Frequenzen im 100kHz bereich 
natürlich nicht darstellen.

Dann habe ich zu testzwecken den Timer0 auf den Prescaler 64 eingestellt 
und dann konnte ich am Oszilloskop die Frequenzen und Pulsbreiten sehen 
die ich über UART einstelle. Das scheint also zu funktionieren!

Den Interrupt in Timer0 brauche ich theoretisch nicht dringend, nur ist 
es schöner die Vergleichswerte zu setzen, wenn der Timer gerade 
übergelaufen ist, als den Wert zufällig mitten im Zählvorgang zu setzen!

Hat noch jemand eine Idee wieso die Frequenzen vielleicht nicht richtig 
erzeugt werden?

Viele Grüße

Christian

von Noname (Gast)


Lesenswert?

Nun, leider stehen wir immer noch bei Aussagen wie: "scheint die 
Frequenzen nicht richtig zu erzeugen". Was heisst "nicht richtig"? Was 
erwartest Du und was geschieht wirklich? Siehe: 
http://www.mikrocontroller.net/articles/Forum-Fragenformulierung

Der Hinweis von Krapao scheint zumindest in eine sinnvolle Richtung zu 
deuten, denn zweifellos kommt es bei vier unterschiedlichen 
Interruptquellen (bzw. 5 falls der USART auch interrupts auslöst) auf 
eine durchdachte und kontrollierte Abstimmung der Ereignisse und der 
Dauer ihrer Verarbeitung an.

Weiter können wir Dir so nicht helfen. Denn da Du nur sehr allgemeine 
Aussagen machst, können wir auch nur allgemeine Antworten liefern. Du 
musst also detaillierte Beschreibungen des Ist- und Sollzustandes 
liefern, bevor wir weiter darüber nachdenken können. Poste bitte auch 
den kompletten Code, denn typischerweise steckt der Fehler gerade in den 
Codestellen deren Bedeutung Menschen mit geringen Analysefähigkeiten 
unterschätzen.

Das lernst Du schon noch. Das ist hier eine gute Gelegenheit dazu.

von spess53 (Gast)


Lesenswert?

Hi

>TCCR1C = (1<<FOC1A);        // Aktiviere Output Compare für Channel A
>TCCR3C = (1<<FOC3A);
>TCCR2B = ...  | (1<<FOC2A);
>TCCR0B = ...  | (1<<FOC0A);

Ist zwar nicht für dein Problem zuständig. Aber diese Bits machen nicht 
das, was du denkst.

MfG Spess

von Christian B. (chbalnuweit)


Angehängte Dateien:

Lesenswert?

Okay dann versuche ich das nochmal zu konkretisieren und zeige euch den 
gesamten Quellcode der an sich auch abgesehen von Timer0 für mich super 
funktioniert!

Grundlegend:
Ich verwende das usb_serial-Projekt von

http://www.pjrc.com/teensy/usb_serial.html

Ich übermittle eine Zeichenkette mit 4 Werten die jeweils 3 Stellen 
haben:

123123123123

im Main-Programm wird diese Zeichenkette eingelesen, zerlegt und den 
Timern zugeordnet.

Zum Problem:
Was soll Timer0 tun:
Er soll ein PWM Signal erzeugen mit einer Grundfrequenz von 100kHz
Nach Formel aus dem Datenblatt errechnet sich die Grundfrequenz wie 
folgt:
f_pwm = f_clk/(n*256) = 16MHz/(1*160) = 100kHz
Daraus folgt, dass ich OCR0A auf 160 setze

Danach soll über OCR0B das Tastverhältnis eingestellt werden, welches 
ich in der Zeichenkette übergebe.
z.B.: 016 -> 10% Pulsbreite

Mache ich das ganze mit Timer0 und einem Prescaler von 64 funktioniert 
alles wie es soll, dass kann ich aufm Oszi sehen. Allerdings ist die 
Grundfrequenz zu niedrig und der Schrittmotor bewegt sich nicht.

Stelle ich den Timer0 auf Prescaler = 1 dann bewegt sich der Motor nicht 
so, wie ich es zuvor in dem anderen Programm ausprobiert habe (anderes 
Programm, NUR Timer0 mit Prescaler = 1)
Da mein Oszilloskop jedoch die hohen Frequenzen nicht anzeigen kann, 
weiß ich auch nicht, wo der Fehler liegt.

Meine Frage ist also, ob es irgendetwas besonderes zu beachten gibt, 
wenn ich mehrere Timer mit unterschiedlichen Vorteilern nutzen möchte.

Ich hoffe so kommen wir irgendwie weiter =)

Viele Dank schonmal!

Christian

von Christian B. (chbalnuweit)


Lesenswert?

spess53 schrieb:
> Hi
>
>>TCCR1C = (1<<FOC1A);        // Aktiviere Output Compare für Channel A
>>TCCR3C = (1<<FOC3A);
>>TCCR2B = ...  | (1<<FOC2A);
>>TCCR0B = ...  | (1<<FOC0A);
>
> Ist zwar nicht für dein Problem zuständig. Aber diese Bits machen nicht
> das, was du denkst.
>
> MfG Spess


Achja, danke Spess, dass Thema hatten wir ja neulich schon. Werd ich 
nochmal überprüfen bei Zeiten! Danke!

von (prx) A. K. (prx)


Lesenswert?

Christian B. schrieb:

> Den Interrupt in Timer0 brauche ich theoretisch nicht dringend, nur ist
> es schöner die Vergleichswerte zu setzen, wenn der Timer gerade
> übergelaufen ist, als den Wert zufällig mitten im Zählvorgang zu setzen!

Soweit ich mich erinnere sind die OCR Register in den PWM-Modi 
entsprechend gepuffert, um ebendies zu verhindern.

von Christian B. (chbalnuweit)


Lesenswert?

A. K. schrieb:
> Christian B. schrieb:
>
>> Den Interrupt in Timer0 brauche ich theoretisch nicht dringend, nur ist
>> es schöner die Vergleichswerte zu setzen, wenn der Timer gerade
>> übergelaufen ist, als den Wert zufällig mitten im Zählvorgang zu setzen!
>
> Soweit ich mich erinnere sind die OCR Register in den PWM-Modi
> entsprechend gepuffert, um ebendies zu verhindern.

Das ist gut zu wissen. IM CTC Mode sind sie es nicht denke ich, 
zumindest sind die Zeiger manchmal willkürlich gesprungen wenn neue 
Werte kamen und das erkläre ich mir damit, das dass Register beschrieben 
wird während der Zähler noch zählt und dann kann es passieren, dass der 
Counter bis TOP (16bit) zählt und die Frequenz dementsprechent abfällt.

Die Temperaturanzeige (Timer2) funktionierte vorher auch ohne Interrupt, 
ich dachte nur so ist es "richtiger".

von (prx) A. K. (prx)


Lesenswert?

Christian B. schrieb:

> IM CTC Mode sind sie es nicht denke ich,

Nein, da nicht, Wann genau das gilt steht im Datasheet.

von Stefan E. (sternst)


Lesenswert?

1
    char data[DATA_NC] = {};        // Leeren Char-Array erzeugen
2
    ...
3
    data[DATA_NC] = '\0';          // Char-Array terminieren
Diese Terminierung landet aber hinter dem Array.

von Noname (Gast)


Lesenswert?

>> IM CTC Mode sind sie es nicht denke ich,

Schön. Aber Du benutzt ja nicht den CTC Mode sondern den Fast-PWM-Mode. 
Da sind die Verhältnisse anders. (Mach Dir nichts draus. Den selben 
Fehler habe ich neulich beim STM gemacht).

Ich sehe Du bist willens ausführlich zu antworten. Das ist gut.
Was hier eigentlich eine Rolle spielt, ist das tatsächliche Verhalten. 
Das es mit dem gewünschten Prescaler nicht so läuft wie erwartet habe 
ich verstanden. OK. Genauer soll das wohl heissen, dass das 
Tastverhältnis der PWM dem via USB kommandierten entspricht.

Wie wir jetzt sehen benutzt Du den USB Port und nicht die serielle 
Schnittstelle. Dazu fehlt der Code für die Initialisierung und das 
auslesen.

Da Du leider nichts messen kannst muss man den Code verändern um weitere 
Informationen zu bekommen.
Mir fällt auf, das Du in der while-Schleife in main für relativ lange 
Zeit die Interrupts sperrst.
1
    char data[DATA_NC] = {};        // Leeren Char-Array erzeugen
2
    while(!usb_serial_available()) {;}    // Tue nichts, solange keine Daten im Puffer
3
    cli();                  // Deaktiviere Interrupts, damit Lesen.. der Daten nicht unterbrochen wird
4
    usb_serial_readline(data,DATA_NC);    // Daten aus Puffer auf Char-Array lesen
5
    data[DATA_NC] = '\0';          // Char-Array terminieren
6
    split_data(data);            // Daten aus Protkoll extrahieren
7
    usb_serial_flush_input();        // Puffer löschen
8
    sei();                  // Interrupts wieder aktivieren

Generell ist es eine schlechte Idee für so lange Zeit die Interrupts zu 
sperren. Es ist zu vermuten, das da was schief laufen kann.

Um auszuschliessen (ich vermute es), das dort zuviel Zeit verbraucht 
wird, schlage ich vor, das Du dort einmal die PWM Ratio in einer 
Schleife sozusagen "manuell" setzt, also nicht aufgrund der eingelesenen 
Daten und die Interrupts nicht sperrst.
1
uint8_t i = 0;
2
while (1) {
3
fuel_val = i++;
4
delay (..);         // so eine Zeit bei der die PWM mindestens einen Zyklus durchläuft
5
}

Dann wird also immer der compare wert von 0 bis 255 laufen und wieder 
bei 0 beginnen.

von Christian B. (chbalnuweit)


Lesenswert?

Stefan Ernst schrieb:
>
1
    char data[DATA_NC] = {};        // Leeren Char-Array erzeugen
2
>     ...
3
>     data[DATA_NC] = '\0';          // Char-Array terminieren
> Diese Terminierung landet aber hinter dem Array.

Achja richtig... früher stand mal char data[DATA_NC+1]. Zuzeit addiere 
ich das +1 im Makro. sollte ich ändern, danke!

@Noname:

Danke ich werde damit mal experimentieren und mich wieder melden!

Edit: Aber wenn ich jetzt für Timer0 gar keine Interrupts mehr benutze, 
sondern direkt nach einlesen der USB-Daten das Register beschreibe und 
dann nichts weiter tue, dürfte das Deaktivieren und Aktivieren der 
Interrupts gar keine Auswirkungen haben oder? Oder nutzen die Timer 
intern auch irgendwelche Interrupts die mich mit cli(); deaktiviere?

Edit 2: Ich hab jetzt mal alles in Main in der while(1) schleife 
auskommentiert und durch den folgenden Code ersetzt. Die Overflow 
Interrupts für die beiden PWM Timer habe ich wieder deaktiviert. Sodass 
der Wert direkt ins Register geschrieben wird.
1
  int i = 0;
2
  while(1)
3
  {  
4
    OCR0B = i;
5
    i++;
6
    _delay_ms(100);
7
  }

Zeiger macht keinen Mucks...

Den usb_serial Code habe ich angehängt.

von Christian B. (chbalnuweit)


Angehängte Dateien:

Lesenswert?

so das Anhängen hat eben nicht funktioniert...

von Noname (Gast)


Lesenswert?

>Aber wenn ich jetzt für Timer0 gar keine Interrupts mehr benutze,
>sondern direkt nach einlesen der USB-Daten das Register beschreibe und
>dann nichts weiter tue, dürfte das Deaktivieren und Aktivieren der
>Interrupts gar keine Auswirkungen haben oder? Oder nutzen die Timer
>intern auch irgendwelche Interrupts die mich mit cli(); deaktiviere?

Schreibe am besten mal Code als Beispiel. Wenigstens Pseudocode. Mir 
wird nicht klar, wie Du das meinst.

Der Knackpunkt ist, das Du die Interrupts überhaupt deaktivierst. Dein 
Kommentar, das dadurch sichergestellt sein soll, das die Daten korrekt 
gelesen werden, deutet auf einen Designfehler hin. Es ist grundsätzlich 
eine schlechte Idee Interrupts für lange Zeit zu deaktivieren.

Du magst für den Timer 0 keinen Interrupt mehr benutzen, hast dann aber 
immer noch das grundsätzliche Problem nicht gelöst. Das besteht darin, 
das Du das einlesen und verarbeiten der Daten mit einem Minimum an 
Interruptsperren, bzw. einer minimalen Zeit während der die Sperre gilt, 
erledigen musst. Im konkreten Fall, hast Du ja noch andere 
Timer-Interrupts die auch auf Probleme führen können.

An dieser Stelle schliesst sich der Kreis in Hinblick auf konkrete und 
detaillierte Beschreibung. Du solltest eine Vorstellung davon haben, wie 
die zeitlichen Abläufe in Deinem Programm genau sind. Wie höufig treten 
Interrupts auf, wie lange dauert die Verarbeitung von Eingaben und wann 
wird sie in Relation zu den Interrupts erledigt? Ist das Design so, das 
die Verarbeitung von Eingabedaten von der eigentlichen Eingabe 
entkoppelt ist?

Um Deine konkrete Frage zu beantworten: Nein. Timer benutzen keine 
sekundären (undokumentierten) Interrupts. Keine anderen als genau die, 
welche Du aktivierst.

von Christian B. (chbalnuweit)


Lesenswert?

Danke nochmal, dass du deine Zeit am Neujahrestag für sowas opferst! ;-)

Also später kommen die Daten im 10ms Takt an den µC und mit Drehzahl 
Geschwindigkeit und Temperatur funktioniert das auch alles schon.

Für Testzwecke sende ich die Daten einmalig mit einem Terminalprogramm, 
sodass die Zeiger auf fixe Werte springen und da verharren ( zb. 1000rpm 
und 100kmh und 90°C) normalerweise kommen die Werte im 10ms Takt und die 
Zeiger bewegen sich dann.

Die Timer für Geschwindigkeit und Drehzahl arbeiten im CTC Mode und 
generieren Frequenzen für die Schrittmotoren. Diese Frequenzen werden 
jedoch nicht direkt nach dem einlesen gesetzt, sondern 
zwischengespeichert und gesetzt wenn der Compare Match Interrupt 
ausgelöst wird.

Die Timer für Temp. und Tank laufen im FastPWM Modus. Die Grundfrequenz 
wird fest im Programm vorgegeben und die Tastverhätlnisse werden 
eingelesen und direkt gesetzt ohne irgendwelche

while(1)
{
warte_auf_werte{};
werte_lesen{};
}

werte_lesen
{
drehzahl auslesen
geschw. auslesen
temp. auslesen UND direkt in OCR Register schreiben
tank auslesen UND direkt in OCR Register schreiben
}

ISR_1
{
drehzahl in OCR Register schreiben
}

ISR_3
{
geschw. in OCR Register schreiben
}

Ich verstehe nicht ganz wieso das Deaktivieren der Interrupts so ein 
Problem ist. Wenn die Interrupts deaktiviert sind, dann bekommen die 
Timer halt keine neuen Werte und behalten die aktuellen Compare-Werte 
bei.

von Noname (Gast)


Lesenswert?

Häh?
1
int i = 0;
Wer hat das gesagt?
Es sollte
1
uint8_t i = 0;
sein.

>Zeiger macht keinen Mucks...

Mach evtl. das Delay länger, falls der Motor zu träge ist (Hier fehlt 
wieder Information)!

Du kannst auch den Prescaler nochmal hochsetzen, damit man sieht ob es 
prinzipiell geht.

Am besten versuche erstmal das zum laufen zu bringen ohne USB (und ohne 
das zu initialisieren).
Ich habe mal so über den USB-Code drüber geschaut. Ich bin zwar nicht 
wirklich qualifiziert, dass zu beurteilen, was den konkreten Code 
betrifft, aber ich sehe das die Interruptroutine elend lang ist und 
haufenweise die Interrupts disabled werden, damit, laut Kommentar, die 
Funktionen auch im Hauptprogramm zu benutzen sind.
Die USB-Interrupts haben sowieso höhere Priorität als die 
Timer-Interrupts. Da kann schon was schiefgehen.

Als das mit dem schnellen Timer 0 funktioniert hat, war das auch mit 
USB, oder ohne?

von Christian B. (chbalnuweit)


Lesenswert?

Das war auch mit USB
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include "usb_serial.h"
4
5
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
6
7
int main(void)
8
{
9
  CPU_PRESCALE(0);
10
    
11
  usb_init();
12
  _delay_ms(500);
13
14
  DDRD = (1<<PD0); 
15
  
16
  TCCR0A = (0<<COM0B0) | (1<<COM0B1) | (0<<COM0A0) | (0<<COM0A1) | (1<<WGM00) | (1<<WGM01);
17
  TCCR0B = (1<<WGM02) | (0<<CS02) | (0<<CS01) | (1<<CS00);
18
  OCR0A = 160;
19
  OCR0B = 1;
20
  
21
  while(1)
22
  {
23
    if(usb_serial_available())
24
    {
25
      char data[4] = {};
26
      usb_serial_readline(data,4);
27
      data[4] = '\0';
28
      usb_serial_write(data,4);
29
      OCR0B = atoi(data);
30
    }  
31
  }
32
}

So funktioniert der Timer wie er soll und ich kann Pulsbreiten übers 
Terminalprogramm vorgeben und die Tankanzeige stellt sich auf die Werte 
ein.

Nagut also mir wird nicht viel übrig bleiben als rumzuprobieren bis 
irgendwas läuft...


Ich danke euch und besonders dir, Noname, für die Hilfe!

von Stefan E. (sternst)


Lesenswert?

1
      char data[4] = {};
2
      ...
3
      data[4] = '\0';
Und schon wieder geht die Terminierung hinter das Array.

von Christian B. (chbalnuweit)


Lesenswert?

Jup, stimmt, war der selbe Fehler im anderen Programm, hat aber 
funktioniert ;-)

von Noname (Gast)


Lesenswert?

>Wenn die Interrupts deaktiviert sind, dann bekommen die
>Timer halt keine neuen Werte und behalten die aktuellen Compare-Werte bei.

Genau. Aber was ist dann das Problem? Da drehen wir uns im Kreis, denn 
es fehlt nach wie vor eine Fehlerbeschreibung welche die 
Ursache-Wirkungskette entlanggeht, die beteiligten Elemente und 
Schaltung beschreibt und erwartetes in eine Beziehung zu tatsächlichem 
Verhalten setzt.

Es ist doch so. Entnehme ich Deinen Texten, das alles geht, auch die 
USB-Kommunikation resp. das dynamische setzen der PWM-Ratio, wenn der 
Takt für Timer 0 langsam ist, aber nicht mehr wenn er schnell ist, dann 
untersuche ich die Auswirkungen dieses schnelleren Takts.
Da ich aber nicht in Realzeit untersuchen kann (Du hast kein Oszi) muss 
ich anhand von plausiblen Vermutungen den Code ändern um Informationen 
zu bekommen.
Es geht jetzt nicht zuerst darum das Pgm. zum laufen zu bringen, 
sondern die Auswirkungen zu sehen um dann Rückschlüsse auf die 
eigentliche Ursache zu ziehen.

von Noname (Gast)


Lesenswert?

>So funktioniert der Timer wie er soll und ich kann Pulsbreiten übers
>Terminalprogramm vorgeben und die Tankanzeige stellt sich auf die Werte
>ein.

Na super. Und ich bin hier noch am schreiben. :-)

von Christian B. (chbalnuweit)


Lesenswert?

Und ich bin immer noch ratlos :D
Am besten ich fahr die Tage in die FH und geh mal an ein richtiges Oszi 
bevor ich hier Tage vertrödle...

von Noname (Gast)


Lesenswert?

>Nagut also mir wird nicht viel übrig bleiben als rumzuprobieren bis
>irgendwas läuft...

Das ist Unsinn (mit Verlaub), ist ineffizient und lehrt Dich nichts.

Sieh es mal positiv. Wir können jetzt mit groesserer Sicherheit 
vermuten, dass das Problem die so elendig lang gesperrten Interrupts 
sind.

Ich würde mich nicht sehr wundern, falls Deine ursprüngliche Schleife 
(Beitrag "Re: Problem mit unterschiedlichen Prescalern") funktioniert 
sobald Du nur die cli/sei herausnimmst. Zum testen in grossen Abständen 
(im 5s Bereich neue Daten senden).

Falls das so ist müssen wir uns eine Lösung für
> // Deaktiviere Interrupts, damit Lesen.. der Daten nicht unterbrochen wird
überlegen.

von Noname (Gast)


Lesenswert?

>geh mal an ein richtiges Oszi
Das wird ohnehin das beste sein.

von Christian B. (chbalnuweit)


Lesenswert?

Du hast ja recht...
also:
ich habe den Code "entschlackt", d.h. ich habe das usb_init 
auskommentiert, den ganzen anderen Kram in der while(1) auskommentiert 
und im timer_init alle Timer ausser Timer0 auskommentiert.
1
// Main-Programm
2
int main(void)
3
{
4
  //Initialisierung
5
  CPU_PRESCALE(0);
6
  //usb_init();
7
  ddr_init();
8
  timer_init();
9
10
  uint8_t i = 0;
11
  while(1)
12
  {  
13
    OCR0B = i;
14
    i++;
15
    _delay_ms(100);
16
17
18
    /*
19
    char data[DATA_NC+1] = {};        // Leeren Char-Array erzeugen
20
    while(!usb_serial_available()) {;}    // Tue nichts, solange keine Daten im Puffer
21
    cli();                  // Deaktiviere Interrupts, damit Lesen.. der Daten nicht unterbrochen wird
22
    usb_serial_readline(data,DATA_NC);    // Daten aus Puffer auf Char-Array lesen
23
    data[DATA_NC] = '\0';          // Char-Array terminieren
24
    split_data(data);            // Daten aus Protkoll extrahieren
25
    usb_serial_flush_input();        // Puffer löschen
26
    sei();                  // Interrupts wieder aktivieren
27
    */
28
    }
29
}
30
31
void timer_init()
32
{
33
  /*
34
  sei();                      // Aktiviere Interrupts global
35
  
36
  // 16Bit-Timer1 für DZM  
37
  TCCR1A = (1<<COM1A0);              // Toggle Pin on Compare Match, siehe Datenblatt Tabelle 14-1
38
  TCCR1B = (1<<WGM12) | (1<<CS10) | (1<<CS11);  // Aktiviere CTC Mode non PWM, siehe Datenblatt Tabelle 14-4
39
  TCCR1C = (1<<FOC1A);              // Aktiviere Output Compare für Channel A
40
  TIMSK1 = (1<<OCIE1A);              // Aktiviere Interrupt, siehe Datenblatt S.147
41
  OCR1A = 0x7D00;
42
  
43
  // 16Bit-Timer3 für Tacho (Initialisierung wie Timer1)
44
  TCCR3A = (1<<COM3A0);
45
  TCCR3B = (1<<WGM32) | (1<<CS30) | (1<<CS31);
46
  TCCR3C = (1<<FOC3A);
47
  TIMSK3 = (1<<OCIE3A);  
48
  OCR3A = 0x7D00;
49
    
50
  // 8Bit-Timer2 für Temp
51
  TCCR2A = (0<<COM2B0) | (1<<COM2B1) | (0<<COM2A0) | 
52
       (0<<COM2A1) | (1<<WGM20)  | (1<<WGM21);
53
  TCCR2B = (1<<WGM22)  | (1<<CS22)   | (0<<CS21) |
54
       (0<<CS20)   | (1<<FOC2A);
55
  OCR2A = 255;  // Wert für PWM-Grundfrequenz (ca. 245 Hz)
56
  OCR2B = 95;  // Wert für Tastverhältnis bei Initialisierung -> 90°C
57
  */
58
  
59
  // 8Bit-Timer0 für Tank
60
  TCCR0A = (0<<COM0B0) | (1<<COM0B1) | (0<<COM0A0) |
61
       (0<<COM0A1) | (1<<WGM00)  | (1<<WGM01);
62
  TCCR0B = (0<<WGM02)  | (0<<CS02)   | (0<<CS01) |
63
       (1<<CS00)   | (1<<FOC0A);
64
  OCR0A = 160;
65
  OCR0B = 5;
66
}

Die Tankanzeige geht langsam von leer zu voll! --> funktioniert!
Also usb_init() wieder aktiviert --> funktioniert immer noch!
Die anderen Timer wieder aktiviert --> funktioniert nicht mehr!

Da sind wir doch schonmal einen Schritt weiter =)

von Noname (Gast)


Lesenswert?

>Da sind wir doch schonmal einen Schritt weiter =)

Hm. Scheint so...

Und wenn Du USB nicht initialisierst aber die restlichen Timer?

von Christian B. (chbalnuweit)


Lesenswert?

Dann funktionierts nicht

ich deaktivere jetzt mal nacheinander die Timer und melde mich wieder...

von Christian B. (chbalnuweit)


Lesenswert?

So, also wenn Timer3 aktiviert wird funktioniert Timer0 nicht mehr.
Bei allen anderen Konstellationen funktioniert Timer0
1
  // 16Bit-Timer3 für Tacho (Initialisierung wie Timer1)
2
  TCCR3A = (1<<COM3A0);
3
  TCCR3B = (1<<WGM32) | (1<<CS30) | (1<<CS31);
4
  TCCR3C = (1<<FOC3A);
5
  TIMSK3 = (1<<OCIE3A);  
6
  OCR3A = 0x7D00;
Irgendwelche Auffälligkeiten bei der Konfiguration?

von Noname (Gast)


Lesenswert?

>Dann funktionierts nicht

Du hast immer noch die FOC (force output compare) bits gesetzt.

von Noname (Gast)


Lesenswert?

Lass die FOC bits bei ALLEN timern unangetastet.

von Noname (Gast)


Lesenswert?

Und poste mal die Schaltung.

von Christian B. (chbalnuweit)


Lesenswert?

Okay also die FOC Bits sind raus. Dennoch geht Timer0 nicht wenn Timer3 
aktiviert wird.

Beim Thema Schaltung hast du mich gerade auf eine Idee gebracht!
Ich habe eben mal das Tacho-Signal abgezogen und dann hat sich der 
Tankzeiger angefangen zu bewegen! Das ganze scheint kein Problem in 
meinem Programm zu sein, sondern irgendeine Plausibilitätsprüfung in der 
Tacho-Elektronik oder so...
Oh man -.-

von Noname (Gast)


Lesenswert?

>Okay also die FOC Bits sind raus. Dennoch geht Timer0 nicht wenn Timer3
aktiviert wird.
Egal. Die waren ohnehin falsch. Also lass sie draussen.

>Oh man -.-

Ich will ja nicht sagen: "Ich habs ja gesagt", aber an der Stelle zeigt 
sich wie wichtig vollständige Information ist.

Es gibt jedenfalls keinen Zusammenhang zwischen Timer 0 und Timer 3 der 
das Verhalten erklären würde. Habe eben nochmal das Datenblatt 
angeschaut.

von Christian B. (chbalnuweit)


Lesenswert?

Ja ich habe selber leider kaum Information zu dem Tacho finden können, 
ausser der Pin-Beleguung (Passat B5 KI)

Jetzt muss ich den Tacho also noch irgendwie "austricksen"...

Danke für deine Hilfe!!!

von Noname (Gast)


Lesenswert?

>Ja ich habe selber leider kaum Information zu dem Tacho finden können,
>ausser der Pin-Beleguung (Passat B5 KI)

Aber wenigsten der Tachotyp wären schon eine Information gewesen. Kann 
ja sein, das einer schonmal das Problem hatte.

Naja. Schwamm drüber. Viel Spass noch. Wenn ich Dich treffe kost das n 
Kaffee. ;-)

von Christian B. (chbalnuweit)


Lesenswert?

Noname schrieb:
>>Ja ich habe selber leider kaum Information zu dem Tacho finden können,
>>ausser der Pin-Beleguung (Passat B5 KI)
>
> Aber wenigsten der Tachotyp wären schon eine Information gewesen. Kann
> ja sein, das einer schonmal das Problem hatte.
>
> Naja. Schwamm drüber. Viel Spass noch. Wenn ich Dich treffe kost das n
> Kaffee. ;-)

Nichts lieber als das! ;-)

Schönen Abend noch!

von Christian B. (chbalnuweit)


Lesenswert?

Falls es noch jemanden interessieren sollte:

Es scheint so zu sein:

Beim Einschalten der Zündung im Stand liegt kein Tachosignal vor und die 
Tankanzeige kann direkt auf den aktuellen Wert springen.

Sobald ein Geschwindigkeitssignal anliegt wird der Wert scheinbar 
gefiltert oder über lange Zeit ein Mittelwert gebildet, denn wenn ich 
lange genug Warte bewegt sich der Zeiger tatsächlich! Das ist mir zuvor 
gar nicht aufgefallen!

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.