PWM von hand?

Gast #1872722
Lesenswert?

Hallo,
ich nutze zurzeit einen ATMega644 mit einem AVR Dragon board und 
programmiere in AVR Stodio 4. Muss gleich dazu sagen ich nutze den 
mega644 nur zum testen da ich dort nen jtag zugriff habe, das Programm 
soll später mal auf nem ATtiny45 laufen und da ist auch schon das 
Problem. Ich möchte eine PWM machen über einen externen Takt und einen 
Sensor an die I²C Schnittstelle anschließen, allerdings teilen sich 
Timer0 (einzigster Timer mit pwm beim tiny45) und I²C einen Pin.

Nun hatte ich die Idee über einen Externen interrupt (beim mega nutze 
ich int0, beim tiny wollte ich dann pcintX nehmen) den Timer/Counter 
direkt hochzuzählen.
Tja, hochzählen funktioniert, aber keine PWM und kein TIMER1 overflow. 
ist es nicht möglich diese funktionen über interne zugriffe zu steuern? 
Brauche ich unbedingt dafür einen direkten Takt am Timer?

hier Programmauszug:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3

4
#ifndef F_CPU
5
#define F_CPU 1000000UL // interner 8MHz oszi mit CKDIV8
6
#endif
7

8

9
ISR (TIMER1_OVF_vect){  //Interrupt bei Timer1 overflow
10
    //hier wird Programm ausgeführt  
11
}
12

13
ISR (INT0_vect){
14
  TCNT1++;  
15
}
16

17
void INT0init(){
18
  EICRA |= (1<<ISC01); //int0 interrupt falling edge
19
  EIMSK |= (1<<INT0);  //int0 interrupt enable
20
}
21

22
void PWMinit(){
23
  OCR1A = 63; //bis dahin soll Timer1 laufen
24
  OCR1B = 32; // 50% PWM durch OCR1B
25

26
  // PWM auf mode 15(Fast PWM, Top OCR1A) und externe clock aus
27
  TCCR1A |= (1<<COM1B1) | (1<<WGM10) |(1<<WGM11);
28
  TCCR1B |= (1<<WGM12) | (1<<WGM13) ;
29
  
30
  TIMSK1 |= (1<<TOIE1); //Timer1 overflow interrupt enable
31

32
}
33

34
int main (){
35
  
36
  // Port Deklaration
37
  DDRD = (1<<PD4); //PD4 als Ausgang
38

39
  //Initialisierungen
40
  INT0init();
41
  PWMinit();
42

43
  sei();
44

45
  //Programmschleife
46
  while(1){}
47

48
return 0;
49
}
#1872737
Lesenswert?

der_hier schrieb:

> Nun hatte ich die Idee über einen Externen interrupt (beim mega nutze
> ich int0, beim tiny wollte ich dann pcintX nehmen) den Timer/Counter
> direkt hochzuzählen.

Warum muss die PWM eigentlich extern getaktet werden.

> Tja, hochzählen funktioniert, aber keine PWM und kein TIMER1 overflow.
> ist es nicht möglich diese funktionen über interne zugriffe zu steuern?
> Brauche ich unbedingt dafür einen direkten Takt am Timer?

Hab ich ehrlich gesagt nie ausprobiert. Aber IMHO kriegst du gar keinen 
Overflow Interrupt sondern einen Compare Match Interrupt

Aber im Ernst: Wenn du sowieso schon extern taktest, kannst du auch 
gleich noch die PWM selber auch noch mit dazusimulieren. Die 2 
C-Anweisungen sind in der ISR auch schon egal und dann kannst du als 
Bonus auch noch die PWM auf den Pin legen, der dir genehm ist.

Du brauchst dann im Grunde noch nicht einmal den Timer, da seine Aufgabe 
eine normale 8-Bit Variable genausogut übernehmen kann.
1
volatile uint8_t nextPwmCompare;  // PWM Wert
2

3
ISR (INT0_vect)
4
{
5
  static uint8_t pwmTimer;
6
  static uint8_t pwmCompare;
7

8
  pwmTimer++;  
9

10
  if( pwmTimer == 63 ) {
11
    pwmTimer = 0;
12
    PWM_PORT &= ~( 1 << PWM_PIN );
13
    pwmCompare = nextPwmCompare
14
  }
15
  else if( pwmTimer == pwmCompare ) {
16
    PWM_PORT |= ~( 1 << PWM_PIN );
17
  }
18
}
Gast #1872749
Lesenswert?

Karl heinz Buchegger schrieb:
> Warum muss die PWM eigentlich extern getaktet werden.

da ich auf ein externes 125KHz Signal eine manchestercodierung 
aufbringen möchte (halbbit 32 takte lang).

Karl heinz Buchegger schrieb:
> Wenn du sowieso schon extern taktest, kannst du auch
> gleich noch die PWM selber auch noch mit dazusimulieren

klingt gut, so hab ich da noch nicht drüber nachgedacht. werds gleich 
mal ausprobieren und dann rückmeldung geben.
Gast #1872895
Lesenswert?

so ich versuchs nun mit:
1
volatile nachr[38];
2

