Hallo Allemaal,
Alvast een voorproefje van de Arduino bestuuring software
voor Foxcopter 2 en 3 met wiper motor en reed contactjes.
Nokia LCD5110
Dubbele relais print maak breek voor CW, CCW en stop
4 push buttons + adjust potmeter
Not all ready yet.
Code:
/* FoxCopter2
Easy to use standalone antenna rotator with wiper moter for foxhunting with a car
Not all working and tested yet!
Hardware:
2x Relais print wiper-motor
16 reedcontacts angle readout
nokia LCD5110
4 x push button + adjust potmeter
26-03-2019
08-04-2019
25-04-2019
26-04-2019
28-04-2019
29-04-2019
30-04-2018
02-05-2019
((C))PA3BNX
L.J.W. Baars
*/
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
// Software SPI (slower updates, more flexible pin options):
// pin 7 - Serial clock out (SCLK)
// pin 6 - Serial data out (DIN)
// pin 5 - Data/Command select (D/C)
// pin 4 - LCD chip select (CS)
// pin 3 - LCD reset (RST)
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);
//String
const String Version("Foxcopter2 V1.00");
const String strStop="Stopped";
const String strNormal="Normal ??";
const String strAdjust="Adjust";
const String strSwing="Swing ### ?? $$$";//Shuttle Swing Commute Pendelen
const String strMenuNormalAdjustSectorX1X2="MenuNormalAdjustSwingOrX1X2";
const String strMenuSwingValues="MenuSwingValues";
//Float
const float AnalogFactor = 360.0/1023.0; // (360 / 1023)
const float AnalogFactor2 = 15.0/360.0;
const float rad =PI/180 ; //0.017453292
//Integer
int x1=0; //Start Swing turning
int x2=360;//Stop Swing turning
int xcenter;//center between x1 and x2
const int xc = (display.width()/2)-1;//Is it here already initialised ?
const int yc = (display.height()/2)-1;
const int cNoDegrees = 999;
const int yL = display.height() -9; //DrawBottomTextLinePosition 37
//Bytes
byte mode; //Can be all mode... values
//All pin used Arduino Nano
const byte cPinMotor1=9;
const byte cPinMotor2=10;
const byte cPinReedContacts=A0;
const byte cPinAdjust=A1;
const byte cPinPush1=A2;
const byte cPinPush2=A3;
const byte cPinPush3=A4;
const byte cPinPush4=A5;
//Some const for easy programming
//Modus in witch mode is the software now
const byte modeStop=0;
const byte modeNormal=1;
const byte modeAdjust=2;
const byte modeSwingToRange=3;
const byte modeSwing=4;
const byte modeMenuNormalAdjustSectorOrX1X2=5;
//Motor immediate CMD's
const byte btnStop=0;
const byte btnCW=1;
const byte btnCCW=2;
const byte btnMenu=3;
//---------------------Fuctions-----------------------------
void ShowSerialInfo()
//Serial port Info About Pins Used
{
Serial.println(Version);
Serial.print("MotorPins");Serial.print(cPinMotor1) ;Serial.print(",");Serial.println(cPinMotor2);
Serial.println("AnalogPins");
}
int LimitDegrees360(int d)
//Degrees only from 0 to 359
{
//Limit degrees 0 to 360 here
int x;
x = d%360;
if (x<0)
{
x+=360;
}
return x;
}//End LimitDegrees360
void SwapX1X2forSmallestSwing()
//ToDo Swap x1,x2
{
if (x1 < 90 && x2 > 270 && x1 !=0)
{
int x;
x=x2;
x2=x1;
x1=x;
}
}//End SwapX1X2forSamallestSwing
void FindCenterX1X2()
//ToDo find center X1 X2 for Swing
{
if (x2 > x1)
{
xcenter = (x1+x2)/2;
}
else if (x1 > x2)
{
xcenter = LimitDegrees360(x1 + x2 + 360)/2;
}
}//End FindCenter
String Format3Degrees(int d)
//ToDo make always 3 digits
{
String str;
int digits[3];
int reminder;
digits[0]=d/100;
reminder=d%100;
digits[1]=reminder/10;
reminder=reminder%10;
digits[2]=reminder;
//str+='%';
str+=digits[0];
str+=digits[1];
str+=digits[2];
return str;
} //End Format3Degrees
int Analog2Degrees(int a)
{
return int(AnalogFactor * float(a));
}//End Analog2Degrees
int Degrees2Contacts(int d)
{
return int( AnalogFactor2 * float(LimitDegrees360(d))) ;
}//End Degrees2Contacts
byte GetBtnPressed(int oldbtn)
//Get witch button is pressed Argument = btnOld
{
//ToDo check if a button is pressed and key logic
//If nothing Pressed return oldBtn
byte b=oldbtn; //Keep last value if nothing pressed
for (byte i;i<10;i++)
{
if (digitalRead(cPinPush1)==LOW){b= btnStop ;}
if (digitalRead(cPinPush2)==LOW){b= btnCW ;}
if (digitalRead(cPinPush3)==LOW){b= btnCCW ;}
if (digitalRead(cPinPush4)==LOW){b= btnMenu ;}
delay(10);
}
return b;
}//End GetBtnPressed
byte Motor(byte btnPressed)
//MotorRelais Cmd's Returns last turning direction
{
//ToDo motor cmd's Stop, CW and CCW and return last TurnDirection RL
bool a;
bool b;
static byte RL;
switch(btnPressed){
case btnStop:
a=false;
b=false;
break;
case btnCW:
RL=1;
a=true;
b=false;
break;
case btnCCW:
RL=2;
a=false;
b=true;
break;
case btnMenu: //Always stop motor
a=false;
b=false;
break;
default:
RL=0;
a=true;
b=true;
break;
}
digitalWrite(cPinMotor1,a);
digitalWrite(cPinMotor2,b);
return RL;
}//End Motor
bool ReadToPointPotmeter(int d, int a )
//See if RotorDegrees = AdjustDegrees
{
//ToDo return true if potmeter AdjustDegrees is RotorDegrees
//Analog to degrees
d=Analog2Degrees(d);
a=Analog2Degrees(a);
d=Degrees2Contacts(d);
a=Degrees2Contacts(a);
//Change degrees in 16 steps
//Check to see if reached in 16 steps
if (a == d)
{
return true;
}
}//End ReadPointPotmeter
void DrawPelorus(int d)
//Draw Pelorus Arrow + Degrees Text 06-07-2018
{
//Float
//const float rad =PI/180 ; //0.017453292
float q;
//Int
static int OldDegrees = cNoDegrees;
//Integer
int r = yc-2;
int s,ss;
byte y;
//Draw ArrowLine
q = (d-90) * rad;
s = xc + int(cos(q) * r);
ss = yc + int(sin(q) * r);
display.drawLine(xc,yc,s,ss,BLACK);
//Nothing ToDo
if (OldDegrees==d)
{
return;
}
display.clearDisplay();
display.drawCircle(xc,yc,yc,BLACK);//Rim of circle
if (d==cNoDegrees)
{
//Draw Just CenterDot
display.fillCircle(xc,yc,2,BLACK);
}
else
{
//Draw Just ArrowLine
display.drawLine(xc,yc,s,ss,BLACK);
//Draw Just Text Degrees Print
if (d > 270 || d < 90)
{
y=yc+3;
}
else
{
y=yc-10;
}
display.setTextSize(1);
display.setCursor(xc-9,y);
display.println(Format3Degrees(d));
}
display.display();
OldDegrees=d;//Backup now
Serial.println(d);
}//End DrawPelorus
void DrawOnlyGotoPoint(int d)
//Draw turntopoint arrow from adjustpotmeter 25-04-2019
{
//int xc = display.width()/2 -1;
//int yc = display.height()/2-1;
int rs = yc -2;//Begin Radius
int r = yc + 2;//End Radius
int xs,ys;
int s,ss;
float q;
if (mode == modeAdjust)
{
//Draw ShortEndArrowLine
q = (d-90) * rad;
xs = xc + int(cos(q) * rs);
ys = yc + int(sin(q) * rs);
s = xc + int(cos(q) * r);
ss = yc + int(sin(q) * r);
display.drawLine(xs,ys,s,ss,BLACK);
}
}//End DrawOnlyGotoPoint
void DrawText(byte RL)
//Draw Text and/or do MenuSettings
{
/*
Value
const byte modeStop=0;
const byte modeNormal=1;
const byte modeAdjust=2;
const bytemodeSwing=3;
const byte modeMenuNormalAdjustSectorOrX1X2=4;
String
const String Version("Foxcopter2 V1.00");
const String strStop="Stopped";
const String strNormal="Normal ##";
const String strAdjust="Adjust";
const String strSwing="Swing ### ?? $$$";
const String strMenuNormalAdjustSector="MenuNormalOrSector";
const String strMenuSwingValues="MenuSectorValues ## ?? $$";
*/
String myval;
bool bFlag;
switch (mode){
case modeStop:
myval= strStop;
bFlag=true;
break;
case modeNormal:
//here it can be Nothing, CW or CCW
myval=strNormal;
if (RL==0)
{
//myval.replace("??","??");
}
else if (RL==1)
{
myval.replace("??",">>");
}
else if (RL==2)
{
myval.replace("??","<<");
}
bFlag=true;
break;
case modeAdjust:
myval=strAdjust;
bFlag=true;
break;
case modeSwing:
myval=strSwing;
myval.replace("###", Format3Degrees(x1)); //Show Swing range
if (RL==1){
myval.replace("??",">>");}
else if (RL==2){
myval.replace("??","<<");}
myval.replace("$$$",Format3Degrees(x2));
bFlag=true;
break;
case modeMenuNormalAdjustSectorOrX1X2:
ModeSetting();
//ToDo Select NormalAdjustSector or X1X2Adjust
bFlag=false;
break;
default:
bFlag=false;
break;
}
if (bFlag==true)
{
display.setTextSize(1);
display.setCursor(0,yL);
display.print(myval);
}
}//End DrawText
void ModeSetting()
//Call this only from DrawText() if modeMenuNormalAdjustSectorOrX1X2
{
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0,15);
display.println(strMenuNormalAdjustSectorX1X2);
display.display();
//Go checking now
//If here mode = modeMenuNormalAdjustSectorX1X2
//So never leave it this mode
byte x;
String myval;
//You must Press a Key
do {
if (digitalRead(cPinPush1)==LOW) {x=1;}
if (digitalRead(cPinPush2)==LOW) {x=2;}
if (digitalRead(cPinPush3)==LOW) {x=3;}
if (digitalRead(cPinPush4)==LOW) {x=4;}
}while(x==0);
switch (x){
case 1:
mode=modeNormal;
myval=strNormal;
break;
case 2:
mode=modeAdjust;
myval=strAdjust;
break;
case 3:
mode=modeSwing;
myval=strSwing + " " + Format3Degrees(x1) + " <> " + Format3Degrees(x2);
break;
case 4:
X1andX2Setting();//Get new values for x1 x2
mode=modeSwingToRange; //If in range then it changes to modeSwing
//mode=modeSwing;
return;
break;
default:
mode=modeNormal;
myval="Nothing";
break;
}
display.setTextSize(1);
display.setCursor(0,15);
display.println(myval);
display.display();
delay(1000);
}//End ModeSetting
void X1andX2Setting()
//Call this only from Function ModeSetting()
{
byte x;
int oldX12;
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0,15);
display.print(strMenuSwingValues);
display.display();
//Go finding out values x1 and x2 with the potmeter
do{
x1=Analog2Degrees(analogRead(cPinAdjust));
if (x1 != oldX12)
{
display.setCursor(0,18);
display.setTextColor(WHITE);
display.print(Format3Degrees(oldX12));//Erease from screen
display.setTextColor(BLACK);
display.print(Format3Degrees(x1));
display.display();
oldX12=x1;
delay(100);
}
if (digitalRead(cPinPush1)==LOW) {x=1;}
if (digitalRead(cPinPush2)==LOW) {x=1;}
if (digitalRead(cPinPush3)==LOW) {x=1;}
if (digitalRead(cPinPush4)==LOW) {x=1;}
}
while(x==0);
x=0;
oldX12=0;
display.setCursor(20,18);
display.setTextColor(BLACK);
display.print("<>");
display.display();
//How run from 270 to 22 degrees ??
//Always run Smallest Swing
do{
x2=Analog2Degrees(analogRead(cPinAdjust));
if (oldX12 != x2 )
{
display.setCursor(30,18);
display.setTextColor(WHITE);
display.print(Format3Degrees(oldX12));//Erease from screen
display.setTextColor(BLACK);
display.print(Format3Degrees(x2));
display.display();
x2=oldX12;
delay(100);
}
if (digitalRead(cPinPush1)==LOW){x=1;}
if (digitalRead(cPinPush2)==LOW){x=1;}
if (digitalRead(cPinPush3)==LOW){x=1;}
if (digitalRead(cPinPush4)==LOW){x=1;}
}
while(x==0);
if (x2 < x1)
{
x2=x1+1;
}
//Swap if needed smallest Swing
SwapX1X2forSmallestSwing();
FindCenterX1X2();
display.setCursor(1,40);
display.setTextColor(BLACK);
display.print("I use this " + Format3Degrees(x1) + " <> " + Format3Degrees(x2));
display.display();
delay(1000);
}//End X1 and X2 Setting
byte TimeMotorRunsOneDirectionLimit(byte btn,byte RL)
//ToDo Time Limit Returns btnStop
{
//Not Okay Yet
const unsigned long tMax=15000; //15 seconds
static unsigned long tStart;
long unsigned tNow;
//Get time
tNow=millis();
//Reset time
// Reset always
if (btn==btnStop || btn==btnMenu)
{
tStart=tNow;//Restart counting
}
//Restart Counting if direction is changed
if (btn!=RL && (btn==btnCW || btn==btnCCW )) //To Long running one direction
{
tStart=tNow;//Restart counting
}
//Time Overflow check
if ((tNow-tStart)>=tMax)
{
return btnStop;//Modify to Stop
}
else
{
return btn;
}
}//End Time Limit
void setup() {
Serial.begin(9600);
//Motor relais
pinMode(cPinMotor1,OUTPUT);
pinMode(cPinMotor2,OUTPUT);
//Buttons
pinMode(cPinPush1,INPUT_PULLUP);
pinMode(cPinPush2,INPUT_PULLUP);
pinMode(cPinPush3,INPUT_PULLUP);
pinMode(cPinPush4,INPUT_PULLUP);
ShowSerialInfo();
display.begin();
display.setContrast(50);
FindCenterX1X2();
mode=modeNormal ; //Can be all mode... values
DrawPelorus(cNoDegrees);
delay(2000);
display.clearDisplay(); //clears the screen and buffer
}//--------------------------------------------------End Setup---------------------------------------------------
void loop() {
//Byte
byte btn; //Witch button is pressed
static byte btnOld=btnStop; //button Old pressed
static byte modeOld=modeNormal; //mode Old
static byte RLOld=btnStop; //Last turning stop, left or right 0.1,2
//Integer
int RotorDegrees; //Analog reedcontactjes degrees
int AdjustDegrees ; //Analog potmeter degrees
static int AdjustDegreesOld; //Old analog potmeter value
//Check button 's pressed
btn=GetBtnPressed(btnOld);
//Get RotorDegrees
RotorDegrees=Analog2Degrees(analogRead(cPinReedContacts));
//Get PotmeterAdjustDegrees
AdjustDegrees=Analog2Degrees(analogRead(cPinAdjust));
switch (mode){
//Turn CW or CCW but not to far so limit turning
//Not used yet
case modeNormal:
if (RotorDegrees >= 337 && btn == btnCW){btn=btnStop;}//Modify btn
else if (RotorDegrees <= 22 && btn == btnCCW){btn=btnStop;}//Modify btn
if(btn != btnOld){RLOld=Motor(btn);}//Switch the Motor
break;
case modeAdjust:
//Run to potmeter value
if (ReadToPointPotmeter(RotorDegrees,AdjustDegrees)==true){btn=btnStop;}//Modify btn
else if (RotorDegrees < AdjustDegrees) {btn=btnCCW;}
else if (RotorDegrees > AdjustDegrees) {btn=btnCW;}
if(btn != btnOld){RLOld=Motor(btn);}//Switch the Motor
break;
case modeSwingToRange:
//Start always xcenter RotorDegrees for Swing
if (ReadToPointPotmeter(RotorDegrees,xcenter)==false)
{
btn=btnCCW;
}
else
{
mode=modeSwing;
btn=btnStop;
}
if(btn != btnOld){RLOld=Motor(btn);}//Switch the Motor
break;
case modeSwing:
//Not Okay here Yet 29-04-2019
//Swing
//Find smallest swing
//Run to in range x1, x2 position xcenter modeSwingToRange
//Swing between x1 and x2
//Change direction automatic
//If btn=btnStop stop motor don't swing
if (btn != btnStop)
{
if (x2 > x1)
//Swinging not over point 0
{
if (RLOld==btnCW && RotorDegrees >=377)
{
Motor(btnStop);
btn=btnCCW;//Modify btn
}
else if (RLOld==btnCCW && RotorDegrees <=0)
{
Motor(btnStop);
btn=btnCW;//Modify btn
}
delay(100);
RLOld=Motor(btn);
}
else if (x1 > x2)
//Swinging over point 0 degrees
{
if (RLOld==btnCW && (RotorDegrees >= x1 && RotorDegrees < x2))
{
Motor(btnStop);
btn=btnCCW;
}
else if (RLOld==btnCCW && (RotorDegrees <= x2 && RotorDegrees > x1))
{
Motor(btnStop);
btn=btnCW;
}
delay(100);
RLOld=Motor(btn);
}
}
if(btn != btnOld){RLOld=Motor(btn);}//Switch the Motor
break;
}
//Display on Nokia LCD5110
//Display (Pelorus + Degrees Now) + GotoArrow + (Text + Menu's)
DrawPelorus(RotorDegrees); //Pelorus
//Only draw GotoPointArrow if mode is adjustpotmeter
DrawOnlyGotoPoint(AdjustDegrees);
//Only Draw text or go to Menu
DrawText(RLOld);
//Display Serial Monitor
//Display the btn
if (btnOld!=btn)
{
Serial.print("btn=");Serial.println(btn);//Only for test purposes print once
btnOld=btn;//Backup
}
//Display the mode
if (modeOld!=mode)
{
Serial.print("mode=");Serial.println(mode);//Only for test purposes print once
modeOld=mode;//Backup
}
//Time motor runs one direction limit 15 seconds ?
btnOld=TimeMotorRunsOneDirectionLimit(btn,RLOld);//It can modify btn to btnStop
}//End Loop End Program