ADC beim Atmega32M1

Du hast AVCC immer noch auf Deiner Referenz zu hängen.
AVCC bildet mit AGND die Spannungsversorgung der analogen Innereien des Controllers.
AVCC sollte mit VCC verbunden sein, ggf über einen RC oder besser LC-Tiefpaß. Und AGND mit GND, allerdings sollte es getrennt von Gnd geroutet werden (ein-Punkt-Verbindung) und den analogen Teil der Schaltung einschließen.
(Störungen, die der Controller selbst auf seiner Spannungsversorgung verursacht, sollen nicht auf die Referenz durchschlagen)
Außerdem gehört zwischen AGND und AVCC (wie bei allen Spannungsversorgungs-Beinen) ein 100nF-Kerko (so dicht wie möglich) - hast Du wahrscheinlich mit C9/C11.
Siehe auch im Datenblatt des Controllers "22.7.2. Analog Noise Canceling Techniques" im ADC-Kapitel.

Grundsätzlich sollte an keinem I/O (und auch nicht dem Referenzeingang) eine höhere Spannung anliegen, als an den Spannungsversorgungs-Pins (bzw nicht niedriger). Das kann bei Kommunikationsleitungen schwierig sein, oder bei irgendwelchen externen Signalen. Bei den I/Os hast Du im allgemeinen interne Ableitdioden gegen (A)Vcc bzw (A)Gnd, wenn auf unterschiedlichen I/Os Spannung liegt, startet der Controller sogar, allerdings sind die Dioden nur begrenzt belastbar.
Aref ist ja hier nicht als I/O nutzbar - der wird keine solche Dioden haben, denk ich. was da im Controller abgeht, wenn ARef Spannung hat, aber der Controller nicht, weiß ich nicht.

