Code Monkey home page Code Monkey logo

triacdimmer's Introduction

TriacDimmer

The high-performance arduino triac dimming library.

This library was designed to perform phase-control dimming control on a triac dimming circuit, leveraging the ATmega328p's built-in timer peripheral to perform all time-critical functionality directly in hardware, without the need to spend CPU time on an expensive control loop.

Note that this library is intended to control mains AC power. Make sure you understand the risks and take appropriate precautions before working with mains AC.

The phase offsets are calculated based on the measured mains frequency, so this code will work regardless of 50/60Hz or any other frequency. This includes correcting for any inaccuracies in the arduino's oscillator or the mains frequency.

This library was developed specifically for the Krida 2 CH Dimmer (amazon, alibaba, inmojo), and has been tested to work with the RobotDyn AC Dimmer (robotdyn), and should work fine with other phase-control dimming circuits that output a positive edge on their sync signal.

See the example for an example of how to use the library. The library methods themselves are documented in the library header.

This library requires the use of certain pins. Pin 8 must be used as the sync input, and pins 9 and 10 are the only pins that can be used as channel outputs. This library will not work on any other pins, period.

fritzing diagram

Flickering, and How to Fix It

If you experience issues with flickering, there are a handful of parameters you can pass to begin that can be adjusted depending on what sort of flickering you have. By default, with no arguments the library uses these values as defaults:

TriacDimmer::begin(pulse_length = 20, min_trigger = 2000, on_thresh = 2, off_thresh = 0.01)

First off, if you experience flickering regardless of the brightness value you set, increase pulse_length from the default 20 to a larger value like 50 or 100 until TriacDimmer::setBrightness(pin, 0.5); results in a stable glow.

Once it's stable at 0.5, set the brightness 1.0 (TriacDimmer::setBrightness(pin, 1.0);) and check for flickering. There shouldn't be any, but if there is you can increase min_trigger from the default 2000 to perhaps 3000 or 4000 until the flickering stops. If you're still experiencing flickering no matter how large min_trigger is, you can also try setting on_thresh to below the highest brightness level that causes flickering. This shouldn't normally be necessary though, as adjusting min_trigger should normally be enough.

The last step is to figure out the lowest brightness value can sustain without flickering. By default the library is set to cut off completely for brightness values smaller than 0.01, but if you still see flickering at 0.015 or 0.02 you can try setting off_thresh to a value that's larger than that.

If you've tried all of these steps and you still get flickering, consider opening an issue. Make sure to include as much information about your setup as you can, including the specific dimmer board you're using. Also, if you have access to an oscilliscope, screenshots are always helpful in trying to diagnose flickering.

triacdimmer's People

Contributors

ajmansfield avatar nsummy avatar per1234 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

triacdimmer's Issues

external interrupt for zero crossing?

What is the advantage of using timer capture over external interrupt? I made this and then I discovered your library and I try to understand.

const byte TRIAC_PIN = 9;
const byte ZC_EI_PIN = 2;

unsigned long topMicroseconds = 9700; // 10000 micros is between zero crossings
int prescaler = 8;
byte prescalerBits = _BV(CS11); // /8

void zeroCrossing() {
  TCNT1 = 0; // reset the timer counter
}

void setup() {
  Serial.begin(115200);
  Serial.println("START");

  attachInterrupt(digitalPinToInterrupt(ZC_EI_PIN), zeroCrossing, RISING);

  pinMode(TRIAC_PIN, OUTPUT);
  uint32_t topPeriod = ((F_CPU / 1000000)* topMicroseconds) / prescaler ;
  ICR1 = topPeriod;
  OCR1A = topPeriod + 1;
  TCCR1A = _BV(WGM11) | _BV(COM1A0) | _BV(COM1A1);
  TCCR1B = _BV(WGM13) | _BV(WGM12) | prescalerBits;
}

void loop() {
  if (Serial.available()) {
    unsigned long microseconds = Serial.parseInt();
    Serial.find("\n");
    uint32_t period = ((F_CPU / 1000000)* microseconds) / prescaler ;
    OCR1A = period;
  }
}

I use Robotdyn Dimmer

Support for more chips/boards.

This library at present only supports 16MHz ATMega 328p boards like the arduino uno, and only on timer/counter 1, but in theory the exact same code could support a much wider range of cpus that have the same peripheral available.

