hello i have steppr moter with l9935 how to connect it to arduino

hello,
I have a steppr moter as shown in photos blow

it's has a complete bord with ic l9935
this from my car from bmw flip screen it's open and close the monitor but i replaced the screen with custom montior and i want to control the stepper moter form arduino for car pc project

this is a link for datasheet for l9935

i connect the power + - 12 to the ship
i don't know how to connect it to arduino

help please

thanks

First I think you'll need to carefully trace which wires from the ribbon connector
go to which pins on the IC (and the two power supplies too). The chip uses 5V SPI
so you'll want to connect up SCK, MISO, MOSI and SS to SCK, SDO, SDI and CSN on
the L9935.

The datasheet isn't great I'm afraid - the drive sequence tables don't explain
the actual meaning of the bits in SPI bytes, but you should be able to just use
the sequence documented.

thank you for reply
i think this will so hard can you tell me what is the best stepper driver
i can bay it to replace this bord
thank you

Hi!

Pictures of my setup are below:

Right Click → View Image to see in full resolution.

Wires are soldered directly to L9935 stepper motor driver:

Closer look to Arduino R3 UNO:

Wiring diagram:

Stepper Motor Basics - understanding channels, polarity, states and direction of rotation.

L9935 datasheet - detailed information about L9935 pinning and basic operating principles including command byte description.

The same info in more details I described aslo here.

This should be good starting point for your setup.

Video Demos:

  1. Video Demo #1 - Turning On/Off screen by ignition, power off delay Timer, saving screen last position to internal memory (EEPROM)

  2. Video Demo #2 - Closing screen manually. Saving screen last position to internal memory (EEPROM). Restoring last screen position from internal memory, Manually Opening screen.

  3. Video Demo #3 - Using Step Open and Step Close button. Saving screen last position to internal memory (EEPROM). Restoring last screen position from internal memory.

Complete video playlist

Code will be placed here soon …

Code - part1/2:

/*==========================================================================================================================
Created by JS online, jsonline1111@gmail.com
Last update 21-May-2015

Arduino R3 UNO code to operate L9935 stepper motor driver.
Main functionality:
1. Opening screen fully - after ignition is turned on or by open button
2. Closing screen fully - after ignition is turned off or by close button
3. Saving monitor last position to Arduino internal EEPROM memory after ignition is turned off (full step only).
4. Opening by small steps - by step open button
5. Closign by small steps - by step close button (min position is limited to half way - the same as in original behavior)

Enable Serial Monitor Ctrl + Shift + M to see debug messages.
==========================================================================================================================*/
#include <SPI.h>
#include <EEPROM.h>

//L9935 pinning
int SLAVESEL=10; //using digital pin 10 for SPI slave select
int DATAOUT=11;  //using digital pin 11 for MOSI (Master Out Slave In) - master line for sending data to slave
int DATAIN=12;   //using digital pin 12 for MISO (Master In Slave Out) - the slave sending data to the master
int SPICLOCK=13; //using digital pin 13 for SCK (Serial Clock) - The clock pulses which synchronize data transmission generated by the master 
int EN=9;        //Enable (Low Active)

//Board Monitor Buttons
#define OPEN_BUTTON 6       //montior open button full
#define CLOSE_BUTTON 7      //montior close button full
#define STEP_OPEN 4         //montior open button step 
#define STEP_CLOSE 5        //montior close button step

/*Ignition key 12V relay 
R3 UNO, L9935 stepper motor (tablet and other consumers) are powered from +12V ACC (Battery) - X18802 18pin white board monitor socket, Pin 8 = +12V ACC (thru fuse F49), Pin 9 = GND). 
Timer is used for power off delay option. Timer is activated by +12V IGN (Ignition). Power off delay is required to allow close screen after ignition key is turned off and to do not leave 
consumers connected to +12V ACC permanently. Timer logic is the following:
1. after ignition is turned on everything is powered on. Timer Output is operational and connected to +12 ACC: consumers are powered.
2. after ignition is turned off Timer is activated and disconnects +12V Timer Output from +12V Timer Input (ACC) after X seconds (time is adjusted by trimmer and is from 1 sec up to 20 mins). 
After timeout Timer disconnects ACC 12V power, so R3 UNO, L9935 stepper motor and other consumers are also unpowered.*/ 

