Arduino based LDR volume and source selection controller

This is really weird. I closed the box completely, closed the opening for both IR and OLED in front, and remote still works!


I've spent some time how to make nice window for IR sensor a few years ago.It was not the best nice looking window and I get the same weird result - no need any window if use some indicator on the front panel.
I've found it very helpful for all next my projects :).

Nice work ZDR!!!
 
bug#2, can't reproduce this one every time: when alternating quickly between volume up/down on apple remote, sometimes direction doesn't change - by pressing volume up for example, it still goes down (and vice versa), until I release it for a while. Again, this might be something I introduced.

This issue has been there to some extent since the original code and is a limitation of the remote code not being ISR driven I think. It is quite hard to reproduce on my system though and I rarely encounter it these days.
 
In my system, I can reproduce it every time in 15s window, maybe because my oled is slower. I will try to narrow it down.

Sent from my SM-G935F using Tapatalk
This is the other reason why I put a check in to only do something with repeat codes received within 750ms of the last IR command (repeat or otherwise). ;)

750ms is arbitrary, found to be a stable value in my implementation.
 
Thats an excellent idea Chris!

Thanks, it seems to work well. The change was originally to prevent repeat codes from other remotes (TV etc...) from triggering volume up/down events some time, i.e. even hours, after initially adjusting the volume of the LDR unit using the Apple remote. It also, unintentionally but usefully, helps prevent the issue described by zdr.

I also moved the LCD fade-in call to only fade-in the LCD if a valid, non-repeat code is received, again to prevent the LCD from fading-in when receiving repeat codes from other remotes.



New global variable declaration:
Code:
unsigned long mil_onRemoteKey = 0; // Stores time of last remote command

Modification of the main loop:

Code:
	/////////////////////////////////////////////////////////////////////////////////////
	// IR Remote
