//#include <ModbusRtu.h>
#include <U8g2lib.h>
#include <Wire.h>
#include <Bounce2.h>
#define ID 1
#define NUM_BUTTONS 6
const uint8_t BUTTON_PINS[NUM_BUTTONS] = {22, 23, 24, 25, 26, 27};
Bounce * buttons = new Bounce[NUM_BUTTONS];
bool button_UP;
bool button_LEFT;
bool button_RIGHT;
bool button_DOWN;
bool button_ESC;
bool button_OK;
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); // initalize the display
//U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
//Create instance
//Modbus slave(ID, Serial, 0); //Node ID. 0 for master, 1-247 for slave
//Serial port (0 = TX: 1 - RX: 0)
//Serial protocol. 0 for RS-232 + USB (default), any pin greater than 1 for RS-485
bool MainMenuEn = false;
bool SubMenuEn = false;
int8_t MainMenuCnt = 0;
int8_t MainMenuItems = 6;
char *MainMenuStr[] = {"Steps per mm","Limit up","Limit down","Anti dive","PID - P","PID - I","PID - D"};
char *MainMenuUnit[] = {"steps","mm","mm","V.","","",""};
int8_t MainMenuDec[] = {-3,-2,-3,-3,-3,-3,-3};
int8_t MainMenuFrac[] = {0,1,1,0,0,0,0};
typedef struct{
char MenuStr[15];
char MenuUnit[10];
int8_t MenuDec;
int8_t MenuFrac;
float MenuValue;
}ParVar;
ParVar Item[7] = {
{"Steps per mm","steps",-3,0,1200},
{"Limit up","mm",-2,2,25.80},
{"Limit down","mm",-2,2,-5.2},
{"Anti dive","V.",-3,0,5384},
{"PID - P","%",-3,0,5384},
{"PID - I","sec",-3,0,5384},
{"PID - D","sec",-3,0,5384},
};
int8_t digit[5];
float TempValue;
bool CursorState;
unsigned long previousMillis = 0;
const long blinktime = 500;
int8_t CursorPos = 0;
int8_t maxDec = 0;
int8_t maxFrag = 0;
const int SensorPin = A0;
int ARC_Voltage;
int ARC_Setpoint;
bool SettingsMenu;
boolean led;
int8_t state = 0;
unsigned long tempus;
uint16_t au16data[9]; //The table of records that you want to share over the network
int8_t pressCnt;
float ParStepMM = 5384;
/*********************************************************
Program settings
*********************************************************/
void setup() {
for (int i = 0; i < NUM_BUTTONS; i++) {
buttons[i].attach( BUTTON_PINS[i] , INPUT_PULLUP ); //setup the bounce instance for the current button
buttons[i].interval(25); // interval in ms
}
io_setup(); //configure inputs and outputs
Serial.begin(19200); //Open communication as slave
//slave.start();
tempus = millis() + 100; //Save current time + 100ms
digitalWrite(13, HIGH ); //Turn on the LED on pin 13 (the one on the board)
u8g2.begin();
u8g2.setFont(u8g2_font_6x12_tr);
u8g2.setDrawColor(1); /* color 1 for the box */
StartScreen();
}
/*********************************************************
Program start
*********************************************************/
void loop() {
for (int i = 0; i < NUM_BUTTONS; i++) {
// Update the Bounce instance :
buttons[i].update();
}
button_UP = buttons[0].fell();
button_LEFT = buttons[1].fell();
button_RIGHT = buttons[2].fell();
button_DOWN = buttons[3].fell();
button_ESC = buttons[4].fell();
button_OK = buttons[5].fell();
ScanMenu();
//Check the input buffer
//state = slave.poll( au16data, 9 ); //Parameters: Table of records for information exchange
// Log table size
//Returns 0 if there is no data request
//Returns 1 to 4 if there was a communication error
//Return more than 4 if the order was processed correctly
if (state > 4) { //If it is greater than 4 = the order was correct
tempus = millis() + 50; //Current time + 50ms
digitalWrite(13, HIGH);//Turn on the led
}
if (millis() > tempus) digitalWrite(13, LOW );//Turn off the LED 50ms later
//Update Arduino pins with Modbus board
io_poll();
}
/**
* pin maping:
* 2 - digital input
* 3 - digital input
* 4 - digital input
* 5 - digital input
* 6 - digital output
* 7 - digital output
* 8 - digital output
* 9 - digital output
* 10 - analog output
* 11 - analog output
* 14 - analog input
* 15 - analog input
*
* pin 13 reserved to view communication status
*/
void io_setup() {
pinMode(2, INPUT);
pinMode(3, INPUT);
pinMode(4, INPUT);
pinMode(5, INPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
pinMode(13, OUTPUT);
digitalWrite(6, LOW );
digitalWrite(7, LOW );
digitalWrite(8, LOW );
digitalWrite(9, LOW );
digitalWrite(13, HIGH ); //Board pin 13 led
analogWrite(10, 0 ); //PWM 0%
analogWrite(11, 0 ); //PWM 0%
}
/*********************************************************
Link the register table with the pins
*********************************************************/
void io_poll() {
// digital inputs -> au16data[0]
// Reads the digital inputs and saves them in bits of the first variable of the vector
// (It's the same as making a mask)
bitWrite( au16data[0], 0, digitalRead( 2 )); //Reads Arduino pin 2 and saves it in bit 0 of the au16data[0] variable
bitWrite( au16data[0], 1, digitalRead( 3 ));
bitWrite( au16data[0], 2, digitalRead( 4 ));
bitWrite( au16data[0], 3, digitalRead( 5 ));
// digital outputs -> au16data[1]
// Reads the bits of the second variable and puts them on the digital outputs
digitalWrite( 6, bitRead( au16data[1], 0 )); //Reads bit 0 of the au16data[1] variable and puts it on pin 6 of the Arduino
digitalWrite( 7, bitRead( au16data[1], 1 ));
digitalWrite( 8, bitRead( au16data[1], 2 ));
digitalWrite( 9, bitRead( au16data[1], 3 ));
// Change the PWM value
analogWrite( 10, au16data[2] ); //The value of au16data[2] is written to the PWM output of pin 10 of the Arduino. (0=0% and 255=100%)
analogWrite( 11, au16data[3] );
ARC_Setpoint = au16data[3];
// Reads analog inputs (ADC)
ARC_Voltage= map(analogRead(SensorPin),0,1023,0,250);
//au16data[4] = analogRead( 0 ); //The analog value read on pin A0 is saved in au16data[4]. (0=0v and 1023=5v)
au16data[4] = ARC_Voltage;
au16data[5] = 0;
// Communication diagnostics (for debugging)
//au16data[6] = slave.getInCnt(); //Returns how many messages were received
//au16data[7] = slave.getOutCnt(); //Returns how many messages were transmitted
//au16data[8] = slave.getErrCnt(); //Returns how many errors there were
}
void ScanMenu(){
if (!MainMenuEn and !SubMenuEn){
UpdateScreen();
if (button_ESC) {
MainMenuEn = true;
SettingsScreen();
}
} else{
if ((!SubMenuEn) and button_ESC) {
MainMenuEn = false;
StartScreen();
}
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= blinktime) {
previousMillis = currentMillis;
//ValueScreen();
if (SubMenuEn){
if (CursorState == false) {
CursorState = true;
ValueScreen();
} else {
CursorState = false;
ValueScreen();
}
}
}
if ((MainMenuEn and !SubMenuEn) and (button_DOWN or button_UP or button_OK)){
if(button_DOWN){
MainMenuCnt++;
if (MainMenuCnt > MainMenuItems){
MainMenuCnt = MainMenuItems;
}
}
if(button_UP){
MainMenuCnt--;
if (MainMenuCnt < 0){
MainMenuCnt = 0;
}
}
SettingsScreen();
if (button_OK) {
SubMenuEn = true;
TempValue = Item[MainMenuCnt].MenuValue;
button_OK = false;
CursorPos = 0;
ValueScreen();
}
}
if (SubMenuEn and button_ESC) {
SubMenuEn = false;
SettingsScreen();
}
if (SubMenuEn and button_OK) {
Item[MainMenuCnt].MenuValue = TempValue;
SubMenuEn = false;
SettingsScreen();
}
if (SubMenuEn and (button_UP or button_DOWN or button_LEFT or button_RIGHT)){
ValueScreen();
if(button_LEFT){
CursorPos--;
}
if(button_RIGHT){
CursorPos++;
}
if (CursorPos < Item[MainMenuCnt].MenuDec){
CursorPos = Item[MainMenuCnt].MenuDec;
}
if (CursorPos > Item[MainMenuCnt].MenuFrac){
CursorPos = Item[MainMenuCnt].MenuFrac;
}
}
}
}
void StartScreen(){
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_t0_14b_mr);
u8g2.drawStr(0, 9, "SP: 0 Volt");
u8g2.drawStr(0, 22, "PV: 0 Volt");
u8g2.drawStr(0, 35, "Pos: -3.2 mm");
u8g2.drawStr(0, 63, "[ESC] for settings");
u8g2.sendBuffer();
}
void UpdateScreen(){
char buf[10];
u8g2.setFontMode(0);
u8g2.setDrawColor(1);
sprintf(buf, "%3d", ARC_Setpoint);
u8g2.drawStr(28, 9, buf);
sprintf(buf, "%3d", ARC_Voltage);
u8g2.drawStr(28, 22, buf);
u8g2.sendBuffer();
}
void SettingsScreen(){
u8g2.clearBuffer();
u8g2.setFontMode(1); /* activate transparent font mode */
u8g2.drawBox(0, 0, 128, 14);
u8g2.setDrawColor(2);
u8g2.drawStr(15, 11, "SETTINGS MENU");
u8g2.drawRFrame(0,30,128,16,6);
u8g2.drawStr(10, 42,Item[MainMenuCnt].MenuStr);
if (MainMenuCnt > 0) {
u8g2.drawStr(10, 28,Item[MainMenuCnt-1].MenuStr);
}
if (MainMenuCnt < MainMenuItems) {
u8g2.drawStr(10, 57,Item[MainMenuCnt+1].MenuStr);
}
if (MainMenuCnt < MainMenuItems - 1) {
u8g2.drawStr(10, 71,Item[MainMenuCnt+2].MenuStr);
}
u8g2.sendBuffer();
}
void ValueScreen(){
SplitValue();
if(button_UP){
if (digit[CursorPos+3] < 9){
digit[CursorPos+3]++;
}
else {
digit[CursorPos+3] = 0;
}
}
if(button_DOWN){
if (digit[CursorPos+3] > 0){
digit[CursorPos+3]--;
}
else {
digit[CursorPos+3] = 9;
}
}
u8g2.clearBuffer();
u8g2.setFontMode(1); /* activate transparent font mode */
u8g2.drawBox(0, 0, 128, 14);
u8g2.setDrawColor(2);
u8g2.drawStr(15, 11, Item[MainMenuCnt].MenuStr);
if (CursorState) {
if (Item[MainMenuCnt].MenuFrac > 0) {
if (CursorPos > 0){
u8g2.drawBox((CursorPos*12)+52+12-12, 19, 12, 18);
} else {
u8g2.drawBox((CursorPos*12)+52+12-24, 19, 12, 18);
}
} else {
u8g2.drawBox((CursorPos*12)+52+12, 19, 12, 18);
}
}
u8g2.setFont(u8g2_font_profont22_mn);
if (MainMenuCnt == 1) {
u8g2.setCursor(5,35);
} else {
u8g2.setCursor(29,35);
}
if ((digit[0] > 0) or ( CursorPos == -3)) {
u8g2.print(digit[0]);
} else {
u8g2.print(" ");
}
if ((digit[1] > 0) or ( CursorPos <= -2) or (TempValue > 999)) {
u8g2.print(digit[1]);
} else {
u8g2.print(" ");
}
if ((digit[2] > 0) or ( CursorPos <= -1) or (TempValue > 99)) {
u8g2.print(digit[2]);
} else {
u8g2.print(" ");
}
u8g2.print(digit[3]);
if (Item[MainMenuCnt].MenuFrac > 0) {
u8g2.print(".");
u8g2.print(digit[4]);
if (Item[MainMenuCnt].MenuFrac < 3){
u8g2.print(digit[5]);
}
}
CombineValue();
//u8g2.print((float)TempValue,MainMenuFrac[MainMenuCnt]);
u8g2.setFont(u8g2_font_t0_14b_mr);
//u8g2.print(MainMenuUnit[MainMenuCnt]);
u8g2.print(Item[MainMenuCnt].MenuUnit);
u8g2.sendBuffer();
}
void SplitValue(){
float TempBuffer = TempValue;
Serial.println(TempValue);
digit[0] = (TempBuffer / 1000);
TempBuffer = TempBuffer - (digit[0]*1000);
digit[1] = (TempBuffer / 100);
TempBuffer = TempBuffer - (digit[1]*100);
digit[2] = (TempBuffer / 10);
TempBuffer = TempBuffer - (digit[2]*10);
digit[3] = (TempBuffer);
TempBuffer = TempBuffer - (digit[3]);
digit[4] = (TempBuffer * 10);
Serial.println(digit[4]);
TempBuffer = TempBuffer - (digit[4]*0.1);
TempBuffer = TempBuffer * 100;
digit[5] = round(TempBuffer);
Serial.print(digit[0]);
Serial.print(digit[1]);
Serial.print(digit[2]);
Serial.print(digit[3]);
Serial.print(digit[4]);
Serial.println(digit[5]);
}
void CombineValue(){
//TempValue = (digit[0]*1000.0)+(digit[1]*100.0)+(digit[2]*10.0)+(digit[3])+(digit[4]*0.1)+(digit[5]*0.01);
}