www.mikrocontroller.net

Forum: Compiler & IDEs PWM von hand?


Autor: der_hier (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
#include <avr/io.h>
#include <avr/interrupt.h>

#ifndef F_CPU
#define F_CPU 1000000UL // interner 8MHz oszi mit CKDIV8
#endif


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

ISR (INT0_vect){
  TCNT1++;  
}

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

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

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

}

int main (){
  
  // Port Deklaration
  DDRD = (1<<PD4); //PD4 als Ausgang

  //Initialisierungen
  INT0init();
  PWMinit();

  sei();

  //Programmschleife
  while(1){}

return 0;
}


Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.
volatile uint8_t nextPwmCompare;  // PWM Wert

ISR (INT0_vect)
{
  static uint8_t pwmTimer;
  static uint8_t pwmCompare;

  pwmTimer++;  

  if( pwmTimer == 63 ) {
    pwmTimer = 0;
    PWM_PORT &= ~( 1 << PWM_PIN );
    pwmCompare = nextPwmCompare
  }
  else if( pwmTimer == pwmCompare ) {
    PWM_PORT |= ~( 1 << PWM_PIN );
  }
}

Autor: der_hier (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: der_hier (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
so ich versuchs nun mit:
volatile nachr[38];

ISR (INT0_vect){
    
    static uint8_t timer;
    static uint8_t j;

    timer++;

    if (timer == 64) { 
        timer = 0 ;
        j++;
        if (j == 39) {j = 0;} 
    }                            //rücksetzen und j hochzählen
    
    if (timer == 0){                    
        if(nachr[j]){ PORTD &= ~(1<<PD4) ; } //erste Halbbit 0 wenn nachr[j] = 1
        else { PORTD |= (1<<PD4) ; }         //erste Halbbit 1 wenn nachr[j] = 0
    }
    else if (timer == 32){
        if(nachr[j]){ PORTD |= (1<<PD4) ; } //zweite Halbbit 1 wenn nachr[j] = 1
        else { PORTD &= ~(1<<PD4) ; }        //zweite Halbbit 0 wenn nachr[j] = 0
    }
    
}


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

Autor: Stefan Weßels (swessels)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: der_hier (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich werd aus deinen Ausführungen nicht schlau. Warum muss der PWM Takt 
von extern kommen?

Autor: der_hier (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: der_hier (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)

/* Programminterner Header ATmega644
--------------------------------------------------------------------------------*/
#include <avr/io.h>
#include <avr/interrupt.h>

#ifndef F_CPU
#define F_CPU 1000000UL
#endif


/*------------------------------------------------------------------------------*/
volatile uint8_t nachr[38];


/* Interrupts
--------------------------------------------------------------------------------*/

ISR (INT0_vect){
  
  static uint8_t timer;
  static uint8_t j;

  if (timer == 63) { 
    timer = 0 ;
    j++;
    if (j == 39) {j = 0;} 
  }              //rücksetzen und j hochzählen
  
  if (timer == 0){          
    if(nachr[j]){ PORTD &= ~(1<<PD4) ; } //erste Halbbit 0 wenn nachr[j] = 1
    else { PORTD |= (1<<PD4) ; }     //erste Halbbit 1 wenn nachr[j] = 0
  }
  else if (timer == 32){
    if(nachr[j]){ PORTD |= (1<<PD4) ; } //zweite Halbbit 1 wenn nachr[j] = 1
    else { PORTD &= ~(1<<PD4) ; }    //zweite Halbbit 0 wenn nachr[j] = 0
  }
  
}
/*------------------------------------------------------------------------------*/




/* int0 und Nachrichten 
--------------------------------------------------------------------------------*/


void nachrinit(){
  uint8_t i;
  for (i=0; i<39; i++){
    switch (i){
      case (0):
      case (1):
      case (2):
      case (3):
      case (4):
      case (5):
      case (6):
      case (7):
      case (8):
      case (9):
      case (10):
      case (14):
      case (16):
      case (19):
      case (20):
      case (21):
      case (22):
      case (24):
      case (25):
      case (26):
      case (33):
        nachr[i]=1;
      break;
      default:
        nachr[i]=0;
            
    }
  }
}




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


/*------------------------------------------------------------------------------*/



/* Hauptprogramm
--------------------------------------------------------------------------------*/
int main (){
  
  // Port Deklaration
  DDRD = (1<<PD4); //PD4 als Ausgang
  PORTD = (1<<PD4);

  //Variablen Deklaration

  //Initialisierungen
  nachrinit();
  int0init();

  sei();

  //Programmschleife
  while(1){
    
    

  }

return 0;
}
/*------------------------------------------------------------------------------*/

Autor: der_hier (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kann das bitte wer löschen da fehlt doch glatt timer++; allerdings 
bleiben die seltsamen 2V an den PORTS da jemand ne idee?

Autor: julian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nach einem Reset sind alle Pins (mehr oder weniger hochohmige) Eingänge. 
Also misst du mit dem Voltmeter irgendwelchen zufälligen Mist der durch 
die Bude fliegt

Autor: der_hier (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, das nehm ich mal so hin.
problem ist auch gelöst. Clock auf 1 MHZ und interrupt 125KHz => 8 Takte 
um den Interrupt auszuführen (zu wenig). auf 8 MHz getaktet und die 
"Bude" rennt.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.