John Bradnam
Published © GPL3+

Electronic Depth Gauge for Dremel Drill Press

A clip-on electronic depth gauge for a Dremel Drill Press. No wires or screws required.

IntermediateFull instructions provided2 days1,483

Things used in this project

Hardware components

Microchip ATtiny1614
×1
4 Digit 7 Segment Common Cathode 0.28in LED Display
×1
PTS 645 Series Switch
C&K Switches PTS 645 Series Switch
17mm shaft with button top
×1
OH49E Linear Hall Effect Sensor
×1
15mm dia x 4mm high neodymium magnet
×1
LM1117-5V
SOT-223
×1
1N4148 – General Purpose Fast Switching
1N4148 – General Purpose Fast Switching
SOD-323 or SOD-523
×9
Capacitor 100 nF
Capacitor 100 nF
0805 package
×2
Capacitor 47 µF
Capacitor 47 µF
10V or 16V - 3216 package
×1
Mini USB through hole socket
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Custom parts and enclosures

STL Files

STL files for your Slicing software. Use 0.2mm layer height

Schematics

Schematic

PCB

Eagle Files

Schematic and PCB in Eagle format

Code

Drill_Depth_Display_V1.ino

C/C++
// Drill Depth Display
// Based on a concept by Thomas Angielsky (https://www.hackster.io/tangielsky/drill-depth-display-with-gyro-sensor-dec5b9)
//
// 
// V1: jlb (jbrad2089@gmail.com)
//  - Wrote software for a ATtiny1614, 4-Digit 7 Segment Display and OH49E ratiometric hall sensor
//

//#define ALLOW_NEGATIVES   //Uncomment to display negative numbers

#ifdef __AVR__
  #include <avr/power.h>
#endif

/*-----------------------------------------------------------------------------
  ATTiny1614 Pins mapped to Ardunio Pins

             +--------+
         VCC + 1   14 + GND
 (SS)  0 PA4 + 2   13 + PA3 10 (SCK)
       1 PA5 + 3   12 + PA2 9  (MISO)
 (DAC) 2 PA6 + 4   11 + PA1 8  (MOSI)
       3 PA7 + 5   10 + PA0 11 (UPDI)
 (RXD) 4 PB3 + 6    9 + PB0 7  (SCL)
 (TXD) 5 PB2 + 7    8 + PB1 6  (SDA)
             +--------+

  PA0 to PA7 can be analog or digital
  PWM on D0, D1, D6, D7, D10

  BOARD: ATtiny1614/1604/814/804/414/404/214/204
  Chip: ATtiny1614
  Clock Speed: 20MHz
  Programmer: jtag2updi (megaTinyCore)

  Pin mapping: https://github.com/SpenceKonde/megaTinyCore/blob/master/megaavr/extras/ATtiny_x14.md

-----------------------------------------------------------------------------*/

//Pins
#define OH49E 0    //(PA4)
#define SWITCH 1   //(PA5)
#define SEG_C 2    //(PA6)
#define SEG_G_4 3  //(PA7)
#define SEG_E 4    //(PB3)
#define SEG_D 5    //(PB2)
#define SEG_F 6    //(PB1)
#define SEG_A_2 7  //(PB0)
#define SEG_B 8    //(PA1)
#define SEG_G_3 9  //(PA2)
#define SEG_A_1 10 //(PA3)

#define PA0_bm PIN0_bm
#define PA1_bm PIN1_bm
#define PA2_bm PIN2_bm
#define PA3_bm PIN3_bm
#define PA4_bm PIN4_bm
#define PA5_bm PIN5_bm
#define PA6_bm PIN6_bm
#define PA7_bm PIN7_bm
#define PB0_bm PIN0_bm
#define PB1_bm PIN1_bm
#define PB2_bm PIN2_bm
#define PB3_bm PIN3_bm



/* 1mS refresh timer for 7 segment display
 * Attiny1614's default clock is 8MHz(RC)
 * CLK_PER is 1.333MHz ( default prescaler rate is 6, then 8/6 == 1.3 )
 * interrupt interval = 1ms ( 1333 / 1.333MHz = 0.001sec )
*/
#define TCB_COMPARE 8000
uint8_t digits[4];      //Holds the current digits to display
uint8_t nextDigit = 0;  //Holds next digit to display

//Digit array
uint8_t segments[16] = {
//    abcdefg   abcdefg   abcdefg   abcdefg   abcdefg   abcdefg   abcdefg   abcdefg
    B01111110,B00110000,B01101101,B01111001,B00110011,B01011011,B01011111,B01110000,
    B01111111,B01111011,B00000000,B00000001,B01011011,B00001111,B00011101,B01100111
};
#define SPACE 10
#define NEG 11
#define S_ 12
#define T_ 13
#define O_ 14
#define P_ 15

#define AVG_SIZE 128
#define AVG_MASK 0x7F
uint32_t zeroValue = 0;
uint32_t lockValue = 0;
uint32_t runningTotal = 0;
uint16_t runningCount = 0;
uint8_t runningHead = 0; 
uint8_t runningTail = 0;
uint16_t runningValues[AVG_SIZE];

#define UPDATE_TIME 300
uint32_t updateTimeout;

#define LONG_PRESS_PERIOD 200
enum SwitchEnum { NONE, SHORT, LONG };

//-------------------------------------------------------------------------
//Initialise Hardware

void setup() 
{
  pinMode(SWITCH, INPUT_PULLUP);
  pinMode(OH49E, INPUT);
 
  //Initialise digits
  memset(&digits[0],SPACE,4);

  //Set up 7 segment display refresh timer
  TCB0.CCMP = TCB_COMPARE;
  TCB0.INTCTRL = TCB_CAPT_bm;
  TCB0.CTRLA = TCB_ENABLE_bm;

  //Enable interrupts
  sei();

  updateTimeout = 0;
  
}

