Pwm cambiando registros arduino uno

consulta, porque no tengo salida , o estoy haciendo algo mal, uso el arduino uno para lograr un pwm mayor que con analogwrite, tambien esta el manejo del encoder, que funciona probé con attachInterrupt y funciono todo bien , algún registro esta mal



volatile int value;
volatile int lastEncoded = 0;
int A = 2;       //variable A a pin digital 2 (DT en modulo)
int B = 4;        //variable B a pin digital 4 (CLK en modulo)

void setup()   
{  
  pinMode(9,OUTPUT);              
  pinMode(A, INPUT);   // A como entrada
  pinMode(B, INPUT);    // B como entrada
  digitalWrite(A, HIGH);
  digitalWrite(B, HIGH);

   OCR1A=value; 
  PCICR |= B00000100; // Activamos las interrupciones del puerto PD
  PCMSK2 |= B00010100;
  sei();
  TCNT1 = 0;
   TCCR1A = _BV(COM1B1) | _BV(WGM11);
  TCCR1B = _BV(CS10) | _BV(WGM12);
} 

void loop() 
{
  
  duty();
  
} 

ISR (PCINT2_vect) {
 int MSB = digitalRead(A); 
  int LSB = digitalRead(B);
 
  int encoded = (MSB << 1) |LSB;
  int sum  = (lastEncoded << 2) | encoded; 
 
  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011)
    value++;
   
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000)
    value--;
 
  lastEncoded = encoded; 
 
  if (value <= 0)
    value = 0;
  if (value >= 255)
    value = 255; 
  
  }
 

   void duty() {
 OCR1A = 255 - value;
 
}

después de estar 4 horas leyendo , así me funciono, todavía no comprendo bien como configurar los timer, pero asi me regula , no se si la frecuencia es correcta ya que uso la placa arduino uno el reloj es de 16.000 y ahora esta calculado en 8.000.000, necesito un tutorial para torpes.....



volatile int value;
volatile int lastEncoded = 0;
int A = 2;       //variable A a pin digital 2 (DT en modulo)
int B = 4;        //variable B a pin digital 4 (CLK en modulo)

void setup()   
{  
  pinMode(9,OUTPUT);              
  pinMode(A, INPUT);   // A como entrada
  pinMode(B, INPUT);    // B como entrada
  digitalWrite(A, HIGH);
  digitalWrite(B, HIGH);

 
 //Endable Interrupts for PCIE2 arduino Pins (D0-7) 
 PCICR |= (1<<PCIE2);
 //Setup pins 2,4
 PCMSK2 |= (1<<PCINT18);  
 PCMSK2 |= (1<<PCINT20);

 TCCR1A = _BV(COM1A1) | _BV(WGM11);
  TCCR1B = _BV(CS10) | _BV(WGM12) | _BV(WGM13) ;
  ICR1 = 73; // frequency = 8000000/73 = 109.589 kHz
 // OCR1A = 0; //0% Duty Cycle or Full Off.


   sei();
} 

void loop() 
{
  
  duty();
  
} 

ISR (PCINT2_vect) {
 int MSB = digitalRead(A); 
  int LSB = digitalRead(B);
 
  int encoded = (MSB << 1) |LSB;
  int sum  = (lastEncoded << 2) | encoded; 
 
  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011)
    value++;
   
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000)
    value--;
 
  lastEncoded = encoded; 
 
  if (value <= 0)
    value = 0;
  if (value >= 255)
    value = 255; 
  
  }
 

   void duty() {
 OCR1A = 255 - value;
 
}

trabajado con el timer 1 probando registros y modos, subo por si alguien le sirve!

 int duty= 50;
 int _freq = 100;
void setup() {
    DDRB |= (1<<DDB1);

  
  // modo ctc
  TCCR1A &=~ (1<<WGM10);
  TCCR1A |=  (1<<WGM11);
  TCCR1B |=  (1<<WGM12);
  TCCR1B |=  (1<<WGM13);
  
  TCCR1A &=~ (1<<COM1A0);
  TCCR1A |=  (1<<COM1A1);

  //1024
  TCCR1B |=  (1<<CS10);
  TCCR1B &=~ (1<<CS11);
  TCCR1B |=  (1<<CS12);
}

void loop() {
 ICR1 = (F_CPU/1024/_freq) - 1;
OCR1A = (((F_CPU/1024/_freq) - 1)*duty)/100;
}

Que es un PWM mayor para ti?

1 Like

Creo que quiso decir de mayor frecuencia.

Saludos

1 Like

Eso no es PWM mayor y de hecho PWM va de 0 a 100 jamás puede ser mayor.

Por otro lado, tiene lógica tu comentario @gatul pero como cuesta expresarse debidamente!!
@callecuatro1976 perdona que sea quisquilloso pero llevas muchos hilos y es importante explicar debidamente lo que se pretende, de lo contrario ocurre que por algo nadie te responde.

1 Like

Ojo que puedo estar equivocado pero como justamente lo único que podría ser distinto al resultado de analogWrite() es la frecuencia, deduje que se refiere a eso.

Saludos

1 Like

La alternativa cual es, ir de 0 a 200%?

1 Like

No, de 0 a 15V. :rofl:

1 Like

Si, quise decir de mayor frecuencia, es verdad hay que explicar mejor!

Este hilo tiene buena información.

Para entender como modificar los registros cualquier tutorial de Atmega328 te servirá.

