LCD screen issues - ppm signal conflicting with LCD screen code?

Hi all,

I have a project to use an Arduino as a translation device between an XBOX controller and a remote control vehicle transmitter by supplying the transmitter with a ppm signal. The fundamental operation of the system is working well, and I can currently use an XBOX controller to operate an RC sailing boat.

Just now I am trying to add an LCD to the project and having troubles. To get started I thought it best to simply add the basic code to my existing sketch to get the LCD to display Hello World, and then move on to getting it to display the desired information. This is where I am stuck … my best efforts and my LCD remains stubbornly blank (though lit).

To test I have wired the LCD correctly I uploaded a basic LCD sketch that only controls the LCD and nothing else, and this worked fine. There is something in my project code that is conflicting with the LCD, but I can’t spot it.

This is my code. Can anyone spot the problem?

#include <XBOXONE.h>
#include <LiquidCrystal.h>

// Satisfy the IDE, which needs to see the include statment in the ino too.
#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif
#include <SPI.h>

USB Usb;
XBOXONE Xbox(&Usb);

bool printAngle;
uint8_t state = 0;
LiquidCrystal lcd(8, 9, 10, 11, 12, 13);


////////////
/*
 * PPM generator originally written by David Hasko
 * on https://code.google.com/p/generate-ppm-signal/ 
 */

//////////////////////CONFIGURATION///////////////////////////////
#define CHANNEL_NUMBER 8  //set the number of chanels
#define CHANNEL_DEFAULT_VALUE 1500  //set the default servo value
#define FRAME_LENGTH 22500  //set the PPM frame length in microseconds (1ms = 1000µs)
#define PULSE_LENGTH 300  //set the pulse length
#define onState 1  //set polarity of the pulses: 1 is positive, 0 is negative
#define sigPin 2  //set PPM signal output pin on the arduino
//////////////////////////////////////////////////////////////////

#define SWITCH_PIN 16
#define CHANNEL_TO_MODIFY 11
#define SWITCH_STEP 100

byte previousSwitchValue;

/*this array holds the servo values for the ppm signal
 change these values in your code (usually servo values move between 1000 and 2000)*/
int ppm[CHANNEL_NUMBER];

float ppm2Adjust = 1500;
int currentChannelStep;
int rudderTrim = 0;
/////////////



void setup() {
  Serial.begin(115200);
#if !defined(__MIPSEL__)
  while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
#endif
  if (Usb.Init() == -1) {
    Serial.print(F("\r\nOSC did not start"));
    while (1); //halt
  }
  Serial.print(F("\r\nXbox USB Library Started"));

///////////////////////////////
  previousSwitchValue = HIGH;
  
  //initiallize default ppm values
  for(int i=0; i<CHANNEL_NUMBER; i++){
    if (i == 2 || i == CHANNEL_TO_MODIFY) {
      ppm[i] = 1000;
    } else {
      ppm[i]= CHANNEL_DEFAULT_VALUE;
    }
  }
  
  ppm[2] = 1500; // Set ppm[2] (i.e. RC Channel 3) to midway point to allow for incremental up/down adjustment in the loop
  ppm2Adjust = 1500; 

  pinMode(sigPin, OUTPUT);
  pinMode(SWITCH_PIN, INPUT_PULLUP);
  digitalWrite(sigPin, !onState);  //set the PPM signal pin to the default state (off)
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("hello, world!");
  
  cli();
  TCCR1A = 0; // set entire TCCR1 register to 0
  TCCR1B = 0;
  
  OCR1A = 100;  // compare match register, change this
  TCCR1B |= (1 << WGM12);  // turn on CTC mode
  TCCR1B |= (1 << CS11);  // 8 prescaler: 0,5 microseconds at 16mhz
  TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
  sei();

  currentChannelStep = SWITCH_STEP;
  
}

/*    Channel Info Currently Setup AS AETR you can change this by changing the PPM Value in the main loop
 * 
Ch1 A (Rudder) ==  ppm[0]
Ch2 E (NOT SET) ==  ppm[1]
Ch3 T (Sail Trim) ==  ppm[2]
Ch4 R (NOT SET) ==  ppm[3]
Ch5 AUX1 (NOT SET) == ppm[4]
Ch6 AUX2 (NOT SET) == ppm[5]
Ch7 AUX3 (NOT SET) == ppm[6]
Ch8 AUX4 (NOT SET) == ppm[7]
 */

