Problem with LCD and Motor

I'm having a really strange problem that I hope someone here can remedy.

I have put together a guitar pickup winder with an LCD interface. The motor is turned on via a relay, and is driven via a PWM signal from the Arduino to control speed. Motor is 12V and isolated via a MOSFET (logic driven by PWM).

The LCD is a JHD204A (20x4) hd44780 compatible display. As the motor turns, the LCD indicates # of turns from interrupt input from an optointerrupter (and some other tid-bits).

The problem is, sometimes in the middle of the operation, the LCD starts to display junk characters, and sometimes when the motor goes low (off state from relay), display goes blank and arduino must be reset. This only does this when the motor is under load, ie. if I detach the drive belt, let motor run without a load, and turn the shaft by hand to increment turns, everything works great.

I'm using a computer supply for the power supply to run both the motor and the logic. The PS is rated +12V @ 26A and +5V @ 30A which should be more than enough to run what I need. The DC motor is out of an old printer.

Could this be an effect of a current change, caused by the motor, which affects the state of the LCD? I'm baffled.
Here is the code.

/*

sketch for counting turns with optointerruptor for pickup
winder. Uses interrupt on pin 2 to increment counts and
displays pertinent information on a 20 x 4 LCD Display.

*/
#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);


// Global Variables
  
volatile unsigned int M_SEC_0 = 0;        // for rpm
volatile unsigned int M_SEC_1 = 0;        // for rpm
volatile unsigned long CUR_WINDS = 0;      // current count of winds
volatile unsigned int RPM_CNT = 0;        // revolution increment for RPM calc


// pin map

const int tachPin = 0;    // infrared tachometer input. Pin 2 for interrupt.
const int motorEng = 4;   // pin for motor relay
const int pwmIn = A5;     // Potentiometer pin to set motor speed pwm
const int pwmOut = 3;     // PWM out for motor speed
const unsigned int A_SW = A0;       // analog switch
 
void setup()
{
  lcd.begin(20,4);          // 20x4 HD44780 compatible LCD display
//  Serial.begin(9600);
  pinMode(tachPin, INPUT);  // input pin for calculating winds and rpm
  pinMode(motorEng, OUTPUT); // connected to motor relay
  pinMode(pwmIn, INPUT);
  pinMode(pwmOut, OUTPUT);
  digitalWrite(tachPin, HIGH); 
  digitalWrite(motorEng, HIGH); 
  
// Attach the Interrupt

 attachInterrupt(tachPin, tachometer, RISING);  // interrupt for counting. Connected to optointerrupter on digital pin 2 (interrupt 0)  
}


// Interrupt function 

void tachometer()
{
  CUR_WINDS++;        // increment # of winds cnt
  RPM_CNT++;          // increment count for RPM calculation
}


// function set to read switches from resistor array to save analog inputs on arduino

int read_ana_switch()
{
  
  /*
  reads analog switch and returns integer val 1::n
  This is done to save digital inputs.  Here we can have numerous switches on
  one analog pin.
  
  switch    int val
  UP_SW      1
  DN_SW      2
  LT_SW      3
  RT_SW      4
  RED_SW     5
  GRN_SW     6
  */
  
 
   const int HYS = 4;           // Hysteresis for selection +/- adc counts
   const int UP_SW = 51;        // adc counts for up switch
   const int DN_SW = 61;        // adc counts for down switch
   const int LT_SW = 71;        // adc counts for left switch
   const int RT_SW = 84;        // adc counts for right switch
   const int RED_SW = 128;      // adc counts for red arcade button
   const int GRN_SW = 108;      // adc counts for green arcade button
   
   int adc = 0;           // raw adc counts
   int which_switch = 0;  // which switch was pressed
   
     adc = analogRead(A_SW);  // dummy read for multiplex settling
     delay(10);
     adc = analogRead(A_SW);
   
     if( ( adc >= UP_SW - HYS ) && ( adc <= UP_SW + HYS ) )
      {
        which_switch = 1;
      }
      else if( ( adc >= DN_SW - HYS ) && ( adc <= DN_SW + HYS ) )
      {
        which_switch = 2;
      }
      else if( ( adc >= LT_SW - HYS ) && ( adc <= LT_SW + HYS ) )
      {
        which_switch = 3;
      }
      else if( ( adc >= RT_SW - HYS ) && ( adc <= RT_SW + HYS ) )
      {
        which_switch = 4;
      }
      else if( ( adc >= RED_SW - HYS ) && ( adc <= RED_SW + HYS ) )
      {
        which_switch = 5;
      }
      else if( ( adc >= GRN_SW - HYS ) && ( adc <= GRN_SW + HYS ) )
      {
        which_switch = 6;
      }
 
 return which_switch; 
}


