Created
January 23, 2023 20:24
-
-
Save fjrg76-com/5f2428caebe719f69fd9baf1e1b9df28 to your computer and use it in GitHub Desktop.
Digital dimmer with the Arduino UNO
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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