void loop() {
  
  Usb.Task();
  if (Xbox.XboxOneConnected) {

    // Rudder
    // Attached to Xbox Left Joystick X Axis, inverted so that left joystick = steer left (swap the 2000 and 1000 to change this)
    // Trim adjusted by pressing L1 or L3 as these are available buttons with Quadstick plugged into XAC, X and Y not available.
    if (Xbox.getButtonClick(L1)){ // Incrementally trim rudder to turn left
      rudderTrim = rudderTrim + 5;
      //Serial.print(F("\r\nA"));
      //Serial.print(rudderTrim);
    }
    if (Xbox.getButtonClick(L3)){ // Incrementally trim rudder to turn right
      rudderTrim = rudderTrim - 5;
      //Serial.print(F("\r\nB"));
      //Serial.print(rudderTrim);
    }
    if (Xbox.getButtonClick(BACK) || Xbox.getButtonClick(START)){ // Reset rudder trim to 0
      rudderTrim = 0;
      //Serial.print(F("\r\nB"));
      //Serial.print(rudderTrim);
    }
    ppm[0] = map(Xbox.getAnalogHat(LeftHatX), -32768 , 32768, 2000, 1000) + rudderTrim; // Get value of X axis on joystick, adjust for trim then publish to ppm value
    
    // Sail trim 
    // Attached to Xbox Left Joystick Y Axis
    // 'IF' statements do three things: 1. provide a deadband, 2. provide incremental adjustment of a ppm value, 
    // allowing a spring-centering joystick to be used for something not normally suited to that style of 
    // joystick, ie. sail trim, and 3. provide a modicum of proportional joystick operation for this adjustment
    long servoLeftHatY = Xbox.getAnalogHat(LeftHatY); //Get value of Y axis on joystick and place in a variable     
    //Serial.println(servoLeftHatY);
    if (servoLeftHatY < -5000 && ppm[2] < 2000) {
      ppm2Adjust = ppm2Adjust + 0.01;
      ppm[2] = round(ppm2Adjust);
    }
    if (servoLeftHatY < -25000 && ppm[2] < 2000) {
      ppm2Adjust = ppm2Adjust + 0.09;
      ppm[2] = round(ppm2Adjust);
    }     
    if (servoLeftHatY > 5000 && ppm[2] > 1000) {
      ppm2Adjust = ppm2Adjust - 0.01;
      ppm[2] = round(ppm2Adjust);
    }
    if (servoLeftHatY > 25000 && ppm[2] > 1000) {
      ppm2Adjust = ppm2Adjust - 0.09;
      ppm[2] = round(ppm2Adjust);
    }


    // Set sail trim all the way out/loose by single button press
    if (Xbox.getButtonClick(A)){
      ppm[2] = 2000;
    }

    // Set sail trim all the way in/tight by single button press
    if (Xbox.getButtonClick(B)){
      ppm[2] = 1000;
    }

    // All available XBOX Buttons      
//    if (Xbox.getButtonClick(UP))
//      Serial.println(F("Up"));
//    if (Xbox.getButtonClick(DOWN))
//      Serial.println(F("Down"));
//    if (Xbox.getButtonClick(LEFT))
//      Serial.println(F("Left"));
//    if (Xbox.getButtonClick(RIGHT))
//      Serial.println(F("Right"));
//
//    if (Xbox.getButtonClick(START))
//      Serial.println(F("Start"));
//    if (Xbox.getButtonClick(BACK))
//      Serial.println(F("Back"));
//    if (Xbox.getButtonClick(XBOX))
//      Serial.println(F("Xbox"));
//    if (Xbox.getButtonClick(SYNC))
//      Serial.println(F("Sync"));
//
//    if (Xbox.getButtonClick(L1))
//      Serial.println(F("L1"));
//    if (Xbox.getButtonClick(R1))
//      Serial.println(F("R1"));
//    if (Xbox.getButtonClick(L2))
//      Serial.println(F("L2"));
//    if (Xbox.getButtonClick(R2))
//      Serial.println(F("R2"));
//    if (Xbox.getButtonClick(L3))
//      Serial.println(F("L3"));
//    if (Xbox.getButtonClick(R3))
//      Serial.println(F("R3"));
//
//
//    if (Xbox.getButtonClick(A))
//      Serial.println(F("A"));
//    if (Xbox.getButtonClick(B))
//      Serial.println(F("B"));
//    if (Xbox.getButtonClick(X))
//      Serial.println(F("X"));
//    if (Xbox.getButtonClick(Y))
//      Serial.println(F("Y"));

//    if (Xbox.getButtonPress(L2) > 0 || Xbox.getButtonPress(R2) > 0) {
//      if (Xbox.getButtonPress(L2) > 0) {
//        Serial.print(F("L2: "));
//        Serial.print(Xbox.getButtonPress(L2));
//        Serial.print("\t");
//      }
//      if (Xbox.getButtonPress(R2) > 0) {
//        Serial.print(F("R2: "));
//        Serial.print(Xbox.getButtonPress(R2));
//        Serial.print("\t");
//      }
//      Serial.println();
//    }
   
  }
    
  if (Xbox.XboxOneConnected == false){
    ppm[4] = 1000;
  }

}



ISR(TIMER1_COMPA_vect){  //leave this alone
  static boolean state = true;
  
  TCNT1 = 0;
  
  if (state) {  //start pulse
    digitalWrite(sigPin, onState);
    OCR1A = PULSE_LENGTH * 2;
    state = false;
  } else{  //end pulse and calculate when to start the next pulse
    static byte cur_chan_numb;
    static unsigned int calc_rest;
  
    digitalWrite(sigPin, !onState);
    state = true;

    if(cur_chan_numb >= CHANNEL_NUMBER){
      cur_chan_numb = 0;
      calc_rest = calc_rest + PULSE_LENGTH;// 
      OCR1A = (FRAME_LENGTH - calc_rest) * 2;
      calc_rest = 0;
    }
    else{
      OCR1A = (ppm[cur_chan_numb] - PULSE_LENGTH) * 2;
      calc_rest = calc_rest + ppm[cur_chan_numb];
      cur_chan_numb++;
    }     
  }
}

check the used pins.
Which pins are used for SPI - which pins are used for the LCD.

As you don’t provide information of the used controller nor a clear schematic, you have to do the analysis on your own.

Thanks for that. Apparently the default pins for SPI are 10-13 (https://www.electroschematics.com/arduino-uno-pinout/) so I’ve just avoided these and it’s now working. Thanks for the suggestion, I don’t know much at all about SPI so wouldn’t have known to go digging there.

This topic was automatically closed after 120 days. New replies are no longer allowed.