HSM 4.0

mash.m

Flashaholic*
8 Juli 2011
858
1.163
93
Kronau / Baden
Hi,

hier nun die vorerst letzte Version meines Handschmeicherl´s:

4swf-19e-10a2.jpg


4swf-19f-570b.jpg


4swf-19g-c363.jpg


4swf-19h-0b72.jpg


4swf-19i-3733.jpg


4swf-19j-581c.jpg


4swf-19k-1680.jpg


4swf-19l-0839.jpg


4swf-19m-fcae.jpg


4swf-19n-9ac7.jpg


Das Teil hat folgendes:

- 128 Gbyte USB Speicher
- Atmel 32u4 µC
- 2 x Osram Oslon high Cri
- 1 x Osram Oslon Deep Red
- 1 x Nichia NCSU276A
- 1 x Bosch BME280
- 1 x TCS34725
- 1 x Selbsgebauter 7135 Treiber
- 1 x Oled 128x32
- 6 x Anglerzubehör

Das Teil kann messen:
- Lux
- Kelvin
- max Lux speichern für entfernte Messungen
- Umgebungstemperatur
- Luftfeuchtigkeit
- Luftdruck (und daraus den Höhenunterschied)

Helligkeit wird ganz klassisch über das Rändelpoti an der Seite eingestellt. Maße des Gehäuses sind 60x40mm. Ich habe viele Stunden in die Lampe investiert. Nicht nur in die Hardware auch in die Software. Der Deckel ist leider nicht so gut geworden. Da werde ich bei Zeit mal einen neuen machen. Der Luxmeter zeigt in etwa das gleiche an wie mein LX133, scheint also gut zu passen.

Gruß Markus
 

mkr

Flashaholic***²
2 Februar 2013
10.898
15.132
113
Nanda Parbat
Wenn es jetzt noch MP3s abspielen könnte und einen Kopfhörerausgang hätte, wäre es die wollmilchlegende Sauerei. :)

Da paßt doch bestimmt noch ein DAC und ein Op-amp rein. :)
 
Zuletzt bearbeitet:

noddi85

Stammgast
23 Januar 2016
73
35
18
Respekt ,Wahnsinns Teil!

Jetzt noch die Schalter , Sensoren? und Display mit schwarzen Gummischutzdingens mit doppelter "lippe" versehen(Gummirand unter dem Karbon - Karbon - bisschen größerer Rand oberhalb) und das ganze würde als Sauteure Luxusedition eines namhaften Herstellers durchgehen!

Da noch Mp3 s abspielen Bluetooth für die Musikübertragung und Kopfhörerausgang und der Handschmeichler wäre die Eierlegende Wollmilchsau und ein bestseller!
Los gehts Fenix led lenser Acebeam oder wer auch immer nehmt den Mann unter vertrag ;)
 
Zuletzt bearbeitet:
  • Danke
Reaktionen: llk und FrankFlash

mash.m

Flashaholic*
8 Juli 2011
858
1.163
93
Kronau / Baden
Hi,

Danke an alle!

Der Deckel ist aus 0,8er carbon. Das Zeug kann man gut schleifen (immer mit Absaugung arbeiten).
Der Usb-Speicher hängt nicht am Atmel, das wäre zu langsam. Daher ist da ne zweite Usb-Buchse. Platz ist da keiner mehr, eventuell bekomme ich noch nen Beschleunigunssensor für ne Wasserwaage rein. Ich mach mal ein Bild vom inneren, da geht es echt eng zu.
Akku wird natürlich über Usb geladen. Ebenso wird die Akkuspannung gemessen.
Das Programm ist recht groß geworden, da ist nicht mehr viel Platz. Mal schauen ob ich das noch ein wenig optimieren kann.

Gruß Markus
 

mash.m

Flashaholic*
8 Juli 2011
858
1.163
93
Kronau / Baden
Hi,

kann da mal einer von Euch drüber schauen? Ich brauche noch ein paar Byte für´s programm damit ich ne Wasserwaage realisieren kann. Ich finde da aber nichts mehr.

Code:
#include <Wire.h>
#include "Adafruit_TCS34725.h"
#include "U8glib.h"
#include "OneButton.h"
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Adafruit_ADXL345_U.h>

U8GLIB_SSD1306_128X32 u8g(U8G_I2C_OPT_NONE);  // I2C / TWI
Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X);
Adafruit_BME280 bme; // I2C
OneButton button(A2, true);
//Adafruit_ADXL345_Unified tilt = Adafruit_ADXL345_Unified(0);

