Jump to content

Code sketchbook repository /Arduino uno/mega boards DCS BIOS and programming help/Please post your working sketches here!


protea1

Recommended Posts

PLEASE post working sketches for dcs modules here many thanks


Edited by protea1
caps

AMD FX-8350

PALLIT GeForce GTX 1080 [ NVIDIA]

CRUCIAL MX500 1TB SDD

DELL P4317Q 43"

TRACK IR

Thrustmaster Hotas Warthog

Viacom VoiceAttack

[sIGPIC][/sIGPIC]

Link to comment
Share on other sites

Let’s not limit this topic to code snippets but expand it to share some programming ideas or tutorials!

 

Drawing analogue pointer needles on digital displays


Sometimes it’s useful to show analogue gauges on digital displays, like it’s done in modern jet cockpits. In the following I want to describe some basics and the way I draw those tiny instruments.

 

Considerations:
To show a round gauge at your display, just let your microprocessor draw a circle and print some marks and values near it. Maybe that’s one of the following topics. But the most significant question for it is, which pixel defines the tip of the needle on your display. The answer is simple: You’ll tell it!


As you already may know, your display is built like a Cartesian coordinate system, where pixels (dots) are addressed by simple x- and y-coordinates. Unlike printing a static pixel or some text in that rectangular coordinate system, the point below the needle’s tip is moving, unfortunately at a circle’s circumference. It easily can be described in polar coordinates. So the microprocessor really needs to know a little about higher-class math. At first let’s repeat the transformation of polar coordinates, please pull out your workbooks and pocket calculators! Just kidding 🙂


To simplify this, that point exactly can be described by the distance from a reference point and the respective angle of the needle. Imagine the big hand of a clock that shows what time it is. If it’s 10 minutes past six, the longer hand is pointing at the two o’clock position. We could take the middle of the clock as reference point and measure the distances of the hand’s tip by using the hand’s length (or half of the clock’s scale diameter). The angle could be determined by counting the marks on the scale. But where do we start to count the marks?


In math the starting point of that angle is defined at the positive x-axis (to the right), which means that we start at the three o’clock position of the scale, counting the marks upwards. The angle grows in the counterclockwise direction. Each mark for a minute at that clock’s scale is 6 degrees away from the next (360° / 60 minutes = 6) and the hand now points at 5 minutes to the zero mark (three o’clock position). That means, the point below the hand’s tip can be described as the needle’s length (that’s the radius of the scale minus the distance from the tip), in an angle of 30 degrees (6 degrees * 5 minutes).


To draw that position on your display we have to transform that polar coordinate into the Cartesian system. Fortunately, we don’t have to do the math, that’s why microprocessors are for. We only have to use the right formulas within our Arduino sketches:
The x-value can be found by multiplying the radius and the cosine of that angle, the y-value by multiplying the radius and the angle’s sine. Beware of, that the angle’s value has to be in radians (-pi to +pi) and not in degrees! But fortunately, our microprocessor is able to calculate that as well (2 * PI = 360 deg).


One more interesting point is, that at our displays the positive y-coordinate points downwards, what mirrors all our former considerations. In the end that makes a growing angle rotating the needle clockwise at our display. Luckily that’s how most of analogue gauge work, like clocks, rpm-indicators or speedometers.

 

Drawing the needle’s tip:
When using digital displays such as OLEDs, you first have to initialise it within your code. It depends on the type of display and driver chips and should be content to other topics. Please use the examples, coming with the library of your display.


To show the way here, I’ll be using a tiny 1.3 inch OLED with the SH1106 driver. Furthermore I’ll describe the procedures, using the “Adafruit_GFX” library. That’s just an example, that should be adaptable to other libraries (such as the monochrome U8g2lib.h) or other drivers (such as the SSD1306 displays).

In my case the tag “display” is used as an object, to talk to the OLED. (That’s the case in most of Adafruit’s examples. Other libraries may use other tags.)

 

#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>
#define OLED_RESET 4
Adafruit_SH1106 display(OLED_RESET);

 

and again in the Setup-Loop

 

  delay(100);  // This delay is needed to let the display initialize
  display.begin(SH1106_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();

 

Then some variables have to be declared, to use them for drawing our instrument and needle. We exactly have to know our display’s resolution, i.e., it’s width and height. That easily can be read out at the serial port. Just put the following lines to the Setup-Loop:
(Be careful not to user the “Serial” command when "DcsBios.h" is already in use!)

 

  Serial.begin(9600);
  Serial.print("Display's width: ");
  Serial.println(display.width());
  Serial.print("Display's height: ");
  Serial.println(display.height());

 

In my case the Serial returns the following dimensions:
Display's width: 128
Display's height: 64


We can take advantage of that behaviour to let the microprocessor calculate the display’s midpoint at half of all dimensions and to use it as reference for the gauge. Unfortunately, all displays have even numbers for width and height. The exact midpoint is in between four pixels (two on top and two below of the midpoint). So we have to shift the midpoint one pixel top and to the left. Let’s draw that pixel in the middle of our screen and a full screen circle and have a look if something went wrong. Put that variables into the header, above of the Setup-Loop!

 

int mid_X = (display.width()/2)-1; // midpoint of x-axis
int mid_Y = (display.height()/2)-1; // midpoint of y-axis
int radius = (display.height()/2)-1;  // radius of the gauge

 

And the following commands below the serial outputs.

 

  display.drawPixel(mid_X, mid_Y, WHITE);  // draw a mid point
  display.drawCircle(mid_X, mid_Y, radius, WHITE);  // draw a circle at mid point
  display.display();

 

If everything went fine, you should already see the outline of your analogue gauge. As the needle’s tip is not intended to touch that line, all the above commands can be used within the Setup-Loop. Be careful not to clear() the display afterwards!


We now need to define the dimensions of the needle, meaning it’s width and height as well the distance of the tip from the outer circle, and some coordinates to calculate, using the above math.

At the beginning the needle will be pointing in the right direction, because the angle starts at zero degrees. To have the needle's tip at the top, a start angle of (-90 deg) could be used. To use only positive numbers, the corresponding angle of 270 degrees is a better choise. Put the following lines below the above variables.

 

int start_angle = 270;  // set to 270 degrees to point in 12 o'clock direction
int tip_length = 7; // length of th pointer tip in pixel
int tip_width = 10;  // width of the pointer tip in degree
int tip_distance = 3; // pointer tip distance from outline (raduis) in pixel
int X0, Y0, X1, Y1, X2, Y2, X3, Y3, X4, Y4;  // coordinates of the needle

 

By using the above explained logic, we now are able to address the pixel where the needle’s tip is:


X-Coordinate = radius * cos(angle), cut by the distance of the tip to the outer border and using degrees instead of radians (angle*PI/180).

To be more specific the position has to be shifted to the midpoint of the screen.

 

So the tip can be addressed as:
X0 = (radius - tip_distance)*cos(start_angle*PI/180) + mid_X    and
Y0 = (radius - tip_distance)*sin(start_angle*PI/180) + mid_Y

 

Further two pixels have to be known, to let the software define the needle’s tip as triangle, centred to the first pixel and slightly shifted by the above defined constrains.

 

  // calculate the tip of the needle
  X0 = (radius - tip_distance)*cos(start_angle*PI/180) + mid_X;
  Y0 = (radius - tip_distance)*sin(start_angle*PI/180) + mid_Y;
  X1 = (radius - tip_distance - tip_length)*cos((start_angle + tip_width)*PI/180) + mid_X;
  Y1 = (radius - tip_distance - tip_length)*sin((start_angle + tip_width)*PI/180) + mid_Y;
  X2 = (radius - tip_distance - tip_length)*cos((start_angle - tip_width)*PI/180) + mid_X;
  Y2 = (radius - tip_distance - tip_length)*sin((start_angle - tip_width)*PI/180) + mid_Y;

 

The needle's body can be defined as a rectangular box, sitting at the base of the needle's triangle. That box is to be devided into two triangles, splitting it diagonal. So two additional coordinates have to be calculated at the oposite end of the needle.

 

   // calculate the rest of a rect (two triangles), starting with above X1,Y1,X2,Y2
  X3 = (radius - tip_distance - (tip_length / 2))*cos((start_angle + 180 + (tip_width - 2))*PI/180) + mid_X;
  Y3 = (radius - tip_distance - (tip_length / 2))*sin((start_angle + 180 + (tip_width - 2))*PI/180) + mid_Y;
  X4 = (radius - tip_distance - (tip_length / 2))*cos((start_angle + 180 - (tip_width - 2))*PI/180) + mid_X;
  Y4 = (radius - tip_distance - (tip_length / 2))*sin((start_angle + 180 - (tip_width - 2))*PI/180) + mid_Y

 

Now it’s time to make real triangles out of the coordinates.

Compile the sketch an let the microprocessor do the job!

 

  display.fillTriangle(X0, Y0, X1, Y1, X2, Y2, WHITE);  // draw the tip of a pointer
  display.fillTriangle(X1, Y1, X3, Y3, X4, Y4, WHITE);  // draw the body of the pointer
  display.fillTriangle(X1, Y1, X2, Y2, X3, Y3, WHITE);
  display.display();

 

Congrats, you draw your first needle!


Let’s turn a needle!

To test the pointer’s needle a “for-Loop” can be used, counting the angle from 0 to 360 degrees. That should bring the needle into a circular motion.

 

As we don’t use the clear() command to the screen, somehow the old position of the needle has to be hidden before drawing it’s new position. Otherwise hundreds of needles will be drawn to the screen, everytime in the slightly rotated position. Therefore a black filled circle can be used to “hide” the old positions before calculating the new coordinates. That circle's radius should be at least one pixel less than the outer border of the instrument, but larger then the needle. Be carefull not to reduce the tip_distance below 2!


Put in the following lines in front of the calculations and set everything after the “for-Loop” into curved brackets. Don’t forget to close the brackets at the end of the main loop.

If your needle turns to slow, use a higher number than 1 in the “for-Loop” and reduce the number of calculations.

 

for (int start_angle=0; start_angle<360; start_angle = start_angle + 1)
  {
  display.fillCircle(mid_X, mid_Y, radius - tip_distance + 1, BLACK); // faster than clear screen()
  ...

 

 

Connecting the gauge to DCS-BIOS:


To use the sketch in connection with DcsBios-Library, all the declarations from the IRQSerial.ino example have to be put in:

 

- Definition of the DCSBIOS_IRQ_SERIAL,

- inclusion of the DcsBios.h,

- DcsBios::setup(); within the Setup-Loop   and

- DcsBios::loop(); in the Main-Loop.


As a good example one of the Warthog’s Engine Core Speed Tenth indicators can be used, as these don’t need dedicated marks or numbers at their scales.

Just put in the stuff from the -> A-10C / Control-Reference / Engine Instruments / Left Engine Core Speed Tenth - above your Setup-Loop and map the 16bit integer value to a full angle of 360 degree.

 

To bring the pointers needle upright at startup, it has to be rotated either 90 degrees counterclockwise (-) or further 270 degrees clockwise (+).

 

 

// ----- Left Engine Core Speed Tenth -----
void onLEngCoreTChange(unsigned int newValue) {
    start_angle = map(newValue, 0, 65535, 0, 360);
    start_angle = start_angle +270;
}
DcsBios::IntegerBuffer lEngCoreTBuffer(0x10a6, 0xffff, 0, onLEngCoreTChange);

 

For information:

In the attached “ino”-file I excluded all DCS-BIOS declarations for using it in a TEST-Mode. Uncomment the first line to use the sketch for tests, comment it (" // ") to connect it to DCS-BIOS. You also may comment (" // ") or delete all “Serial”-statements as they are no longer used.

 

- Have a further look if all test lines are commented or deleted and fire up DCS-World!

- Use the dashboard to connect your COM port and start a quick mission with running engines.

- Compare the display’s needle with the most left instrument of the second row of the engine cluster (see below clip).

 

Congrats again! You let spin your first instrument needle.

 

Regards, Vinc

 

 

LeftEngineCoreSpeedTenth.ino


Edited by Vinc_Vega
typo correction
  • Like 5
  • Thanks 3

Regards, Vinc

real life: Royal Bavarian Airforce

online: VJS-GermanKnights.de

[sIGPIC][/sIGPIC]

Link to comment
Share on other sites

  • protea1 changed the title to Code sketchbook repository /Arduino uno/mega boards DCS BIOS and programming help/Please post your working sketches here!

Nice one Vinc; I was looking at putting in the RPM 10th guages, and was going to try to use micro stepper motors, but this seems a much better solution.

 

To the original poster, I started a thread some time back which did what you asked, with working sketches I made with hardware descriptions . Let me dig out the link and paste it here for reference

 

Les

Link to comment
Share on other sites

ok I'll play then.

my CMSC script. 
designed to drive HCMS-2973 displays
 

Spoiler

/*
  The following #define tells DCS-BIOS that this is a RS-485 slave device.
  It also sets the address of this slave device. The slave address should be
  between 1 and 126 and must be unique among all devices on the same bus.
*/
#define DCSBIOS_IRQ_SERIAL

/*
  The Arduino pin that is connected to the
  /RE and DE pins on the RS-485 transceiver.
*/
#define TXENABLE_PIN 2
#include "DcsBios.h"

#include <LedDisplay.h>

// Define pins for the LED display.
// You can change these, just re-wire your board:
#define dataPin 9              // connects to the display's data in
#define registerSelect 11       // the display's register select pin
#define clockPin 12             // the display's clock pin
#define enable 10               // the display's chip enable pin
#define reset 8              // the display's reset pin
#define displayLength 24        // number of characters in the display

// create am instance of the LED display library:
LedDisplay myDisplay = LedDisplay(dataPin, registerSelect, clockPin,
                                  enable, reset, displayLength);
int brightness = 15;        // screen brightness

void onCmscTxtChaffFlareChange(char* newValue) {
    /* your code here */
    
   myDisplay.setCursor(8);
   myDisplay.print(newValue);
}
DcsBios::StringBuffer<8> cmscTxtChaffFlareBuffer(0x108e, onCmscTxtChaffFlareChange);

void onCmscTxtJmrChange(char* newValue) {
    /* your code here */
   myDisplay.setCursor(0);
   myDisplay.print(newValue);
}
DcsBios::StringBuffer<8> cmscTxtJmrBuffer(0x1096, onCmscTxtJmrChange);

void onCmscTxtMwsChange(char* newValue) {
    /* your code here */
   myDisplay.setCursor(16);
   myDisplay.print(newValue);
}

DcsBios::StringBuffer<8> cmscTxtMwsBuffer(0x12b0, onCmscTxtMwsChange);

DcsBios::PotentiometerEWMA<5, 128, 5> cmscRwrVol("CMSC_RWR_VOL", A2);
DcsBios::PotentiometerEWMA<5, 128, 5> cmscBrt("CMSC_BRT", A1);
DcsBios::LED cmscLaunch(0x1012, 0x0100, A3);
DcsBios::LED cmscPrio(0x1012, 0x0200, A4);
DcsBios::LED cmscUnkn(0x1012, 0x0400, A5);

DcsBios::Switch2Pos cmscSep("CMSC_SEP", 6);
DcsBios::Switch2Pos cmscPri("CMSC_PRI", 7);
DcsBios::Switch2Pos cmscUnk("CMSC_UNK", 5);
DcsBios::Switch2Pos cmscJmr("CMSC_JMR", 3);
DcsBios::Switch2Pos cmscMws("CMSC_MWS", 4);

void setup() {
  DcsBios::setup();
  pinMode(A3, OUTPUT);
  pinMode(A4, OUTPUT);
  pinMode(A5, OUTPUT);
  myDisplay.begin();
  // set the brightness of the display:
  myDisplay.setBrightness(brightness);
}

void loop() {
  DcsBios::loop();
}



I do have links to pair of repositories, but they are owned by active members here. I'll leave it up to theese members to chime in with their work if they deem necessary. 


Edited by agrasyuk
  • Like 1

Anton.

 

My pit build thread .

Simple and cheap UFC project

Link to comment
Share on other sites

Here is a working sketch for a simple digital clock in the Warthog's cockpit.

Written for a 1.3 inch I2C OLED, resolution is 128x64 pixels and using Adafruit's GFX library.

See below for a short clip.

 

Regards, Vinc

Spoiler
#include <Adafruit_GFX.h>  // Include core graphics library for the display
#include <Adafruit_SH1106.h> // Library downloaded as zip and installed into IDE as not found within IDE "manage libraries" option
#define OLED_RESET 4
Adafruit_SH1106 display(OLED_RESET);

#define DCSBIOS_IRQ_SERIAL
#include "DcsBios.h"

// ---------- Inputs for the Digital Clock ---------- // to be defined during design
/*
// Clock CTRL knob
DcsBios::Switch2Pos clockCtrl("CLOCK_CTRL", PIN);

// Clock SET knob
DcsBios::Switch2Pos clockSet("CLOCK_SET", PIN);
*/


// ---------- Display Time of Digital Clock @ 1.3 inch OLED ----------
// display hours on OLED in first line
void onClockHhChange(char* newValue) {
  display.setTextSize(4);
  display.setCursor(7, 0);
  display.print(newValue);
}
DcsBios::StringBuffer<2> clockHhBuffer(0x10fe, onClockHhChange);

// display minutes on OLED in first line
void onClockMmChange(char* newValue) {
  display.setTextSize(4);
  display.setCursor(79, 0);
  display.print(newValue);
}
DcsBios::StringBuffer<2> clockMmBuffer(0x1100, onClockMmChange);

// display seconds on OLED in second line
void onClockSsChange(char* newValue) {
  display.setTextSize(3);
  display.setCursor(49, 40);
  display.print(newValue);
}
DcsBios::StringBuffer<2> clockSsBuffer(0x1102, onClockSsChange);

// display "ET" or "C" on OLED in second line
void onClockEtcChange(char* newValue) {
  display.setTextSize(2);
  display.setCursor(7, 40);  // 88, 40
  display.print(newValue);
}
DcsBios::StringBuffer<3> clockEtcBuffer(0x1104, onClockEtcChange);





// ---------- Setup Loop and Display initialization (show some zeros at startup) ----------

void setup() {                
 DcsBios::setup();
  delay(100);  // This delay is needed to let the display initialize
  display.begin(SH1106_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();  // Clear the buffer
  display.setTextColor(WHITE, BLACK);
    display.setTextSize(2);
  display.setCursor(20, 0);
  display.print("DIGITAL");
  display.setCursor(7, 20);
  display.print("C L O C K");
  display.setTextSize(3);
  display.setCursor(00, 40);
  display.print("T E S T");
  display.display();
  delay(1500);
  display.clearDisplay();
    display.setTextSize(4);
  display.setCursor(7, 0);
  display.print("88");
    display.setCursor(55, 0);
  display.print(":");
  display.setCursor(79, 0);
  display.print("88");
    display.setTextSize(3);
  display.setCursor(49, 40);
  display.print("88");
    display.setTextSize(2);
  display.setCursor(7, 40);
  display.print("ETC");
  display.display();
  delay(1500);
  display.clearDisplay();    
    display.setTextSize(4);
  display.setCursor(7, 0);
  display.print("00");
    display.setCursor(55, 0);
  display.print(":");
  display.setCursor(79, 0);
  display.print("00");
    display.setTextSize(3);
  display.setCursor(49, 40);
  display.print("00");
    display.setTextSize(2);
  display.setCursor(7, 40);
  display.print("  C");
}


// ---------- Loop and diplay refresh ----------
void loop() {
DcsBios::loop();
display.display();  // refresh the display every loop!!!
} 

 

 

 


Edited by Vinc_Vega
  • Like 2

Regards, Vinc

real life: Royal Bavarian Airforce

online: VJS-GermanKnights.de

[sIGPIC][/sIGPIC]

Link to comment
Share on other sites

This more complex digital clock I want to share has been coded on a 3.5 inch TFT and was intended to run at the 1.28 inch color display, that fortunately has been in the mail today. I've found out, that the driver and the Arduino_GFX_library are not working at an UNO but at the NANO. Therefore the code for that display (GC9A01 chip) is included just quick & dirty, TEST-mode can be activated to see the pointer running.

Resolution should be 240x240 pixel at the minimum, colors can be adjusted if necessary. The gauge outline is hidden if "hide_border" is set to TRUE. Digits and fonts are taken from this website: http://oleddisplay.squix.ch/#/home

 

As I'm not a programmer, it's far away from beeing perfect and the sketch still needs to be rewritten and improved for more performance and details.
But in principle it's already working! See below clips for your consideration.
The sketch from the clip at the bottom is also "still work in progress" and will be finally postet if "ready".


Regards, Vinc

 

1.28_LCD_NANO_clock02b.ino

 

DSEG7_Classic_Mini_Bold_36.h

 

Monospaced_plain_28.h

 

Digital Clock

 

Test Mode

 

Work in progress ...

 


Edited by Vinc_Vega
sketch and fonts attached
  • Like 3

Regards, Vinc

real life: Royal Bavarian Airforce

online: VJS-GermanKnights.de

[sIGPIC][/sIGPIC]

Link to comment
Share on other sites

Here is another working sketch for the Warthog: The Airspeed Indication.

Instead of using the stepper and drum solution I want to use an OLED for the Airspeed Dial.

I took parts of Middlefart’s code for the altimeter and developed horizontal flipping bitmaps.

Beware of, that the OLED has to be connected by the SPI interface for speed reasons.

Using an I2C OLED makes the display blurry during rapid changes.

Unfortunately that display is very dark. I don't know if it's driver related or I blow up a display's capacitor.

 

Have a look at the clip, that's an 0.96 OLED, 128x32 pixel, SSD1306 SPI display

 

Regards, Vinc

 

AirSpeed_indicator_40x32_SPI_a.ino

 

and the bitmaps

 

bitmaps_40.h

 

 


Edited by Vinc_Vega
  • Like 1
  • Thanks 1

Regards, Vinc

real life: Royal Bavarian Airforce

online: VJS-GermanKnights.de

[sIGPIC][/sIGPIC]

Link to comment
Share on other sites

  • 2 weeks later...

Hope I m not out of topic here since I ve done some coding to only drive a 7seg 8digit lcd display and a couple of led's through Uno.

This one will work as a charm for any of these modules :

F-16 > Fuel Quantity Total + Vertical Velocity Indicator + Green Led ( On when Spdbrakes ) + Red Led ( On when Landing gear down + Blink when Enemy missile launch )

F-18 > Fuel Quantity + Fuel Flow + Green Led ( On when Spdbrakes ) + Red Led ( On when Landing gear down )

Huey > Radar Altimeter + Compass Heading 

A10-C2 > HSI Heading + Fuel Quantity Total + Green Led ( On when Spdbrakes ) + Red Led ( On when Landing gear down )

F-14B > Altimeter + Compass Heading + Green Led ( On when Spdbrakes ) + Red Led ( On when Landing gear down )

***EDITED after the F-16 recent Address changes.***

 

 

Fuel_quantity_F-16-18-Huey-A10CII-F14B.ino


Edited by Vortex7
  • Like 2
Link to comment
Share on other sites

  • 2 months later...

Hello, I know this is for working sketches, I would love to add mine, but I have an oscillation problem when using a MUX or multiple for pushbutton interfacing 

here is the code I'm using. fa18_simpit.ino

I don't want to do a button matrix but may have to if 

I'm having trouble trying to figure out what I'm missing or doing wrong.

a lot is commented out just because I'm still trying to diagnose the issue. i believe it has to do with dcs bios being interrupted by the ReadPanel();

but I'm not sure as this is my first time working with dcs bios 

 

this is the sketch I'm using to make sure the multiplexer is wired correctly  ADMUX_DEBUG.ino

 

 

if anyone could take a look at the F18_simpit and maybe confirm that i need some variables to store that state of each mux channel, I know it's pretty far from working like it should, as I certainly bit off more than I can chew. thanks in advance.

 

Ok so I figured out what I was doing wrong trying to pass the mux channel as a pin. There's a couple ways I can think of to handle this. 1 modify the header file to accept a 4 bit binary address and a pin to read. This is above my skill and knowledge. 2 read the mux store the output of each channel and assign them to "something" not sure what data type I would need than place that something's  in the dcs-bios ",pin" pointer so dcs bios only writes when a new channel value is written and not when a channel has been changed as my simpit sketch does... 

 


Edited by Trigger357
Added context/info
  • Like 2
Link to comment
Share on other sites

  • 4 weeks later...
  • 4 months later...

Converted my previous sketch for a 16x2 RGB adding some extras, also initializing screen when swapping modules.

F-16 > Fuel Flow + Chaff/Flare + AoA + Vertical Velocity Indicator + Fuel Quantity Total + Green Led ( On when Spdbrakes ) + Red Led ( On when Landing gear down + Blink when Enemy missile launch )

F-18 > Fuel Quantity + Fuel Flow + Green Led ( On when Spdbrakes ) + Red Led ( On when Landing gear down )

Huey > Radar Altimeter + Compass Heading 

A10-C2 > HSI Heading + Fuel Quantity Total + Green Led ( On when Spdbrakes ) + Red Led ( On when Landing gear down )

F-14B > Altimeter + Compass Heading + Green Led ( On when Spdbrakes ) + Red Led ( On when Landing gear down )

AJS37 > Mach + Heading + G + AoA (W.I.P) + Total Fuel

RGB2.ino


Edited by Vortex7
  • Like 1
Link to comment
Share on other sites

  • 10 months later...

Well it took a while but I want to share another totally reworked script for the Warthog’s digital clock.

Code is written for a 240x240 pixel Waveshare 1.28” round SPI LCD module, driven by an ESP32 development board.

Display: https://eckstein-shop.de/WaveShare128inchRoundLCDDisplayModule240x2402C65KRGBforArduino2FRaspberryPi?googlede=1&gclid=Cj0KCQjwjvaYBhDlARIsAO8PkE2JqP4jUlS3IvEzCE6XaI9XeNbNOekgpZslHC49gSfubxa_UoYsoJAaAmeOEALw_wcB

Or here: https://www.ebay.com/itm/265030625039

ESP32 board 30 pin version: https://joy-it.net/en/products/SBC-NodeMCU-ESP32

ESP32 board 38 pin version: https://www.az-delivery.de/products/esp32-developmentboard

or similar https://www.amazon.co.uk/gp/product/B07VJ34N2Q/ref=ppx_yo_dt_b_asin_title_o01_s00?ie=UTF8&psc=1

 

 

You further need some libraries for the ESP32:

AnalogWrite for the ESP32 if you want to use it with DcsBios: https://www.arduino.cc/reference/en/libraries/esp32-analogwrite/

Bodmer’s TFT_eSPI to draw nice screens: https://github.com/Bodmer/TFT_eSPI

 

I've tryed to comment as much as possible within the code, so you have some explanations what I did and what may be adapted by yourself.

The script can be used in demo mode to see the clock’s display and adjust the colours (just uncomment the first line). To save memory the used fonts are within separate files and only include the digits and letters E, C and T. Both files have to be saved within the same folder like the Arduino sketch.

 

Feel free to play around, adjust and show your results!

 

EDIT: you may define the pin setup for the display within the TFT_eSPI library. See above link for a dedicated description.

I personally use the following configuration:
Setup_GC9A01_ESP32_240x240.h

 

Code for the ESP32 development board

Spoiler
// #define TEST  // uncomment for testmode

#ifndef TEST
  #define DCSBIOS_DEFAULT_SERIAL
  #include "analogWrite.h"  //to be used with the ESP32 chip   https://www.arduino.cc/reference/en/libraries/esp32-analogwrite/
  #include "DcsBios.h"
#endif

#include <Arduino.h>
#include <TFT_eSPI.h> // Master copy here: https://github.com/Bodmer/TFT_eSPI
#include <SPI.h>

// The custom font file attached to this sketch must be included
  #include "DSEG7_Classic_Mini_Bold_45_dc.h"
  #include "Monospaced_plain_32_etc.h"

// Easily remembered name for the font
  #define MYFONT45 &DSEG7_Classic_Mini_Bold_45_dc
  #define MYFONT32 &Monospaced_plain_32_etc

// define the colors for the clock face; Color Picker: http://www.barth-dev.de/online/rgb565-color-picker/
#define LED_ON   0xD6BA // GREEN -> 0x6767 (green) // 0x66CE or 0x45EA (backlight kind of green) // 0xD6BA light grey
#define LED_OFF  0x10A2 // VERRY DARK GREEN -> 0x0920 // 0x10A2 dark grey

// Use hardware SPI
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite face = TFT_eSprite(&tft);

// ---------- declaration of variables ----------
const int mid_X = tft.height() /2 -1; // midpoint of x-axis
const int mid_Y = tft.width() /2 -1; // midpoint of y-axis
const float radius = ((tft.width() / 2)-1) + 0.5; // radius of the gauge
int angle = 270;  // set to -90 or 270 degrees to point in 12 o'clock direction
const byte length_pointer = (tft.width() / 10) + 4; // length of the pointer 
#define DEG2RAD 0.0174532925 // equals Pi/180 to convert degrees in radians

const byte width_b1 = 37;    // width of the bitmap big font
const byte height_b1 = 50;    // height of the bitmap big font
const byte width_b2 = 19;    // width of the bitmap small font
const byte height_b2 = 38;    // height of the bitmap small font

int X_l1_hh, X_l1_dp, X_l1_mm, Y_l1, X_l2, Y_l2, X_l3, Y_l3; // coordinates to print the time
float ax, ay, bx, by; // ccordinates to print the pointer
float aw = 3;
float bw = 2;

int hh = 0; // temporary values for digital time indication
int mm = 0;
int ss = 0;
String etc = "ET ";
int test_delay = 1000;

// setup PWM for the Backlighting
const int pwmFreq = 12000;
const int pwmResolution = 8;  // 8bit PWM signal from 0 to 255
const int pwmLedChannelTFT = 0;
int brightness = 190;

// ---------- DCS.BIOS stuff here ----------
#ifndef TEST
// ---------- Inputs for the Digital Clock ---------- // pins to be defined during design
/*
// Clock CTRL knob
DcsBios::Switch2Pos clockCtrl("CLOCK_CTRL", PIN);

// Clock SET knob
DcsBios::Switch2Pos clockSet("CLOCK_SET", PIN);
*/

// ---------- Flight Instrument Lights --------------
void onLcpFlightInstChange(unsigned int newValue) {  // Min. Value 0 - Max. Value: 65535
    brightness = (newValue/256);                    // for the 8 bit PWM signal
    brightness = constrain(brightness, 30, 255);  // limit range of brightness between 30 and 255
    ledcWrite(pwmLedChannelTFT, brightness);     // writes as PWM (0 - 255)
}
DcsBios::IntegerBuffer lcpFlightInstBuffer(0x114a, 0xffff, 0, onLcpFlightInstChange);

// ---------- Display Time of Digital Clock ---------- 
// display hours in first line
void onClockHhChange(char* newValue) {
    hh = atoi(newValue);
    print_CLOCK();
}
DcsBios::StringBuffer<2> clockHhBuffer(0x10fe, onClockHhChange);

// display minutes in first line
void onClockMmChange(char* newValue) {
    mm = atoi(newValue);
    print_CLOCK();
}
DcsBios::StringBuffer<2> clockMmBuffer(0x1100, onClockMmChange);

// display seconds in second line
void onClockSsChange(char* newValue) {
    hide_pointer(); // delete old pointer position  
    ss = atoi(newValue);
    angle = (ss * 6) - 90; // calculate the new pointer position
    calc_pointer();
    show_pointer();
    print_CLOCK();
}
DcsBios::StringBuffer<2> clockSsBuffer(0x1102, onClockSsChange);

// display "ET" or "C" in bottom line
void onClockEtcChange(char* newValue) {
    etc = newValue;
    print_CLOCK();
}
DcsBios::StringBuffer<3> clockEtcBuffer(0x1104, onClockEtcChange);
#endif

// ---------- SETUP Loop ----------
void setup() {
  
#ifdef TEST
  Serial.begin(115200);
  Serial.println("Booting...");
#endif

#ifndef TEST
  DcsBios::setup();

  // control LCD brightness
  ledcSetup(pwmLedChannelTFT, pwmFreq, pwmResolution);
  ledcAttachPin(TFT_BL, pwmLedChannelTFT);	// see library configuration for the pin setup (TFT_BL)
  ledcWrite(pwmLedChannelTFT, 90);
#endif

// Initialise the screen
  tft.init();
  tft.setRotation(0);
  tft.fillScreen(TFT_BLACK);  // clear the whole screen area
  tft.setTextColor(LED_ON);
#ifdef TEST
  tft.setCursor(15, 75);
  tft.setTextSize(3);
  tft.print("  A-10C II");
  tft.setCursor(5, 110);
  tft.print("Digital Clock");
  tft.setCursor(13, 145);
  tft.print("by Vinc_Vega");
  delay(1500);
  face.fillSprite(TFT_BLACK); // clear active screen
#endif
// Create the clock face sprite
  face.setColorDepth(16); // 1 bit (two colors), 8 bit, commented for standard 16 bit colors
  face.createSprite(tft.width(), tft.height());

// draw depowered pointer LEDs at startup
  calc_LED_ccordinates();// calculate the standard coordinates for the clock face  
  draw_DARK_clock();
  print_CLOCK();
}

// ---------- LOOP Loop ----------
void loop() {

  #ifdef TEST
    run_display_test();
  #endif
  
  #ifndef TEST
    DcsBios::loop();
  #endif
}

// ---------- functions to be used within the DCS:BIOS section ----------
void print_CLOCK()
{
  // show depowered LEDs (off) color  
  face.setTextColor(LED_OFF);
  face.setFreeFont(MYFONT45);
  face.setCursor(X_l1_hh, Y_l1);
  face.print("88"); 
  face.setCursor(X_l1_dp, Y_l1);
  face.print(":");
  face.setCursor(X_l1_mm, Y_l1);
  face.print("88");
  face.setCursor(X_l2, Y_l2);
  face.print("88");
  face.setFreeFont(MYFONT32);
  face.setCursor(X_l3, Y_l3);
  face.print("ETC");

if (etc != "   "){  // if electrical power is ON
  // show the actual time values in LED (on) color
  face.setTextColor(LED_ON);
  face.setFreeFont(MYFONT45);
  face.setCursor(X_l1_hh, Y_l1);
  face.printf("%02d", hh); 
  face.setCursor(X_l1_dp, Y_l1);
  face.print(":");
  face.setCursor(X_l1_mm, Y_l1);
  face.printf("%02d", mm);
  face.setCursor(X_l2, Y_l2);
  face.printf("%02d", ss);
  face.setFreeFont(MYFONT32);
  face.setCursor(X_l3, Y_l3);
  face.print(etc); 
}

  // print_CLOCK() is always the last order: -> draw the whole clock face (Sprite)
  face.pushSprite(0, 0, TFT_TRANSPARENT);
}

// calculate coordinates for the pointer
void calc_pointer()
{
// outer coordinates
ax = mid_X + (radius * cos((angle) * DEG2RAD)) + 0.5;
ay = mid_X + (radius * sin((angle) * DEG2RAD)) + 0.5;

// inner coordinates
bx = mid_X + ((radius - length_pointer) * cos((angle) * DEG2RAD)) + 0.5;
by = mid_X + ((radius - length_pointer) * sin((angle) * DEG2RAD)) + 0.5;
}

// draw pointer LEDs
void show_pointer()
{
  if (etc != "   "){  // if electrical power is ON
  //  Draw an anti-aliased wide line from ax,ay to bx,by with different width at each end aw, bw and with radiused ends
  // If bg_color is not included the background pixel colour will be read from TFT or sprite
  //  void  drawWedgeLine(float ax, float ay, float bx, float by, float aw, float bw, uint32_t fg_color, uint32_t bg_color = 0x00FFFFFF);
  face.drawWedgeLine(ax, ay, bx, by, aw, bw, LED_ON, 0x00FFFFFF);
  }
}

// draw depowered pointer LEDs
void hide_pointer()
{
  face.drawWedgeLine(ax, ay, bx, by, aw, bw, LED_OFF, TFT_BLACK);
}


// ---------- supporting functions ----------

// calculate coordinates for the digital time LEDs
void calc_LED_ccordinates()
{

// ----- ccordinates to print in the first line (hh:mm)
  X_l1_hh = (mid_X - 77);  // x-value to display the hours (hh)
  Y_l1 = (mid_Y); // y-value to display the hours, dp and minutes
  X_l1_dp = (mid_X - 2);  // x-value to display the DP (dp)
  X_l1_mm = (mid_X + 4);  // x-value to display the minutes (mm)
// ----- ccordinates to print in the second line (seconds)
  X_l2 = (mid_X - 37);  // x-value to display the seconds (ss)
  Y_l2 = (mid_Y + 52); // y-value to display the seconds (ss)
// ----- ccordinates to print in the thirth line (ETC)
  X_l3 = (mid_X - 29);  // x-value to display ET or C
  Y_l3 = (mid_Y + 82); // y-value to display ET or C
}

// animate digital time LEDs in TEST mode
void run_display_test()
{
// ----- test digits
for (int s = 1; s <61; s = s + 1)
      {
      ss = s;
        if (ss == 60){
          mm = mm +1;
          ss = 0;
        }
      if (mm == 60)
      {
        hh = hh +1;
        mm = 0;
      }
  #ifdef TEST
  // print time to serial port      
  Serial.printf("%02d:%02d:%02d",hh, mm, ss); 
  Serial.println();
  #endif
    hide_pointer();
    angle = (ss * 6) - 90;
    calc_pointer();
    show_pointer();
    print_CLOCK();
  delay(test_delay); 
  }
}

// draw depowered pointer LEDs at the startup
void draw_DARK_clock()
{
  for (int angle=-90; angle<270; angle = angle + 6) // to run the pointer in TEST MODE
  {
    // outer coordinates
    ax = mid_X + (radius * cos((angle) * DEG2RAD)) + 0.5;
    ay = mid_X + (radius * sin((angle) * DEG2RAD)) + 0.5;
    
    // inner coordinates
    bx = mid_X + ((radius - length_pointer) * cos((angle) * DEG2RAD)) + 0.5;
    by = mid_X + ((radius - length_pointer) * sin((angle) * DEG2RAD)) + 0.5;
    
    face.drawWedgeLine(ax, ay, bx, by, aw, bw, LED_OFF, TFT_BLACK);
  }
}

 

 

Digits

DSEG7_Classic_Mini_Bold_45_dc.h

 

Letters

Monospaced_plain_32_etc.h

 

 

Regards, Vinc


Edited by Vinc_Vega
  • Like 1

Regards, Vinc

real life: Royal Bavarian Airforce

online: VJS-GermanKnights.de

[sIGPIC][/sIGPIC]

Link to comment
Share on other sites

I also want to share the code for the A-10C Standby ADI for the 1.28" round display.

This sketch is written for an ESP32 development board (sources see above posting).

The graphics are converted with LCD Image Converter tool into 16bit RGB565. https://lcd-image-converter.riuson.com/en/about/

If you connect a potentiometer or rotary for pitch adjustment, you still have to declare the respective pin.

I've tryed to comment as much as possible within the code so you may see what I did and adjust to your needs.

 

Feel free to play around, adjust and show your results!

Spoiler
// DCS A-10C II - Standby Attitude Indicator (SAI) display
// in use: ESP32 chipset and round 1.28 inch SPI display

// SAI pitch trim -> potentiometer still tbd during physical design

#define DCSBIOS_DEFAULT_SERIAL  // for use with no Arduino Chips
#include "analogWrite.h"  // PWM functionality to be used with the ESP32 chip   https://www.arduino.cc/reference/en/libraries/esp32-analogwrite/
#include "DcsBios.h"

#include <TFT_eSPI.h>	// Library has to be adjusted for the display driver and resolution in use !!!
#include <SPI.h>

#include "SAI_graphics.h"	// self made bitmaps for the SAI: ColorDepth 16bit

// Easily to remember names for the bitmaps in use
  #define BAND SAI_band		// whole SAI scale
  #define BANK_B SAI_bank_b	// bank indication (black stripe bottom of the scale)
  #define BANK_T SAI_bank_t	// bank indication (blue stripe top of the scale) 
  #define WING SAI_wing		// indication of the horizontal bar (aircraft symbol)
  #define FLAG SAI_flag		// OFF flag

// Definition of the instrument Layers (Sprites)
  TFT_eSPI tft=TFT_eSPI();
  TFT_eSprite gaugeBack = TFT_eSprite(&tft);
  TFT_eSprite band = TFT_eSprite(&tft);
  TFT_eSprite bank_b = TFT_eSprite(&tft);
  TFT_eSprite bank_t = TFT_eSprite(&tft);
  TFT_eSprite wing = TFT_eSprite(&tft);
  TFT_eSprite flag = TFT_eSprite(&tft);

// Startup values to center the SAI display
  int16_t  SaiPitch = 421;  // set SAI band to center: 1012(bitmap height) - 170(Sprite height) = 842 -> 842 / 2 = 421 px (y-direction)
  int16_t  SaiBank = 0;  // level: 0°
  int16_t  SaiPitchAdj = 115;  // set adjustment to center: 115 px
  int16_t  SaiWarningFlag = 0; // set warning flag: ON (65535 = rotation 0°); OFF (0 = rotation -25°)

// setup PWM for the Backlighting
  const int pwmFreq = 12000;		// works best with 12000 Hz
  const int pwmResolution = 8;  	// 8bit PWM signal from 0 to 255
  const int pwmLedChannelTFT = 0;	// PWM Channel 1
  int brightness = 190;			// startup brightness value

// ---------- DCS.BIOS stuff here ----------
// --- SAI Bank -> rotating the band left / right
void onSaiBankChange(unsigned int newValue) {
  SaiBank = map(newValue, 0, 65535, -180, 180); // bank angle from -180 to +180 degrees
  createBitmaps(SaiPitch, SaiPitchAdj, SaiWarningFlag);
  plotGauge(SaiBank, SaiWarningFlag);
}
DcsBios::IntegerBuffer saiBankBuffer(0x102a, 0xffff, 0, onSaiBankChange);


// --- SAI Pitch -> moving the band up / down
void onSaiPitchChange(unsigned int newValue) {
  SaiPitch = map(newValue, 0, 65535, 850, 4); // 1012 (bitmap height) - 170 (Sprite height) = 842 px (plus 8 px for adjustment)
  // ->> to be corrected by the real instrument height (240px) instead of the Sprite height (170px)
  createBitmaps(SaiPitch, SaiPitchAdj, SaiWarningFlag);
  plotGauge(SaiBank, SaiWarningFlag);
}
DcsBios::IntegerBuffer saiPitchBuffer(0x1028, 0xffff, 0, onSaiPitchChange);


// --- SAI pitch adjustment -> moving the wing up / down
void onSaiPitchAdjChange(unsigned int newValue) {
  SaiPitchAdj = map(newValue, 0, 65535, 155, 75); // 120 (tft center) - 5 (midpoint) = 115 -> 115 + 40 (bitmap height) and 115 - 40 (bitmap height) 
  createBitmaps(SaiPitch, SaiPitchAdj, SaiWarningFlag);
  plotGauge(SaiBank, SaiWarningFlag);
}
DcsBios::IntegerBuffer saiPitchAdjBuffer(0x102e, 0xffff, 0, onSaiPitchAdjChange);

/*
// --- input for the SAI pitch adjustment (trim) -> tbd
DcsBios::PotentiometerEWMA<5, 128, 5> SaiPitchAdj("SAI_PITCH_TRIM", PIN);
*/

// --- show the SAI OFF flag
void onSaiWarningFlagChange(unsigned int newValue) {
  SaiWarningFlag = map(newValue, 0, 65535, -25, 0); // set warning flag: ON (0° = 65535); OFF (-25° = 0)
  createBitmaps(SaiPitch, SaiPitchAdj, SaiWarningFlag);
  plotGauge(SaiBank, SaiWarningFlag);
}
DcsBios::IntegerBuffer saiWarningFlagBuffer(0x102c, 0xffff, 0, onSaiWarningFlagChange);


// ---------- Flight Instrument Lights --------------
void onLcpFlightInstChange(unsigned int newValue) {  // Min. Value 0 - Max. Value: 65535
  brightness = (newValue/256);                     // for an 8 bit PWM signal
  brightness = constrain(brightness, 30, 255);     // limit range of brightness between 30 and 255
  ledcWrite(pwmLedChannelTFT, brightness);         // write PWM signal (0 - 255) to PWM Channel 1
}
DcsBios::IntegerBuffer lcpFlightInstBuffer(0x114a, 0xffff, 0, onLcpFlightInstChange);

// ---------- SETUP Loop ----------

void setup() {
  
  DcsBios::setup();

// setup the display
  tft.init();
  tft.setRotation(0);
  tft.fillScreen(0x0000); 	// clear the whole screen area
  tft.setPivot(120, 120);	// midpoint of the resolution (240x240)

// control LCD brightness
  ledcSetup(pwmLedChannelTFT, pwmFreq, pwmResolution);
  ledcAttachPin(TFT_BL, pwmLedChannelTFT);	// see library configuration for the pin setup (TFT_BL)
  ledcWrite(pwmLedChannelTFT, 90);

// setup of graphics (bitmaps) and initiate the master functions (no need to call them within the LOOP-section)
  createBitmaps(SaiPitch, SaiPitchAdj, SaiWarningFlag);
  plotGauge(SaiBank, SaiWarningFlag);
  
}

// ---------- Main Loop (if possible, keep emty) ----------
void loop() {
  DcsBios::loop();
}
// ---------- END of Main Loop ----------


// ---------- FUNCTIONS declaration ----------

void plotGauge(int16_t SaiBank, int16_t SaiWarningFlag){
  
  bank_b.pushRotated(&gaugeBack, SaiBank);
  bank_t.pushRotated(&gaugeBack, SaiBank);
  band.pushRotated(&gaugeBack, SaiBank);
  wing.pushRotated(&gaugeBack, 0, 0x0000);
  if (SaiWarningFlag > -20)	// show OFF-Flag only if it's within the round display area ( 0° to -20°)
    {
    createFlag(SaiWarningFlag);
    }
  gaugeBack.pushSprite(0 , 0);
}

void createBitmaps(int16_t SaiPitch, int16_t SaiPitchAdj, int16_t SaiWarningFlag){
  createGauge();
  createBand(SaiPitch);
  createBank_B();
  createBank_T();
  createWing(SaiPitchAdj);
}

void createGauge(){
  gaugeBack.setColorDepth(16);
  gaugeBack.createSprite(240, 240);
  gaugeBack.fillSprite(TFT_BLACK);
}

void createBand(int16_t SaiPitch){
  band.setColorDepth(16);
  band.deleteSprite();
  band.createSprite(240, 170); 
  band.setPivot(120, 85);
  band.fillSprite(TFT_BLACK);
  band.pushImage(20, -SaiPitch, 200, 1012, BAND);
}

void createBank_B(){
  bank_b.setColorDepth(16);
  bank_b.deleteSprite();
  bank_b.createSprite(240, 35); 
  bank_b.setPivot(120, -85);
  bank_b.pushImage(0, 0, 240, 35, BANK_B);
}

void createBank_T(){
  bank_t.setColorDepth(16);
  bank_t.deleteSprite();
  bank_t.createSprite(240, 35); 
  bank_t.setPivot(120, 120);
  bank_t.pushImage(0, 0, 240, 35, BANK_T);
}

void createWing(int16_t SaiPitchAdj){
  wing.setColorDepth(16);
  wing.deleteSprite();
  wing.createSprite(240, 30); 
  wing.setPivot(120, SaiPitchAdj - 110);
  wing.fillSprite(TFT_TRANSPARENT);
  wing.pushImage(0, 0, 240, 30, WING);
}

void createFlag(int16_t SaiWarningFlag){
  flag.setColorDepth(16);
  flag.deleteSprite();
  flag.createSprite(62, 80);
  flag.setPivot(0, 80);
  flag.fillSprite(0x0000);
  flag.pushImage(0, 0, 62, 80, FLAG);
  gaugeBack.setPivot(0, 125);
  flag.pushRotated(&gaugeBack, SaiWarningFlag, 0x0000);
  gaugeBack.setPivot(120, 120);
}

 

 

Graphics that have to be saved within the same folder like the Arduino sketch

SAI_graphics.h

 

Regards, Vinc


Edited by Vinc_Vega
  • Like 3

Regards, Vinc

real life: Royal Bavarian Airforce

online: VJS-GermanKnights.de

[sIGPIC][/sIGPIC]

Link to comment
Share on other sites

The third sketch to share is for the Warthog's Accelerometer (G-Meter) and is an example for a three pointers gauge.

Same conditions as above (ESP32 dev board and 1.28" round colur display).

16bit RGB565 graphis files have to be saved within the same folder like the sketch.

The reset button (Push to Set) may be used if a dedicatd pin is defined.

Feel free to play around, adjust and show your results!

Spoiler
// DCS A-10C II - Accelerometer display (G-Meter)
// in use: ESP32 chipset and round 1.28 inch SPI display

// Push to Set -> push button still tbd during physical design

// compiler switches to adjust the sketch - if not wanted, just comment the lines
  #define MARK1 0xB800 // red limit marks at +5g, -2g, -3g
//  #define MARK2 0xEF5B // white limit mark at -5g
  #define BACKLIGHT
  const byte colorDepth = 16;
   
#define DCSBIOS_DEFAULT_SERIAL  // for use with no Arduino Chips
#include "analogWrite.h"  // PWM functionality to be used with the ESP32 chip   https://www.arduino.cc/reference/en/libraries/esp32-analogwrite/
#include "DcsBios.h"

#include <TFT_eSPI.h>	// Library has to be adjusted for the display driver and resolution in use !!!
#include <SPI.h>

#include "g-meter_scale.h"	// bitmaps for the Accelerometer, ColorDepth 16bit
#include "g-load_pointer.h"
#include "g-limit_pointer.h"

// Easily to remember names for the bitmaps in use
  #define SCALE scale		// whole accelerometer scale
  #define LOAD load_pointer    // G-Load Pointer
  #define LIMIT limit_pointer    // G-Limit Pointers (Max / Min G)

// Definition of the instrument Layers (Sprites)
  TFT_eSPI tft=TFT_eSPI();
  TFT_eSprite gaugeBack = TFT_eSprite(&tft);
  TFT_eSprite load = TFT_eSprite(&tft);
  TFT_eSprite maxLim = TFT_eSprite(&tft);
  TFT_eSprite minLim = TFT_eSprite(&tft);

// Startup values to center the pointers
  int16_t  accelG = 0;  // values in degree (0° = +1g)
  int16_t  accelMax = 0;
  int16_t  accelMin = 0;

// setup PWM for the Backlighting
#ifdef BACKLIGHT
  const int pwmFreq = 12000;		// works best with 12000 Hz
  const int pwmResolution = 8;  	// 8bit PWM signal from 0 to 255
  const int pwmLedChannelTFT = 0;	// PWM Channel 1
  int brightness = 250;			// startup brightness value
#endif

// ----------------------------------------------------------------------------------------
//            DCS.BIOS stuff here
// ----------------------------------------------------------------------------------------

// ----- Accelerometer G Load Pointer
void onAccelGChange(unsigned int newValue) {
  accelG = map(newValue, 0, 65535, 225, 562); // 0° = 1g; end of pos scale +10g = 360 + 202,5 = 562; end of neg scale -5g = 360 - 135 = 225
  createBitmaps(accelMin, accelMax, accelG);
  plotGauge(accelMin, accelMax, accelG);
}
DcsBios::IntegerBuffer accelGBuffer(0x1070, 0xffff, 0, onAccelGChange);

// ----- Accelerometer Max Pointer
void onAccelMaxChange(unsigned int newValue) {
  accelMax = map(newValue, 0, 65535, 225, 562);
  createBitmaps(accelMin, accelMax, accelG);
  plotGauge(accelMin, accelMax, accelG);
}
DcsBios::IntegerBuffer accelMaxBuffer(0x1074, 0xffff, 0, onAccelMaxChange);

// ----- Accelerometer Min Pointer
void onAccelMinChange(unsigned int newValue) {
  accelMin = map(newValue, 0, 65535, 225, 562);
  createBitmaps(accelMin, accelMax, accelG);
  plotGauge(accelMin, accelMax, accelG);
}
DcsBios::IntegerBuffer accelMinBuffer(0x1072, 0xffff, 0, onAccelMinChange);

// ----- Accelerometer Push to Set (reset button)
// DcsBios::Switch2Pos accelPts("ACCEL_PTS", PIN);  // tbd during physical design of the gauge

// ---------- Flight Instrument Lights --------------
#ifdef BACKLIGHT
  void onLcpFlightInstChange(unsigned int newValue) {  // Min. Value 0 - Max. Value: 65535
      brightness = (newValue/256);                    // for the 8 bit PWM signal
      brightness = constrain(brightness, 30, 255);  // limit range of brightness between 30 and 255
      ledcWrite(pwmLedChannelTFT, brightness);     // writes as PWM (0 - 255)
  }
  DcsBios::IntegerBuffer lcpFlightInstBuffer(0x114a, 0xffff, 0, onLcpFlightInstChange);
#endif

// ----------------------------------------------------------------------------------------
//            SETUP Loop
// ----------------------------------------------------------------------------------------

void setup() {
  
  DcsBios::setup();

// setup the display
  tft.init();
  tft.setRotation(0);
  tft.fillScreen(0x0000); 	// clear the whole screen area
  tft.setPivot(120, 120);	// midpoint of the resolution (240x240)

#ifdef BACKLIGHT
  // control LCD brightness
  ledcSetup(pwmLedChannelTFT, pwmFreq, pwmResolution);
  ledcAttachPin(TFT_BL, pwmLedChannelTFT);	// see library configuration for the pin setup (TFT_BL)
  ledcWrite(pwmLedChannelTFT, 90);
#endif

// setup of graphics (bitmaps) and initiate the master functions (no need to call them within the LOOP-section)
  createBitmaps(accelMin, accelMax, accelG);
  plotGauge(accelMin, accelMax, accelG);
  
}

// ----------------------------------------------------------------------------------------
//            Main Loop (if possible, keep emty)
// ----------------------------------------------------------------------------------------

void loop() {
  DcsBios::loop();
}

// ----------------------------------------------------------------------------------------
//            FUNCTIONS declaration
// ----------------------------------------------------------------------------------------

void createLoad_pointer(int16_t accelG)
{
  load.setColorDepth(colorDepth);
  load.createSprite(182, 33); 
  load.setPivot(107, 16);
  load.fillSprite(TFT_TRANSPARENT);
  load.pushImage(0, 0, 182, 33, LOAD);
}

void createMax_poiter(int16_t accelMax)
{
  maxLim.setColorDepth(colorDepth);
  maxLim.createSprite(182, 33); 
  maxLim.setPivot(107, 16);
  maxLim.fillSprite(TFT_TRANSPARENT);
  maxLim.pushImage(0, 0, 182, 33, LIMIT);
}

void createMin_pointer(int16_t accelMin)
{
  minLim.setColorDepth(colorDepth);
  minLim.createSprite(182, 33); 
  minLim.setPivot(107, 16);
  minLim.fillSprite(TFT_TRANSPARENT);
  minLim.pushImage(0, 0, 182, 33, LIMIT);
}

void createBitmaps(int16_t accelMin, int16_t accelMax, int16_t accelG)
{
  gaugeBack.setColorDepth(colorDepth);
  gaugeBack.createSprite(240, 240); 
  gaugeBack.setPivot(120, 120);
  gaugeBack.pushImage(0, 0, 240, 240, SCALE); // (x, y, _dwidth, _dheight, _img );

  #ifdef MARK1  // ----- draw red limit marks to the scale at +5g, -2g, -3g
    gaugeBack.drawWedgeLine(120, 0, 120, 22, 4, 4, MARK1, 0x00FFFFFF);
    gaugeBack.drawWedgeLine(120, 240, 120, 218, 4, 4, MARK1, 0x00FFFFFF);
    gaugeBack.drawWedgeLine(73, 230, 83, 209, 4, 4, MARK1, 0x00FFFFFF);
  #endif
  #ifdef MARK2  // ----- draw white limit mark to the scale  at -5g
    gaugeBack.drawWedgeLine(204, 204, 187, 187, 4, 4, MARK2, 0x00FFFFFF);
  #endif
  
  createLoad_pointer(accelG);
  createMax_poiter(accelMax);
  createMin_pointer(accelMin);
}

void plotGauge(int16_t accelMin, int16_t accelMax, int16_t accelG)
{
  minLim.pushRotated(&gaugeBack, accelMin, 0x0000);
  maxLim.pushRotated(&gaugeBack, accelMax, 0x0000);
  load.pushRotated(&gaugeBack, accelG, 0x0000);
  gaugeBack.pushSprite(0 , 0);  // (int32_t x, int32_t y, uint16_t transp)

  load.deleteSprite();  // delete all sprites and free RAM
  maxLim.deleteSprite();
  minLim.deleteSprite(); 
  gaugeBack.deleteSprite();
}

 

 

Graphic files

g-meter_scale.h

g-load_pointer.h

g-limit_pointer.h

 

No pics available yet, feel free to post yours.

 

Regards, Vinc


Edited by Vinc_Vega
  • Like 2

Regards, Vinc

real life: Royal Bavarian Airforce

online: VJS-GermanKnights.de

[sIGPIC][/sIGPIC]

Link to comment
Share on other sites

Vinc's three gauges above work perfectly, I have made them using his code myself. However his first post set out the hardware and from personal experience I can attest to the fact that you are best going with the devices specified to avoid issues. 

Thanks for all the help and for posting Vinc!

Les

  • Thanks 1
Link to comment
Share on other sites

  • 2 months later...

I am building a helicopter collective. I have a leonardo and have tested the 5 axis sketch (from a source on youtube) and it works. However I will be editing the sketch to use 4 axis. I need to add 13 buttons to it but I cant find a template I can edit. I will be using the digital pins 0 to 12 not a matrix. Can anyone help me?

Link to comment
Share on other sites

I have seen that but I know diddly squat about code. I know that you have to tell the leonardo which pin is an input and it watches if the state changes but the example is for pin 9 and I cant work out how to tell it to watch pins 0 to 12. I need a template which has at least 4 pins being monitored so I can copy/paste the code for the buttons and then combine it with the 4 axis sketch. Thanks in advance.

Link to comment
Share on other sites

The "JoystickButton" example sketch has code to read four buttons starting with pin 9.

BTW: 
One thing to bear in mind, though, is that you basically can't use pins 0 and 1 for IO when you use the ATMega328P Arduinos for DCS-BIOS because those pins are used by the processor for the USB comms.  I don't know if the 32u4 Arduinos, like the Pro Micro are the same.


Edited by No1sonuk
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...