#define IGN_PWR 8           //igntion 12V power detection. Relay connected to 12V iginition power connects/disconnects GND with IGN_PWR wire.
int ignState = 0;
  
//Delays - miliseconds used for various delays
int DELAY_SS=1;     //very short delay
int DELAY_S=16;     //short delay
int DELAY_N=100;    //standard delay
int DELAY_L=500;    //long delay

//Monitor positioning: over movement protection and last position. Last saved position works by operating buttons only. Positioning is not tracked if monitor is adjusted manually.
//Last position of monitor is saved after ignition 12v power is turned off. Last position of monitor is restored after ingnition 12v power is tuned on.
float POS_CUR=0;          //monitor current positon full step counter
int POS_CUR_HS=0;         //monitor position half step counter
float POS_STEP_HS=0.25;   //monitor position half step
int POS_STEP_MIN=7;       //limiting min half step position
float POS_MAX=10.7;       //monitor maximum position
int POS_CUR_SAVED=0;      //monitor saved position (full step only)
int POS_CUR_ADDR=0;       //EEPROM address for storing current position (full step only)

//int ERR_CODE;    //read L9935 SPI error code in case if DATAIN pin is connected

// the setup function runs once when you press reset or power the board
void setup() {
  
  pinMode(SLAVESEL, OUTPUT);           //CSN
  pinMode(DATAOUT, OUTPUT);            //SDI
  pinMode(DATAIN, INPUT);              //SDO not used
  pinMode(SPICLOCK, OUTPUT);           //SCK
  pinMode(EN, OUTPUT);                 //Enable

  pinMode(OPEN_BUTTON, INPUT_PULLUP);      //Open Button Full
  pinMode(CLOSE_BUTTON, INPUT_PULLUP);     //Close Button Full
  pinMode(STEP_OPEN, INPUT_PULLUP);        //Open Button Step
  pinMode(STEP_CLOSE, INPUT_PULLUP);       //Close Button Step  
  
  pinMode(IGN_PWR, INPUT_PULLUP);          //Iginition 12V
      
  SPI.begin();                           //wake up the SPI bus.
  SPI.setBitOrder(MSBFIRST);             //data to be sent MSB (most significant byte) first
  SPI.setClockDivider(SPI_CLOCK_DIV16);  //1Mhz SPI clock 16/16
  SPI.setDataMode(SPI_MODE3);            //SPI_MODE3 - CPOL=1 the base value of the clock is one; CPHA=1, data are captured on clock's rising edge and data is propagated on a falling edge

  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  
  //detect initial state of ignition 12V power
  ignState = digitalRead(IGN_PWR);
  if (ignState==LOW)   {
    //ignition 12V power is on
    readPOS_CUR(POS_CUR_ADDR); //reading current monitor position from internal EEPROM memory
    screenUp(POS_CUR_SAVED);
  }
  else   {
    //ignition 12V power is off
    screenDown();
  } 
  
}

