Forum: Mikrocontroller und Digitale Elektronik ATTINY13 - ADC im free running mode blockiert irgendwie den Hardware PWM


von Sebastian S. (dualsbiker)


Lesenswert?

Hallo,

für ein Exponat soll ich ein kleines ferngesteuertes langsamer fahren 
lassen. Das Auto selbst kann in 4 Stufen geradeaus fahren. Dafür wird in 
der Elektronik des Autos eine PWM erzeugt. Ich habe nun vor das 
PWM-Signal über den AD-Wandler des TINY13 aufzuzeichnen und das 
Tastverhältnis zu berechnen. So kann ich die 4 Stufen erkennen und kann 
entsprechend eine "langsamere" PWM ausgeben.
Die Berechnung des Tastverhältnisses funktioniert schon wunderbar, nur 
auf einmal will die von mir erzeugt PWM nicht mehr. Wenn ich den 
PWM-Teil in einem neuen Projekt kompiliere, funktioniert sie, also denke 
ich, ist der Code an sich nicht verkehrt. Kann es sein, dass sich die 
Interrupts gegenseitig beeinflussen ?
Nicht wundern, warum ich beide Hardware-PWM-Ausgänge konfiguriert habe. 
Rückwärtsfahren soll er schließlich auch noch.
1
/*
2
 * PWM_Mini_LNdW.c
3
 *
4
 * Created: 15.04.2014 15:40:50
5
 *  Author: schu_s2
6
 */ 
7
8
#define F_CPU 1200000UL
9
#include <avr/io.h>
10
#include <util/delay.h>
11
#include <avr/interrupt.h>
12
#define NUM_SAMPLES 16
13
14
volatile uint16_t x[NUM_SAMPLES];
15
uint8_t i = 0;
16
17
ISR(ADC_vect){
18
  x[i] = ADCW;
19
  i++;
20
  if (i == 16){
21
    i = 0;
22
  }
23
}
24
25
uint16_t average(uint16_t *Feld, unsigned char n_samples){
26
  uint16_t relation = 0;
27
  uint16_t sum = 0;
28
  for (int j = 0; j < n_samples; j++){
29
    sum = sum + Feld[j];
30
  }
31
  relation = sum / n_samples;
32
  return relation;
33
}
34
35
int main(void)
36
{
37
  DDRB = 0b00000111;
38
  TCCR0A |= (1<<WGM01) | (1<<WGM00);
39
  TIMSK0 |= (1<<OCIE0A)|(1<<OCIE0B);
40
  TCCR0B |= (1<<CS00);
41
  //OCR0A = 0x80;
42
  //OCR0B = 0x80;*/
43
  ADMUX |= (1<<MUX1);            //MUX1 für ADC2
44
  ADCSRA |= (1<<ADEN) | (1<<ADSC) | (1<<ADIE) | (1<<ADATE) | (1<<ADPS0) | (1<<ADPS1) | (1<<ADPS2);            
45
  //Teiler 128 //free running mode
46
  uint16_t Wert = 0;
47
  sei();
48
  
49
  for(int j=0;j<NUM_SAMPLES;j++){
50
    x[j]=0;
51
  }
52
53
  while(1){
54
55
    Wert = average(x, NUM_SAMPLES);
56
          
57
    if ( Wert <= 100 ){                //Wenn ADC-Mittelwert unter 100, schalte PWM aus
58
      TCCR0A &= ~((1<<COM0A1) | (1<<COM0A0));
59
      //PORTB |= (1<<PINB1);  
60
    }
61
    if ( Wert > 100 && Wert < 400){
62
      OCR0A = 0x19;                //10% Tastverhältnis
63
      TCCR0A |= (1<<COM0A1) | (1<<COM0A0);
64
      
65
    }
66
    if ( Wert >= 400 && Wert < 600){
67
      OCR0A = 0x33;                //20% Tastverhältnis
68
      TCCR0A |= (1<<COM0A1) | (1<<COM0A0);
69
      //PORTB ^= (1<<PINB2);
70
    }
71
    if ( Wert >= 600 && Wert < 750){
72
      OCR0A = 0x40;                //25% Tastverhältnis
73
      TCCR0A |= (1<<COM0A1) | (1<<COM0A0);
74
      //PORTB ^= (1<<PINB1);
75
    }
76
    if ( Wert >= 750){
77
      OCR0A = 0x4D;                //30% Tastverhältnis
78
      TCCR0A |= (1<<COM0A1) | (1<<COM0A0);
79
      //PORTB ^= (1<<PINB2);
80
    }  
81
    
82
    
83
  }
84
}

