Add Laser Based I2C Ammeter Feature (#21835)
This commit is contained in:
parent
588a74fd9d
commit
002e1d49fe
|
@ -3283,6 +3283,15 @@
|
|||
//#define AIR_ASSIST_PIN 44 // Override the default Air Assist pin
|
||||
#endif
|
||||
|
||||
//
|
||||
// Laser I2C Ammeter (High precision INA226 low/high side module)
|
||||
//
|
||||
//#define I2C_AMMETER
|
||||
#if ENABLED(I2C_AMMETER)
|
||||
#define I2C_AMMETER_IMAX .1 // Calibration value for the expected current range in Amps (use float e.g. 1.0)
|
||||
#define I2C_AMMETER_SHUNT_RESISTOR .1 // Calibration shunt resistor value in ohms
|
||||
#endif
|
||||
|
||||
//#define SPINDLE_SERVO // A servo converting an angle to spindle power
|
||||
#ifdef SPINDLE_SERVO
|
||||
#define SPINDLE_SERVO_NR 0 // Index of servo used for spindle control
|
||||
|
|
49
Marlin/src/feature/ammeter.cpp
Normal file
49
Marlin/src/feature/ammeter.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../inc/MarlinConfig.h"
|
||||
|
||||
#if ENABLED(I2C_AMMETER)
|
||||
#include "ammeter.h"
|
||||
|
||||
INA226 ina;
|
||||
|
||||
Ammeter ammeter;
|
||||
|
||||
float Ammeter::scale;
|
||||
float Ammeter::current;
|
||||
|
||||
void Ammeter::init() {
|
||||
ina.begin();
|
||||
ina.configure(INA226_AVERAGES_16, INA226_BUS_CONV_TIME_1100US, INA226_SHUNT_CONV_TIME_1100US, INA226_MODE_SHUNT_BUS_CONT);
|
||||
ina.calibrate(I2C_AMMETER_SHUNT_RESISTOR,I2C_AMMETER_IMAX);
|
||||
}
|
||||
|
||||
float Ammeter::read() {
|
||||
scale = 1;
|
||||
current = ina.readShuntCurrent();
|
||||
if (current <= .0001) current = 0; // Cleanup lsb bit amplification errors
|
||||
if (current < .1) scale = 1000;
|
||||
return current * scale;
|
||||
}
|
||||
|
||||
#endif //I2C_AMMETER
|
44
Marlin/src/feature/ammeter.h
Normal file
44
Marlin/src/feature/ammeter.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../inc/MarlinConfigPre.h"
|
||||
|
||||
#include <Wire.h>
|
||||
#include <INA226.h>
|
||||
|
||||
#ifndef I2C_AMMETER_IMAX
|
||||
#define I2C_AMMETER_IMAX .500 // Calibration range 500 Milli Amps
|
||||
#endif
|
||||
|
||||
class Ammeter {
|
||||
private:
|
||||
static float scale;
|
||||
|
||||
public:
|
||||
static float current;
|
||||
static void init();
|
||||
static float read();
|
||||
|
||||
};
|
||||
|
||||
extern Ammeter ammeter;
|
|
@ -34,6 +34,10 @@
|
|||
#include "../module/servo.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(I2C_AMMETER)
|
||||
#include "../feature/ammeter.h"
|
||||
#endif
|
||||
|
||||
SpindleLaser cutter;
|
||||
uint8_t SpindleLaser::power;
|
||||
#if ENABLED(LASER_FEATURE)
|
||||
|
@ -74,6 +78,10 @@ void SpindleLaser::init() {
|
|||
#if ENABLED(AIR_ASSIST)
|
||||
OUT_WRITE(AIR_ASSIST_PIN, !AIR_ASSIST_ACTIVE); // Init Air Assist OFF
|
||||
#endif
|
||||
#if ENABLED(I2C_AMMETER)
|
||||
ammeter.init(); // Init I2C Ammeter
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if ENABLED(SPINDLE_LASER_PWM)
|
||||
|
|
|
@ -50,6 +50,10 @@
|
|||
#include "../../feature/cooler.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(I2C_AMMETER)
|
||||
#include "../../feature/ammeter.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_UBL)
|
||||
#include "../../feature/bedlevel/bedlevel.h"
|
||||
#endif
|
||||
|
@ -588,12 +592,26 @@ FORCE_INLINE void _draw_cooler_status(const char prefix, const bool blink) {
|
|||
|
||||
#if ENABLED(LASER_COOLANT_FLOW_METER)
|
||||
FORCE_INLINE void _draw_flowmeter_status() {
|
||||
lcd_put_u8str("~ ");
|
||||
lcd_put_u8str("~");
|
||||
lcd_put_u8str(ftostr11ns(cooler.flowrate));
|
||||
lcd_put_wchar('L');
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLED(I2C_AMMETER)
|
||||
FORCE_INLINE void _draw_ammeter_status() {
|
||||
lcd_put_u8str(" ");
|
||||
ammeter.read();
|
||||
if (ammeter.current <= .999) {
|
||||
lcd_put_u8str(ftostr3ns(ammeter.current));
|
||||
lcd_put_u8str("mA");
|
||||
} else {
|
||||
lcd_put_u8str(ftostr12ns(ammeter.current));
|
||||
lcd_put_wchar('A');
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
FORCE_INLINE void _draw_bed_status(const bool blink) {
|
||||
_draw_heater_status(H_BED, TERN0(HAS_LEVELING, blink && planner.leveling_active) ? '_' : LCD_STR_BEDTEMP[0], blink);
|
||||
}
|
||||
|
@ -835,6 +853,9 @@ void MarlinUI::draw_status_screen() {
|
|||
#if ENABLED(LASER_COOLANT_FLOW_METER)
|
||||
_draw_flowmeter_status();
|
||||
#endif
|
||||
#if ENABLED(I2C_AMMETER)
|
||||
_draw_ammeter_status();
|
||||
#endif
|
||||
|
||||
#endif // LCD_WIDTH >= 20
|
||||
|
||||
|
|
|
@ -107,7 +107,18 @@
|
|||
#define STATUS_FLOWMETER_BYTEWIDTH BW(STATUS_FLOWMETER_WIDTH)
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// Laser Ammeter
|
||||
//
|
||||
#if !STATUS_AMMETER_WIDTH && ENABLED(I2C_AMMETER)
|
||||
#include "status/ammeter.h"
|
||||
#endif
|
||||
#ifndef STATUS_AMMETER_WIDTH
|
||||
#define STATUS_AMMETER_WIDTH 0
|
||||
#endif
|
||||
#ifndef STATUS_AMMETER_BYTEWIDTH
|
||||
#define STATUS_AMMETER_BYTEWIDTH BW(STATUS_AMMETER_WIDTH)
|
||||
#endif
|
||||
|
||||
//
|
||||
// Bed
|
||||
|
@ -603,6 +614,32 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if ENABLED(I2C_AMMETER)
|
||||
#if STATUS_AMMETER_WIDTH
|
||||
|
||||
#ifndef STATUS_AMMETER_X
|
||||
#define STATUS_AMMETER_X (LCD_PIXEL_WIDTH - (STATUS_AMMETER_BYTEWIDTH + STATUS_FLOWMETER_BYTEWIDTH + STATUS_FAN_BYTEWIDTH + STATUS_CUTTER_BYTEWIDTH + STATUS_COOLER_BYTEWIDTH) * 8)
|
||||
#endif
|
||||
|
||||
#ifndef STATUS_AMMETER_HEIGHT
|
||||
#define STATUS_AMMETER_HEIGHT(S) (sizeof(status_ammeter_bmp1) / (STATUS_AMMETER_BYTEWIDTH))
|
||||
#endif
|
||||
|
||||
#ifndef STATUS_AMMETER_Y
|
||||
#define STATUS_AMMETER_Y(S) (18 - STATUS_AMMETER_HEIGHT(S))
|
||||
#endif
|
||||
|
||||
#ifndef STATUS_AMMETER_TEXT_X
|
||||
#define STATUS_AMMETER_TEXT_X (STATUS_AMMETER_X + 7)
|
||||
#endif
|
||||
|
||||
static_assert(
|
||||
sizeof(status_ammeter_bmp1) == (STATUS_AMMETER_BYTEWIDTH) * STATUS_AMMETER_HEIGHT(0),
|
||||
"Status ammeter bitmap (status_ammeter_bmp1) dimensions don't match data."
|
||||
);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//
|
||||
// Bed Bitmap Properties
|
||||
//
|
||||
|
@ -696,6 +733,9 @@
|
|||
#if ENABLED(LASER_COOLANT_FLOW_METER)
|
||||
#define DO_DRAW_FLOWMETER 1
|
||||
#endif
|
||||
#if ENABLED(I2C_AMMETER)
|
||||
#define DO_DRAW_AMMETER 1
|
||||
#endif
|
||||
|
||||
#if HAS_TEMP_CHAMBER && STATUS_CHAMBER_WIDTH && HOTENDS <= 4
|
||||
#define DO_DRAW_CHAMBER 1
|
||||
|
|
71
Marlin/src/lcd/dogm/status/ammeter.h
Normal file
71
Marlin/src/lcd/dogm/status/ammeter.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// lcd/dogm/status/ammeter.h - Status Screen Laser Ammeter bitmaps
|
||||
//
|
||||
#if ENABLED(I2C_AMMETER)
|
||||
|
||||
#define STATUS_AMMETER_WIDTH 20
|
||||
|
||||
const unsigned char status_ammeter_bmp_mA[] PROGMEM = {
|
||||
B00000000,B11111100,B00000000,
|
||||
B00000011,B00000011,B00000000,
|
||||
B00000100,B00000000,B10000000,
|
||||
B00001000,B00000000,B01000000,
|
||||
B00010000,B00000110,B00100000,
|
||||
B00010000,B00001001,B00100000,
|
||||
B00100000,B00001001,B00010000,
|
||||
B00100011,B01001111,B00010000,
|
||||
B11100010,B10101001,B00011100,
|
||||
B00100010,B10101001,B00010000,
|
||||
B00100010,B10101001,B00010000,
|
||||
B00010000,B00000000,B00100000,
|
||||
B00010000,B00000000,B00100000,
|
||||
B00001000,B00000000,B01000000,
|
||||
B00000100,B00000000,B10000000,
|
||||
B00000011,B00000011,B00000000,
|
||||
B00000000,B11111100,B00000000
|
||||
};
|
||||
|
||||
const unsigned char status_ammeter_bmp_A[] PROGMEM = {
|
||||
B00000000,B11111100,B00000000,
|
||||
B00000011,B00000011,B00000000,
|
||||
B00000100,B00000000,B10000000,
|
||||
B00001000,B00000000,B01000000,
|
||||
B00010000,B00000000,B00100000,
|
||||
B00010000,B00110000,B00100000,
|
||||
B00100000,B01001000,B00010000,
|
||||
B00100000,B01001000,B00010000,
|
||||
B11100000,B01111000,B00011100,
|
||||
B00100000,B01001000,B00010000,
|
||||
B00100000,B01001000,B00010000,
|
||||
B00010000,B01001000,B00100000,
|
||||
B00010000,B00000000,B00100000,
|
||||
B00001000,B00000000,B01000000,
|
||||
B00000100,B00000000,B10000000,
|
||||
B00000011,B00000011,B00000000,
|
||||
B00000000,B11111100,B00000000,
|
||||
};
|
||||
|
||||
#endif
|
|
@ -29,40 +29,40 @@
|
|||
#define STATUS_COOLER_WIDTH 22
|
||||
|
||||
const unsigned char status_cooler_bmp2[] PROGMEM = {
|
||||
B00000100,B00000010,B00000000,
|
||||
B00000100,B10010010,B01000000,
|
||||
B00010101,B00001010,B10000000,
|
||||
B00001110,B00000111,B00000000,
|
||||
B00111111,B10111111,B11000000,
|
||||
B00001110,B00000111,B00000000,
|
||||
B00010101,B00001010,B10000000,
|
||||
B00100100,B00100010,B01000000,
|
||||
B00000100,B00100000,B00000000,
|
||||
B00000001,B00100100,B00000000,
|
||||
B00000000,B10101000,B00000000,
|
||||
B00000000,B01110000,B00000000,
|
||||
B00000111,B11111111,B00000000,
|
||||
B00000000,B01110000,B00000000,
|
||||
B00000000,B10101000,B00000000,
|
||||
B00000001,B00100100,B00000000
|
||||
B00000001,B00000000,B10000000,
|
||||
B00000001,B00100100,B10010000,
|
||||
B00000101,B01000010,B10100000,
|
||||
B00000011,B10000001,B11000000,
|
||||
B00001111,B11101111,B11110000,
|
||||
B00000011,B10000001,B11000000,
|
||||
B00000101,B01000010,B10100000,
|
||||
B00001001,B00001000,B10010000,
|
||||
B00000001,B00001000,B00000000,
|
||||
B00000000,B01001001,B00000000,
|
||||
B00000000,B00101010,B00000000,
|
||||
B00000000,B00011100,B00000000,
|
||||
B00000001,B11111111,B11000000,
|
||||
B00000000,B00011100,B00000000,
|
||||
B00000000,B00101010,B00000000,
|
||||
B00000000,B01001001,B00000000
|
||||
};
|
||||
const unsigned char status_cooler_bmp1[] PROGMEM = {
|
||||
B00000100,B00000010,B00000000,
|
||||
B00000100,B10010010,B01000000,
|
||||
B00010101,B00001010,B10000000,
|
||||
B00001010,B00000101,B00000000,
|
||||
B00110001,B11011000,B11000000,
|
||||
B00001010,B00000101,B00000000,
|
||||
B00010101,B00001010,B10000000,
|
||||
B00100100,B00100010,B01000000,
|
||||
B00000100,B00100000,B00000000,
|
||||
B00000001,B00100100,B00000000,
|
||||
B00000000,B10101000,B00000000,
|
||||
B00000000,B01010000,B00000000,
|
||||
B00000111,B10001111,B00000000,
|
||||
B00000000,B01010000,B00000000,
|
||||
B00000000,B10101000,B00000000,
|
||||
B00000001,B00100100,B00000000
|
||||
B00000001,B00000000,B10000000,
|
||||
B00000001,B00100100,B10010000,
|
||||
B00000101,B01000010,B10100000,
|
||||
B00000010,B10000001,B01000000,
|
||||
B00001100,B01110110,B00110000,
|
||||
B00000010,B10000001,B01000000,
|
||||
B00000101,B01000010,B10100000,
|
||||
B00001001,B00001000,B10010000,
|
||||
B00000001,B00001000,B00000000,
|
||||
B00000000,B01001001,B00000000,
|
||||
B00000000,B00101010,B00000000,
|
||||
B00000000,B00010100,B00000000,
|
||||
B00000001,B11100011,B11000000,
|
||||
B00000000,B00010100,B00000000,
|
||||
B00000000,B00101010,B00000000,
|
||||
B00000000,B01001001,B00000000
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -205,6 +205,14 @@ FORCE_INLINE void _draw_centered_temp(const celsius_t temp, const uint8_t tx, co
|
|||
}
|
||||
#endif
|
||||
|
||||
#if DO_DRAW_AMMETER
|
||||
FORCE_INLINE void _draw_centered_current(const float current, const uint8_t tx, const uint8_t ty) {
|
||||
const char *str = ftostr31ns(current);
|
||||
const uint8_t len = str[0] != ' ' ? 3 : str[1] != ' ' ? 2 : 1;
|
||||
lcd_put_u8str(tx - len * (INFO_FONT_WIDTH) / 2 + 1, ty, &str[3-len]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DO_DRAW_HOTENDS
|
||||
|
||||
// Draw hotend bitmap with current and target temperatures
|
||||
|
@ -404,6 +412,13 @@ FORCE_INLINE void _draw_centered_temp(const celsius_t temp, const uint8_t tx, co
|
|||
}
|
||||
#endif
|
||||
|
||||
#if DO_DRAW_AMMETER
|
||||
FORCE_INLINE void _draw_ammeter_status() {
|
||||
if (PAGE_CONTAINS(28 - INFO_FONT_ASCENT, 28 - 1))
|
||||
_draw_centered_current(ammeter.read(), STATUS_AMMETER_TEXT_X, 28);
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// Before homing, blink '123' <-> '???'.
|
||||
// Homed but unknown... '123' <-> ' '.
|
||||
|
@ -677,6 +692,13 @@ void MarlinUI::draw_status_screen() {
|
|||
u8g.drawBitmapP(STATUS_FLOWMETER_X, flowmetery, STATUS_FLOWMETER_BYTEWIDTH, flowmeterh, blink && cooler.flowpulses ? status_flowmeter_bmp2 : status_flowmeter_bmp1);
|
||||
#endif
|
||||
|
||||
// Laser Ammeter
|
||||
#if DO_DRAW_AMMETER
|
||||
const uint8_t ammetery = STATUS_AMMETER_Y(status_ammeter_bmp_mA),
|
||||
ammeterh = STATUS_AMMETER_HEIGHT(status_ammeter_bmp_mA);
|
||||
if (PAGE_CONTAINS(ammetery, ammetery + ammeterh - 1))
|
||||
u8g.drawBitmapP(STATUS_AMMETER_X, ammetery, STATUS_AMMETER_BYTEWIDTH, ammeterh, (ammeter.current < .1) ? status_ammeter_bmp_mA : status_ammeter_bmp_A);
|
||||
#endif
|
||||
|
||||
// Heated Bed
|
||||
TERN_(DO_DRAW_BED, _draw_bed_status(blink));
|
||||
|
@ -690,6 +712,9 @@ void MarlinUI::draw_status_screen() {
|
|||
// Flowmeter
|
||||
TERN_(DO_DRAW_FLOWMETER, _draw_flowmeter_status());
|
||||
|
||||
// Flowmeter
|
||||
TERN_(DO_DRAW_AMMETER, _draw_ammeter_status());
|
||||
|
||||
// Fan, if a bitmap was provided
|
||||
#if DO_DRAW_FAN
|
||||
if (PAGE_CONTAINS(STATUS_FAN_TEXT_Y - INFO_FONT_ASCENT, STATUS_FAN_TEXT_Y - 1)) {
|
||||
|
|
|
@ -217,6 +217,15 @@ const char* ftostr41ns(const_float_t f) {
|
|||
return &conv[2];
|
||||
}
|
||||
|
||||
// Convert unsigned float to string with 123 format
|
||||
const char* ftostr3ns(const_float_t f) {
|
||||
const long i = UINTFLOAT(f, 3);
|
||||
conv[4] = DIGIMOD(i, 100);
|
||||
conv[5] = DIGIMOD(i, 10);
|
||||
conv[6] = DIGIMOD(i, 1);
|
||||
return &conv[4];
|
||||
}
|
||||
|
||||
// Convert signed float to fixed-length string with 12.34 / _2.34 / -2.34 or -23.45 / 123.45 format
|
||||
const char* ftostr42_52(const_float_t f) {
|
||||
if (f <= -10 || f >= 100) return ftostr52(f); // -23.45 / 123.45
|
||||
|
|
|
@ -74,6 +74,9 @@ const char* ftostr31ns(const_float_t x);
|
|||
// Convert unsigned float to string with 123.4 format
|
||||
const char* ftostr41ns(const_float_t x);
|
||||
|
||||
// Convert unsigned float to string with 123 format
|
||||
const char* ftostr3ns(const_float_t x);
|
||||
|
||||
// Convert signed float to fixed-length string with 12.34 / _2.34 / -2.34 or -23.45 / 123.45 format
|
||||
const char* ftostr42_52(const_float_t x);
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ HAS_L64XX = Arduino-L6470@0.8.0
|
|||
NEOPIXEL_LED = adafruit/Adafruit NeoPixel@~1.8.0
|
||||
src_filter=+<src/feature/leds/neopixel.cpp>
|
||||
TEMP_.+_IS_MAX31865 = Adafruit MAX31865 library@~1.1.0
|
||||
I2C_AMMETER = peterus/INA226Lib@1.1.2
|
||||
USES_LIQUIDCRYSTAL = fmalpartida/LiquidCrystal@1.5.0
|
||||
USES_LIQUIDCRYSTAL_I2C = marcoschwartz/LiquidCrystal_I2C@1.1.4
|
||||
USES_LIQUIDTWI2 = LiquidTWI2@1.2.7
|
||||
|
|
Loading…
Reference in a new issue