Hello, I am trying to control a Hifi receiver via IR and am running into some problems. As the hardware part is trivial (I'm using just a a TSSP4400 LED on my LED pin), I am asing here, though I cannot rule out hardware issues (switching speed?). I am using an Arduino Ethernet Board.
The code below uses the same parameters as lirc config files. (However, I am not completely sure that I interpret them right, so that might be an issue.)
The generated signal is generally recognized by my IR Toy v2 (i.e. the LED is blinking on the toy, so it is basically 38kHz), but the output from IRGraph (from WinLIRC) is shit and it does not work on the receiver (of course). For real commands, no consistent signal is recognized by IRGraph.
Even a sendElement(HEADER) does not output
-------________ as I expected, but somthing like
----------____ or even
----_-----____
I am quite at the beginning of Arduino and stuff, so any advice is appreciated.
#define BIT_IS_SET(i, bits) (1 << i & bits)
// LED connected to LED pin (13 for Uno, 9 for Arduino Ethernet)
const int LED_PIN = 9;
// Width of a pulse, in microseconds
const unsigned int FREQUENCY = 38;
// {pulse time, space time}, checked this via IRGraph on the remote.
const int HEADER[] = {8500,4250};
const int ONE[] = {500,1500};
const int ZERO[] = {500,500};
const int TRAIL[] = {500,0}; //{ptrail,0}
// # of bytes per command
const int BITS = 16;
const int PRE_DATA_BITS = 16;
//PRE_DATA is prepended to every command, no delay between
const unsigned int PRE_DATA = 0xA55A;
//Command
const unsigned int ON = 0x38C7;
const unsigned int OFF = ON;
const unsigned int VOLUME_UP = 0x50AF;
const unsigned int VOLUME_DOWN = 0xD02F;
const int TESTPULSE[] = {1000,0};
void setup()
{
pinMode(LED_PIN, OUTPUT);
Serial.begin(9600);
}
//Send a single pulse/space combination modulated with FREQUENCY
void sendElement(const int times[])
{
static const int PERIOD = 1000/FREQUENCY;
for (int periods = times[0]/PERIOD; periods > 0; periods--) {
digitalWrite(LED_PIN, HIGH);
delayMicroseconds(PERIOD/2);
digitalWrite(LED_PIN, LOW);
delayMicroseconds(PERIOD/2);
}
delayMicroseconds(times[2]);
}
//Sends a signal
void sendSignal(const unsigned int signal, const int bits) {
for (int i = bits; i >= 0; i--)
{
if (BIT_IS_SET(i, signal)) {
sendElement(ONE);
} else {
sendElement(ZERO);
}
}
}
//Sends a full command with HEADER, PRE_DATA, command and TRAIL
void command(const unsigned int command) {
sendElement(HEADER);
sendSignal(PRE_DATA,PRE_DATA_BITS);
sendSignal(command,BITS);
sendElement(TRAIL);
}
void loop()
{
command(VOLUME_UP);
delay(1000);
command(VOLUME_DOWN);
delay(1000);
//sendElement(TESTPULSE);
}
//Send a single pulse/space combination modulated with FREQUENCY
void sendElement(const int times[])
{
static const int PERIOD = 1000/FREQUENCY;
for (int periods = times[0]/PERIOD; periods > 0; periods--) {
digitalWrite(LED_PIN, HIGH);
delayMicroseconds(PERIOD/2);
digitalWrite(LED_PIN, LOW);
delayMicroseconds(PERIOD/2);
}
delayMicroseconds(times[1]); //<<<<<<<<<<<<<<<<<<<<<<<<
}
Still doesn't work, but gives recognizable signal.
Working code (just some minor errors in the previous version):
#define BIT_IS_SET(i, bits) (1 << i & bits)
// LED connected to LED pin (13 for Uno, 9 for Arduino Ethernet)
const int LED_PIN = 9;
// Width of a pulse, in microseconds
const unsigned int FREQUENCY = 38;
const int HEADER[] = {8500,4250};
const int ONE[] = {500,1500};
const int ZERO[] = {500,500};
const int TRAIL[] = {500,0}; //{ptrail,0}
// # of bytes per command
const int BITS = 16;
const int PRE_DATA_BITS = 16;
const unsigned int PRE_DATA = 0xA55A;
const unsigned int ON = 0x38C7;
const unsigned int OFF = ON;
const unsigned int VOLUME_UP = 0x50AF;
const unsigned int VOLUME_DOWN = 0xD02F;
const int TESTPULSE[] = {500,500};
unsigned long time_tmp = 1;
void setup()
{
pinMode(LED_PIN, OUTPUT);
Serial.begin(9600);
}
void sendElement(const int times[])
{
static const int PERIOD = 1000/FREQUENCY;
static const int WAIT_TIME = PERIOD/2-3; // Due to other operations taking time, WAIT_TIME is shorter than PERIOD/2. Value obtained through testing with IR Toy.
for (int periods = times[0]/PERIOD; periods > 0; periods--) {
digitalWrite(LED_PIN, HIGH);
delayMicroseconds(WAIT_TIME); //Due to the fact that
digitalWrite(LED_PIN, LOW);
delayMicroseconds(WAIT_TIME);
}
delayMicroseconds(times[1]);
}
void sendSignal(const unsigned int signal, const int bits) {
for (int i = bits-1; i >= 0; i--)
{
if (BIT_IS_SET(i, signal)) {
sendElement(ONE);
} else {
sendElement(ZERO);
}
}
}
void command(const unsigned int command) {
sendElement(HEADER);
sendSignal(PRE_DATA,PRE_DATA_BITS);
sendSignal(command,BITS);
sendElement(TRAIL);
}
void loop()
{
delay(1000);
command(VOLUME_DOWN);
delay(1000);
command(VOLUME_UP);
}
This stuff is actually fairly hard, certainly not easy. You have modulation with your signal over it. You need some way to see what is being generated as well as an understanding of the encoding.
It sounds like you don't actually have anything working but occasionally an LED blinks which may mean the code is being decoded right.
Two things that could help are looking at the signal and using a library (like Ken's). These are both challenging and you will learn a great deal. So I am suggesting Ken's library again. You can start straight with the library and do the visualization after.
With Ken's library, guess at the common protocols with your device. Right a sketch to receive. Aim you remote and see if it works. Work through the common protocols until you find one that works. This will also tell you the key mapping, like what key is generated when you press stop. Then you write a sketch using the library to send the signals. (If you done have an IR receiver, you can just try sending signals.)
Ken's site has lots of info on IR and you can look at the protocols.
Another thing you can do is look at the signal from your remote control. There are sketches posted on this site for this: Arduino Playground - InfraredReceivers
. This will record a bunch of levels that would then have to be plotted. Once plotted, you can figure out the encoding. THis requires reading about the common formats. There are links on Ken's site. This step is fairly hard.
Plotting the IR output of your code would be a good way to debug your code. But it is probably better to start with the library. You will learn a lot by using it which will help you with your own code.
Hello Andy, thanks for the reply, but with "working code" I meant: it's working. As on the one hand, there are a lot of questions on this topic around here that got no satisfying answer in my opinion, and on the other hand I am still eager to learn if I did it basically right, if there are severe mothods of improvement and if it doesn't just work by luck, I am goning to comment on some of your points:
This stuff is actually fairly hard, certainly not easy. You have modulation with your signal over it. You need some way to see what is being generated as well as an understanding of the encoding.
I have based this code on LIRC config files, so I just have to understand how they are build, which is faily easy. They say what a one and a zero is (in pulse/space microseconds) and then give the binary for remote codes. If the carrier frequency is not geven it should be 38kHz.
To investigate my own remotes that are not in the database, I use the Dangerous Prototypes IR Toy with WinLIRC's irrecord.
It sounds like you don't actually have anything working but occasionally an LED blinks which may mean the code is being decoded right.
Well, what I have working is an occasionally blinking LED that blinks in the way that my Hifi receiver does what it is expected to do - at least roughly enough that it is recognized by the receiver (and also, the irgraph plot from IR Toy looks identical). I.e. I do have the carrier frequency right. Recognizing codes with my own hardware is not what I want to do, as said