Otra opción pero requiere trabajo es esta librería

Esta para el ATtiny85 tendrás que agregar una para el ATtiny84

Pero.... buscando se encuentra y acá este tutorial que es perfecto para tu caso

https://andreasrohner.at/posts/Electronics/How-to-set-the-PWM-frequency-for-the-Attiny84/

Como lo veo es muy parecido a como se hace en un ATmega328p

1 Like

TCCR1A &=~ (1<<WGM10);
TCCR1A |= (1<<WGM11);
TCCR1B |= (1<<WGM12);
TCCR1B |= (1<<WGM13);

con estas lineas configuras el modo pwm o captura.

y configurando con 1 o 0 estas lineas el pre escalador

TCCR1B |=  (1<<CS10);
  TCCR1B &=~ (1<<CS11);
  TCCR1B |=  (1<<CS12);

ahora no tengo bien claro que funcion tienen estas lineas de codigo?

TCCR1A &=~ (1<<COM1A0);
 TCCR1A |=  (1<<COM1A1);

esto es para el atmega328 lafrecuencia se calcula

fre

hola, ya casi esta terminado el proyecto, ahora tengo una duda y no se como resolverla, me gustaría mostrar el voltaje en un oled, eso lo logro con el adc, bien me gustaría hacerlo sin el adc, ósea tengo la variable value que mueve el pwm, va de 0 a 255, como haría el calculo para que una variable x sea 18.0 en la pantalla oled cuando value es 255 subo el codigo para que se vea y se entienda mejor.

#include "avr/interrupt.h"; 
#include <EEPROM.h>
#include <stdio.h>

#include <Wire.h>      // libreria para bus I2C
#include <Adafruit_GFX.h>   // libreria para pantallas graficas
#include <Adafruit_SSD1306.h>   // libreria para controlador SSD1306
 
#define ANCHO 128     // reemplaza ocurrencia de ANCHO por 128
#define ALTO 64       // reemplaza ocurrencia de ALTO por 64

#define OLED_RESET 4      // necesario por la libreria pero no usado
Adafruit_SSD1306 oled(ANCHO, ALTO, &Wire, OLED_RESET);  // crea objeto
volatile int value;
volatile int lastEncoded = 0;
int A = 2;       //variable A a pin digital 2 (DT en modulo)
int B = 4;        //variable B a pin digital 4 (CLK en modulo)
int m =8;
int cont;
float volt;
void setup()   
{  
  
    EEPROM.get(0, value); 
      Wire.begin();         // inicializa bus I2C
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C); // inicializa pantalla con direccion 0x3C 
  pinMode(9,OUTPUT);              
  pinMode(A, INPUT);   // A como entrada
  pinMode(B, INPUT);    // B como entrada
  digitalWrite(A, HIGH);
  digitalWrite(B, HIGH);
  pinMode(m,INPUT);
 
 //Endable Interrupts for PCIE2 arduino Pins (D0-7) 
 PCICR |= (1<<PCIE2);
 //Setup pins 2,4
 PCMSK2 |= (1<<PCINT18);  
 PCMSK2 |= (1<<PCINT20);

 TCCR1A = _BV(COM1A1) | _BV(WGM11);
  TCCR1B = _BV(CS10) | _BV(WGM12) | _BV(WGM13) ;
  ICR1 = 250; // frequency = 16000000/ = 64.000 kHz


   sei();
} 

void loop() 
{
  oled.clearDisplay();      // limpia pantalla
  oled.setTextColor(WHITE);   // establece color al unico disponible (pantalla monocromo)
  oled.setCursor(10, 20);     // ubica cursor en inicio de coordenadas 0,0
  oled.setTextSize(3);      // establece tamano de texto en 1
  oled.print(volt);  // escribe en pantalla el texto
  oled.display();     // muestra en pantalla todo lo establecido anteriormente
  energia();
  duty();
  voltimetro();
  
} 

ISR (PCINT2_vect) {
 int MSB = digitalRead(A); 
  int LSB = digitalRead(B);
 
  int encoded = (MSB << 1) |LSB;
  int sum  = (lastEncoded << 2) | encoded; 
 
  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011)
    value++;
   
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000)
    value--;
 
  lastEncoded = encoded; 
 
  if (value <= 0)
    value = 0;
  if (value >= 255)
    value = 255; 
  
  }
 

   void duty() {
 OCR1A = value;
 
}
void energia (){
if(digitalRead(m)==LOW){ 
cont++;
delay(3);
if (cont >5) {
 EEPROM.put(0,value);
delay(50);
cont = 0; 
}
}
} 
 void voltimetro(){
  volt=value;
  
  
  


Ahí subí las fotos para que se me entienda mejor, simular un voltimetro, con un contador ascendente y descendente de 0 a 5 volt o de 0 a 18 volt , ahí me trabe no se como hacerlo!

Usando una regla de 3 simple, haces

18 ------------- 255
1 ------------- 1 x 255/18 = 14.1666

Entonces cada paso tuyo sera de incrementos 255/18
Si tu X quieres que sea 15 entonces 15*255/18 = 212.5 que redondeando te da 212

Asi con cada situación.

1 Like

Si lo pensé, pero pude implementarlo bien, en la función,

void voltimetro(){
  volt=value;
x= map(volt, 0,255, 0,180);
  x=x/10.0;
  }

asi funciono, para sacar el ultimo digito y que quede 18.1 con esta linea oled.print(x,1) agregando el ,1