601 lines
11 KiB
C++
601 lines
11 KiB
C++
/*
|
|
* nzs_lcd.cpp
|
|
*
|
|
* Created on: Dec 8, 2016
|
|
* Author: trampas
|
|
*
|
|
Copyright (C) 2018 MisfitTech, All rights reserved.
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
Written by Trampas Stern for MisfitTech.
|
|
|
|
Misfit Tech invests time and resources providing this open source code,
|
|
please support MisfitTech and open-source hardware by purchasing
|
|
products from MisfitTech, www.misifittech.net!
|
|
*********************************************************************/
|
|
|
|
#include "nzs_lcd.h"
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <Wire.h>
|
|
|
|
|
|
#ifndef DISABLE_LCD
|
|
void LCD::begin(StepperCtrl *ptrsCtrl)
|
|
{
|
|
#ifndef MECHADUINO_HARDWARE
|
|
pinMode(PIN_SW1, INPUT_PULLUP);
|
|
pinMode(PIN_SW3, INPUT_PULLUP);
|
|
pinMode(PIN_SW4, INPUT_PULLUP);
|
|
#endif
|
|
buttonState=0;
|
|
|
|
//we need access to the stepper controller
|
|
ptrStepperCtrl=ptrsCtrl; //save a pointer to the stepper controller
|
|
|
|
|
|
ptrMenu=NULL;
|
|
menuIndex=0;
|
|
menuActive=false;
|
|
optionIndex=0;
|
|
ptrOptions=NULL;
|
|
displayEnabled=true;
|
|
|
|
//check that the SCL and SDA are pulled high
|
|
pinMode(PIN_SDA, INPUT);
|
|
pinMode(PIN_SCL, INPUT);
|
|
if (digitalRead(PIN_SDA)==0)
|
|
{
|
|
//pin is not pulled up
|
|
displayEnabled=false;
|
|
}
|
|
if (digitalRead(PIN_SCL)==0)
|
|
{
|
|
//pin is not pulled up
|
|
displayEnabled=false;
|
|
}
|
|
|
|
if (displayEnabled)
|
|
{
|
|
displayEnabled=display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
|
|
}else
|
|
{
|
|
WARNING("SCL/SDA not pulled up");
|
|
}
|
|
if (false == displayEnabled)
|
|
{
|
|
WARNING("NO display found, LCD will not be used");
|
|
}
|
|
Wire.setClock(800000);
|
|
|
|
//showSplash();
|
|
|
|
}
|
|
|
|
|
|
void __attribute__ ((optimize("Ofast"))) LCD::lcdShow(const char *line1, const char *line2,const char *line3)
|
|
{
|
|
|
|
if (false == displayEnabled)
|
|
{
|
|
return;
|
|
}
|
|
display.clearDisplay();
|
|
display.setTextSize(2);
|
|
display.setTextColor(WHITE);
|
|
display.setCursor(0,0);
|
|
display.println(line1);
|
|
display.setCursor(0,20);
|
|
display.println(line2);
|
|
display.setCursor(0,40);
|
|
display.println(line3);
|
|
display.display();
|
|
|
|
}
|
|
|
|
void LCD::showSplash(void)
|
|
{
|
|
if (false == displayEnabled)
|
|
{
|
|
return;
|
|
}
|
|
#ifdef A5995_DRIVER
|
|
lcdShow("MisfitTech","NEMA 23", VERSION);
|
|
#else
|
|
lcdShow("MisfitTech","NEMA 17", VERSION);
|
|
#endif
|
|
}
|
|
|
|
|
|
void LCD::setMenu(menuItem_t *pMenu)
|
|
{
|
|
if (false == displayEnabled)
|
|
{
|
|
return;
|
|
}
|
|
ptrMenu=pMenu;
|
|
menuIndex=0;
|
|
}
|
|
|
|
|
|
void LCD::showOptions(void)
|
|
{
|
|
int32_t i,j;
|
|
char str[3][26]={0};
|
|
if (false == displayEnabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
i=optionIndex;
|
|
j=0;
|
|
while(strlen(ptrOptions[i].str)>0 && j<3)
|
|
{
|
|
if (i == optionIndex)
|
|
{
|
|
sprintf(str[j],"*%s",ptrOptions[i].str);
|
|
}else
|
|
{
|
|
sprintf(str[j]," %s",ptrOptions[i].str);
|
|
}
|
|
j++;
|
|
i++;
|
|
}
|
|
|
|
lcdShow(str[0], str[1], str[2]);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void __attribute__ ((optimize("Ofast"))) LCD::showMenu(void)
|
|
{
|
|
int32_t i,j;
|
|
char str[3][26]={0};
|
|
if (false == displayEnabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
i=menuIndex;
|
|
j=0;
|
|
while(ptrMenu[i].func!=NULL && j<3)
|
|
{
|
|
if (i == menuIndex)
|
|
{
|
|
sprintf(str[j],"*%s",ptrMenu[i].str);
|
|
}else
|
|
{
|
|
sprintf(str[j]," %s",ptrMenu[i].str);
|
|
}
|
|
j++;
|
|
i++;
|
|
}
|
|
|
|
//show exit if there is room
|
|
if (j<3)
|
|
{
|
|
if (j==0)
|
|
{
|
|
sprintf(str[j],"*Exit");
|
|
}else
|
|
{
|
|
sprintf(str[j]," Exit");
|
|
}
|
|
}
|
|
|
|
lcdShow(str[0], str[1], str[2]);
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void __attribute__ ((optimize("Ofast"))) LCD::updateMenu(void)
|
|
{
|
|
if (false == displayEnabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (ptrOptions != NULL)
|
|
{
|
|
showOptions();
|
|
}else
|
|
{
|
|
showMenu();
|
|
}
|
|
|
|
//handle push buttons
|
|
if (digitalRead(PIN_SW3)==0 && (buttonState & 0x02)==0)
|
|
{
|
|
buttonState |= 0x02;
|
|
|
|
LOG("SW3 pressed");
|
|
if (ptrMenu[menuIndex].func == NULL)
|
|
{
|
|
//exit pressed
|
|
menuIndex=0; //reset menu index
|
|
menuActive=false;
|
|
return;
|
|
}
|
|
|
|
if (ptrMenu[menuIndex].func != NULL)
|
|
{
|
|
LOG("Calling function for %s",ptrMenu[menuIndex].str);
|
|
if (ptrOptions != NULL)
|
|
{
|
|
char *ptrArgV[1];
|
|
char str[25]={0};
|
|
ptrArgV[0]=str;
|
|
sprintf(str,"%d",optionIndex);
|
|
LOG("Calling function for %s %s",ptrMenu[menuIndex].str,str);
|
|
ptrMenu[menuIndex].func(1,ptrArgV);
|
|
ptrOptions=NULL;
|
|
optionIndex=0;
|
|
}else
|
|
{
|
|
int i;
|
|
i=ptrMenu[menuIndex].func(0,NULL);
|
|
if (ptrMenu[menuIndex].ptrOptions != NULL)
|
|
{
|
|
LOG("displaying options for %s %d",ptrMenu[menuIndex].str,i);
|
|
ptrOptions=ptrMenu[menuIndex].ptrOptions;
|
|
optionIndex=i;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
}
|
|
if (digitalRead(PIN_SW1)==0 && (buttonState & 0x01)==0)
|
|
{
|
|
buttonState |= 0x01;
|
|
LOG("SW1 pressed");
|
|
if (ptrOptions != NULL)
|
|
{
|
|
optionIndex++;
|
|
if (strlen(ptrOptions[optionIndex].str) == 0)
|
|
{
|
|
optionIndex=0;
|
|
}
|
|
} else
|
|
{
|
|
if (ptrMenu[menuIndex].func != NULL)
|
|
{
|
|
menuIndex++;
|
|
} else
|
|
{
|
|
menuIndex=0;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (digitalRead(PIN_SW1))
|
|
{
|
|
buttonState &= ~0x01;
|
|
}
|
|
|
|
if (digitalRead(PIN_SW3))
|
|
{
|
|
buttonState &= ~0x02;
|
|
}
|
|
}
|
|
|
|
void LCD::forceMenuActive(void)
|
|
{
|
|
|
|
menuActive=true;
|
|
}
|
|
|
|
void __attribute__((optimize("Ofast")))LCD::process(void)
|
|
{
|
|
if (false == displayEnabled)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (false == menuActive || ptrMenu==NULL)
|
|
{
|
|
updateLCD();
|
|
}else
|
|
{
|
|
updateMenu();
|
|
}
|
|
|
|
if (digitalRead(PIN_SW4)==0 && (buttonState & 0x04)==0)
|
|
{
|
|
buttonState |= 0x04;
|
|
menuActive=!menuActive;
|
|
}
|
|
|
|
if (digitalRead(PIN_SW4))
|
|
{
|
|
buttonState &= ~0x04;
|
|
}
|
|
}
|
|
#endif
|
|
/*
|
|
//does the LCD menu system
|
|
void StepperCtrl::menu(void)
|
|
{
|
|
|
|
bool done=false;
|
|
int menuItem=0;
|
|
char str[100];
|
|
int sw1State=0;
|
|
int sw3State=0;
|
|
|
|
pinMode(PIN_SW1, INPUT_PULLUP);
|
|
pinMode(PIN_SW3, INPUT_PULLUP);
|
|
pinMode(PIN_SW4, INPUT_PULLUP);
|
|
|
|
|
|
while (!done)
|
|
{
|
|
display.clearDisplay();
|
|
display.setTextSize(2);
|
|
display.setTextColor(WHITE);
|
|
|
|
if (menuItem==0)
|
|
{
|
|
sprintf(str,"*Run Cal");
|
|
display.setCursor(0,0);
|
|
display.println(str);
|
|
}else
|
|
{
|
|
sprintf(str," Run Cal");
|
|
display.setCursor(0,0);
|
|
display.println(str);
|
|
}
|
|
|
|
if (menuItem==1)
|
|
{
|
|
sprintf(str,"*Check Cal");
|
|
display.setCursor(0,20);
|
|
display.println(str);
|
|
}else
|
|
{
|
|
sprintf(str," Check Cal");
|
|
display.setCursor(0,20);
|
|
display.println(str);
|
|
}
|
|
|
|
if (menuItem==2)
|
|
{
|
|
sprintf(str,"*Exit");
|
|
display.setCursor(0,40);
|
|
display.println(str);
|
|
}else
|
|
{
|
|
sprintf(str," Exit");
|
|
display.setCursor(0,40);
|
|
display.println(str);
|
|
}
|
|
|
|
display.display();
|
|
|
|
if (sw1State==1)
|
|
{
|
|
while (digitalRead(PIN_SW1)==0);
|
|
sw1State=0;
|
|
}
|
|
|
|
if (digitalRead(PIN_SW1)==0)
|
|
{
|
|
sw1State=1;
|
|
menuItem=(menuItem+1)%3;
|
|
}
|
|
|
|
if (sw3State==1)
|
|
{
|
|
while (digitalRead(PIN_SW3)==0);
|
|
sw3State=0;
|
|
}
|
|
|
|
if (digitalRead(PIN_SW3)==0)
|
|
{
|
|
sw3State=1;
|
|
switch(menuItem)
|
|
{
|
|
case 0:
|
|
display.clearDisplay();
|
|
display.setTextSize(2);
|
|
display.setTextColor(WHITE);
|
|
display.setCursor(0,0);
|
|
display.println("Running");
|
|
display.setCursor(0,20);
|
|
display.println("Cal");
|
|
display.display();
|
|
calibrateEncoder();
|
|
break;
|
|
case 1:
|
|
{
|
|
display.clearDisplay();
|
|
display.setTextSize(2);
|
|
display.setTextColor(WHITE);
|
|
display.setCursor(0,0);
|
|
display.println("Testing");
|
|
display.setCursor(0,20);
|
|
display.println("Cal");
|
|
display.display();
|
|
int32_t error,x,y,m;
|
|
error=maxCalibrationError();
|
|
x=(error*100 *360)/ANGLE_STEPS;
|
|
m=x/100;
|
|
y=abs(x-(m*100));
|
|
display.clearDisplay();
|
|
display.setTextSize(2);
|
|
display.setTextColor(WHITE);
|
|
display.setCursor(0,0);
|
|
display.println("Error");
|
|
|
|
sprintf(str, "%02d.%02d deg",m,y);
|
|
display.setCursor(0,20);
|
|
display.println(str);
|
|
display.display();
|
|
while (digitalRead(PIN_SW3));
|
|
break;
|
|
}
|
|
case 2:
|
|
return;
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
void LCD::updateLCD(void)
|
|
{
|
|
if (false == displayEnabled)
|
|
{
|
|
return;
|
|
}
|
|
char str[3][25];
|
|
static int highRPM=0;
|
|
int32_t y,z,err;
|
|
|
|
static int64_t lastAngle,deg;
|
|
static int32_t RPM=0;
|
|
static int32_t lasttime=0;
|
|
|
|
bool state;
|
|
static int32_t dt=40;
|
|
static uint32_t t0=0;
|
|
|
|
static bool rpmDone=false;
|
|
|
|
if ((millis()-t0)>500)
|
|
{
|
|
|
|
int32_t x,d;
|
|
|
|
//do first half of RPM measurement
|
|
if (!rpmDone)
|
|
{
|
|
//LOG("loop time is %dus",ptrStepperCtrl->getLoopTime());
|
|
lastAngle=ptrStepperCtrl->getCurrentAngle();
|
|
lasttime=millis();
|
|
rpmDone=true;
|
|
return;
|
|
}
|
|
|
|
//do the second half of rpm measurement and update LCD.
|
|
if (rpmDone && (millis()-lasttime)>(dt))
|
|
{
|
|
rpmDone=false;
|
|
deg=ptrStepperCtrl->getCurrentAngle();
|
|
y=millis()-lasttime;
|
|
err=ptrStepperCtrl->getLoopError();
|
|
|
|
t0=millis();
|
|
d=(int64_t)(lastAngle-deg);
|
|
|
|
d=abs(d);
|
|
|
|
x=0;
|
|
if (d>0)
|
|
{
|
|
x=((int64_t)d*(60*1000UL))/((int64_t)y * ANGLE_STEPS);
|
|
}
|
|
|
|
lastAngle=deg;
|
|
RPM=(int32_t)x; //(7*RPM+x)/8; //average RPMs
|
|
if (RPM>500)
|
|
{
|
|
dt=10;
|
|
}
|
|
if (RPM<100)
|
|
{
|
|
dt=100;
|
|
}
|
|
str[0][0]='\0';
|
|
//LOG("RPMs is %d, %d, %d",(int32_t)x,(int32_t)d,(int32_t)y);
|
|
switch(ptrStepperCtrl->getControlMode())
|
|
{
|
|
case CTRL_SIMPLE:
|
|
sprintf(str[0], "%dRPM simp",RPM);
|
|
break;
|
|
case CTRL_TORQUE:
|
|
sprintf(str[0], "%dRPM torque",RPM);
|
|
break;
|
|
case CTRL_POS_PID:
|
|
sprintf(str[0], "%dRPM pPID",RPM);
|
|
break;
|
|
case CTRL_POS_VELOCITY_PID:
|
|
sprintf(str[0], "%dRPM vPID",RPM);
|
|
break;
|
|
case CTRL_OPEN:
|
|
sprintf(str[0], "%dRPM open",RPM);
|
|
break;
|
|
case CTRL_OFF:
|
|
sprintf(str[0], "%dRPM off",RPM);
|
|
break;
|
|
default:
|
|
sprintf(str[0], "error %u",ptrStepperCtrl->getControlMode());
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
err=(err*360*100)/(int32_t)ANGLE_STEPS;
|
|
//LOG("error is %d %d %d",err,(int32_t)ptrStepperCtrl->getCurrentLocation(),(int32_t)ptrStepperCtrl->getDesiredLocation());
|
|
z=(err)/100;
|
|
y=abs(err-(z*100));
|
|
|
|
sprintf(str[1],"%01d.%02d err", z,y);
|
|
|
|
|
|
deg=ptrStepperCtrl->getDesiredAngle();
|
|
|
|
#ifndef NZS_LCD_ABSOULTE_ANGLE
|
|
deg=deg & ANGLE_MAX; //limit to 360 degrees
|
|
#endif
|
|
|
|
deg=(deg*360*10)/(int32_t)ANGLE_STEPS;
|
|
int K=0;
|
|
if (abs(deg)>9999)
|
|
{
|
|
K=1;
|
|
deg=deg/1000;
|
|
}
|
|
|
|
x=(deg)/10;
|
|
y=abs(deg-(x*10));
|
|
|
|
if (K==1)
|
|
{
|
|
sprintf(str[2],"%03d.%01uKdeg", x,y);
|
|
}else
|
|
{
|
|
sprintf(str[2],"%03d.%01udeg", x,y);
|
|
}
|
|
str[0][10]='\0';
|
|
str[1][10]='\0';
|
|
str[2][10]='\0';
|
|
lcdShow(str[0],str[1],str[2]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|