Forum: Mikrocontroller und Digitale Elektronik Software PWM


von Marius M. (micro4)


Lesenswert?

Hallo zusammen

Ich wollte mal hier meinen C-Code posten und fragen, was daran falsch 
sein sollte. Es funktioniet nicht wirklich. Ich realisiere mein PWM 
Signal mit einem Counter welcher funktioniert. Jedoch wird in der 
Interrupt Serviceroutine das PWM Signal nicht richtig erzeugt:
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <stdio.h>
4
#include <string.h>
5
#include <avr/interrupt.h>
6
7
#define t_Period  1000;
8
9
//pwm_on & pwm_off sind das Tastverhältnis
10
unsigned int pwm_on, pwm_off;
11
unsigned int pwm_on_count, pwm_off_count;
12
13
14
void init_timer()
15
{
16
  TCCR1A = 0b00000000; //Set timer to compare OCR1A register
17
  TCCR1B = 0b00001011; //Set prescaler to 64 and set Timer to compare OCR1A register
18
  TIMSK = 0b00010000; //Enable Timer 1 Compare A Interrupt
19
  OCR1A = 0x20; //Exact number for 2ms interrupts
20
21
  sei();
22
}
23
24
25
26
ISR(TIMER1_COMPA_vect)
27
{
28
  if(pwm_on_count < pwm_on) {
29
    PORTC |= (0 << 0);
30
    pwm_on_count++;  
31
  }
32
33
  else {
34
    if(pwm_off_count < pwm_off) {
35
      PORTC |= (1 << 0);
36
      pwm_off_count++;  
37
    }
38
39
    else {
40
      pwm_on--;
41
      pwm_on_count = 0;
42
      pwm_off = t_Period - pwm_on;
43
      pwm_off_count = 0;
44
    }
45
    
46
  }
47
48
  
49
50
}
51
52
53
54
void initIO(void) 
55
{
56
  DDRC = 0xff;
57
}
58
59
void main()
60
{
61
  //Initialisieren
62
  initIO();
63
  init_timer();
64
  pwm_on = t_Period;
65
  pwm_off = 0;
66
  pwm_on_count = 0;
67
  pwm_off_count = 0;
68
69
  while(1) {
70
71
  }
72
73
}
74
75
76
}

Ich verwende eine Atmega16. Ich danke für die Hilfe.

MFG

von Benedikt K. (benedikt)


Lesenswert?

Marius Meier schrieb:

> Ich wollte mal hier meinen C-Code posten und fragen, was daran falsch
> sein sollte. Es funktioniet nicht wirklich.

Lass mich raten: Der Pin ist dauerhaft an?

Der Fehler liegt wohl hier:
1
 PORTC |= (0 << 0);

Damit schaltest du den Pin nicht ab, sondern machst garnichts.
So sollte es besser gehen:
1
 PORTC &=~(1 << 0);

von Mark B. (markbrandis)


Lesenswert?

Benedikt K. schrieb:
>
1
 PORTC &=~(1 << 0);

Warum eigentlich schiebt Ihr Bits um Null Stellen? Ist das besonders 
performant? ;-)

von Michael (Gast)


Lesenswert?

Hallo,

wenn Du in der ISR auf Variablen zugreifst, musst Du sie als "volatile 
deklarieren".

Michael

von Benedikt K. (benedikt)


Lesenswert?

Mark Brandis schrieb:

> Warum eigentlich schiebt Ihr Bits um Null Stellen? Ist das besonders
> performant? ;-)

Es macht den Code leichter lesbar.

Wenn man einmal
1
PORTC &=~0;
das nächste mal
1
PORTC &=~(1 << 1);
oder dann auch mal noch
1
PORTC &=~_BV(2);
oder gar
1
cbi(PORTC,3);
schreibt, dann trägt das nicht wirklich zum leichten Verständnis des 
Codes bei.
Man sollte daher eine der 4 Schreibweisen durchgehend im gesamten Code 
verwenden.

von Vlad T. (vlad_tepesch)


Lesenswert?

und statt literalen sollte man aber auch dann
(1 << PIN0) oder (1 << PINB0) schreiben, wobei ich letzteres schon 
wieder sinnlos finde, da mann, wenn man den Port ändert auch überall 
PINxn in PINynx ändern muss.

Edit:
>Ist das besonders performant? ;-)
der kompiler optimiert das sowiso weg.

Edit Edit:
@benedikt:
du hast die beiden ersten Varianten von Marius vergessen:
1
>  TIMSK = 0b00010000; //Enable Timer 1 Compare A Interrupt
2
>  OCR1A = 0x20; //Exact number for 2ms interrupts

von Marius M. (micro4)


Lesenswert?

Danke vielmals. Ich habe die ganze Zeit am falschen Ort den Code 
betrachtet. Habe nicht gesehen das ich das Bit falsch lösche. Danke!

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.