Investigate waveform asymmetry.

In cases where either:

  • the mains voltage source used for an application has a significant DC component,
  • the zero-crossing detector is biased (i.e. emits its pulse earlier on a positive-to-negative transition than a negative-to-positive transition), OR
  • the triac and/or triac driver circuitry used to switch the output is biased (i.e. the triac switches on more quickly in one direction than in the other)

It's possible that better performance and higher accuracy could be achieved by treating alternating half-waves independently from a timing perspective.

As an extreme example, take this:
waveform

A reasonably simple solution would be to split all current timing variables into two separate variables, corresponding to the separate positive and negative periods. This would involve some overhead from needing to track the alternating phase and index.
This would eliminate any asymmetry caused by a DC offset.

The other two asymmetry modes would require adding an additional half-wave offset configuration parameter that describes the asymmetry caused by the zero crossing detector and triac characteristics.
We would also need some way to synchronize with the correct half of the phase to ensure the offset is applied in the correct direction on every power-up. Assuming some of the asymmetry is caused by the zero-crossing detector, this could potentially be determined purely based on which half of the phase is longer, but if that is not the case this will require additional input circuitry and another input pin to read the phase directly.

Note that at present these issues are purely conjectural possibilities. Before trying to remedy this hypothetical problem, we need to take actual measurements on actual hardware to assess how significant these actually are.
We also need to assess whether this edge case is significant enough to be worth the performance penalty a fix would incur against the general case.

wavedrom source for image:

{signal: [
  {name: 'mains', wave: 'du.d...u.d.'},
  {name: 'zero',  wave: 'lPlPl..PlPl',
                  node: '.A.C...E...'},
  {               node: '.B.D...F...'},
  {               node: '...IH..L.K.'},
  {name: 'triac', wave: 'l...Pl...Pl',
                  node: '....GM..OJ.'},
  {               node: '.....N..P..'},
],
edge: [
  'A-B', 'C-D', 'B<->D t1',
  'C-D', 'E-F', 'D<->F t2',
  'C-I', 'G-H', 'I<->H 50% t1',
  'E-L', 'J-K', 'L<->K 50% t2',
  'N->M', 'N should be here',
  'P->O', 'P should be here'
],
config: {
  hscale: 2
}}

Allow using only a single channel.

Split from #11.

Credit to @JAndrassy for his suggestion:

Additionally I use pin 10 as slave select for Ethernet shield and your library doesn't have an option to use only one pin of Timer1.

The library ought to be able to be configured to use only one of the two channels and leave the other free for other uses.

doesn't work with Robotdyn AC Dimmer

With Robotdyn AC Dimmer (schematics) and basic_example.ino the light is full on and sometimes flickers.
I test with Arduino Nano.
I added some debug prints in ISR(TIMER1_CAPT_vect) after last_icr = ICR1:

  Serial.print(micros());
  Serial.print("\t");
  Serial.print(last_icr);
  Serial.print("\t");
  Serial.println(TriacDimmer::detail::period);

output is

1408	2793	2793
11420	22824	20031
12168	22824	0
21440	42855	20031
31460	62905	20050
32208	62905	0
40448	17381	20012
50464	37423	20042
51212	37423	0
60476	57439	20016
70500	11952	20049
80512	31984	20032
81260	31984	0
90540	52027	20043

sorry I rewrote this issue twice until I debugged the problem.
the problem is, there are some phantom zero crossings resulting in period 0 and brightness is calculated with this value

Warning in pin comparison

/home/anson/Arduino/libraries/TriacDimmer/src/TriacDimmer.cpp:48:10: warning: suggest parentheses around comparison in operand of '&' [-Wparentheses]
  if (pin & 0x01 == 0x01){ // if (pin == 9){

Use with potentiometer?

Hi, I am attempting to use this with a potentiometer and am not able to get it to work at all. I realize its looking for a floating point value between 0 and 1. Is there a good way to set this up? Or a simple way to modify the source to use an integer input? Unfortunately I am still learning to code, so while I understand the problem, I am not sure of the solution. Thanks :)

Use with boards with >2 channels

I can see that there are a limitation for controlling only 2 channels.

Is it possible to adapt this library to control boards with >2 channels, for example Krida 8CH Dimmer board?

If yes, could someone point me to the direction what needs to be updated in code and what are the challenges?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.