byte helligkeit;
int potValue;
int averagewled1;
byte batterystatus;
int altinit = 0;
byte readIndex = 0;
byte ledout = 1;
byte taster = 1;

const byte wled = 9;
const byte rled = 13;
const byte uled = 10;
const byte volt = A1;

long lux;
long maxlux;
long kelvin;
long ledbar1 = 0;
long ledbar2 = 0;

float SEALEVELPRESSURE_HPA = 1000.00;
const float G = 9.80665;
float averagetemp;
float averagepressure;
float averagefeucht;
float averagealti;
float averagetemp1;
float averagepressure1;
float averagefeucht1;
float averagealti1;
float voltadc;
float volt1;
float volt2;
float volt3;

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// declare some things...

// some magic numbers for this device from the DN40 application note
#define TCS34725_R_Coef 0.136
#define TCS34725_G_Coef 1.000
#define TCS34725_B_Coef -0.444
#define TCS34725_GA 1.0
#define TCS34725_DF 310.0
#define TCS34725_CT_Coef 3810.0
#define TCS34725_CT_Offset 1391.0

// Autorange class for TCS34725
class tcs34725 {
  public:
    tcs34725(void);

    boolean begin(void);
    void getData(void);

    boolean isAvailable, isSaturated;
    uint16_t againx, atime, atime_ms;
    uint16_t r, g, b, c;
    uint16_t ir;
    uint16_t r_comp, g_comp, b_comp, c_comp;
    uint16_t saturation, saturation75;
    float cratio, cpl, ct, lux, maxlux;

  private:
    struct tcs_agc {
      tcs34725Gain_t ag;
      tcs34725IntegrationTime_t at;
      uint16_t mincnt;
      uint16_t maxcnt;
    };
    static const tcs_agc agc_lst[];
    uint16_t agc_cur;

    void setGainTime(void);
    Adafruit_TCS34725 tcs;
};
const tcs34725::tcs_agc tcs34725::agc_lst[] = {
  { TCS34725_GAIN_60X, TCS34725_INTEGRATIONTIME_154MS,  0, 63000 },
  { TCS34725_GAIN_16X, TCS34725_INTEGRATIONTIME_154MS, 16790, 63000 },
  { TCS34725_GAIN_4X,  TCS34725_INTEGRATIONTIME_154MS, 15740, 63000 },
  { TCS34725_GAIN_1X,  TCS34725_INTEGRATIONTIME_154MS, 15740, 0 }
};
tcs34725::tcs34725() : agc_cur(0), isAvailable(0), isSaturated(0) {
}

// initialize the sensor
boolean tcs34725::begin(void) {
  tcs = Adafruit_TCS34725(agc_lst[agc_cur].at, agc_lst[agc_cur].ag);
  if ((isAvailable = tcs.begin()))
    setGainTime();
  return (isAvailable);
}

// Set the gain and integration time
void tcs34725::setGainTime(void) {
  tcs.setGain(agc_lst[agc_cur].ag);
  tcs.setIntegrationTime(agc_lst[agc_cur].at);
  atime = int(agc_lst[agc_cur].at);
  atime_ms = ((256 - atime) * 2.4);
  switch (agc_lst[agc_cur].ag) {
    case TCS34725_GAIN_1X:
      againx = 1;
      break;
    case TCS34725_GAIN_4X:
      againx = 4;
      break;
    case TCS34725_GAIN_16X:
      againx = 16;
      break;
    case TCS34725_GAIN_60X:
      againx = 60;
      break;
  }
}

// Retrieve data from the sensor and do the calculations
void tcs34725::getData(void) {
  // read the sensor and autorange if necessary
  tcs.getRawData(&r, &g, &b, &c);
  while (1) {
    if (agc_lst[agc_cur].maxcnt && c > agc_lst[agc_cur].maxcnt)
      agc_cur++;
    else if (agc_lst[agc_cur].mincnt && c < agc_lst[agc_cur].mincnt)
      agc_cur--;
    else break;

    setGainTime();
    delay((256 - atime) * 2.4 * 2); // shock absorber
    tcs.getRawData(&r, &g, &b, &c);
    break;
  }

  // DN40 calculations
  ir = (r + g + b > c) ? (r + g + b - c) / 2 : 0;
  r_comp = r - ir;
  g_comp = g - ir;
  b_comp = b - ir;
  c_comp = c - ir;
  cratio = float(ir) / float(c);

  saturation = ((256 - atime) > 63) ? 65535 : 1024 * (256 - atime);
  saturation75 = (atime_ms < 150) ? (saturation - saturation / 4) : saturation;
  isSaturated = (atime_ms < 150 && c > saturation75) ? 1 : 0;
  cpl = (atime_ms * againx) / (TCS34725_GA * TCS34725_DF);
  maxlux = 65535 / (cpl * 3);

  lux = (TCS34725_R_Coef * float(r_comp) + TCS34725_G_Coef * float(g_comp) + TCS34725_B_Coef * float(b_comp)) / cpl;
  ct = TCS34725_CT_Coef * float(b_comp) / float(r_comp) + TCS34725_CT_Offset;
}

tcs34725 rgb_sensor;

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void setup(void) {

  bme.begin();
  rgb_sensor.begin();
  button.attachClick(shortclick);
  button.attachLongPressStart(longclick);

  analogReference(INTERNAL);  // set internal ref voltage to 2.56 volt (atmega32u4) other maybe 1.1 volts

  pinMode(5, OUTPUT);    // start reset procedure for display
  digitalWrite(5, HIGH);
  delay(10);
  digitalWrite(5, LOW);
  delay(10);
  digitalWrite(5, HIGH);  // end of reset procedure for display


  u8g.setRot180();  // rotale the display by 180°
  u8g.setFont(u8g_font_fixed_v0);  // set font for u8glib one time; this reduce memory usage

  //   tilt.begin();
  //   tilt.setRange(ADXL345_RANGE_2_G);
  //   tilt.setDataRate(ADXL345_DATARATE_25_HZ);
}

//draw pages include logo on startup
void draw(void)
{
  switch (taster)
  {
    case 1: page1(); break;  // flashlite
    case 2: page2(); break;  // bosch sensor
    case 3: page3(); break;  // light sensor
      //    case 4: logo(); break;  // startup screen
  }
}

void page1(void) {

  u8g.drawFrame(100, 0, 18, 12); //draw battery
  u8g.drawFrame(117, 2, 4, 8); //draw battery
  u8g.drawBox(101, 0, batterystatus, 12); //draw battery status bar
  u8g.drawTriangle(0, 12, ledbar1, 12, ledbar1, ledbar2);  // draw brighness status bar

  if (ledout == 1) // write "white" in white mode
  { u8g.setPrintPos(60, 12);
    u8g.print("Weiss");
  }
  if (ledout == 2) // write "red" in red mode
  { u8g.setPrintPos(60, 12);
    u8g.print("Rot");
  }
  if (ledout == 3) // write "uv" in uv mode
  { u8g.setPrintPos(60, 12);
    u8g.print("UV");
  }
  u8g.setPrintPos(0, 23);
  u8g.print("Helligkeit:");
  u8g.setPrintPos(64, 23);
  u8g.print(helligkeit);

  u8g.setPrintPos(0, 32);
  u8g.print("Akku:");
  u8g.setPrintPos(27, 32);
  u8g.print(volt3);
}

//draw second page for bosch sensor
void page2(void) {
  u8g.setPrintPos(0, 7);
  u8g.print("Temp:");
  u8g.setPrintPos(27, 7);
  u8g.print(averagetemp1);
  u8g.setPrintPos(0, 15);
  u8g.print("Hu:");
  u8g.setPrintPos(27, 15);
  u8g.print(averagefeucht1);
  u8g.setPrintPos(0, 23);
  u8g.print("hPa:");
  u8g.setPrintPos(27, 23);
  u8g.print(averagepressure1);
  u8g.setPrintPos(0, 31);
  u8g.print("alt");
  u8g.setPrintPos(27, 31);
  u8g.print(averagealti1);
}

//draw third page for light sensor
void page3(void) {
  u8g.setPrintPos(0, 9);
  u8g.print("Lux:");
  u8g.setPrintPos(64, 9);
  u8g.print(lux);
  u8g.setPrintPos(0, 21);
  u8g.print("Kelvin:");
  u8g.setPrintPos(64, 21);
  u8g.print(kelvin);
  u8g.setPrintPos(0, 32);
  u8g.print("max Lux:");
  u8g.setPrintPos(64, 32);
  u8g.print(maxlux);
}

//define actions for short press
void shortclick() {
  taster++;
  if (taster > 3)
  {
    taster = 1;
  }
}

//define actions for long press
void longclick()
{
  if (taster == 1)
  {
    ledout = ledout + 1; // switch between white, red and uv
  }
  if (ledout > 3) //go back to white after uv
  {
    ledout = 1;
  }

  if (taster == 3)  //reset max lux buffer
  {
    maxlux = 0;
  }

  if (taster == 2)  //set altitude to 0
  {
    SEALEVELPRESSURE_HPA = averagepressure1;
  }
}

void loop(void) {

  //draw startup logo
  //  if (taster == 4 & millis() > 2000)
  //  {
  //   taster = 1;
  //  }

  button.tick();

  potValue = analogRead(0); //read pot value
  if (potValue > 995)
  {
    potValue = 995;
  }
  averagewled1 = map(potValue, 0, 995, 0, 255); //map pot value to pwm out

  if (ledout == 1)  //set output to white
  { analogWrite(wled, averagewled1);
    analogWrite(rled, 0);
    analogWrite(uled, 0);
  }
  if (ledout == 2)  //set output to red
  { analogWrite(rled, averagewled1);
    analogWrite(wled, 0);
    analogWrite(uled, 0);
  }
  if (ledout == 3)  //set output to uv
  { analogWrite(uled, averagewled1);
    analogWrite(wled, 0);
    analogWrite(rled, 0);
  }

  sensors_event_t event;
  // float x, y, bx, by;

  // get the latest event:
  // tilt.getEvent(&event);

  // get the accel readings from the event:
  // x = event.acceleration.x; // m/s^2
  //  y = event.acceleration.y; // m/s^2


  //if menu for flashlite is active do some actions
  if (taster == 1)
  {
    volt1 = (analogRead(volt)) * 2.52 / 1023; //read battery voltage
    volt2 = ( volt2 * 19 + volt1 ) / 20;     // it requires a few loops for average for smoothing
    volt3 = ((volt3 * 9) + (volt2 / (14.93 / (14.93 + 17.93)))) / 10; // voltage divider 2,200937709310114
    voltadc = volt3 * 241; // calculation for batterystatus

    helligkeit = map(potValue, 0, 995, 0, 100); //  map potvalue to % for brightness
    ledbar1 = (map(potValue, 0, 995, 0, 48)) + 5; // map values for brightness bar
    ledbar2 = (map(potValue, 0, 995, 12, 0)) - 2; // map vlaues for brighness bar2

    if (millis() > 3000)
    {
      batterystatus = map(voltadc, 602, 1024, 0, 17); // map batterystatus for batterybar
    }
  }

  //collect bosch sensor data when page two is active
  if (taster == 2)
  {
    averagetemp1 = ((averagetemp1 * 9) + bme.readTemperature()) / 10;
    averagepressure1 = ((averagepressure1 * 19) +  (bme.readPressure() / 100.0F))  / 20;
    averagefeucht1 = ((averagefeucht1 * 19) + bme.readHumidity()) / 20;
    averagealti1 = ((averagealti1 * 19) + (bme.readAltitude(SEALEVELPRESSURE_HPA))) / 20;
  }

  //collect sensor data and draw page3
  if (taster == 3)
  {
    rgb_sensor.getData();
    lux = rgb_sensor.lux;
    kelvin = rgb_sensor.ct;

    if (lux > maxlux)
    {
      maxlux = lux;
    }
  }

  //draw Picture loop
  u8g.firstPage();
  do {
    draw();
  } while ( u8g.nextPage() );

}
 

Wieselflinkpro

Flashaholic***
1 Dezember 2014
5.472
3.090
113
Goslar
Bringt es was die Variablen kürzer zu benennen?
Sonst könntest du noch Zeilenumbrüche rund um die geschweiften Klammern weg nehmen. Sind bei einzelnen Befehlen die geschweiften Klammern überflüssig? Ist leider bei mir schon ne Weile her mit C.
Einige Leerzeichen bei Vergleichen und Wertzuweisungen sind auch nicht erforderlich, oder?
Die Volt-Berechnung kannst du ggf mit komplexeren Formeln und weniger Variablen machen.
Nehmen die Kommentare Platz weg?


Generell weiß ich aber nicht, wie die Hexumwandlung arbeitet und was dabei Speicherplatz verbracht.
 

mkr

Flashaholic***²
2 Februar 2013
10.898
15.132
113
Nanda Parbat
Bringt es was die Variablen kürzer zu benennen?
Sonst könntest du noch Zeilenumbrüche rund um die geschweiften Klammern weg nehmen. Sind bei einzelnen Befehlen die geschweiften Klammern überflüssig? Ist leider bei mir schon ne Weile her mit C.
Einige Leerzeichen bei Vergleichen und Wertzuweisungen sind auch nicht erforderlich, oder?
Das bringt alles nichts.Variablennamen und Leerzeichen usw enden alle nicht im Kompilat.

Nehmen die Kommentare Platz weg?
Auch nicht.

Es geht ja wahrscheinlich nicht darum, den Quellcode kürzer zu machen, sondern die kompilierte Binärdatei.
 

mash.m

Flashaholic*
8 Juli 2011
858
1.163
93
Kronau / Baden
Hi,

Ich brauche etwas mehr programmspeicherplatz, daher geht es um optimierung der kopilierten datei.
Ihr seht ja schon in den teilweise auskommentierten sachen das ich noch ne wasserwaage inetgrieren will. Aktuell geht das aber aus platzgründen nicht. Platz für variablen wäre noch genug. Leider frisst die u8glib recht viel platz. Vielleicht wäre die adafruit lib da besser, aber dazu müsste ich vieles umschreiben.

Gruß Markus
 

mash.m

Flashaholic*
8 Juli 2011
858
1.163
93
Kronau / Baden
Hi,

am Code selbst hab ich bis jetzt nicht mehr viel zum optimieren gefunden. Aber ich habe mir mal die Bibliotheken angeschaut. Da konnte ich noch etwas optimieren. Da z.B. der Bosch Sensor via SPI oder via I²C benutzt werden kann sind hier einige Abfragen drin für beides enthalten. SPI konnte ich komplett raus nehmen. Hat knapp 1kByte gebracht.
Wasserwaage ist jetzt auch implementiert. Die Anzeige erfolgt in Grad und anhand einer Blase:
4swf-19q-2985.jpg


Gruß Markus
 

mash.m

Flashaholic*
8 Juli 2011
858
1.163
93
Kronau / Baden
Hi,

hab noch eine andere Version für ein CPF Member gebaut:
4swf-1be-c463.jpg


Dieses mal mit Gravur:
4swf-1bd-1e2b.jpg


Dann noch eine 3.9er Version ohne USB-Speicher und Lagesensor:
4swf-1ba-345f.jpg


Im Moment experimentiere ich etwas mit Holz:
4swf-1bf-dff0.jpg


Ich hab schon wieder ne neue Idee für eine Version 4.1 Mal schauen ob der Speicher für das Programm reicht.

Gruß Markus
 

mash.m

Flashaholic*
8 Juli 2011
858
1.163
93
Kronau / Baden
Hi,

HSM 4.1

4swf-1c0-8120.jpg


4swf-1c1-6966.jpg


Neue Version zusätzlich mit Carbon/Riesen Lebensbaum Verbund-Deckel, TMP007 ir Temperatur-Sensor und Cree XM-L RGB LED. Wobei die weiße LED jetzt den Lese/Schreibstatus des USB-Speichers anzeigt und die RGB für Moodlight, Farbrad (mit dem Poti von rot, gelb, grün, türkis, blau, lia zurück zu rot kommt ) Ansonsten wie gehabt:

- 128 Gbyte USB Speicher
- Atmel 32u4 µC
- 2 x Osram Oslon high Cri
- 1 x Osram Oslon Deep Red
- 1 x Nichia NCSU233A-D1
- 1 x Bosch BME280
- 1 x TCS34725
- 1 x Selbsgebauter 7135 Treiber
- 1 x Oled 128x32
- 6 x Anglerzubehör

Das Teil kann messen:
- Lux
- Kelvin
- max Lux speichern für entfernte Messungen
- Umgebungstemperatur
- Luftfeuchtigkeit
- Luftdruck (und daraus den Höhenunterschied)
- ir Temperatur

Gruß Markus
 

Reflektor

Flashaholic*
13 August 2011
893
264
63
Geniale Teile! :thumbsup: Sehs erst jetzt durch Querverweis in anderem Thread. So kann die TaLa-Zukunft aussehen. Geniale Kombi von Form und Multi-Funktionalität. :thumbup::thumbup::thumbup: Dafür lass ich jedes Smartphone mit Mimosen-Display :eek: liegen! :) Super auch die Möglichkeiten der Oberflächengestaltung!