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();
}