Sto cercando di creare una luce LED RGB con telecomando usando un ATtiny13A.
So che ATtiny85 è più adatto a questo scopo e so che alla fine potrei non essere in grado di adattare l'intero codice, ma per ora la mia preoccupazione principale è generare un PWM software usando gli interrupt in modalità CTC.
Non posso operare in qualsiasi altra modalità (ad eccezione di PWM veloce con OCR0A
quanto TOP
che è fondamentalmente la stessa cosa) perché il codice ricevitore IR sto usando ha bisogno di una frequenza di 38 kHz, che genera con CTC e OCR0A=122
.
Quindi sto cercando di (e ho visto persone menzionarlo su Internet) usare gli interrupt Output Compare A
e Output Compare B
per generare un software PWM.
OCR0A
, che viene utilizzato anche dal codice IR, determina la frequenza, che non mi interessa. E OCR0B
determina il duty cycle del PWM che userò per cambiare i colori dei LED.
Mi aspetto di poter ottenere un PWM con duty cycle 0-100% modificando il OCR0B
valore da 0
a OCR0A
. Questa è la mia comprensione di ciò che dovrebbe accadere:
Ma ciò che sta realmente accadendo è questo (questo è dalla simulazione ISIS di Proteus):
Come puoi vedere di seguito, sono in grado di ottenere circa il 25% -75% di duty cycle ma per ~ 0-25% e ~ 75-100% la forma d'onda è bloccata e non cambia.
Linea GIALLA: Hardware PWM
Linea ROSSA: software PWM con ciclo di lavoro fisso
Linea VERDE: software PWM con ciclo di lavoro variabile
Ed ecco il mio codice:
#ifndef F_CPU
#define F_CPU (9600000UL) // 9.6 MHz
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
int main(void)
{
cli();
TCCR0A = 0x00; // Init to zero
TCCR0B = 0x00;
TCCR0A |= (1<<WGM01); // CTC mode
TCCR0A |= (1<<COM0A0); // Toggle OC0A on compare match (50% PWM on PINB0)
// => YELLOW line on oscilloscope
TIMSK0 |= (1<<OCIE0A) | (1<<OCIE0B); // Compare match A and compare match B interrupt enabled
TCCR0B |= (1<<CS00); // Prescalar 1
sei();
DDRB = 0xFF; // All ports output
while (1)
{
OCR0A = 122; // This is the value I'll be using in my main program
for(int i=0; i<OCR0A; i++)
{
OCR0B = i; // Should change the duty cycle
_delay_ms(2);
}
}
}
ISR(TIM0_COMPA_vect){
PORTB ^= (1<<PINB3); // Toggle PINB3 on compare match (50% <SOFTWARE> PWM on PINB3)
// =>RED line on oscilloscope
PORTB &= ~(1<<PINB4); // PINB4 LOW
// =>GREEN line on oscilloscope
}
ISR(TIM0_COMPB_vect){
PORTB |= (1<<PINB4); // PINB4 HIGH
}
OCR0A
viene utilizzato dal codice IR, quindi ho solo OCR0B
. Sto cercando di usarlo per generare software PWM su 3 pin non PWM.