//-------------------------------------------------------------------------
//Timer B Interrupt handler interrupt each mS - output segments
ISR(TCB0_INT_vect)
{
  uint8_t d = segments[digits[3 - nextDigit]];
  
  //Segment order for d is pabcdefg
  PORTA.DIR = PA6_bm | PA4_bm | PA1_bm;
  PORTB.DIR = PB3_bm | PB2_bm | PB1_bm;

  //Set all digit cathodes HIGH
  uint8_t a = PA7_bm | PA3_bm | PA2_bm;
  uint8_t b = PB0_bm;
  //Set the cathode of the current digit LOW - Rest FLOAT
  switch (nextDigit)
  {
    case 0: a &= ~PA3_bm; PORTA.DIRSET = PA3_bm; break;
    case 1: b &= ~PB0_bm; PORTB.DIRSET = PB0_bm; break;
    case 2: a &= ~PA2_bm; PORTA.DIRSET = PA2_bm; break;
    case 3: a &= ~PA7_bm; PORTA.DIRSET = PA7_bm; break;
  }

  //Set the segment anodes HIGH
  if (d & B10000000) a |= PA4_bm;  //DP
  if (d & B00100000) a |= PA1_bm;  //B
  if (d & B00010000) a |= PA6_bm;  //C
  if (d & B00001000) b |= PB2_bm;  //D
  if (d & B00000100) b |= PB3_bm;  //E
  if (d & B00000010) b |= PB1_bm;  //F
  //Segments A and G are multiplexed with Digits pins - Set Segment HIGH
  if (d & B01000000)  //A
  {
    if (nextDigit == 0) { b |= PB0_bm; PORTB.DIRSET = PB0_bm; } //A2
    else                { a |= PA3_bm; PORTA.DIRSET = PA3_bm; } //A1
  }
  if (d & B00000001)  //G
  {
    if (nextDigit == 2) { a |= PA7_bm; PORTA.DIRSET = PA7_bm; } //G4
    else                { a |= PA2_bm; PORTA.DIRSET = PA2_bm; } //G3
  }
  //Set the output pins
  PORTA.OUT = a;  //Set the outputs
  PORTB.OUT = b;

  //Setup for next digit
  nextDigit = (nextDigit + 1) & 0x03;

  //Clear interrupt flag
  TCB0.INTFLAGS |= TCB_CAPT_bm; //clear the interrupt flag(to reset TCB0.CNT)
}


//-------------------------------------------------------------------------
// Handle interactions

void loop() 
{
  switch (readSwitch())
  {
    case LONG:  setZeroValue(); break;
    case SHORT: setLockValue(); break;
  }
  
  //Read the hall sensor and add it to the running average list
  int hall = analogRead(OH49E);
  if (runningCount == AVG_SIZE)
  {
    //Remove oldest value from running total
    runningTotal = runningTotal - runningValues[runningTail];
    runningTail = (runningTail + 1) & AVG_MASK;
    runningCount--;
  }
  //Add new value to running total
  runningValues[runningHead] = hall;
  runningHead = (runningHead + 1) & AVG_MASK;
  runningTotal = runningTotal + hall;
  runningCount++;

  //Display running average
  if (millis() > updateTimeout)
  {
    uint16_t value = runningTotal / runningCount;
    if (lockValue == 0)
    {
      displayNumber(value - zeroValue);
    }
    else if (value < lockValue)
    {
      displayNumber(lockValue - value);
    }
    else
    {
      digits[3] = S_;
      digits[2] = T_;
      digits[1] = O_;
      digits[0] = P_;
    }
    updateTimeout = millis() + UPDATE_TIME;
  }
}

//-----------------------------------------------------------------------------------
//Read switch value and return a SwitchEnum value
SwitchEnum readSwitch()
{
  uint32_t longTimeOut = millis() + LONG_PRESS_PERIOD;
  SwitchEnum result = NONE;
  if (digitalRead(SWITCH) == LOW)
  {
    //debounce
    delay(10);
    if (digitalRead(SWITCH) == LOW)
    {
      //wait for release
      while (digitalRead(SWITCH) == LOW)
      {
      }
      result = (millis() >= longTimeOut) ? LONG : SHORT;
    }
  }
  return result;
}

//-----------------------------------------------------------------------------------
//Uses the current hall sensor value as 0mm
void setZeroValue()
{
  zeroValue = 0;
  for(int i = 0; i < 100; i++)
  {
      zeroValue += analogRead(OH49E);
  }
  zeroValue = zeroValue / 100;
  lockValue = 0;    //Clear any lock value
  runningCount = 1;
  runningHead = 1;
  runningTail = 0;
  runningTotal = zeroValue;
  runningValues[runningTail] = zeroValue;
}


//-----------------------------------------------------------------------------------
//Uses the current hall sensor value as the lock value
void setLockValue()
{
  lockValue = runningTotal / runningCount;
}

//-----------------------------------------------------------------------------------
//Display a number on the 7 segment display
void displayNumber(int number)
{
  bool neg = false;
  if (number < 0)
  {
    #ifdef ALLOW_NEGATIVES    
      number = -number;
      neg = true;
    #else
      number = 0;
    #endif
  }
  for (uint8_t i = 0; i < 4; i++)
  {
    if (number > 0 || i == 0)
    {
      digits[i] = number % 10;
    }
    else
    {
      digits[i] = SPACE;
    }
    number = number / 10;
  }
  if (neg)
  {
    digits[3] = NEG;
  }
}

Credits

John Bradnam

John Bradnam

141 projects • 167 followers

Comments