// the loop function runs over and over again forever
void loop() {
  
  int switchValue; 
  
    switchValue = digitalRead(IGN_PWR);
    if (switchValue != ignState)
    {
      if (switchValue==LOW) {
        //ignition 12V power has been turned on
        readPOS_CUR(POS_CUR_ADDR); //reading current monitor position from internal EEPROM memory
        screenUp(POS_CUR_SAVED);
      }
      else {
        //ignition 12V power has been turned off
        writePOS_CUR(POS_CUR_ADDR, POS_CUR); //writing current monitor position to internal EEPROM memory
        screenDown();
      }
      //udpate state
      ignState = switchValue;
    }  
  
  switchValue = digitalRead(OPEN_BUTTON);
  if (switchValue==LOW) {
    screenUp(-1);    //sending -1 to execute standard logic without restoring last position 
  }
  
  switchValue = digitalRead(CLOSE_BUTTON);
  if (switchValue==LOW) {
    screenDown();
  }
  
  switchValue = digitalRead(STEP_OPEN);
  if (switchValue==LOW) {
    activateL9935EN();
    stepUpHalf();
  }
  
  switchValue = digitalRead(STEP_CLOSE);
  if (switchValue==LOW) {
    activateL9935EN();
    stepDownHalf();
  }
}

/* L9935 basic info. For more info see L9935 technical data sheet.
Command byte: 6 first bits (0-5) are used for command, Last 2 bits (6,7) are used for command response - return error code (not processed in current code, can be read and processed thru DATAIN pin).
Command byte bits: 76543210 
bit5,bit4: current range of bridge A (Outputs A1 and A2)
bit3: polarity of bridge A
bit2,bit1: current range of bridge B (Outputs B1 and B2)
bit0: polarity of bridge B
bit7,bit6: Error1 and Error 2
Command byte should be converted from binary to decimal (00001111 = 15) and passed as decimal to setValue function.

Current settings (bit5 bit4 for A1 and A2 or bit2 bit1 for B1 and B2). HIGH=H=1; LOW=L=0;
H H = 1 1 = 0 - not used in current code
H L = 1 0 = 60 mA  6% internally sensed - used in current code for parking, screen can be moved manually in this mode.
L H = 0 1 = 550 mA 61 % - used in current code for step opening and step closing
L L = 0 0 = 900 mA 100 % - used in current code for opening and closing screen fully
*/

//functions
void setSPIValue(int SPI_COMMAND)
{
  digitalWrite(SLAVESEL, LOW);       //Start of frame. Falling slope of CSN indicates start of frame. 
  SPI.transfer(SPI_COMMAND);         //Send value (0~255) in decimal format. Data transfer (reading SDI into the register) takes place at the rising slopes of SCK.
//  ERR_CODE = digitalRead(DATAIN);  //Read error code
  digitalWrite(SLAVESEL, HIGH);      //End of frame
  delay(DELAY_S);
}

void activateL9935EN(void) {
    digitalWrite(EN, HIGH);     //disable L9935 
    delay(DELAY_SS);
    digitalWrite(EN, LOW);      //enable L9935. Falling slope of EN activates the device. After ten.sck the device is ready to work.
    delay(DELAY_SS);
}

Code - part2/2:

void screenUp(float POS) { 
  
    activateL9935EN();
    
    float b;   
    //Initial opening: saved positon from internal EEPROM will be used. Other cases: standard logic calculating current and max position.
    if (POS >= 0) b = POS; else b = POS_MAX-POS_CUR;     
    for (int a = 0; a < b; a++)
    {
      stepUp();
    }    
    screenPark(); 
    
}

void screenDown(void) { 
    
    activateL9935EN();

    int b = POS_CUR;
    while (POS_CUR >= 1)
    {    
      stepDown();
    }
    
    POS_CUR=0;        //resetting current position
    POS_CUR_HS=0;     //resetting half step position
    screenPark();

}

void stepUp(void) { 
  
   //full step mode processing for complete opening;
   //POS_CUR direction 0 --> 1 --> 2 --> 3
   /*States:
    0 = CH A enabled, polarity=HIGH. CH B disabled.
    1 = CH A disabled. CH B disabled, polarity=LOW.
    2 = CH A enabled, polarity = LOW. CH B disabled.
    1 = CH A disabled. CH B enabled, polarity=HIGH.
   */
   
   if(POS_CUR <= (POS_MAX - 1)) {  
      setSPIValue(15);    //00001111 CH A enabled, polarity=HIGH (Current=900mA). CH B disabled.
      setSPIValue(56);    //00111000 CH A disabled. CH B enabled, polarity=LOW (Current=900mA).
      setSPIValue(6);     //00000110 CH A enabled, polarity=LOW (Current=900mA). CH B disabled. 
      setSPIValue(57);    //00111001 CH A disabled. CH B enabled, polarity=HIGH (Current=900mA). 
      POS_CUR += 1;
      Serial.print("POS_CUR=");Serial.println(POS_CUR); 
   }
}

void stepDown(void) {
   //full step mode processing for complete closing;
   //POS_CUR direction 0 --> 3 --> 2 --> 1

   if(POS_CUR > 0) {     
      setSPIValue(15);    //00001111 CH A enabled, polarity=HIGH (Current=900mA). CH B disabled.
      setSPIValue(57);    //00111001 CH A disabled. CH B enabled, polarity=HIGH (Current=900mA). 
      setSPIValue(7);     //00000111 CH A enabled, polarity=LOW (Current=900mA). CH B disabled.
      setSPIValue(48);    //00110000 CH A disabled. CH B enabled, polarity=LOW (Current=900mA).
      POS_CUR -= 1;
      Serial.print("POS_CUR=");Serial.println(POS_CUR);
   }
}

void screenPark(void) { 
    /*Parking allows manual movement of screen by hand (counter is not working in this case). 
      Stepper motor current is set to HL (internally sensed).
      HH will not fix monitor at all as current is 0.
      HL and LL with 550mA and 900mA current will hold monitor and will not allow manual movement.
    */  
    setSPIValue(47);    //00101111 CH A enabled, polarity=HIGH. CH B disabled (Current 60mA).
    delay(DELAY_S); 
}


void stepUpHalf(void) {
/*Half steps can be used here by using middle states (currently not used) - step 1.2, step 2.2, step 3.2, step 4.2.
In this case both channels are enabled, use current max 550mA (avoid higher current 900mA, overheating risk exists).
*/
   if(POS_CUR <= (POS_MAX - POS_STEP_HS) && POS_CUR >= POS_STEP_MIN) {  
   //POS_CUR_HS direction 0 --> 1 --> 2 --> 3

   if(POS_CUR_HS == 0) {
      setSPIValue(31);    //00011111 CH A enabled, polarity=HIGH (Current=550mA). CH B disabled.  --current step
      setSPIValue(58);    //00111010 CH A disabled. CH B enabled, polarity=LOW. (Current=550mA). --next step
      setSPIValue(60);    //00111100 CH A disabled. CH B enabled, polarity=LOW (Current=60mA).   --park
      Serial.print("STEP1"); 
  }
  
   if(POS_CUR_HS == 1) {
      setSPIValue(58);    //00111010 CH A disabled. CH B enabled, polarity=LOW (Current=550mA).  --current step
      setSPIValue(22);    //00010110 CH A enabled, polarity=LOW (Current=550mA). CH B disabled. --next step
      setSPIValue(38);    //00100110 CH A enabled, polarity=LOW (Current=60mA). CH B disabled.  --park
      Serial.print("STEP2"); 
   }   

   if(POS_CUR_HS == 2) {
      setSPIValue(22);    //00010110 CH A enabled, polarity=LOW (Current=550mA). CH B disabled.   --current step
      setSPIValue(51);    //00110011 CH A disabled. CH B enabled, polarity=HIGH (Current=550mA). --next step
      setSPIValue(53);    //00110101 CH A disabled. CH B enabled, polarity=HIGH (Current=60mA).  --park
      Serial.print("STEP3"); 
   }   

   if(POS_CUR_HS == 3) { 
      setSPIValue(51);    //00110011 CH A disabled. CH B enabled, polarity=HIGH (Current=550mA).  --current step
      setSPIValue(31);    //00011111 CH A enabled (Current=550mA), polarity=HIGH. CH B disabled. --next step
      setSPIValue(47);    //00101111 CH A enabled (Current=60mA), polarity=HIGH. CH B disabled.  --park
      Serial.print("STEP4"); 
   }   
       
      if(POS_CUR_HS == 3) POS_CUR_HS=0; else POS_CUR_HS +=1;   
      Serial.print(" POS_CUR_HS=");Serial.print(POS_CUR_HS); 
      POS_CUR += POS_STEP_HS;
      Serial.print(" POS_CUR=");Serial.println(POS_CUR);
      delay(DELAY_L);
   }
}