(Anekdote am Rande: bei den ganzen kleinen OLED-Displays gibts laut Datenblatt 'ne empfohlene Reihenfolge, in der die Stromversorgungsbeine des Chips hoch-/runterzufahren sind. Bei den ganzen hippen Maker-Boards hält sich allerdings kein Schwein dran - die sind einfach alle zusammen auf die Spannungsversorgung geroutet...)
 
Du hast AVCC immer noch auf Deiner Referenz zu hängen.
AVCC bildet mit AGND die Spannungsversorgung der analogen Innereien des Controllers.
AVCC sollte mit VCC verbunden sein, ggf über einen RC oder besser LC-Tiefpaß. Und AGND mit GND, allerdings sollte es getrennt von Gnd geroutet werden (ein-Punkt-Verbindung) und den analogen Teil der Schaltung einschließen.
(Störungen, die der Controller selbst auf seiner Spannungsversorgung verursacht, sollen nicht auf die Referenz durchschlagen)
Ja, das mit AVCC und Referenz ist Blödsinn und wird noch korrigiert, bzw. ist schon, lade nachher noch die Schaltung hoch.
Die AGND und GND werde ich noch auftrennen und sie dann an einem einzigen Punkt zusammenführen, mit einer 0R- oder einer Lötbrücke, mal schauen.
Ich Frage mich gerade, ob der GND vom REF50XX an AGND oder an GND soll... Der C4 (am Vout Pin) geht definitiv an AGND, genau so wie GNDS vom CJ125.

Außerdem gehört zwischen AGND und AVCC (wie bei allen Spannungsversorgungs-Beinen) ein 100nF-Kerko (so dicht wie möglich) - hast Du wahrscheinlich mit C9/C11.
Siehe auch im Datenblatt des Controllers "22.7.2. Analog Noise Canceling Techniques" im ADC-Kapitel.
Ja, genau, C9 und C11 sind defür gedacht, aber falsche Masse... sollte AGND sein oder?
Grundsätzlich sollte an keinem I/O (und auch nicht dem Referenzeingang) eine höhere Spannung anliegen, als an den Spannungsversorgungs-Pins (bzw nicht niedriger). Das kann bei Kommunikationsleitungen schwierig sein, oder bei irgendwelchen externen Signalen. Bei den I/Os hast Du im allgemeinen interne Ableitdioden gegen (A)Vcc bzw (A)Gnd, wenn auf unterschiedlichen I/Os Spannung liegt, startet der Controller sogar, allerdings sind die Dioden nur begrenzt belastbar.
Aref ist ja hier nicht als I/O nutzbar - der wird keine solche Dioden haben, denk ich. was da im Controller abgeht, wenn ARef Spannung hat, aber der Controller nicht, weiß ich nicht.
Steht bestimmt im Datenblatt irgendwo, wobei ich habe es noch nicht gesehen, glaube Atmegas haben da keine Reihenfolge wie was eingeschaltet wird.
(Anekdote am Rande: bei den ganzen kleinen OLED-Displays gibts laut Datenblatt 'ne empfohlene Reihenfolge, in der die Stromversorgungsbeine des Chips hoch-/runterzufahren sind. Bei den ganzen hippen Maker-Boards hält sich allerdings kein Schwein dran - die sind einfach alle zusammen auf die Spannungsversorgung geroutet...)
Ist doch egal, es geht auch so :D (Ironie!!!)

Ich beschäftige mich gerade mit dem PID-Regler und der ClosedLoop-Temperaturregelung der Lambdasonde... sprich was passiert nach die Sonde die Betriebstemperatur erreicht hat und die heißen Abgase kommen, wenn die Sonde eben "extern" angeheizt wird...

EDIT: der CJ125 zieht am Pin VCC maximal 76mA, was gar kein Problem sind. Am Pin VCCS (also analoge Referenz) will er zwischen 0,5 und 4mA haben. Damit ist der REF5050 zu 40% "ausgereizt", er hat "recomended maximum current" von 10mA. Ist in diesem Fall ausreichend, bei einem Dual CJ125 muss ich das im Hinterkopf behalten. ADC und DAC wollen dann auch etwas haben...

Der aktuelle Schaltplan ist angehängt.
 

Anhänge

  • schematic.pdf
    30,7 KB · Aufrufe: 1
Zuletzt bearbeitet:
Mir ist gerade beim Messen von PWM was aufgefallen und zwar, auch wenn duty_cycle auf 0 gesetzt wurde, habe ich am Gate kurze Peaks von 0,11% (PWM Frequenz ist 244Hz).

1639051080025.png

Hier ist das Setzen von duty_cycle:


CodeBox C
void pwm_set_duty (uint16_t duty)
{
    OCR1B = duty;        
}

Eigentlich nichts besonders. Initialisiert ist PWM mit:


CodeBox C
void pwm_init (void)
{
    // pin pc1 (OC1B, Timer 1 output compare B) connected to probe heater
    // fast pwm mode, prescaler 64,  top 0x03ff (1023) = 244Hz
    // pwm mode 7, 10-bit resolution
    // clear oc1b on compare match
    
    TCCR1A |= (1 << WGM11)|(1 << WGM10)|(1 << COM1B1);
    TCCR1B |= (1 << WGM12)|(1 << CS11)|(1 << CS10);
    pwm_set_duty(0);
}

auch nichts besonderes. Ich habe das "gefixt", ich dem ich den Timer angehalten habe, wenn duty = 0 ist:


CodeBox C
void pwm_set_duty (uint16_t duty)
{
    if (duty == 0)
    {
        TCCR1B &= ~((1 << CS11)|(1 << CS10));
    } 
    else 
    {
        TCCR1B |= (1 << CS11)|(1 << CS10);
        OCR1B = duty;        
    }
}

Ist das Verhalten normal?
 
Ist das Verhalten normal?
Ja.
Alternativ kannst Du das Verhalten umdrehen (inverted), dann gibt's allerdings keine 100%.
Statt den Timer anzuhalten, kannst Du auch den CompareOutputMode ändern.

Erklärungen tippe ich jetzt aber nicht ins Telefon - wenn weiterhin Bedarf besteht, später... ;)

Bevor ich das jetzt raussuchen muß: Du verwendest fastPWM?
 
Also...

das erste relevante Zitat aus dem Datenblatt ist:
16.10. Output Compare Units

The 16-bit comparator continuously compares TCNT1 with the Output Compare Register (OCR1x). If TCNT equals OCR1x the comparator signals a match. A match will set the Output Compare Flag (TIFR1.OCFx) at the next timer clock cycle. If enabled (TIMSK1.OCIEx = 1), the Output Compare Flag generates an Output Compare interrupt. The OCFx Flag is automatically cleared when the interrupt is executed. Alternatively the OCFx Flag can be cleared by software by writing a logical one to its I/O bit location. The Waveform Generator uses the match signal to generate an output according to operating mode set by the Waveform Generation mode (WGM1[3:0]) bits and Compare Output mode (COM1x[1:0]) bits.
und:
16.12.3. Fast PWM Mode

The Fast Pulse Width Modulation or Fast PWM modes (modes 5, 6, 7, 14,and 15, WGM1[3:0]= 0x5, 0x6, 0x7, 0xE, 0xF) provide a high frequency PWM waveform generation option. The Fast PWM differs from the other PWM options by its single-slope operation. The counter counts from BOTTOM to TOP then restarts from BOTTOM. In non-inverting Compare Output mode, the Output Compare (OC1x) is cleared on the compare match between TCNT1 and OCR1x, and set at BOTTOM. In inverting Compare Output mode output is set on compare match and cleared at BOTTOM.
Grundsätzlich wird OC1B also beim "Überlauf" des Timers (1023->0) high, das Compare-Event triggert aber erst einen Timer-Takt (also 64 Takte (Prescaler)) später, und setzt OC1B wieder null.

Genauer nochmal ganz am Ende des Absatzes:
The extreme values for the OCR1x registers represents special cases when generating a PWM waveform output in the Fast PWM mode. If the OCR1x is set equal to BOTTOM (0x0000) the output will be a narrow spike for each TOP+1 timer clock cycle. Setting the OCR1x equal to TOP will result in a constant high or low output (depending on the polarity of the output which is controlled by COM1x[1:0]).
OCR1B=0 liefert also Deine "Spikes".
OCR1B=-1 (also 1023) liefert im noninverting durchgehend high, im inverting hingegen durchgehend low (dafür hast Du da die invertierten "Spikes" also keine 100% mehr, klar?

Zu Deinem Fix:
Im Worst Case könntest Du den Timer jetzt aber anhalten, wenn der Pin gerade high ist. Dann wären da statt 0% 100% zu sehen. Klar kannst Du das auch abfangen.
Ich würde stattdessen einfach den Output Compare Mode umschalten. Also solange der Timer den Pin ansteuern soll wie gehabt COM1B1="1".
Zum Abschalten COM1B1="0".
COM1B1="1" übersteuert via Port Value Override Enable (PVOE) den Zustand des OC1B-Pins und legt eben da (PVOV - Port Value Overide Value) die Waveform aus dem Timer drauf. Deine Vorgabe im PORT-Output-Register bleibt aber so stehen, wie sie ist - sobald COM1B1 gelöscht wird, greift das PORT-Register also wieder.
Das umsetzen der COM-Bits sollte sofort greifen.

Also mußt Du nur Datenrichtung auf Ausgang und PORT auf low-Pegel setzen -> Grundzustand=0%

Für PWM mehr als 0% entsprechenden duty ins OCR1B und COM1B1 setzen.
Für PWM=0 COM1B1 löschen.

(ich meine mich sogar zu erinnern, daß in irgend'nem Tiny so'n COM-Bit sogar mal direct bit accessible war)
 
Vielen Dank für die Erklärung! Das Deaktivieren vom Timer bei Pin = 1 würde den Tod des Sensors nach sich ziehen. Diese Dinger sind sehr empfindlich, sowohl bei Kondenswasser als auch bei der Temperatur. Die nominale Spannung der Heizung liegt bei 7,5V, zum schnellen Aufheizen wird sie bis 13V hochgedreht, aber eben nur kurz, bis die Regelung greift. In dem Fall würden da aber 14,xV anliegen und dazu noch heiße Abgase (deswegen schaltet man die Heizung ja aus)...

Ich habe es jetzt so umgebaut:



CodeBox C
void pwm_set_duty (uint16_t duty)
{
    if (duty == 0)
    {
        TCCR1A &= ~(1 << COM1B1);        
    } 
    else 
    {
        OCR1B = duty;
        if (!(TCCR1A & (1 << COM1B1)))
        {
            TCCR1A |= (1 << COM1B1);
        }        
    }
}


Das müsste jetzt so passen.

Könntest Du Dir noch die Schaltung anschauen, vor allem die Masseverbindungen?
Vielen Dank!
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)