void spinit()
{
  /*
  Turns motor and counts total turns and calculates RPM  
  
  */
  
  static unsigned int num_winds = 100;  // default number of winds to perform
  unsigned int wind_inc = 1;             // increment num_winds by...
  unsigned int ms_elapsed = 0;           // number of milliseconds elapsed when counting to 1 second for rpm calc
  unsigned int rpm = 0;                  // average speed of guitar pickup
  unsigned int loop_cnt = 0;
  int ana_sw = 0;
  int prev_ana_sw = 0;
  
//    M_SEC_0 = millis();    // initalize rpm gate time
//    M_SEC_1 = M_SEC_0;
   
 while( ana_sw != 5 ) 
  {
    if(num_winds >= (CUR_WINDS+1))
    digitalWrite(motorEng, HIGH);
    else digitalWrite(motorEng, LOW);
    int sensorValue = analogRead(pwmIn); // read speed potentiometer
    int outputValue = map(sensorValue, 0, 1023, 0, 255); // map the sensor value to a range from 0 - 255:
    analogWrite(pwmOut, outputValue); // use that to control the transistor
    
    long winds_rem = (num_winds - CUR_WINDS);
    ana_sw = read_ana_switch();      // read the analog switch
    
    if( ana_sw == 1 | ana_sw == 2 )  // inc/dec faster if sw is held down
    {
      if( ana_sw == prev_ana_sw )
      {
        wind_inc++;
      }
      else
      {
        wind_inc = 1;
      }
    }
    
    if( ana_sw == 1 )
    {
      lcd.clear();
      num_winds += wind_inc;  // if the up switch is pressed, increment the number of winds to do
    }
    if( ana_sw == 2 )
    {
      lcd.clear();
      num_winds -= wind_inc;  // if the down switch is pressed, decrement the number of winds to do
    }
    prev_ana_sw = ana_sw;   
    // calculate RPM in 1hz intervals 
    
    M_SEC_1 = millis();                 // get elapsed time
    ms_elapsed = M_SEC_1 - M_SEC_0;

    if( ms_elapsed >= 1000 )  
    {
      rpm = ( ( 60000 / ms_elapsed ) * RPM_CNT );          // calculate rpm
        
      M_SEC_0 = millis();    //reset counters
      M_SEC_1 = M_SEC_0;
      RPM_CNT = 0;
    }
  

      if (CUR_WINDS >= num_winds)
         {
          lcd.setCursor(0,3);
          lcd.print("Winding is Complete!");
         }
      lcd.setCursor(0,0);
      lcd.print("# Winds: ");
      lcd.print(num_winds);
      lcd.setCursor(0,1);
      lcd.print("RPM: ");
      lcd.print(rpm);
      lcd.setCursor(0,2);
      lcd.print("Total Winds: ");
      lcd.print(CUR_WINDS);
      lcd.setCursor(0,3);
      
//      if (CUR_WINDS >= num_winds)
//        digitalWrite(motorEng, LOW);
      
      
 
 }
 

  lcd.clear();
  digitalWrite(motorEng, LOW);
  CUR_WINDS = 0; 
  delay(400);
}


void loop()

{
  
   spinit(); 
  
}

Do you have a diode connected across the motor to catch the back emf when the mosfet switches off?

Do you have a diode connected across the motor to catch the back emf when the mosfet switches off?

Yes I do. I also have a diode across the coil of the relay. Cathode to Vcc (+12V).

I may have solved the problem. I connected a 1000 uF cap across the supply voltage for the LCD, and it's working much better. Now only having problems about 9 out of 10 iterations. I think I can solve the problem by filtering the motor supply a bit with a cap across the +12 supply. Should have done this before I made the PCB.

Here it is, working.

Sorry for the jerky camera. Kinda hard to look through and push buttons at the same time.

wbegg:

Do you have a diode connected across the motor to catch the back emf when the mosfet switches off?

Yes I do. I also have a diode across the coil of the relay. Cathode to Vcc (+12V).

