Hi everyone, I found the following code here ATTiny85 3 channel software PWM to drive RGB LED · GitHub (It's for ATTiny85 3 channel software PWM to drive RGB LED)
I tried it in the ATtiny85. It works. But I want to add a sensor through the analogRead, Unfortunately it isn't WORK. =( Whether the sofeware PWM and analogread not be used simultaneously?
Could someone can help me to give some advice? Thanks.
// based largely on Atmel's AVR136: Low-Jitter Multi-Channel Software PWM Application Note:
// http://www.atmel.com/dyn/resources/prod_documents/doc8020.pdf
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define CHMAX 3 // maximum number of PWM channels
#define PWMDEFAULT 0x00 // default PWM value at start up for all channels
#define RED_CLEAR (pinlevelB &= ~(1 << RED)) // map RED to PB0
#define GREEN_CLEAR (pinlevelB &= ~(1 << GREEN)) // map GREEN to PB1
#define BLUE_CLEAR (pinlevelB &= ~(1 << BLUE)) // map BLUE to PB2
//! Set bits corresponding to pin usage above
#define PORTB_MASK (1 << PB0)|(1 << PB1)|(1 << PB2)
#define set(x) |= (1<<x)
#define clr(x) &=~(1<<x)
#define inv(x) ^=(1<<x)
#define RED PB0
#define GREEN PB1
#define BLUE PB2
#define LED_PORT PORTB
#define LED_DDR DDRB
#define SENSOR_PIN 2
void delay_ms(uint16_t ms);
void init();
unsigned char compare[CHMAX];
volatile unsigned char compbuff[CHMAX];
int r_val = 0x00;
int g_val = 0x55;
int b_val = 0xAA;
float dim = 1;
void setup()
{
pinMode( SENSOR_PIN, INPUT );
}
void loop()
{
init();
int const rawVal = analogRead( SENSOR_PIN ); // It isn't works!
int r_dir = 1;
int g_dir = 2;
int b_dir = 4;
for(;;) {
if (r_val > 254 - 1) {
r_dir = -1;
}
if (r_val < 1 + 1) {
r_dir = 1;
}
if (g_val > 254 - 3) {
g_dir = -2;
}
if (g_val < 1 + 3) {
g_dir = 2;
}
if (b_val > 254 - 4) {
b_dir = -4;
}
if (b_val < 1 + 4) {
b_dir = 4;
}
r_val += r_dir;
g_val += g_dir;
b_val += b_dir;
compbuff[0] = r_val;
compbuff[1] = g_val;
compbuff[2] = b_val;
delay_ms(50);
}
}
void delay_ms(uint16_t ms) {
while (ms) {
_delay_ms(1);
ms--;
}
}
void init(void) {
// set the direction of the ports
LED_DDR set(RED);
LED_DDR set(GREEN);
LED_DDR set(BLUE);
unsigned char i, pwm;
CLKPR = (1 << CLKPCE); // enable clock prescaler update
CLKPR = 0; // set clock to maximum (= crystal)
pwm = PWMDEFAULT;
// initialise all channels
for(i=0 ; i<CHMAX ; i++) {
compare[i] = pwm; // set default PWM values
compbuff[i] = pwm; // set default PWM values
}
TIFR = (1 << TOV0); // clear interrupt flag
TIMSK = (1 << TOIE0); // enable overflow interrupt
TCCR0B = (1 << CS00); // start timer, no prescale
sei();
}
ISR (TIM0_OVF_vect) {
static unsigned char pinlevelB=PORTB_MASK;
static unsigned char softcount=0xFF;
PORTB = pinlevelB; // update outputs
if(++softcount == 0){ // increment modulo 256 counter and update
// the compare values only when counter = 0.
compare[0] = compbuff[0]; // verbose code for speed
compare[1] = compbuff[1];
compare[2] = compbuff[2];
pinlevelB = PORTB_MASK; // set all port pins high
}
// clear port pin on compare match (executed on next interrupt)
if(compare[0] == softcount) RED_CLEAR;
if(compare[1] == softcount) GREEN_CLEAR;
if(compare[2] == softcount) BLUE_CLEAR;
}
merrywhale:
Hi everyone, I found the following code here ATTiny85 3 channel software PWM to drive RGB LED · GitHub (It's for ATTiny85 3 channel software PWM to drive RGB LED)
I tried it in the ATtiny85. It works. But I want to add a sensor through the analogRead, Unfortunately it isn't WORK. =( Whether the sofeware PWM and analogread not be used simultaneously?
Could someone can help me to give some advice? Thanks.
#define RED PB0
#define GREEN PB1 #define BLUE PB2 #define LED_PORT PORTB #define LED_DDR DDRB
#define SENSOR_PIN 2
Pin 2 is used for an LED, you can't use it for SENSOR_PIN.
You are using PB0,1,2 for your LED. ADC0 is shared with the reset pin, which you probably want to keep as reset so you can program via ICSP. ADC1 is shared with the PB2 pin. So that leaves ADC2 and ADC3 free for your sensor, assuming you are using the internal clock.
However, if you connect RED to PB4 instead, then you will have hardware PWM on all 3 LED pins, You can then use ADC1 for the sensor.
I plan to make a light with three rgb fade and thermistor control. This 3 rgb not just blink and it must smoothly fades from red to green to blue. But Attiny85 only have 2 PWM. That's why I need 3 software PWM and an analog input for the thermistor. :~
merrywhale:
But Attiny85 only have 2 PWM. That's why I need 3 software PWM and an analog input for the thermistor. :~
No, the ATtiny 25/45/85 have four independent timer/counter registers (OC0A, OC0B, OC1A, OC1B) that can be used for PWM. However, OC0B and OC1A share the same pin, so in practice you can have 3 PWM pins.
merrywhale:
Thanks dc42, Based on your reply I can used pin0, pin1 and pin4 for PWM, And pin2 for analog input. But the pin4 can't used analogWrite(4,0-255).
Oh, now I have a new problem. =( I want to monitor the value of the thermistor through SoftwareSerial. It will render with garbled text like this "€€€€€€€€€€€". Am I doing something wrong? Or SoftwareSerial can not be used in Attiny85? If yes, how do I do?
merrywhale:
Or SoftwareSerial can not be used in Attiny85?
SoftwareSerial will not work well for your application: three pins for PWM and one pin for analogRead means there is one pin remaining. SoftwareSerial needs two.
The other problem with using SoftwareSerial on an ATtiny is that the clock needs to be accurate to within about 2%, which may not be the case when you are using the internal oscillator, unless you calibrate it using the OSCCAL register. This is another reason to use Knock-Bang or a self-clocking protocol instead of regular serial.