Modulación de ancho de pulso (PWM) en AVR Studio
Pregunta
Estoy tratando de usar PWM para un LED en un ATMEGA8, cualquier PIN de Puerto B. Configuración de los temporizadores ha sido molesto, y no sé qué hacer con mi OCR1A.Aquí está mi código, y me encantaría algunos comentarios.
Solo estoy tratando de averiguar cómo usar PWM.Sé el concepto, y se supone que OCR1A es la fracción de todo el tiempo que quiero el pulso.
#define F_CPU 1000000 // 1 MHz
#include <avr/io.h>
#include <avr/delay.h>
#include <avr/interrupt.h>
int main(void){
TCCR1A |= (1 << CS10) | (1 << CS12) | (1 << CS11);
OCR1A = 0x0000;
TCCR1A |= ( 0 << WGM11 ) | ( 1 << WGM10 ) | (WGM12 << 1) | (WGM13 << 0);
TCCR1A |= ( 1 << COM1A0 ) | ( 0 << COM1A1 );
TIMSK |= (1 << TOIE1); // Enable timer interrupt
DDRB = 0xFF;
sei(); // Enable global interrupts
PORTB = 0b00000000;
while(1)
{
OCR1A = 0x00FF; //I'm trying to get the timer to alternate being on for 100% of the time,
_delay_ms(200);
OCR1A = 0x0066; // Then 50%
_delay_ms(200);
OCR1A = 0x0000; // Then 0%
_delay_ms(200);
}
}
ISR (TIMER1_COMA_vect) // timer0 overflow interrupt
{
PORTB =~ PORTB;
}
Solución 2
Debe inicializar su OCR1A con estas dos líneas:
TCCR1A = (1 << WGM10) | (1 << COM1A1);
TCCR1B = (1 << CS10) | (1 << WGM12);
y luego use esto:
OCR1A = in
y saber que el rango es 0-255.Cuenta tus porcentajes, ¡y ahí lo tienes!
#define F_CPU 1000000 // 1 MHz
#include <avr/io.h>
#include <avr/delay.h>
#include <avr/interrupt.h>
int main(void){
TCCR1A = (1 << WGM10) | (1 << COM1A1);
TCCR1B = (1 << CS10) | (1 << WGM12);
DDRB = 0xFF;
sei(); // Enable global interrupts
PORTB = 0b00000000;
while(1)
{
OCR1A = 255;
_delay_ms(200);
OCR1A = 125;
_delay_ms(200);
OCR1A = 0;
_delay_ms(200);
}
}
Otros consejos
No, esto es no de la forma en que debe hacer un pwm. Por ejemplo, ¿cómo establece una tasa de PWM, por ejemplo, 42% con ella? Además, el tamaño del código es grande, se puede hacer de una manera mucho más eficiente. Además, desperdicias un temporizador de 16 bits para hacer operaciones de 8 bits. Tiene 2 veces temporizadores de 8 bits (temporizador / contador 0 y 2), y un temporizador de 16 bits, Timer/Counter 1
.
También es una mala idea establecer los portadores no utilizados para que salgan. Todos los portadores que no están conectados a nada, deben dejarse como entradas.
El ATMEGA8 tiene un generador PWM incorporado en los temporizadores 1 y 2, no hay necesidad de simularlo a través del software. Ni siquiera tiene que configurar sus puertos manualmente (solo tiene que configurar el portpin correspondiente a la salida)
Ni siquiera necesitas ninguna interrupción.
#define fillrate OCR2A
//...
// main()
PORTB=0x00;
DDRB=0x08; //We use PORTB.3 as output, for OC2A, see the atmega8 reference manual
// Mode: Phase correct PWM top=0xFF
// OC2A output: Non-Inverted PWM
TCCR2A=0x81;
// Set the speed here, it will depend on your clock rate.
TCCR2B=0x02;
// for example, this will alternate between 75% and 42% PWM
while(1)
{
fillrate = 191; // ca. 75% PWM
delay_ms(2000);
fillrate = 107; // ca. 42% PWM
delay_ms(2000);
}
Tenga en cuenta que puede usar otro LED con otro PWM, usando el mismo temporizador y configurando OCR2B en lugar de OCR2A. No se olvide de establecer TCCR2A para habilitar OCR2B como salida para su PWM, como en este ejemplo, solo se permite OCR2A.