I may have solved the problem. I connected a 1000 uF cap across the supply voltage for the LCD, and it's working much better. Now only having problems about 9 out of 10 iterations. I think I can solve the problem by filtering the motor supply a bit with a cap across the +12 supply. Should have done this before I made the PCB.

Yes, a large cap across the motor supply is important, negative side connected as close to the mosfet source terminal as possible (I am assuming you are using an n-channel mosfet as a low side switch).

Is it just me or does anybody else get scared by a device called "Willy winder" running at 100 RPM :slight_smile: :slight_smile: :slight_smile: :slight_smile:

(I am assuming you are using an n-channel mosfet as a low side switch).

Yes, that is correct. With logic level switching. I'll put 1000uF across and give it a whirly-whirl. Thanks a bunch.

Is it just me or does anybody else get scared by a device called "Willy winder" running at 100 RPM

You should see the guitar amps I build. The "Little Willy" and the "Fat Willy".

What's the purpose of the relay, given that you already have a mosfet controlling the motor? Additional safety?

What's the purpose of the relay, given that you already have a mosfet controlling the motor? Additional safety?

Well ... not really. I am using the parts on hand. The relay has 12V coil , so it's being driven by an NPN transistor from a digital output from arduino (engages and disengages motor).

The relay supplies 12VDC to the motor, and it's speed is controlled by a PWM signal into the MOSFET.
I know I could accomplish the same with 2 mosfets or maybe a power transistor for the motor engage/disengage, but I just like the "clickety-click" of the mechanical relay. I'll post a schematic here shortly.

Do you mean that the motor incorporates an electric clutch to engage it, and you are driving that clutch with the relay?

Maybe this schematic explains it.

All the relay does is supply 12V to the motor. I use this to turn off the motor when a certain number of winds has been reached. The Motor is connected to a MOSFET which is driven by 5V PWM from a digital pin on the arduino. A Potentiometer controls the duty cycle via an analog input. I guess I could controlled the state of the motor with the digital pwm pin. Maybe I've overthought this. At any rate, since this is an LCD question, the cap will be added across the 12V supply close to the MOSFET to quiet some of the electrical noise from the motor and this should solve the issue of my LCD resetting.

OK, that looks like overkill, but it should work. The capacitor should help, but make sure the negative side is connected as close to the mosfet source as possible, to avoid noise on the ground connection. Other things that may help are keeping the wires between the LCD and then Arduino (especially the ground wire) short and away from the motor wiring, and putting a 10uF capacitor between the Vdd and Vss pins of the LCD.

Thanks dc42.

I did away with the relay, and designed a new board with a standalone arduino and motor driver together. Do you see anything that might interfere signal wise?

Should I use shielded cable to run my logic to the LCD?

I don't see any decoupling capacitors on the microprocessor power pins.

Don

As Don days, you need at least one decoupling capacitor for the microprocessor. Your layout for the mosfet, 1000uF capacitor and motor terminals is good, however you should connect the ground side of the 12v supply direct to the junction of the mosfet source terminal and 1000uF capacitor, instead of via the mcu ground pins as you appear to be doing.

however you should connect the ground side of the 12v supply direct to the junction of the mosfet source terminal and 1000uF capacitor, instead of via the mcu ground pins as you appear to be doing.

I'm using an old computer supply with both 12 and 5 volts with a common ground.

I'll add the decoupling caps as suggested. Thanks a bunch, guys.

wbegg:
I'm using an old computer supply with both 12 and 5 volts with a common ground.

In that case, if you can't design the pcb with a ground plane, then I suggest you put a separate ground pin on your pcb for the PSU input, connected direct to that mosfet/capacitor junction. You can use the ground pin you already have for connecting the ground sides of input devices and the LCD. What you don't want is high switched currents from the psu to the motor going along a long pcb trace with devices connected to different points on that trace.

Thanks. I think I might have a completed PCB design.

No, you've now broken the connection between mosfet source and Arduino ground.

you've now broken the connection between mosfet source and Arduino ground

There is one ground on the modified PSU (+5, +12, Gnd), so technically the source of the mosfet is connected to the arduino ground via the power supply wiring. The two grounds on the PCB are connected, just with 3 inches of wire instead of a trace. Should I still do this locally on the board as well? (i.e. add trace from mosfet source to arduino ground).