//8CH RC Transmitter with OLED display interface for Menu Options i.e Reverse, Borders, Elevon, Servo Trim, Battery & Factory Reset.
//The Transmitter now has got STM32F103 aka BluePil and is an upgrade version of the previous with Nano and NRF24LO1.
//by Neel. 10.01.2024
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//#include <EEPROM.h>
#include "icon_arrays.h" //header file contains OLED icon/images arrays
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3c ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
//
//See icon_arrays.h for icon & images arrays
//
const int potPin = A0; int potVal; int value; //for debugging & testing only.
// pins for buttons >> dn, up, back/cancel, select/Ok >> Wokwi Btn Color GRN,YLW,BLU,RED
const byte dnKey = 9; const byte upKey = 10; const byte bacKey = 11; const byte selKey = 12; // pins for buttons up, dn, back, select
byte page1 = 0; //Main Menu page switch case // Menu Options i.e Reverse, Borders, Elevon, Servo Trim, Battery & Factory Reset Transmitter
byte page2 = 0; //Reverse menu switch case // Channel Reverse function To Opposite movement of servo
byte page3 = 0; //Boarders menu switch case // set the PWM maximun & minimum // Servo max-min movement
byte page4 = 0; //Elevon menu switch case // Elevon menu is for Mixing Roll & Pitch for deltaWings
//Current menus status. // 0 = not selected & 1 = selected.
bool menuStatus = 0; bool reverseStatus = 0; bool borderStatus = 0; bool elevonStatus = 0; bool offsetStatus = 0;
bool trimStaus = 0; bool batteryStatus = 0; bool resetStatus = 0; //Current menus/sub menu status for entering concern menu while loop
// Channels Border Set.
int rollMax=255; int rollMin=0; int pitchMax=255; int pitchMin=0; // Max & Min Borders for servo movement called in Border_Map Function
int thtMax=255; int thtMin=255; int yawMax=255; int yawMin=0;
// Channels Reverse Status.
bool revCh1 = false; bool revCh2 = false; bool revCh3 = false; bool revCh4 = false; // Channels Reverse Status.
bool revCh5 = false; bool revCh6 = false; bool revCh7 = false; bool revCh8 = false;
// Elevon Status
bool elevonMix = false; // Elevon mode status. //True = Activated,
byte offsetMix = 50; // Roll+Pitch mix offset in %, default 50%,
void setup() {
pinMode(dnKey, INPUT_PULLUP);
pinMode(upKey, INPUT_PULLUP);
pinMode(bacKey, INPUT_PULLUP);
pinMode(selKey, INPUT_PULLUP);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
setupGreet();
delay(1000);
display.clearDisplay();
}
void loop() {
//
//Put Transmitter Main Code Here
//
mainPage(); // main ch value page default screen i.e home page
checkMenuStatus();
while (menuStatus==1 ){ // menu page after press select button
menuCheck();
updateMenu();
checkMenuStatus();
checkReverseStatus();
checkBorderStatus();
checkElevonStatus();
checkBorderStatus();
checkBatteryStatus();
checkResetStatus();
while(reverseStatus==1){ //sub menu Reverse Page //menuPage/reversePage
reverseCheck();
updateReverse();
checkReverseStatus();
}
while(borderStatus==1){ //sub menu Borders Page //menuPage/BordersPage
borderCheck();
updateBorder();
checkBorderStatus();
}
while(elevonStatus==1){ //sub menu Elevon Page //menuPage/elevonPage
elevonCheck();
updateElevon();
checkElevonStatus();
checkOffsetStatus();
while(offsetStatus==1){ //menuPage/eleronPage/offsetPage
offsetPage();
checkOffsetStatus();
}
}
while(batteryStatus==1){ //sub menu Battery Page //menuPage/BatteryPage
batteryPage();
checkBatteryStatus();
}
while(resetStatus==1){ //sub menu Battery Page //menuPage/BatteryPage
resetPage();
checkResetStatus();
}
}//main while loop end
}//loop end
void checkBorderStatus(){
if(page1==2){
if (!digitalRead(selKey) && borderStatus==0){
borderPage();
borderStatus=1;
while (!digitalRead(selKey));
}
else if (!digitalRead(bacKey) && borderStatus==1){
menuPage();
borderStatus=0;
page3 =1;
page1=1;
while (!digitalRead(bacKey));
}
}
}
void borderCheck(){
if (!digitalRead(upKey)){ //When Button is Pressed change screen page
page3--;
while (!digitalRead(upKey));
}
if (!digitalRead(dnKey)){ //When Button is Pressed change screen page
page3++;
while (!digitalRead(dnKey));
}
}
void updateBorder(){
switch(page3){
case 0:
page3=1;
break;
case 1:
borderPage();
break;
case 2:
borCh2();
break;
case 3:
borCh3();
break;
case 4:
borCh4();
break;
case 5:
borderPage();
page3=1;
break;
}
}
void borderPage(){
display.clearDisplay();
display.drawRect(14, 2, 58, 13, 1);
display.drawRect(14, 17, 58, 13, 1);
display.drawBitmap(4, 6, image_ButtonRight_4x7_bits, 4, 7, 1);
display.drawRect(14, 32, 58, 13, 1);
display.drawRect(14, 47, 58, 13, 1);
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(25, 5);
display.setTextWrap(false);
display.print("Ch - 1");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(25, 20);
display.setTextWrap(false);
display.print("Ch - 2");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(25, 35);
display.setTextWrap(false);
display.print("Ch - 3");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(25, 50);
display.setTextWrap(false);
display.print("Ch - 4");
display.drawRect(81, 2, 39, 13, 1);
display.drawRect(81, 17, 39, 13, 1);
display.drawRect(81, 32, 39, 13, 1);
display.drawRect(81, 47, 39, 13, 1);
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(90, 5);
display.setTextWrap(false);
display.print("ROLL");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(86, 20);
display.setTextWrap(false);
display.print("PITCH");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(86, 35);
display.setTextWrap(false);
display.print("THRTL");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(92, 50);
display.setTextWrap(false);
display.print("YAW");
display.display();
}
void borCh2(){
display.clearDisplay();
display.drawRect(14, 2, 58, 13, 1);
display.drawRect(14, 17, 58, 13, 1);
display.drawBitmap(4, 20, image_ButtonRight_4x7_bits, 4, 7, 1);
display.drawRect(14, 32, 58, 13, 1);
display.drawRect(14, 47, 58, 13, 1);
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(25, 5);
display.setTextWrap(false);
display.print("Ch - 1");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(25, 20);
display.setTextWrap(false);
display.print("Ch - 2");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(25, 35);
display.setTextWrap(false);
display.print("Ch - 3");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(25, 50);
display.setTextWrap(false);
display.print("Ch - 4");
display.drawRect(81, 2, 39, 13, 1);
display.drawRect(81, 17, 39, 13, 1);
display.drawRect(81, 32, 39, 13, 1);
display.drawRect(81, 47, 39, 13, 1);
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(90, 5);
display.setTextWrap(false);
display.print("ROLL");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(86, 20);
display.setTextWrap(false);
display.print("PITCH");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(86, 35);
display.setTextWrap(false);
display.print("THRTL");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(92, 50);
display.setTextWrap(false);
display.print("YAW");
display.display();
}
void borCh3(){
display.clearDisplay();
display.drawRect(14, 2, 58, 13, 1);
display.drawRect(14, 17, 58, 13, 1);
display.drawBitmap(4, 35, image_ButtonRight_4x7_bits, 4, 7, 1);
display.drawRect(14, 32, 58, 13, 1);
display.drawRect(14, 47, 58, 13, 1);
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(25, 5);
display.setTextWrap(false);
display.print("Ch - 1");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(25, 20);
display.setTextWrap(false);
display.print("Ch - 2");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(25, 35);
display.setTextWrap(false);
display.print("Ch - 3");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(25, 50);
display.setTextWrap(false);
display.print("Ch - 4");
display.drawRect(81, 2, 39, 13, 1);
display.drawRect(81, 17, 39, 13, 1);
display.drawRect(81, 32, 39, 13, 1);
display.drawRect(81, 47, 39, 13, 1);
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(90, 5);
display.setTextWrap(false);
display.print("ROLL");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(86, 20);
display.setTextWrap(false);
display.print("PITCH");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(86, 35);
display.setTextWrap(false);
display.print("THRTL");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(92, 50);
display.setTextWrap(false);
display.print("YAW");
display.display();
}
void borCh4(){
display.clearDisplay();
display.drawRect(14, 2, 58, 13, 1);
display.drawRect(14, 17, 58, 13, 1);
display.drawBitmap(4, 50, image_ButtonRight_4x7_bits, 4, 7, 1);
display.drawRect(14, 32, 58, 13, 1);
display.drawRect(14, 47, 58, 13, 1);
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(25, 5);
display.setTextWrap(false);
display.print("Ch - 1");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(25, 20);
display.setTextWrap(false);
display.print("Ch - 2");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(25, 35);
display.setTextWrap(false);
display.print("Ch - 3");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(25, 50);
display.setTextWrap(false);
display.print("Ch - 4");
display.drawRect(81, 2, 39, 13, 1);
display.drawRect(81, 17, 39, 13, 1);
display.drawRect(81, 32, 39, 13, 1);
display.drawRect(81, 47, 39, 13, 1);
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(90, 5);
display.setTextWrap(false);
display.print("ROLL");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(86, 20);
display.setTextWrap(false);
display.print("PITCH");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(86, 35);
display.setTextWrap(false);
display.print("THRTL");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(92, 50);
display.setTextWrap(false);
display.print("YAW");
display.display();
}
void borRoll(){
display.clearDisplay();
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(8, 5);
display.setTextWrap(false);
display.print("Ch-1 Roll Min - Max");
display.setTextColor(1);
display.setTextSize(2);
display.setCursor(15, 20);
display.setTextWrap(false);
display.print("Max-");
display.drawLine(3, 14, 124, 14, 1);
display.setTextColor(1);
display.setTextSize(2);
display.setCursor(15, 44);
display.setTextWrap(false);
display.print("Min-");
display.setTextColor(1);
display.setTextSize(2);
display.setCursor(74, 20);
display.setTextWrap(false);
display.print("255");
display.setTextColor(1);
display.setTextSize(2);
display.setCursor(76, 44);
display.setTextWrap(false);
display.print("0");
display.drawBitmap(7, 24, image_ButtonRight_4x7_bits, 4, 7, 1);
display.drawRect(2, 2, 124, 60, 1);
display.display();
}
void trimPage(){ // Temporarey Under Construction
display.clearDisplay();
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(10, 8);
display.setTextWrap(false);
display.print("THIS PAGE IS UNDER");
display.setTextColor(1);
display.setTextSize(1);
display.setCursor(28, 24);
display.setTextWrap(false);
display.print("CONSTRUCTION");
display.setTextColor(1);
display.setTextSize(3);
display.setCursor(36, 38);
display.setTextWrap(false);
display.print("(!)");
display.display();
}
nano:12
nano:11
nano:10
nano:9
nano:8
nano:7
nano:6
nano:5
nano:4
nano:3
nano:2
nano:GND.2
nano:RESET.2
nano:0
nano:1
nano:13
nano:3.3V
nano:AREF
nano:A0
nano:A1
nano:A2
nano:A3
nano:A4
nano:A5
nano:A6
nano:A7
nano:5V
nano:RESET
nano:GND.1
nano:VIN
nano:12.2
nano:5V.2
nano:13.2
nano:11.2
nano:RESET.3
nano:GND.3
oled1:GND
oled1:VCC
oled1:SCL
oled1:SDA
pot1:GND
pot1:SIG
pot1:VCC
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
btn2:1.l
btn2:2.l
btn2:1.r
btn2:2.r
btn3:1.l
btn3:2.l
btn3:1.r
btn3:2.r
btn4:1.l
btn4:2.l
btn4:1.r
btn4:2.r