No se puede hacer que PWM funcione en un PIC12F683 con MPLAB XC8

2

Estoy tratando de hacer que PWM funcione en PIC12F683 . De acuerdo con mis cálculos, debería obtener un PWM de 8 bits a 20 kHz en GPIO2, pero eso no sucede. En cambio, recibo una señal PWM "extraña" de 5 kHz, de modo que cuando establezco el deber de ser 255, que debería ser el máximo, obtengo este 5kHz ola . ¿Cuál podría ser el problema?

EDITAR: estoy siguiendo este procedimiento que está escrito en la hoja de datos PIC12F683, pero no estoy haciendo lo correcto o hay algo más que debo hacer.

Este es el código:

  /*
   * 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;
  }
  }
    
pregunta Calin

2 respuestas

3

Algunos problemas que veo:

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

Esta línea en realidad está configurando el preescalador en 4, no en 1. Según los valores que haya elegido para PR2, Tosc y TMR2 preescalador, calculo una frecuencia PWM de 4902 Hz. Si configura el prescaler en 1, debe obtener una frecuencia de ~ 19608 Hz. Creo que esto es lo que pretendías. Debería escribir 0b00 en T2CONbits.T2CKPS en su lugar.

También el ciclo de trabajo PWM se establece con un valor de 10 bits. La ecuación para la relación del ciclo de trabajo es:

  

Relación del ciclo de trabajo = (CCPR1L: CCP1CON < 5: 4 >) / (4 * (PR2 + 1))

Para lograr un ciclo de trabajo del 100%, debe escribir 408 (o 0x198), no 255.

    
respondido por el ConduitForSale
1

Dos cosas que veo:

No uses #include y #include al mismo tiempo. Solo usa xc.h

También está sobrecargando su ciclo de trabajo. El ciclo de trabajo es una fracción del período. Su periodo es de 65 cuentas. El ciclo de trabajo que intenta establecer es 255. Solo puede establecer un ciclo de trabajo entre 0-65.

Con algunos trucos, el temporizador 2 (el temporizador para PWM) y el ciclo de trabajo admiten hasta 10 bits. La palabra clave es "hasta".

Nada en el procesador puede suceder más rápido que el reloj provisto. Si su temporizador 2 prescalar está configurado en 1, entonces el temporizador está funcionando lo más rápido posible. Esto significa que la resolución máxima del temporizador es una cuenta única. Eso también restringe la resolución máxima del ciclo de trabajo a un solo contador de temporizador. El hecho de que pueda admitir hasta 10 bits no significa que el procesador subdivida el período en 1024 unidades, no puede porque ya se está ejecutando lo más rápido posible.

La forma en que funciona el PWM es cuando el registro TMR2 se desplaza a cero y la línea se pone alta. Desde aquí, cuando los recuentos en TMR2 coinciden con el CCPR1L (más 2 bits), la señal baja. Finalmente, cuando los conteos en TMR2 coinciden con PR2, el temporizador se pone a cero y todo comienza de nuevo.

    
respondido por el vini_i

Lea otras preguntas en las etiquetas

Comentarios Recientes

128 Todavía no está claro cómo funciona este problema, así que hice algunas modificaciones menores en algunos de los archivos incluidos en el archivo PIXELOSP_fft.c para solucionarlo. Escribí el siguiente parche para reemplazar el sombreador flotante por uno que usara un tipo escalar más simple que el que se usa comúnmente en los juegos de PC. El nombre era Open Open de Pool Little World como componente GIMP Big-Scope de NGL. ShaderPimend es un sombreador de fragmentos que adapta los píxeles de VBO a la realidad... Lees verder