Skip to content

Instantly share code, notes, and snippets.

@fjrg76-com
Created January 23, 2023 20:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fjrg76-com/5f2428caebe719f69fd9baf1e1b9df28 to your computer and use it in GitHub Desktop.
Save fjrg76-com/5f2428caebe719f69fd9baf1e1b9df28 to your computer and use it in GitHub Desktop.
Digital dimmer with the Arduino UNO
/* Copyright (C)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* fjrg76 dot com
*/
/*
* Digital dimmer with the Arduino UNO.
*
* It works for 60Hz (due to some math calculations)
*
* For details visit my blog: fjrg76 dot com (be patient if you find the article in spanish;
* soon it will be available in english too).
*/
#define TIM_PRESCALER 7
#define SYNC_PIN 2
#define TRIAC_PIN 3
enum{ STOP, START };
bool led_state = false;
class PowerOutput
{
private:
uint8_t output{0};
bool ready{false};
public:
void read( uint8_t adc_channel )
{
this->output = analogRead( adc_channel ) / 8;
this->ready = true;
}
uint8_t get_output_val()
{
return this->output;
}
void apply()
{
if( this->ready )
{
this->ready = false;
// max power:
if( this->output < 2 )
{
OCR2B = 1;
}
// dim control:
else if( this->output < 127 )
{
OCR2B = this->output;
}
// off:
else
{
OCR2B = 200;
}
}
}
};
PowerOutput power;
void timer_ctrl( int new_state )
{
if( new_state == STOP )
{
TCCR2A = 0;
TCCR2B = 0;
TCNT2 = 0;
}
else
{
TCNT2 = 0;
TCCR2B = (1<<3) | (TIM_PRESCALER<<0);
TCCR2A = (3<<4) | (3<<0);
}
}
void Sync_ISR()
{
timer_ctrl( STOP );
power.apply();
digitalWrite( 13, (led_state=led_state?false:true) );
timer_ctrl( START );
}
void setup()
{
TCCR2A =
(3<<4) // COM2B1:0=0x3 -- Set OC2B on compare match
| (3<<0); // WGM21:0 =0x3 -- Fast PWM (along with WGM22 on TCCR2B)
TCCR2B = (1<<3); // WGM22 =0x1 -- Fast PWM (along with WGM21:0 on TCCR2A)
// Start / stop is performed in another rutine. For start counting we would do:
// TCCR2B = (1<<3)
// | (7<<0); // CS22:CS2:0 -- Choose CLK / 1024
TCNT2 = 0; // Counter.
OCR2A = 128; // Period. There will be 128 counts on one AC's semicycle
OCR2B = 127; // Duty cycle. 1 -> 100% power, 127 -> 0% power. It starts at 0% (off)
TIMSK2 = 0; // Don't use any interrupt from the timer
TIFR2 = 0;
pinMode( TRIAC_PIN, OUTPUT );
digitalWrite( TRIAC_PIN, LOW );
pinMode( SYNC_PIN, INPUT_PULLUP );
attachInterrupt( digitalPinToInterrupt( SYNC_PIN ), Sync_ISR, RISING );
pinMode( 13, OUTPUT );
Serial.begin( 230400 );
timer_ctrl( START );
}
#define SYSTEM_TICK 100
void loop()
{
delay( SYSTEM_TICK );
power.read( A0 );
// Serial.println( power.get_output_val() );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment