Problems with IR commands and PWM

Hello all.

I’ve stumbled on strange problem with IR remote and trying to control DC motor via PWM on pin 11.

Project is to make motor for Lego train, i have original Lego train motor, just want to make custom “brain” to drive it. I have TSOP1838B to receive remote signals (I used z3t0’s irremote library) and then act accordingly. Turn on or off headlights/taillights, go forward, accelerate, decelerate, go backwards. This is of course not done directly with Arduino but with L298D chip.

I already made all of this and it works. I used mini universal remote.

Now comes the problem. I found cheaper remote, it’s not universal, but it cost around $0.69 a piece and, what’s more important, it has more buttons. I could control more than one train with it. I would just need to use different key codes for each controller board, no problem, in theory.

I recorded codes from all buttons and changed command to them to give it a test drive. It almost worked, lights turned on/off, but when I told it to start it went on but didn’t respond to any other command.

To cut the story a bit shorter, turned out that as soon as PWM starts IR command received is different.

I.e. stop code is 16736925, start code is 16769565. I can press stop button any number of times while PWM is not active and I’ll get 16736925 every time, but as soon as I press forward button, it’ll receive 16769565 OK, pwm will start with analogWrite value 175 and further presses of forward button (that should now accelerate) will be received as 4001918335, what was before stop code would now be 5316027, backwards/decelerate will be received as 3810010651 instead of 16753245.

It’s not DC motor noise that does this. Currently I have Arduino Uno on table, only TSOP1838B connected to it, no motor, no L298D, and the same thing happens. Only thing that happens is PWM starts on pin 11.

I don’t have a clue what could be at fault here. More so because that other remote works fine, every time it gets the same code. Same code, same arduino, only different remote/code set.

Another interesting thing is that I tried to switch PWM pin to pin 9 and for some reason it worked fine. No problem. Only difference is timers related to these PWM pins.

Here’s the code, I’ve removed unneeded parts that control direction of motor (INPUT1/2 pins on L298D) and left only these that are relevant to this problem

/* 

CH-  - 16753245
CH   - 16736925
CH+  - 16769565
Prev - 16720605
Next - 16712445
Play - 16761405
Vol- - 16769055
Vol+ - 16754775
EQ   - 16748655
0    - 16738455
100+ - 16750695
200+ - 16756815
1    - 16724175
2    - 16718055
3    - 16743045
4    - 16716015
5    - 16726215
6    - 16734885
7    - 16728765
8    - 16730805
9    - 16732845

*/


// to remove serial comm comment line below
#define DEBUGMODE

#ifdef DEBUGMODE
  #define DEBUG_PRINT(x)  Serial.print(x);
  #define DEBUG_PRINTLN(x)  Serial.println(x);
  #define DEBUG_PRINTDEC(x) Serial.print(x, DEC);
  #define DEBUG_PRINTLNDEC(x) Serial.println(x, DEC);
#else
  #define DEBUG_PRINT(x)
  #define DEBUG_PRINTLN(x)
  #define DEBUG_PRINTDEC(x)
  #define DEBUG_PRINTLNDEC(x)
#endif

#include <IRremote.h>

int IRpin = 14;   // signal pin from TSOP1838B is connected to Atmega PC0 pin, or A0 with Arduino, but when called as 14 it acts as digital IO
IRrecv irrecv(IRpin);
decode_results results;

uint8_t RFinc;
uint8_t Buffer;

int controlpin = 11;    // connected to enable PIN on L298D, PWM pin to controll speed
int frontled = 16;      // front led control, Atmega PC2 - Arduino A2, 16 as digital IO
int rearled = 17;       // rear led control, Atmega PC3 - Arduino A3, 17 as digital IO
int mode = 0;           // used to differentiate from backwards and forwards
int pwmspeed = 0;       // counter for PWM array "position"
int pwmsettings[] = {0, 175, 225, 255}; // array with values for PWM output that controlls speed


void setup() {

  pinMode(controlpin, OUTPUT);
  pinMode(frontled, OUTPUT);
  pinMode(rearled, OUTPUT);
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);

  irrecv.enableIRIn(); // Start the receiver
  #ifdef DEBUGMODE
    Serial.begin(9600);
  #endif
  DEBUG_PRINTLN("waiting for input");
  Buffer = 0;
}

void loop() {
  // put your main code here, to run repeatedly:
  if (irrecv.decode(&results)) {
    DEBUG_PRINT("Decoded value: ");
    DEBUG_PRINTLNDEC(results.value);
    irrecv.resume();   // Receive the next value
    delay(300);
  }
  switch(results.value){
    case 16769565:  // button CH+
      results.value = 0;
      if ((pwmspeed > 0) && (mode == 2)){
        DEBUG_PRINTLN("Slower");
        pwmspeed--;
      }
      else if ((pwmspeed == 0) && (mode != 1)){
        DEBUG_PRINTLN("Starting forward");
        pwmspeed++;
        mode = 1;
      }
      else {
        DEBUG_PRINTLN("Faster");
        pwmspeed++;
      }
      apply();
      break;

    case 16753245: // button CH+
      results.value = 0;
      if ((pwmspeed > 0) && (mode == 1)){
        DEBUG_PRINTLN("Slower");
        pwmspeed--;
      }
      else if ((pwmspeed == 0) && (mode != 2)){
        DEBUG_PRINTLN("Starting backwards");
        pwmspeed++;
        mode = 2;
      }
      else {
        DEBUG_PRINTLN("Faster");
        pwmspeed++;
      }
      apply();
      break;

    case 16736925: // tipka power
      results.value = 0;
      DEBUG_PRINTLN("Stop");
      allStop();
      break;

    case 16712445: // tipka left
      digitalWrite(frontled, !digitalRead(frontled));
      break;

    case 16720605: // tipka right
      digitalWrite(rearled, !digitalRead(rearled));
      break;
  }
}

void allStop(){
  mode = 0;
  pwmspeed = 0;
  analogWrite(controlpin, 0);
}

void apply(){
  if (pwmspeed < 4) {
    analogWrite(controlpin, pwmsettings[pwmspeed]);
    DEBUG_PRINTLN(pwmsettings[pwmspeed]);
  }
  else pwmspeed = 3;
}

Example of terminal output for this code

waiting for input
Decoded value: 16736925
Stop
Decoded value: 16769565
Starting forward
175
Decoded value: 4001918335
Decoded value: 4001918335
Decoded value: 4001918335
Decoded value: 5316027
Decoded value: 5316027
Decoded value: 5316027
Decoded value: 3810010651
Decoded value: 3810010651
Decoded value: 3810010651

Reason why I simply don’t switch to pin9 is because for final PCB I use Atmega8, and in case of Atmega8 irremote library uses timer that’s related to PWM on these pins. Btw. same problem happens on Atmega8.

Sorry for the wall of text :confused:

(deleted)

Oh poo, that's not good news :). What puzzles me most is that it worked fine with the other remote as can be seen here.

Oh well, I'll have to either switch from Atmega8 to Atmega168/328 so I can use pin 9, which works fine, or try to see if there's some other IR library.

Thanks

If you have pins free for software serial, you could use one of those modules, that handles NEC IR messages.

5V-IR-Infrared-Remote-Decoder-Encoding-Transmitter-Receiver-Wireless-Module 1.42 €

IREnDecoder.png

I have, but it needs to be as small as possible (in the end I make custom mini PCB that holds only needed parts, not whole arduino) so it can fit inside the train.

But luckily I made it work in the end :). I dug through IR library source and found that you can switch which timer it uses. I switched to Timer1 (my problematic Pin 11 is tied to Timer2, which IR library uses by default on Atmega328) and IR codes were read correctly after that.

But digging through library I found something else. One can enable or disable specific signal types decoding. When I disable every decoding type I get those codes I got when PWM was active. For some reason, with PWM active, it didn't recognize any signal type and returned raw values.

I left decoding disabled so I get raw codes every time, plus it saves on code space so it fits without problem even in Atmega8, almost twice :).

So if anyone else has problems similar to this check which timer ir library uses (this can be changed in IRremoteInt.h file), or even disable some or all signal decoding (can be set in IRremote.h file)