#pragma region loop_remote
	if (millis() - mil_onRemote > TIME_IGNOREREMOTE_CMD && digitalRead(PIN_REMOTE) == LOW && (state == STATE_RUN || state == STATE_IO)) {

		IRkey = getIRkey();
		if (IRkey != 255 && IRkey != 2) {

			mil_onAction = millis();
			isIRrepeat = IRkey == 0;

			// Prevent repeating if a code has not been received for a while.
			if ((millis() - mil_onRemoteKey) > 750)  {
			   isIRrepeat = 0; 
			}

			if (IRkey == cIR_UP || IRkey == cIR_DOWN || IRkey == cIR_LEFT || IRkey == cIR_RIGHT || IRkey == cIR_PLAY || IRkey == cIR_MENU) {
				startLCDFadeIn();
			}                        
                        
			if (isIRrepeat && (previousIRkey == cIR_UP || previousIRkey == cIR_DOWN))  // Repeat the specified keys
				IRkey = previousIRkey;
			else
				previousIRkey = IRkey;

			mil_onRemoteKey = millis();

			//PRINT("IR: "); PRINTLN(IRkey);

			switch (IRkey) {
 
Last edited:
// Conditionally set the address of the LCD I2C controller (depends on chipset)
#if LCDCOLUMNS == 20
#define LCDADDRESS 0x27
#else
#define LCDADDRESS 0x3F
#endif


I had some problem to understand this part of code because I don't knew the LCD I2C controller's behaviour. Now, with a quick search I understood.
Perhaps it's better to point out that code 0X27 is for PCF8574T and code 0X3F is for PCF8574AT controller. :)
 
// Conditionally set the address of the LCD I2C controller (depends on chipset)
#if LCDCOLUMNS == 20
#define LCDADDRESS 0x27
#else
#define LCDADDRESS 0x3F
#endif


I had some problem to understand this part of code because I don't knew the LCD I2C controller's behaviour. Now, with a quick search I understood.
Perhaps it's better to point out that code 0X27 is for PCF8574T and code 0X3F is for PCF8574AT controller. :)

Hi, yes you're correct. My local version of the code was updated to include the comments but I guess I must have added these after uploading the file to the forum.

Code:
#if LCDCOLUMNS == 20
#define LCDADDRESS 0x27 //PCF8574
#else
#define LCDADDRESS 0x3F //PCF8574A
#endif

This was added only because my 20 col display used a PCF8574 and the 16 col display used PCF8574A. This may or may not be necessary depending on your displays.
 
I tried your code tonight Chris with 1602 LCD and it works well except for the volume sticking in one direction sometimes on repeat as ZDR mentioned. I will try to implement your new fixes when I get a chance. Thanks once again! BTW the 1602 had the same address as the 2004 display so I set LCDADDRESS to 0x27 in both cases.
 
Last edited:
I tried your code tonight Chris with 1602 LCD and it works well except for the volume sticking in one direction on repeat as ZDR mentioned. I will try to implement your new fixes when I get a chance. Thanks once again! BTW the 1602 had the same address as the 2004 display so I set LCDADDRESS to 0x27 in both cases.

Great news! Let us know how you get on with the latest change.

I had problems with the remote 'sticking' on the original code so I don't think it's something I introduced, or at least I hope it wasn't.

I was switching between the 1602 and 2004 displays when making the changes for the 1602 version, so that's why I included the two addresses. Took me a while to work out why the 1602 display wasn't working and it took a bit of research to determine that there were two versions of the driver IC! I moved the address out to the top of the code so that it was easier to locate and update.
 
Last edited:
To me, it seems like a problem with repeat routine not checking properly if the same key is still pressed before command is repeated, so you can "hijack" repeat sequence with a different key. I will check the code when I get home, since I can easily reproduce it in my setup.
Could well be. I was focussing on the problem of (much) later repeat codes causing the unit to perform the previous action so didn't consider this.
 
Could well be. I was focussing on the problem of (much) later repeat codes causing the unit to perform the previous action so didn't consider this.

From what I remember the code either doesn't see the respective command code before the repeat sequence or the remote does not transmit it (unlikely). Triggering repeat action on code 2 was just something I picked up from the debug output as I couldn't find and detailed documentation about how the apple remote behaves in repeat mode. PulseIn is pretty flaky. The code for it seems to change with every IDE release. Its difficult and problematic to measure pulse width/delay with software polling though.
 
From what I remember the code either doesn't see the respective command code before the repeat sequence or the remote does not transmit it (unlikely). Triggering repeat action on code 2 was just something I picked up from the debug output as I couldn't find and detailed documentation about how the apple remote behaves in repeat mode. PulseIn is pretty flaky. The code for it seems to change with every IDE release. Its difficult and problematic to measure pulse width/delay with software polling though.

The NEC IR protocol is described here:

NEC Infrared Transmission Protocol | Online Documentation for Altium Products

It could be that the LDR unit is occasionally not capturing the initial data burst that describes the key pressed, but is picking up later repeat codes sent by the remote causing the last command to be repeated if the last command was a change to the volume level. The remote repeat codes are often the same regardless of which key was pressed (although on my clone remote some of the keys result in a repeat code of '4' rather than the '2' specified in the original software).

I have noticed that my LDR unit occasionally misses initial keypresses, this has become more noticeable on the volume level adjustments now that I have implemented the 750ms check between repeat codes.

This is why my LG TV's remote's repeat codes were causing the volume level to change. The LDR unit was essentially ignoring the initial data burst from the LG remote as the data did not originate from an Apple remote, however repeat codes have no context and so it treated them no differently to those received from the Apple remote.

Due to memory constraints maybe the unit needs two Arduino Nanos. One dedicated to the remote handling (maybe using one of the dedicated IR libraries), possibly using interrupts (to remove the need to regularly poll in software) to pass commands to the other Nano which controls the rest of the LDR unit. Arduino Nano clones are certainly cheap enough to make this viable. This would also help remove the dependency on a specific IDE version. Whether this is worth the effort, I don't know. Food for thought though.
 
Last edited: