Forum: Mikrocontroller und Digitale Elektronik PWM auslesen Duty-Cycle


von Benno (Gast)


Lesenswert?

Hallo Leute,
Befasse mich jetzt seit geraumer Zeit mit der Programmierung von Atmel 
uC.
Jetzt befasse ich mich gerade mit Timer-Interrupts und versuche den 
Duty-Cycle eines 1khz PWM-Signals auszulesen.

Zum testen wollte ich einfach zu unterschiedlichen Duty-Cycle´n 
verschiedene Ausgänge schalten. Habe mich an einem Code aus einem 
anderen Beitrag orientiert und diesen leicht angepasst. Leider bekomme 
ich keine Ergebnisse und kein Ausgang schaltet. Vielleicht sieht ja 
einer den Fehler oder hat so etwas selber schon einmal gemacht.
Hier mein Code:


/*
 * PWM einlesen Interrupt.c
 *
 * Created: 22.03.2019 08:16:52
 * Author : Benno
 */


/*Beschreibung:

Ich habe den AT90CAN128 auf 16Mhz eingestellt, mit einem Vorteiler von 
64
ergibt das: 0,000004 Sekunden für einen Timerdurchlauf. Das PWM-Signal
hat 1kHz ==> 0.001 Sekunden
Daraus ergibt sich 0.001 / 0,000004 = 250

Der PortB sollen je nach Dutycycle geschaltet.

Nun zum Code:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#define F_CPU 16000000UL
4
5
volatile int flanke=0;
6
volatile int aktuell_pwm_l=0;
7
volatile int aktuell_pwm_h=0;
8
9
ISR(TIMER1_CAPT_vect)
10
{
11
12
  if (flanke==0)
13
  {
14
    TCNT1H = 0;             //Timer auf null zurück
15
    TCNT1L = 0;
16
    TCCR1B&= ~(1<<ICES1);  //ICP-Pin auf fallende Flanke einstellen
17
    flanke=1;
18
  }
19
  else
20
  {
21
    flanke=0;
22
    TCCR1B|=(1<<ICES1);     //ICP auf steigende Flanke wieder aktivieren
23
    aktuell_pwm_l=ICR1L;  //Zählerstand speichern
24
    aktuell_pwm_h=ICR1H;    //zählerstand speichern
25
  }
26
}
27
28
void init_prozedur(void)
29
{
30
  TCCR1B |=  (1<<ICNC1)|(1<<ICES1)|(1<<CS11)|(1<<CS10) ; // Mittelung ON, steigende flanke, vorteiler 64
31
  TIMSK1 |= (1<<ICIE1);//INTERRUPT ON
32
33
  sei();
34
}
35
36
int main (void)
37
{
38
  init_prozedur();
39
  DDRB=0b00001101;
40
  DDRD=0x00;
41
  
42
  while(1) 
43
  {
44
    
45
    if (aktuell_pwm_h >= 50 && aktuell_pwm_h < 100)
46
    {
47
      PORTB|=(1<<PB0);
48
    }
49
    if (aktuell_pwm_h >= 100 && aktuell_pwm_h <250)
50
    {
51
      PORTB|=(1<<PB2);
52
    }
53
    else
54
    {
55
      PORTB |= (0<<PB0)|(0<<PB2);
56
    }
57
  }
58
59
}

: Bearbeitet durch Moderator
von Sebastian R. (sebastian_r569)


Lesenswert?


von Benno (Gast)


Lesenswert?

Die habe ich mir auch schon angeschaut, hat mir nur leider nicht 
wirklich weiter geholfen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Benno schrieb:
> Nun zum Code
Bitte künftig die Bedienungsanleitung über dem Texteingabefeld beachten:
1
Wichtige Regeln - erst lesen, dann posten!
2
    ...
3
Formatierung (mehr Informationen...)
4
    [c]C-Code[/c]
5
    ...

von foobar (Gast)


Lesenswert?

Keine Ahnung bzgl des Interrupt-Kodes, aber in main sind zwei Fehler:

1) Die Ports werden nie gelöscht, ein Statement wie "y |= (0<<x)" macht 
nichts.  Wenn das Bit gelöscht werden soll, wäre "y ~= ~(1<<x)" richtig.

2) Du liest aktuell_pwm_h mehrmals aus.  Da sich der Wert durch einen 
Interrupt ändert, können beide if-Bedingungen wahr werden.
1
  while(1) 
2
  {
3
    uint8_t port = PORTB & ~((1<<PB0)|(1<<PB2));
4
    uint8_t pwm = aktuell_pwm_h;
5
6
    if (pwm >= 50 && pwm < 100)
7
       port |= 1<<PB0;
8
    if (pwm >= 100 && pwm < 250)
9
       port |= 1<<PB2;
10
11
    PORTB = port;
12
  }

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.