Kann PWM nicht auf einem PIC12F683 mit MPLAB XC8 zum Laufen bringen

Ich versuche, PWM auf dem PIC12F683 zum Laufen zu bringen . Nach meinen Berechnungen sollte ich bei GPIO2 eine 8-Bit-20-kHz-PWM bekommen, aber das passiert nicht. Stattdessen erhalte ich ein "seltsames" 5-kHz-PWM-Signal, sodass ich diese 5-kHz-Welle erhalte, wenn ich die Einschaltdauer auf 255 einstelle, was maximal sein sollte . Was könnte das Problem sein?

BEARBEITEN: Ich folge diesem Verfahren, das im PIC12F683-Datenblatt geschrieben ist, aber ich mache es entweder nicht richtig oder ich muss etwas anderes tun.

Dies ist der Code:

  /*
   * File:   main.c
   * Author: Calin
   *
   * Created on November 9, 2015, 11:10 PM
   */


  #define _XTAL_FREQ 8000000
  #include <xc.h>
  #include <PIC12F683.h>
  #define CHECK_BIT(var,pos) ((var) & (1<<(pos)))

  /* Prototypes *****************************************************************/
  long calculatePower(void);
  unsigned int readVoltage(void);
  unsigned int readCurrent(void);
  void PWM_setup(void);
  void PWM_set_duty(int);
  void interrupt ISR(void);
  /******************************************************************************/

  void main(void) {
  // Select 8Mhz internal clock
  OSCCON |= 0b01110001;
  // Configure GP0 and GP1 as analog inputs
  TRISIO  = 0b00000011; //input
  ANSEL   = 0b00000011; // clock = 1 meg and analog configure
  INTCONbits.PEIE = 1;
  INTCONbits.GIE = 1;
  INTCONbits.T0IE = 1;
  PIE1bits.CCP1IE = 1;
  PIE1bits.TMR2IE = 1;
  PWM_setup();

  PWM_set_duty(255);
  while (1){
      //long power = calculatePower();
  }
  return;
  }

  void PWM_setup(){
  TRISIO &= 0b11111011; // make sure GP2 is OUTPUT
  PR2 = 0x65;
  CCP1CON = 0b00001100; // active high PWM
  PIR1bits.TMR2IF = 0;
  T2CONbits.T2CKPS = 0x1; // set prescaler to 1
  T2CONbits.TMR2ON = 1; // enable Timer 2 and therefor PWM
  }

  void PWM_set_duty(int duty_cycle){
  // Sets the PWM duty cycle by setting
  // the 2 LSB's in DCB and the 8 MSB's
  // in CCPR1L. 10 bit resolution
  CCP1CONbits.DC1B = duty_cycle;
  CCPR1L = duty_cycle >> 2;
  }

  long calculatePower(){
  return readVoltage()*readCurrent();
  }

  unsigned int readVoltage(){
  /*
   * Reads and returns the voltage at AN0
   */
  // Select channel 0 and turn on ADC
  ADCON0 = 0b10000001; // enable ADC
  ADCON0 = 0b10000011; // GO

  while (CHECK_BIT(ADCON0, 1)){
      // wait
  }

  // 10 bit ADC result
  unsigned int voltage = ADRESL | (ADRESH << 8);
  return voltage;
  }

  unsigned int readCurrent(){
  /*
   * Reads and returns the current at AN1
   */
  // Select channel 1 and turn on ADC
  ADCON0 = 0b10000101; // enable ADC & select channel
  ADCON0 = 0b10000111; // GO

  while(CHECK_BIT(ADCON0, 1)){
      // wait
  }
  unsigned int current = ADRESL | (ADRESH << 8);
  return current;
  }

  void interrupt ISR(){
  // Timer2 overflow => start a new PWM cycle
  if(PIR1bits.TMR2IF == 1){
      PIR1bits.TMR2IF = 0;
      TRISIObits.TRISIO2 = 0;
  }
  }

Antworten (2)

Ein paar Probleme, die ich sehe:

T2CONbits.T2CKPS = 0x1; // set prescaler to 1

Diese Zeile setzt den Vorteiler tatsächlich auf 4, nicht 1. Basierend auf den Werten, die Sie für PR2, Tosc und den TMR2-Vorteiler gewählt haben, berechne ich eine PWM-Frequenz von 4902 Hz. Wenn Sie den Prescaler auf 1 setzen, sollten Sie eine Frequenz von ~19608 Hz erhalten. Ich denke, das ist, was Sie beabsichtigt haben. Sie sollten stattdessen 0b00 in T2CONbits.T2CKPS schreiben.

Auch das PWM-Tastverhältnis wird durch einen 10-Bit-Wert festgelegt. Die Gleichung für das Tastverhältnis lautet:

Arbeitszyklusverhältnis = (CCPR1L:CCP1CON<5:4>) / (4*(PR2 + 1))

Um eine Einschaltdauer von 100 % zu erreichen, müssen Sie 408 (oder 0x198) schreiben, nicht 255.

Zwei Dinge sehe ich:

Verwenden Sie #include und #include nicht gleichzeitig. Verwenden Sie nur xc.h

Auch Ihre Überlastung Ihres Arbeitszyklus. Das Tastverhältnis ist ein Bruchteil der Periode. Ihre Periode beträgt 65 Zähler. Das Tastverhältnis, das Sie einstellen möchten, ist 255. Sie können nur ein Tastverhältnis zwischen 0-65 einstellen.

Mit einigen Tricks unterstützt Timer 2 (der Timer für PWM) und das Tastverhältnis bis zu 10 Bit. Das Schlüsselwort dort ist "bis zu".

Nichts im Prozessor kann schneller passieren als der bereitgestellte Takt. Wenn Ihr Timer 2 Preskalar auf 1 eingestellt ist, läuft der Timer so schnell wie möglich. Das bedeutet, dass die maximale Auflösung des Zeitgebers eine einzelne Zählung ist. Dadurch wird auch die maximale Auflösung des Tastverhältnisses auf einen einzelnen Timer-Zählwert beschränkt. Die Tatsache, dass er bis zu 10 Bit unterstützen kann, bedeutet nicht, dass der Prozessor die Periode in 1024 Teile unterteilt, er kann es nicht, weil er bereits so schnell wie möglich läuft.

Geben Sie hier die Bildbeschreibung ein

Die PWM funktioniert so, dass die Leitung hoch wird, wenn das TMR2-Register auf Null wechselt. Ab hier, wenn die Zählwerte in TMR2 mit CCPR1L (plus 2 Bits) übereinstimmen, geht das Signal auf Low. Schließlich, wenn die Zählungen in TMR2 mit PR2 übereinstimmen, rollt der Timer auf Null und das Ganze beginnt von vorne.

Die meisten PIC-Geräte, mit denen ich gearbeitet habe, verwenden 10 Bit für das Tastverhältnis und 8 Bit zum Einstellen der Periode. Siehe Seiten 78 und 79 im oben verlinkten Datenblatt.
Danke schön! Meine tatsächliche Auflösung war also im Grunde "8,67 Bit", daher konnte ich mit dem Arbeitszyklus auf 408 hochgehen.