Solved (Sorta) - Controlling Lutron Maestro dimmer only works 30% of the time

Hi, found the below code and attempted to apply it. I contacted Lutron and they sent me the following specs:
IR carrier Frequency 40.0 kHz
Duty Cycle 40%
Baud Rate 437 bps
Bit on time 10 usec, off time 15 usec

When I run the scrip the up command is processed about 30% of the time. So I assume much of the code is correct, but the processing by the dimmer is inconsistent. I suspect perhaps the baud rate but not sure how to set it or perhaps the duty cycle. I changed the pulse width from 2300 to 2200 and processing improved about 15%. Any other thoughts on how to proceed etc?
Thanks in advance
_Ernie

/* Control a Lutron Maestro light dimmer */
#define BIT_IS_SET(i, bits) (1 << i & bits)
// LED connected to digital pin 4
const int LED_PIN = 4;
// Width of a pulse, in microseconds 2200 is better than 2300
const int PULSE_WIDTH = 2200;
// # of bytes per command
const int COMMAND_LENGTH = 4;

const int UP[] = {255, 136, 130, 34};
const int DOWN[] = {255, 136, 130, 20};
const int ON[] = {255, 136, 132, 184};
const int OFF[] = {255, 136, 189, 18};
const int RECALL[] = {255, 136, 132, 183};

void setup()
{
pinMode(LED_PIN, OUTPUT);
}

/* Modulate pin at 39 kHz for give number of microseconds */
void on(int pin, int time) {
static const int period = 25;
// found wait_time by measuring with oscilloscope
static const int wait_time = 9;

for (time = time/period; time > 0; time--) {
digitalWrite(pin, HIGH);
delayMicroseconds(wait_time);
digitalWrite(pin, LOW);
delayMicroseconds(wait_time);
}
}

/* Leave pin off for time (given in microseconds) */
void off(int pin, int time) {
digitalWrite(pin, LOW);
delayMicroseconds(time);
}

/* Send a byte over the IR LED */
void send_byte(int bits) {
for (int i = 7; i >= 0; i--)
{
if (BIT_IS_SET(i, bits)) {
on(LED_PIN, PULSE_WIDTH);
} else {
off(LED_PIN, PULSE_WIDTH);
}
}
}

/* Send a full command /
void command(const int bytes[]) {
for (int i = 0; i < COMMAND_LENGTH; i++) {
send_byte(bytes
);*

  • }*
    off(LED_PIN, 4 * PULSE_WIDTH);
    }
    void loop()
    {
  • command(UP);*
  • delay(2000);*
    }
/* Send a full command */
void command( const int bytes[] ) 
{ for (int i = 0; i < COMMAND_LENGTH; i++) 
  {  send_byte(bytes);                                        <-----  bytes[i]  ???
  }
  off(LED_PIN, 4 * PULSE_WIDTH);
}

Do you have a scope/ logic analyser to take a peek at the signal ?.

This document might be good reference:
www.lutron.com/TechnicalDocumentLibrary/048158.doc

The timer 0 interrupt will be interfering with your timing. You need to:

  1. Stop generating the 40kHz by bit toggling and use one of the timers to generate it instead.

  2. For the PULSE_WIDTH delay, don't use delayMicroseconds, instead sit in a loop calling micros() until the required time since the start of the byte has elapsed.

Here is code I use to generate a fixed frequency on pin 9 of a Uno:

// Generate a square wave of a given frequency on the OCR1A pin

#define REQUIRED_FREQUENCY  (38000)
#define REQUIRED_DIVISOR ((F_CPU/REQUIRED_FREQUENCY)/2)

#if (REQUIRED_DIVISOR < 65536)
# define PRESCALER  (1)
# define PRESCALER_BITS  (1)
#elif (REQUIRED_DIVISOR < 8 * 65536)
# define PRESCALER  (8)
# define PRESCALER_BITS  (2)
#elif (REQUIRED_DIVISOR < 64 * 65536)
# define PRESCALER  (64)
# define PRESCALER_BITS  (3)
#elif (REQUIRED_DIVISOR < 256 * 65536)
# define PRESCALER  (256)
# define PRESCALER_BITS  (4)
#elif (REQUIRED_DIVISOR < 1024 * 65536)
# define PRESCALER  (1024)
# define PRESCALER_BITS  (5)
#else
# error Bad frequency
#endif

# define TOP        (((REQUIRED_DIVISOR + (PRESCALER/2))/PRESCALER) - 1)

void setup()
{
  pinMode(9, OUTPUT);
  digitalWrite(9, LOW);
  TCCR1A = 0;
  TCCR1B = (1 << WGM12) | PRESCALER_BITS;
  TCCR1C = 0;
  OCR1AH = (TOP >> 8);
  OCR1AL = (TOP & 0xFF);
}

void on()
{
  TCNT1H = 0;
  TCNT1L = 0;  
  TCCR1A = (1 << COM1A0);
}

void off()
{
  TCCR1A = 0;
}

void loop()
{
  // Generate a burst 2ms long, then wait 10ms before generating the next one
  on();
  delay(2);  
  off();
  delay(10);
}

Would it be possible to use the folowing while the IR bits are being send ?.
To disable interrupts: cli(); // disable global interrupts
and to enable them: sei(); // enable interrupts
Note that the millis timer, and serial communication will be affected by disabling interrupts. The delayMicroseconds() function disables interrupts while it is running.

Thanks I'll try these ideas tonight or tomorrow.
_Ernie

Problem solved - sorta. I gave up trying to send the proper codes with the proper carrier frequency, instead I hacked the Lutron remote. Connected two small wires, one to its ground and the other to the up tracings. I then short the two wires via an optocoupler (4n28) and fire it from the UNO. Works perfectly every time.
_Ernie