Bin gerade am programmieren eines Höhenmessers mit dem BMP280 und dem SH1106 Display.
Es klappt alles soweit, den Code habe ich aus einem fertigen Projekt (bin Anfänger) und passe ihn für mich gerade an. Auf der Startseite steht nun die Höhe in Fuß, das geschieht mit großen Zahlen und ich bin erschrocken dass nur das schon fast den kompletten Speicher gefressen hat. :o
Jetzt bin ich auf das Tool "bdfconv" gestoßen mit dem man wohl nur die genutzten Zeichen angeben kann um Platz zu sparen.
Das wären bei mir der Befehl
-m '32,46,48-58,72,78,81,102,116'
Leider aber reicht mein Verständnis für das Tool und der u8glib nicht aus. Welche Datei aus der u8glib muss ich nehmen und verändern? Muss ich das für jede Schriftart einzeln machen? Kann vielleicht jemand ein Beispiel der Befehlszeile nennen? Bin ich auf dem Holzweg?
Das Programm soll am Schluss erst einmal groß die Höhe in Fuß anzeigen und darunter klein den Druck P0 zum abgleichen den ich mit einem Encoder verstellen möchte.
Leider sind aber ohne Verstellung schon 92% vom Nano belegt und die Schriftgröße reicht mir eigentlich noch gar nicht.
Schriftart ist: u8g_font_fub20
bei Deiner Anzeige kann ich Dir nicht helfen.
Wäre es eine SSD1306 (128x64 oder 128x32) und Du sagen würdest, daß Du nur ASCII brauchst, dann würde ich Dir diese Lib. empfehlen:
Die benutze ich aus diesem Grund selbst, benötigt nur 2 oder 3% RAM, dafür ist man eingeschränkt auf ASCII, aber den jeweils verwendeten Font kann man mit ASCII-Zeichen erweitern, die man braucht, bei mir als Beispiel µ und Ω.
Wenn Du nur Text brauchst, nimm die U8x8, ansonsten die u8g2lib. Genauere Infos findest Du im Wiki dazu.
Genaueres kann man ohne Sketch (bitte in Codetags) nicht sagen.
Also es wird der Programmspeicher knapp. Hatte mal die u8g2lib installiert aber beim kompilieren von einem Beispiel zeigt es immer dass es die Dateien in der lib nicht findet.
Mein Programm bekomme ich übrigens jetzt auch nicht mehr auf den Uno, der Nano ist zu 97% belegt, es funktioniert aber. Ich benötige tatsächlich nur die Zeichen 0-9, Q, N, H, f, t, ., : und Leerzeichen.
Hier mal der Sketch:
#include "U8glib.h"
#include "BMP280.h"
#include "Wire.h"
#define P0 1018.00 // Luftdruck (soll später einstellbar sein)
BMP280 bmp;
U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NO_ACK);
char sA[9]; // Was bedeutet [9]?
char sP0[9];
void draw(double A) {
u8g.setFont(u8g_font_fub20); //Soll eigentlich noch größer sein
dtostrf(A, 4, 0, sA);
dtostrf(P0, 4, 2, sP0);
u8g.drawStr( 5, 20, sA);
u8g.drawStr( 80, 20, " ft");
u8g.setFont(u8g_font_9x18B);
u8g.drawStr( 0, 63, "QNH: ");
u8g.drawStr( 40 , 63, sP0);
}
void setup() {
Serial.begin(9600);
if (!bmp.begin()) {
Serial.println("BMP init failed!");
while (1);
}
else Serial.println("BMP init success!");
bmp.setOversampling(4);
u8g.setColorIndex(1);
u8g.setFont(u8g_font_unifont);
}
void loop(void) {
double T, P;
char result = bmp.startMeasurment();
if (result != 0) {
delay(result);
result = bmp.getTemperatureAndPressure(T, P);
if (result != 0) {
double A = (bmp.altitude(P, P0) * 3.28084);
u8g.firstPage();
do {
draw(A);
} while ( u8g.nextPage() );
u8g.firstPage();
delay(1000);
}
}
}
Werde es mal ausprobieren. Bin noch nicht so der schnellste
Bisher hab ich nur die LED zum blinken gebracht und mal zur Reinigung Einspritzdüsen mit MOSFET getaktet.
Habe nun die Library installiert und mir das Beispiel geladen:
#include <Arduino.h>
#include <SPI.h>
#include <U8x8lib.h>
/* Constructor */
U8X8_SSD1306_128X64_NONAME_4W_SW_SPI u8x8(/* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
/* u8x8.begin() is required and will sent the setup/init sequence to the display */
void setup(void)
{
u8x8.begin();
}
void loop(void)
{
u8x8.setFont(u8x8_font_chroma48medium8_r);
u8x8.drawString(0, 0, "Hello World!");
delay(1000);
}
In der Liste der Displays nehme ich an dass es eines der folgenden ist:
SH1106 128X64_NONAME
Controller “sh1106”, Display “128x64_noname”
U8X8_SH1106_128X64_NONAME_SW_I2C(clock, data [, reset])
U8X8_SH1106_128X64_NONAME_HW_I2C([reset [, clock, data]])
U8X8_SH1106_128X64_NONAME_2ND_HW_I2C([reset])
Leider weiß ich nicht genau wie ich mein Display einfügen bzw welche Zahlen ich reinschreiben muss
Kommen da die Ausgangspins rein? Was ist dieser Reset?
Das ist die Lösung!
Display zeigt den Text an. Wenn ich Zeit habe versuche ich das alles auf mein Projekt zu übertragen und mein Glück zu versuchen. Mal gespannt ob mir dann etwas speicher übrig bleibt.
Leider aber bleibt das Display schwarz. Mit dem Example lief es, nur als ich eine Zeile mit anderer Schriftart eingefügt habe flackerte diese mit dem delay…
result dürfte auch nicht das sein, was Du ausgeben willst.
Gib Dir die Werte mal zusätzlich auf Serial aus, am besten als HEX, damit Du siehst, was da steht.
Moin!
Nachdem ich mich mit der u8x8 ein bisschen schwer getan habe bin ich nochmal an die u8g2 gegangen.
Es klappt jetzt mit größerer Shriftart mit 47% Speicherbelegung.
Das bedeutet ich kann die Schrift richtig groß machen und die Einheit auf das Gehäuse drucken!
So sieht der code aus:
Jetzt versuche ich den wert P0 zur Kalibrierung (hier 1020.00) mit dem Drehencoder in 0.01 Schritten zu ändern. Das example für den Encoder funktioniert schon mal. Wie würdet ihr das am einfachsten machen? Hatte die Idee mit dem Knopfdruck am Encoder das eigentliche Programm anzuhalten um den Wert zu ändern und mit erneutem Knopfdruck fortzusetzen. Geht das überhaupt so? Oder gibt es vielleicht eine bessere Lösung?
Okay. Naja werde mich da wohl etwas mit auseinander setzen müssen. Möchte mit Linksdrehung den Wert um 0.01 senken und mit Rechtsdrehung um 0.01 erhöhen. Hatte bisschen herumprobiert, da konnte ich den Wert erhöhen, Sogar der Höhenwert im Display hat durch die Druckanpassung reagiert. Allerdings startete P0 bei 0 und erhöhte sich nur um 2 und das in beide Richtungen. Immerhin hat er sich bewegt
Leider bekomme ich es nicht hin.
Hier ist der Code für den Encoder. Mit ihm kann der veränderte Wert mit dem Switch im eeprom gespeichert werden, laut Monitor funktioniert das prima:
#include <EEPROM.h>
int reclk = 6;
int redt = 7;
int resw = 8;
int pos, alast, aval;
int eeadr = 14;
void setup() {
pinMode (reclk, INPUT);
pinMode (redt, INPUT);
pinMode(resw, INPUT);
digitalWrite(resw, HIGH);
EEPROM.get(eeadr, pos);
alast = digitalRead(reclk);
}
void loop() {
if ( digitalRead(resw) == 0) {
EEPROM.put(eeadr, pos);
while (digitalRead(resw) == 0);
}
aval = digitalRead(reclk);
if (aval != alast) {
if (digitalRead(redt) != aval) {
pos++;
}
else {
pos--;
}
}
alast = aval;
}
Ich hatte (pos) bei P0 in meinem Programm verwendet und es ließ sich tatsächlich bedingt der Wert verändern, speichern und wurde beim Neustart wieder aus dem eeprom ausgelesen.
Leider habe ich zwei Probleme:
Muss ich denn nicht eine separate loop für den Encoder machen und das Hauptprogramm in der Zeit unterbrechen in welcher ich Änderungen am Wert vornehme? Die Aktualisierung der Höhenanzeige und somit die Loop des Hauptprogramms sollen ja auf 1000ms bleiben. So ganz weiß ich nicht wie man das bewerkstelligen soll.
Der Wert wird immer in Ganzzahlen verändert, jedoch möchte ich 0.01 Schritte. Muss ich hier durch 100 dividieren oder geht das anders?
Da Dein loop() in minimaler Zeit durchlaufen wird, bist Du doch eh in jedem Durchlauf am Prüfen, was nun gemacht werden soll.
Wenn bei dieser Prüfung raus kommt, daß Da gerade Wer am Poti spielt, wirst Du wohl den aktuellen Wert anzeigen wollen, damit man nicht 'die Katze im Sack' kauft ... oder im EEprom speichert.
MALE Dir auf, was wann wie passieren soll - und programmiere den Kram dann.
Dein aktuelles Programm ist dann halt nur noch einer der vielen Status Deiner State-Maschine und wird dann halt nur abgearbeitet, wenn die Bedingungen dafür gegeben sind - z.B., wenn eben kein neuer Wert eingestellt wird.
MfG
PS: Du verwendest den EEprom, dort werden BYTES drin gespeichert, Du speicherst dort aber Variablen des Typ int (= 2 Byte lang) - vll. erklärt Das auch schon, warum Das nur 'so halbwegs' klappt.
PPS: Warum int? Auch im EEprom wird's keine negativen Adressen geben - also zumindest unsigned int für die Adressen.
PINs werden sich wohl nicht im Programmlauf ändert - also mach Diese const.
Ebenfalls keine negativen Nummern, also auch hier mindestens unsigned int.
Da wohl keine Pin-Nummern über 255 zu erwarten sind - reicht dafür also auch BYTE.
PPPS: Durch 00 Teilen ist schon Mal nicht der schlechteste Weg - ist nur die Frage, wie Du Das machst.
float braucht spezielle Rechen-Routinen, 'günstiger' dürfte % und / sein.
Habe mich mal an den encoder gemacht, vielleicht ist es ja so okay. Er tut zumindest was ich will, jedoch komme ich ja beim speichern um long nicht herum wenn ich durch dividieren zwei Nachkommastellen möchte oder liege ich falsch? Auf jeden Fall lässt sich die Position speichern und auf zwei Nachkommastellen ändern wie gewünscht.
Hier einmal der code.
Werde das ganze jetzt aber ändern und die Drehgeberabfrage über Interrupts machen. Jetzt ist es aber etwas OT geworden. Ich danke allen denn mein ursprüngliches Problem ist gelöst, mein Speicher macht keine Probleme mehr und ich habe bei dem Projekt schon einiges gelernt. 8)