Sunspot

"Ratting a scanner"
Byvac BV4213 stepper motor driver used to convert a scanner into a linear camera mover

personal notes for my backup

Objective
Learn about stepper motors by using an old image scanner mechanism that was about to be tipped.
Drive by the existing 4 wire stepper motor
to move a web camera attached to a glass-walled bee hive.
Attempt to make a close up time lapse film of bees building a queen cell (next year!)

The Byvac BV4213 has several drive modes.
I need a second i2c device to detect the end of transit of the stepped scan,
to detect the end of scan microswitch state, to drive the motor power, to drive the white LEDs that illuminate the bees
and to drive the Byvac directly- (I tried and failed to drive the Byvac via it's own i2c port)

- so I used an i2c to 8 wire PCF8574P
- the 8 pin chip is a long i2c line driver - a 82B715

Circuit

The stepper motor drives a carriage that holds a web camera.
Microswitches detect when the carriage is at the end of its allowed area.
Three white LEDs illuminate the bees, but only when the system is live.
The scanner flexible ribbon cable was used for all signals by cutting out the existing connections with Dremmel.

scan circuit

#!/usr/sbin/blassic
'test direct control of Byvac 4213 stepper driver
' stepper_test.bas <full=0/half=1> <direction=0/1> <delay-0=fastest> <steps>
' e.g. -
' /home/graham/stepper_direct/stepper_test.bas 0 1 0 24 (= 1 turn)
' /home/graham/stepper_direct/stepper_test.bas 0 1 0 240 (= 10 turns)
' /home/graham/stepper_direct/stepper_test.bas 1 1 0 24 (= 1/2 turn)
' /home/graham/stepper_direct/stepper_test.bas 0 0 0 24 (= 1 turn, reverse)
' /home/graham/stepper_direct/stepper_test.bas 0 0 100 24 (= 1 turn, reverse, slower)

full = VAL(PROGRAMARG$(1))
direction = VAL(PROGRAMARG$(2))
delay = VAL(PROGRAMARG$(3))
steps = VAL(PROGRAMARG$(4))

LABEL StartHere

' line 0 must be low for the motor to receive power via the P channel MOSFET
' line 1 must be low to turn off the white LEDs when we have finished looking at the bees

' line 4 (value 16) used to pulse the motor - both transitions

byte_out_HI = 128 + full*64 +direction*32 + 16
byte_out_LO = 128 + full*64 +direction*32

byte_out_HI$ = STR$(byte_out_HI)
byte_out_LO$ = STR$(byte_out_LO)

PRINT byte_out_HI$, byte_out_LO$

FOR i=1 to steps ' switch line 4 HI and LO (motor steps on transition up or down)
FOR j = 1 to 24 ' each step is a full turn of the stepper
PRINT i
BV$ = BIN$ (VAL(PCF8574_inputs$)): PRINT BV$ ' see the line states
SHELL "PCF8574_addr_byteout 38 "+ byte_out_HI$ ' output 4 switched HI
PAUSE delay
SHELL "PCF8574_addr_byteout 38 "+ byte_out_LO$ ' output 4 switched LO
PAUSE delay
next j

' are we on the buffer?
SHELL "echo -n `PCF8574_addr_read_sweex_nowrite2 38`>/var/www/ramdisk/read_PCF8574_inputs.txt"
OPEN "/var/www/ramdisk/read_PCF8574_inputs.txt" FOR INPUT AS #1 : INPUT #1,PCF8574_inputs$ : CLOSE #1
IF VAL(PCF8574_inputs$) > 127 THEN GOTO EndStop
next i

'turn the LEDs and motor power off now the motor is not needed
SHELL "PCF8574_addr_byteout 38 2"

SYSTEM

LABEL EndStop
BV$ = BIN$ (VAL(PCF8574_inputs$)): PRINT BV$ ' see the line states
PRINT "you hit the buffers!"
if direction = 1 THEN direction = 0: GOTO CarryOn
direction = 1
LABEL CarryOn
steps = 48 ' back off the buffer by two turns

byte_out_HI = 128 + full*64 +direction*32 + 16
byte_out_LO = 128 + full*64 +direction*32
byte_out_HI$ = STR$(byte_out_HI)
byte_out_LO$ = STR$(byte_out_LO)

FOR i=1 to steps
PRINT i
BV$ = BIN$ (VAL(PCF8574_inputs$)): PRINT BV$ ' see the line states

SHELL "PCF8574_addr_byteout 38 "+ byte_out_HI$
PAUSE delay
SHELL "PCF8574_addr_byteout 38 "+ byte_out_LO$
PAUSE delay
next i

'turn the LEDs and motor power off
SHELL "PCF8574_addr_byteout 38 2"

SYSTEM

'switch full dirn HI/LO 3 2 1 0-used for <Motor_Power (ON = 0)>
' 1 1 1 1 0 0 0 0 = byte_out_HI
' 1 1 1 0 0 0 0 0 = byte_out_LO

' note if the main power is turned on but no control is received
' the motor power defaults to off - bit 0 HI- (P channel MOSFET gate HI)


/*
PCF8574_addr_read_sweex_nowrite2.c
-------------------
read the data on the 8 line port of an i2c bus PCF8574
------------------------------------------------------

1) set the i2c address of the PCF8574
2) send data 255 to turn off all 8 lines - make them inputs
3) read the data on the 8 port lines as a byte
usage :- type (without the < >)
<PCF8574_address_read_4> <space> <i2c_bus_address_of_PCF8574_as_decimal>
*/

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/i2c.h>

int i2c;
int buf[1];
int address; /* i2c bus address of the PCF8574 */
int byte; /* the 8 bit byte that represents the data present on the 8 wire port */

int main(int argc, char** argv)
{
if (argc != 2) /* report error if we are not getting just 1 input after the program name */

{

printf("Error. usage: %s i2c_chip_address\n", argv[0]);

}

address = atoi(argv[1]); /* address is the first number after the program name */

i2c = open("/dev/i2c/0",O_RDWR); /* open the i2c-bus number 0 */

ioctl(i2c,I2C_SLAVE, address); /* set the address of the chip we will talk to */

buf[0] = 255;

read(i2c,buf,1); /* now buf(0) contains the byte of data on the 8 port lines*/

byte = buf[0];

printf("%d", byte);
/* BYTE value is 0-256)*/

i2c = close(i2c);
}


/*
PCF8574_addr_read.c
-------------------
read the data on the 8 line port of an i2c bus PCF8574
------------------------------------------------------

1) set the i2c address of the PCF8574
2) send data 255 to turn off all 8 lines - make them inputs
3) read the data on the 8 port lines as a byte
usage :- type (without the < >)
<PCF8574_address_read_4> <space> <i2c_bus_address_of_PCF8574_as_decimal>
*/

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/i2c.h>

int i2c;
int buf[1];
int address; /* i2c bus address of the PCF8574 */
int byte; /* the 8 bit byte that represents the data present on the 8 wire port */

int main(int argc, char** argv)
{
if (argc != 2) /* report error if we are not getting just 1 input after the program name */

{
printf("Error. usage: %s i2c_chip_address\n", argv[0]);
}

address = atoi(argv[1]); /* address is the first number after the program name */

i2c = open("/dev/i2c/0",O_RDWR); /* open the i2c-bus number 0 */

ioctl(i2c,I2C_SLAVE, address); /* set the address of the chip we will talk to */

buf[0] = 255;

write(i2c,buf,1); /* we send 255 to make all lines go off, ready for input data */

read(i2c,buf,1); /* now buf(0) contains the byte of data on the 8 port lines*/

byte = buf[0];

printf("BYTE = %d \n", byte);
/* BYTE value is 0-256)*/

i2c = close(i2c);
}

Bee pictures to follow ?!?!
More here

Sunspot