3
ISR (INT0_vect){
4
    
5
    static uint8_t timer;
6
    static uint8_t j;
7

8
    timer++;
9

10
    if (timer == 64) { 
11
        timer = 0 ;
12
        j++;
13
        if (j == 39) {j = 0;} 
14
    }                            //rücksetzen und j hochzählen
15
    
16
    if (timer == 0){                    
17
        if(nachr[j]){ PORTD &= ~(1<<PD4) ; } //erste Halbbit 0 wenn nachr[j] = 1
18
        else { PORTD |= (1<<PD4) ; }         //erste Halbbit 1 wenn nachr[j] = 0
19
    }
20
    else if (timer == 32){
21
        if(nachr[j]){ PORTD |= (1<<PD4) ; } //zweite Halbbit 1 wenn nachr[j] = 1
22
        else { PORTD &= ~(1<<PD4) ; }        //zweite Halbbit 0 wenn nachr[j] = 0
23
    }
24
    
25
}


zum wirklichen testen werd ich erst morgen zeit haben, muss erstmal 
anderweitig schaffen. ich lass wissen obs funktioniert
#1873756
Lesenswert?

der_hier schrieb:
> .....Timer0 (einzigster Timer mit pwm beim tiny45).....

Der Timer 1 des Tiny45 kann sehr wohl PWM. Auszug aus dem Datenblatt:

Peripheral Features
– 8-bit Timer/Counter with Prescaler and Two PWM Channels
– 8-bit High Speed Timer/Counter with Separate Prescaler
  • 2 High Frequency PWM Outputs with Separate Output Compare Registers
  • Programmable Dead Time Generator

Timer 1 soll für PWM sogar besonders geeignet sein.

Gruß,
Stefan
Gast #1876122
Lesenswert?

Ah, entschuldigung hab ich verwechselt, timer0 ist der einzige mit 
externer Clock (T0), deswegen könnte ich wenn nur den verwenden (Problem 
bleibt leider). konnte aufgrund anderer arbeiten den neuen code auch 
noch nicht ausprobieren.(bleibt dabei, ich sag bescheid obs 
funktioniert)
Gast #1876993
Lesenswert?

der_hier schrieb:
> Karl heinz Buchegger schrieb:
>> Warum muss die PWM eigentlich extern getaktet werden.
>
> da ich auf ein externes 125KHz Signal eine manchestercodierung
> aufbringen möchte (halbbit 32 takte lang).

das Signal wird von einer externen Quelle vorgegeben und ist nicht exakt 
125 KHz und variable (sagen wir mal 120-130 KHz, je nachdem). 32 Takte 
soll heißen 32 Schwingungen des 125KHz signals
Gast #1877029
Lesenswert?

So sieht mein Programm nun aus. leider funktioniert es nicht wirklich. 
Seltsamste Sache: an PORTD und PORTC (außer JTAG) liegen nun dauerhaft 
+2V (5V versorgungsspannung bzw. high signal)

1
/* Programminterner Header ATmega644
2
--------------------------------------------------------------------------------*/
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5

6
#ifndef F_CPU
7
#define F_CPU 1000000UL
8
#endif
9

10

11
/*------------------------------------------------------------------------------*/
12
volatile uint8_t nachr[38];
13

14

15
/* Interrupts
16
--------------------------------------------------------------------------------*/
17

18
ISR (INT0_vect){
19
  
20
  static uint8_t timer;
21
  static uint8_t j;
22

23
  if (timer == 63) { 
24
    timer = 0 ;
25
    j++;
26
    if (j == 39) {j = 0;} 
27
  }              //rücksetzen und j hochzählen
28
  
29
  if (timer == 0){          
30
    if(nachr[j]){ PORTD &= ~(1<<PD4) ; } //erste Halbbit 0 wenn nachr[j] = 1
31
    else { PORTD |= (1<<PD4) ; }     //erste Halbbit 1 wenn nachr[j] = 0
32
  }
33
  else if (timer == 32){
34
    if(nachr[j]){ PORTD |= (1<<PD4) ; } //zweite Halbbit 1 wenn nachr[j] = 1
35
    else { PORTD &= ~(1<<PD4) ; }    //zweite Halbbit 0 wenn nachr[j] = 0
36
  }
37
  
38
}
39
/*------------------------------------------------------------------------------*/
40

41

42

43

44
/* int0 und Nachrichten 
45
--------------------------------------------------------------------------------*/
46

47

48
void nachrinit(){
49
  uint8_t i;
50
  for (i=0; i<39; i++){
51
    switch (i){
52
      case (0):
53
      case (1):
54
      case (2):
55
      case (3):
56
      case (4):
57
      case (5):
58
      case (6):
59
      case (7):
60
      case (8):
61
      case (9):
62
      case (10):
63
      case (14):
64
      case (16):
65
      case (19):
66
      case (20):
67
      case (21):
68
      case (22):
69
      case (24):
70
      case (25):
71
      case (26):
72
      case (33):
73
        nachr[i]=1;
74
      break;
75
      default:
76
        nachr[i]=0;
77
            
78
    }
79
  }
80
}
81

82

83

84

85
void int0init(){
86
  EICRA |= (1<<ISC01);
87
  EIMSK |= (1<<INT0); //int0 interrupt falling edge
88
}
89

90

91
/*------------------------------------------------------------------------------*/
92

93

94

95
/* Hauptprogramm
96
--------------------------------------------------------------------------------*/
97
int main (){
98
  
99
  // Port Deklaration
100
  DDRD = (1<<PD4); //PD4 als Ausgang
101
  PORTD = (1<<PD4);
102

103
  //Variablen Deklaration
104

105
  //Initialisierungen
106
  nachrinit();
107
  int0init();
108

109
  sei();
110

111
  //Programmschleife
112
  while(1){
113
    
114
    
115

116
  }
117

118
return 0;
119
}
120
/*------------------------------------------------------------------------------*/

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren