RPM meter for a milling machine

CNCRPMMeter

My home workshop’s Milling machine now has a brand new rpm meter. Even though the machine has markings on the rpm adjustment dial, often it is hard to tell what is the actual rotation of the milling tool. Milling speeds and feed rates are important in obtaining a nice finish on the workpiece and prolonging tool life. The principle behind the rpm meters is quite simple; as the drawbar rotates, every revolution is counted by a Hall-effect sensor. The sensor is triggered by a small, yet strong magnet attached to the top of the drawbar via a custom 3D-printed holder. The counts from the sensor are transferred to a micro-controller, which displays it on a 4-digit LED screen.

The meter was constructed using a PIC micro-controller and a  MELEXIS MLX90217 Hall-Effect Cam Sensor. The display is a Lite-On Elec. LTC-4727JS 4 digit, 7-segment, common Cathode display driven by a MAX7221 LED Driver.

This short article concentrates on the rpm meter prope. Pretty much any PIC micro-controller can be used to run the device. Mine is a PIC16F876A on a home-brew printed circuit board. The schematics, and the PCB layout shown below along with the PIC BASIC Pro firmware source code should be sufficient to wire up the LED driver and the Hall-effect sensor to your particular flavour of micro-controller.

The PCB containing the display and its driver and the PIC board are housed in a box made of 1/8″ thick MDF with custom milled cutout for the display. The box is attached to a 3D printed cylinder that sleeves over a protrusion on top the mill’s gearbox. Thus the rpm meter can be taken off with ease and replaced by the plastic cap that came with the mill.

The following schematic illustrates the wiring between various components. Note that the PIC connects to the PCB board via four wires at JP1. The power to the board is supplied via the POWER connection and the Hall-effect sensor is labeled by MLX90217. The LED display, although missing a label (…my bad…) is the one in the upper right corner. Capacitor C1 and resistor R2 are per the MELEXIS data sheet (page 6, bottom left diagram), while resistor R1 and capacitors C2 and C3 follow the data sheet for the MAX7221 display driver (see page 10 for the capacitors and their types [C2 is a ceramic one and C3 is an electrolytic], place the capacitor as close as possible to the LED driver) .

SchematicsSchematics

The matching PCB layout was created in EAGLE. Although I am attaching an image of it with the component placement, it is best to re-design it to suit your needs. My meager PCB making skills only cover one-sided PCBs, so I laid out the components and traces for a single-layer PCB. Of course, double-layer PCB could make the PCB much smaller.

PCBLayout

The firmware, which is responsible for polling the Hall-effect sensor and displaying the RPM is presented next. It was written in PIC BASIC Pro, but I am sure that any variant of a micro- controller programming language can be used to adapt the code. The source code is commented enough, I hope, that it is easy to follow what is going on. The Hall-effect sensor is accessed via port B.3 on the PIC, while the MAX7721 is communicated to via ports B.0 for clock (CLK), B.1 for data and B.2 for CS. The main program, after setting up and initializing the LED driver enters into an infinite loop. Within the loop the PIC polls the MELEXIS sensor and sends the rpm value as ones, tens, hundreds and thousands (the four digits) to the LED driver. A note on how the actual rpm value is computed. Revolutions or rotations per minute are displayed, but the number is arrived at by counting the pulses from the Hall-effect sensor for 4 seconds and multiplying this value by 15 to arrive at the number of revolutions per 60 seconds (or a minute). This is done so the display of the rpm is updated relative frequently, yet allowing enough time to sample the Hall-effect sensor’s output.

'****************************************************************
'* Name : CNCRPM.BAS *
'* Author : Dr. A.M. Zsaki *
'* Notice : Copyright (c) 2012 All right reserved 2012 *
'* : All Rights Reserved *
'* Date : 12/15/2012 *
'* Version : 1.0 *
'* Notes : *
'* : *
'****************************************************************

'****************************************************************
'* *
'* Equipment used: Homebrew PIC16F876A microcontroller *
'* Melexis MLX90217 Hall-Effect Cam Sensor *
'* MAX7221 LED Driver *
'* Lite-On Elec. LTC-4727JS 4 digit, 7-segment *
'* Common Cathode display *
'* Misc. passive components; resistors, *
'* capacitors, see datasheets and EAGLE *
'* schematics *
'* *
'****************************************************************

INCLUDE "modedefs.bas"

' PIC16F876A is running at 4MHz
DEFINE OSC 4

' Serial port setup for debug
DEFINE DEBUG_REG PORTC
DEFINE DEBUG_BIT 6
DEFINE DEBUG_BAUD 9600
Define DEBUG_MODE 0

' Port and variable for communicating with the Hall effect sensor
'HallPort var PORTC.3
HallPort var PORTB.3
Hall_Counter VAR WORD

' Ports for communicating with the MAX7221 LED driver
MAX7221Data VAR PORTB.1
CLK VAR PORTB.0
CS VAR PORTB.2

' Variables for the codes (bit serquences) for setting up and communicating
' with MAX7221
DisplayTestOpcode VAR WORD
ScanLimitEnableAllOpcode VAR WORD
NoDecodeOpcode VAR WORD
ClearDigit1Opcode VAR WORD
ClearDigit2Opcode VAR WORD
ClearDigit3Opcode VAR WORD
ClearDigit4Opcode VAR WORD
ClearDigit5Opcode VAR WORD
ClearDigit6Opcode VAR WORD
ClearDigit7Opcode VAR WORD
ClearDigit8Opcode VAR WORD
ShutdownModeOffOpcode VAR WORD
ShutdownModeOnOpcode VAR WORD
SetIntensity8Opcode VAR WORD

' Variables for the current opcode, the current number to display and
' the position (digit location) for display the number
' NOTE: DigitPosition is counted left to right on the display (or as
' wired between the MAX7221 and LTC-4727JS
Opcode VAR WORD
DigitPosition VAR BYTE
DigitNumber VAR BYTE

' Constants holding the on/off bits for various numbers from 0 to 9
Numbers VAR BYTE[10]

' Constants holding the opcode for digit locations 0-7 on the display
Digits VAR BYTE[8]

' Counter
Counter VAR BYTE

' Variable holding the current number to display
Number VAR BYTE

' Variable holding the current digit to display
Digit VAR BYTE

'****************************************************************
'* *
'* Initialize variables and constants *
'* *
'****************************************************************

' Make the MAX7221 communication pins outputs
TRISB.0=0
TRISB.1=0
TRISB.2=0

' Initialize the Opcodes for MAX7221 communication
' for the meaning of each see the MAX7221 datasheet
DisplayTestOpcode=%000011110000000
ScanLimitEnableAllOpcode=%0000101100000111
NoDecodeOpcode=%0000100100000000
ClearDigit1Opcode=%0000000100000000
ClearDigit2Opcode=%0000001000000000
ClearDigit3Opcode=%0000001100000000
ClearDigit4Opcode=%0000010000000000
ClearDigit5Opcode=%0000010100000000
ClearDigit6Opcode=%0000011000000000
ClearDigit7Opcode=%0000011100000000
ClearDigit8Opcode=%0000100000000000
ShutdownModeOffOpcode=%0000110000000000
ShutdownModeOnOpcode=%0000110000000001
SetIntensity8Opcode=%0000101000000111

' Definitions of numbers as displayed by segments
' for the meaning of each see the MAX7221 datasheet
NUMBERS[1]=%01111110 ' 0
NUMBERS[2]=%00110000 ' 1
NUMBERS[3]=%01101101 ' 2
NUMBERS[4]=%01111001 ' 3
NUMBERS[5]=%00110011 ' 4
NUMBERS[6]=%01011011 ' 5
NUMBERS[7]=%01011111 ' 6
NUMBERS[8]=%01110000 ' 7
NUMBERS[9]=%01111111 ' 8
NUMBERS[10]=%01111011 ' 9

' Definitions of opcodes for setting sigits on the LED display
' for the meaning of each see the MAX7221 datasheet
DIGITS[1]=%00000001 ' Position 0
DIGITS[2]=%00000010 ' Position 1
DIGITS[3]=%00000011 ' Position 2
DIGITS[4]=%00000100 ' Position 3
DIGITS[5]=%00000101 ' Position 4
DIGITS[6]=%00000110 ' Position 5
DIGITS[7]=%00000111 ' Position 6
DIGITS[8]=%00001000 ' Position 7

'****************************************************************
'* *
'* Main program starts here *
'* *
'****************************************************************

main:

' Initialize the MAX7221 LED Driver
GOSUB MAX7221Initialize

' Shutdown Mode - Turn On
OPCODE=ShutdownModeOnOpcode
GOSUB SPICommand

' Set Intensity to 8
OPCODE=SetIntensity8Opcode
GOSUB SPICommand

' Display 0000 on the LED display
DigitPosition=0
DigitNumber=0
GOSUB DisplayNumberAtDigit

DigitPosition=1
DigitNumber=0
GOSUB DisplayNumberAtDigit

DigitPosition=2
DigitNumber=0
GOSUB DisplayNumberAtDigit

DigitPosition=3
DigitNumber=0
GOSUB DisplayNumberAtDigit

loop:

' Obtain reading for the Hall-effect device
' by counting the number of crossings for 4 seconds
' Multiply this value (Hall_Counter) by 15 to obtain
' RPM
HALL_COUNTER=0
COUNT HallPort,4000,HALL_COUNTER
HALL_COUNTER=HALL_COUNTER*15
debug "RPM:",#HALL_COUNTER," ",10,13

' Show the RPM count on the LED display
' Rightmost digit (ones)
DigitPosition=3
DigitNumber=HALL_COUNTER DIG 0
GOSUB DisplayNumberAtDigit

' (tens)
DigitPosition=2
DigitNumber=HALL_COUNTER DIG 1
GOSUB DisplayNumberAtDigit

' (hundreds)
DigitPosition=1
DigitNumber=HALL_COUNTER DIG 2
GOSUB DisplayNumberAtDigit

' (thousands)
DigitPosition=0
DigitNumber=HALL_COUNTER DIG 3
GOSUB DisplayNumberAtDigit

' Loop back forever
goto loop

END

'****************************************************************
'* *
'* Initialize the MAX7221 LED driver *
'* *
'* See the MAX7221 datasheet for the meaning of these codes *
'* *
'****************************************************************
MAX7221Initialize

HIGH CS

' Set Display Test
OPCODE=DisplayTestOpcode
GOSUB SPICommand

' Set Scan Limit - Enable All eight digits
OPCODE=ScanLimitEnableAllOpcode
GOSUB SPICommand

' Set Decode Mode - No Decode
OPCODE=NoDecodeOpcode
GOSUB SPICommand

' Set Clear Display 1
OPCODE=ClearDigit1Opcode
GOSUB SPICommand

' Set Clear Display 2
OPCODE=ClearDigit2Opcode
GOSUB SPICommand

' Set Clear Display 3
OPCODE=ClearDigit3Opcode
GOSUB SPICommand

' Set Clear Display 4
OPCODE=ClearDigit4Opcode
GOSUB SPICommand

' Set Clear Display 5
OPCODE=ClearDigit5Opcode
GOSUB SPICommand

' Set Clear Display 6
OPCODE=ClearDigit6Opcode
GOSUB SPICommand

' Set Clear Display 7
OPCODE=ClearDigit7Opcode
GOSUB SPICommand

' Set Clear Display 8
OPCODE=ClearDigit8Opcode
GOSUB SPICommand

' Set Shutdown Mode - Off
OPCODE=ShutdownModeOffOpcode
GOSUB SPICommand

RETURN

'****************************************************************
'* *
'* Send an SPI command to the MAX7221 *
'* *
'****************************************************************
SPICommand

low CS
ShiftOut MAX7221Data,clk,MSBFIRST,[OPCODE\16]
HIGH CS

RETURN

'****************************************************************
'* *
'* Display a number at a 'digit' location *
'* *
'****************************************************************
DisplayNumberAtDigit

DIGIT=DIGITS[DigitPosition+1]
NUMBER=NUMBERS[DigitNumber+1]

' Lower byte of word - Number to display
FOR COUNTER=0 TO 7
OPCODE.0(COUNTER)=NUMBER.0(COUNTER)
NEXT

' Upper byte of word - Digit position
FOR COUNTER=8 TO 15
OPCODE.0(COUNTER)=DIGIT.0(COUNTER-8)
NEXT

GOSUB SPICommand

RETURN

Well, there is nothing much else to it. Now it is relatively easy to add an RPM meter to any milling machine.

Now, off to make more chips…