von MWS (Gast)


Lesenswert?

Sebastian Schulz schrieb:
> Wenn ich den
> PWM-Teil in einem neuen Projekt kompiliere, funktioniert sie

Das ist zu bezweifeln, bzw. scheint nur so. Interrupts erlauben ohne 
ISRs führt per Default zu Neustarts.

> TIMSK0 |= (1<<OCIE0A)|(1<<OCIE0B);

von Sebastian S. (dualsbiker)


Lesenswert?

Ok, also wenn ich den PWM-Teil in einem neuen Projekt kompiliere, lasse 
ich sei() weg. Und mein Oszilloskop lügt mich ja nicht an.
Meinst du also, dass es durch den nun angewendeten sei()-Befehl und die 
jetzt fehlende Interrupt-Routine nicht funktioniert ?

von holger (Gast)


Lesenswert?

>Meinst du also, dass es durch den nun angewendeten sei()-Befehl und die
>jetzt fehlende Interrupt-Routine nicht funktioniert ?

Das meint nicht nur er. Wieso probierst du es nicht
ohne die Interruptfreigabe für die Timer aus?

Ist das denn so schwer?

von Sebastian S. (dualsbiker)


Lesenswert?

Scheinbar genauso schwer wie höflich zu bleiben...
Ich kann es leider erst morgen wieder testen, da es auf der Arbeit liegt 
und ich zuhause bin.
Wenn ich die Interrupt-Freigabe weglasse, dann funktioniert ja der 
ADC-Interrupt nicht mehr. Oder ???

von MWS (Gast)


Lesenswert?

Sebastian Schulz schrieb:
> Meinst du also, dass es durch den nun angewendeten sei()-Befehl und die
> jetzt fehlende Interrupt-Routine nicht funktioniert ?

Ja, das ist ganz sicher so. Ohne ISR zeigt der entsprechende 
Interruptvektor auf den Resetvektor und damit resettet der uC laufend.

Warum erlaubst Du überhaupt Interrupts, die offensichtlich nicht 
benötigt werden?

von holger (Gast)


Lesenswert?

>Wenn ich die Interrupt-Freigabe weglasse, dann funktioniert ja der
>ADC-Interrupt nicht mehr. Oder ???

Wer hat denn gesagt das du sei() weglassen sollst?

Bist du irgendwie schwer von Begriff?
Und das war jetzt ein klein wenig unhöflich;)

von Sebastian S. (dualsbiker)


Lesenswert?

>Warum erlaubst Du überhaupt Interrupts, die offensichtlich nicht
benötigt werden?

Die Interrupts für den Timer habe ich ja, um das Tastverhältnis zu 
bestimmen. Das Interrupt für den ADC habe ich, um mir jeden generierten 
Wert zu holen. Für die gleitende Mittelwertbildung.

von Sebastian S. (dualsbiker)


Lesenswert?

>Bist du irgendwie schwer von Begriff?
Naja wenn ich die Ahnung davon hätte, müsste ich mich hier ja nich blöde 
anmachen lassen.

von Sebastian S. (dualsbiker)


Lesenswert?

>Ja, das ist ganz sicher so. Ohne ISR zeigt der entsprechende
>Interruptvektor auf den Resetvektor und damit resettet der uC laufend.

Super, das probier ich morgen gleich mal aus.

von MWS (Gast)


Lesenswert?

Sebastian Schulz schrieb:
> Die Interrupts für den Timer habe ich ja, um das Tastverhältnis zu
> bestimmen.

Der Timer erzeugt die PWM allein in Hardware, dazu wird kein Interrpt 
benötigt. Man kann Interrupts zusätzlich verwenden, jedoch macht das 
sowiso nur Sinn, wenn es dafür entsprechende Routinen gibt.

von Peter D. (peda)


Lesenswert?

Für jeden freigegebenen Interrupt muß ein Handler aufgesetzt werden.
Er kann auch leer sein (EMPTY_INTERRUPT), aber da sein muß er.

http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html

von Sebastian S. (dualsbiker)


Lesenswert?

Super, jetzt klappts, vielen Dank an euch.

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.