void stepDownHalf(void) {
/*Half steps can be used here by using middle states (currently not used) - step 1.2, step 2.2, step 3.2, step 4.2.
  In this case both channels are enabled, use current max 550mA (avoid 900mA current, overheating risk exists).
*/

   if(POS_CUR > POS_STEP_MIN) {   
   //POS_CUR_HS direction 0 --> 3 --> 2 --> 1
    
   if(POS_CUR_HS == 0) {
      setSPIValue(31);    //00011111 CH A enabled, polarity=HIGH (Current=550mA). CH B disabled.  --current step
      setSPIValue(59);    //00111011 CH A disabled. CH B enabled, polarity=HIGH (Current=550mA). --next step
      setSPIValue(61);    //00111101 CH A disabled. CH B enabled, polarity=HIGH (Current=60mA).  --park
      Serial.print("STEP1"); 
   }

   if(POS_CUR_HS == 3) {
      setSPIValue(59);    //00111011 CH A disabled. CH B enabled, polarity=HIGH (Current=550mA). --current step
      setSPIValue(23);    //00010111 CH A enabled, polarity=LOW. CH B disabled (Current=550mA). --next step
      setSPIValue(39);    //00100111 CH A enabled, polarity=LOW. CH B disabled (Current=60mA).  --park
      Serial.print("STEP2");
   }   

   if(POS_CUR_HS == 2) {
      setSPIValue(23);    //00010111 CH A enabled, polarity=LOW. CH B disabled (Current=550mA).  --current step
      setSPIValue(58);    //00111010 CH A disabled. CH B enabled, polarity=LOW (Current=550mA). --next step
      setSPIValue(60);    //00111100 CH A disabled. CH B enabled, polarity=LOW (Current=60mA).  --park
      Serial.print("STEP3"); 
   }   

   if(POS_CUR_HS == 1) { 
      setSPIValue(58);    //00111010 CH A disabled. CH B enabled, polarity=LOW (Current=550mA).   --current step
      setSPIValue(31);    //00011111 CH A enabled, polarity=HIGH (Current=550mA). CH B disabled. --next step
      setSPIValue(47);    //00101111 CH A enabled, polarity=HIGH (Current=60mA). CH B disabled.  --park      
      Serial.print("STEP4"); 
   }      

      if(POS_CUR_HS == 0) POS_CUR_HS=3; else POS_CUR_HS -=1;
      
      Serial.print(" POS_CUR_HS=");Serial.print(POS_CUR_HS); 
      POS_CUR -= POS_STEP_HS;
      Serial.print(" POS_CUR=");Serial.println(POS_CUR);
      delay(DELAY_L);
   }
}

void readPOS_CUR(int ADDR) {
//Reads a byte from the EEPROM. Locations that have never been written to have the value of 255. 

  //Serial.println("Reading current position from internal EEPROM!"); 
  POS_CUR_SAVED = EEPROM.read(ADDR); 
  Serial.print("Reading DONE! Current position: ");Serial.println(POS_CUR_SAVED);
}

void writePOS_CUR(int ADDR, int VAL) {
//Write a byte to the EEPROM. The value is written only if differs from the one already saved at the same address. 

  //Serial.print("Writing current positon to internal EEPROM: "); Serial.println(POS_CUR);
  EEPROM.update(ADDR, VAL);
  Serial.println("Writing DONE!");
}