Hallo Allemaal,
Alweer een arduino update
Nu kun je ook met cmd 'AV averaging In schakelen
Vergeet niet een 1uF elco over de voeding te zetten van de arduino.
Oh de led13 van de arduino reageert als de squelch led..
Have fun..
Vandaag ook weer zitten solderen aan de Foxcopter 3 hardware...
Code:
/*
((C))PA3BNX Arduino Agrelo to USB converter
19-09-2017 Not all ready yet!
2^5 data bits from PA8W and Strobe
I think tap from 4017 the 5 bits(4017 pins 15,13,14,6,4) and tap (40174 pin 9) as Strobe/Squelch
Through a CD4050 non 6x level inverter
2^4 data bits and strobe from other dopplers
Purpose is to give Agrelo Serial out with a cheap arduino(Uno,Nano)
on existing doppler.
-------
Use a inverting transistor to interface bits and strobe from doppler to arduino
-------
Arduino outputs Agrelo like %DDD<cr><lf>
Replacement 1995-N7LUE.pdf Agrelo Interface BY ROBERT SWAIN
4 or 5 counter hardware bits from 4040 or 4060 in hardware doppler
and the strobe Zerocross pin.
Strobe is positive edge triggerd on pa8w doppler pin9 at 40174 chip
//Options also possible with arduino ?
Arduino could also do GPS Module and output NMEA on software serial port ?
Arduino could also do FluxCompas HMC5883 TWI interface ?
22-09-2017
04-08-2018
20-11-2019
26-11-2019
29-11-2019
08-12-2019
10-12-2019
16-12-2019
17-12=2019
potmeter zero offset degrees so hardware pelorus same as agrelo pelorus ??? 22-11-2019
hc4050= Hex non-inverting HIGH-to-LOW level shifter also non pullup r's
25-12-2019
29-12-2019 Agrelo Send Rate timer
PA8W fuction for keeping squelch at %999 due to error in zerocrossdetector pa8w doppler
ToDo maybe
Second software serial for picodopp display adding 6-1-2020 ?
Eerpom save AV cmd ?
*/
//Const
const byte pinData=B01111100;//7-0 //5 Data pins = 8, 4, 2, 1, .5 kHz
const byte pinStrobe = B10000000; //1 Strobe pin Strobe 7-0
const byte pinOffset = 0; //Pin offset Potmeter
//Const
const String strMulti = "%---"; //Multipath
const int cNodegrees = 999; //Squelch
const int cReset = 888; //Reset averaged with last degrees value only
const unsigned long cSquelchOpenMax = 7500; //Max averaged time in Averaged sub (mSec)
const unsigned long cDisplayAgreloTime = 1500; //No faster then 1 sec agrelo updates
//Int
int Offset = 0; //For PA8W Doppler 2.3
unsigned long SquelchOpenStart = millis() + cSquelchOpenMax;
unsigned long DisplayAgreloTime = millis() + cDisplayAgreloTime;
//Bool
const bool bHC4050 = true; //Use 4050 high low inverter So no PullUp R on input pins
const bool bDemo = false; //Simulates agrelo output
bool bAverage = true; //Averaged Yes or No
bool bMultiPathAverage = false;
//Remote Control cmd AV
String inputString;
bool bStringComplete;
//=============SerialRx Event===========================
void serialEvent() {
while (Serial.available()) {
//get the new byte:
char inChar=(char)Serial.read();
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar=='z'||inChar=='\r'||inChar=='\n'||inputString.length() > 4 ){
bStringComplete=true;
}
else
{
//add it to the inputString:
inputString+=inChar;
}
}
}
int PA8W(int x)//Squelch problem PA9W ZeroCrossDetector
{
int i;
static byte c=0;
static int oldies[3]={cNodegrees,cNodegrees,cNodegrees};
oldies[c]=x;
c++;
if (c>2) {c=0;}
for (i=0;i<3;i++)
{
if (oldies[i]==cNodegrees)
{
x=cNodegrees;
}
}
return x;
}//Last PA8W
void Message()
{
Serial.println(F("((C))PA3BNX v1.02 USB Agrelo Doppler Interface"));
Serial.println(F("---------------------------------------------------"));
Serial.print(F("cmd AV Average="));Serial.println(bAverage);
if (bDemo == true) {
Serial.println(F("DemoMode"));
}
if (bHC4050==true){Serial.println(F("HC4050 Mode"));}
Serial.print(F("Data pins MSB to LSB="));
for (byte i=0; i<8; i++)
{
if (bitRead(pinData,i)==1)
{
Serial.print(i) ; Serial.print(" ");
}
}
Serial.println();
for (byte i=0 ;i<8;i++)
{
if (bitRead(pinStrobe,i)==1)
{
Serial.print(F("Strobe pin=")); Serial.println(i);
}
}
Serial.println(F("Squelch=LED_BUILDIN"));
Serial.print(F("Max AverageTime="));Serial.println(cSquelchOpenMax);
Serial.print(F("DisplayAgreloSendInterval="));Serial.println(cDisplayAgreloTime);
Serial.print(F("Cal Offset pin=A"));Serial.println(pinOffset);
}//==================Last Message==========================
int GetDemo(int x1, int x2)
{
const byte m=55;
static byte i;
int x;
i++;
x = random(x1, x2);
if (i > m)
{
i=0;
return cNodegrees;
}
else
{
return x;
}
}//=============================Last Demo==============================
bool GetOffset()
{
int tmp;
int x;
// 3.3V = ca 755
x=map(analogRead(pinOffset),0,755,-180,180);
//Only print if you turn the potmeter
tmp=abs(Offset-x);
if (tmp > 3)
{
Offset=x ;
Serial.print(F("Offset="));Serial.println(Offset);
return true;
}
else
{
return false;
}
}//========================================Last GetOffset===============================
int Calibrate(int x)
{
if (x == cNodegrees) {
return x;
}
else
{
return LimitDegrees360(x + Offset);
}
}//========================================Last Calibrate================================
//Return Agrelo formatted string % and always 3 digits
String Format3Degrees(int d) {
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;
}//==============================Last Format3Degrees==================================
//Limit Degrees 0 to 360 degrees
int LimitDegrees360(int d) {
//Limit degrees 0 to 360 here
//If 999 then return 999
if (d == cNodegrees)
{
return d;
}
else
{
int x;
x = d % 360;
if (x < 0)
{
x += 360;
}
return x;
}
}//===================================Last LimitDegrees360==============================
void SquelchLed13(int d)
{
if (d !=cNodegrees)
{
digitalWrite(LED_BUILTIN,HIGH);
}
else
{
digitalWrite(LED_BUILTIN,LOW);
}
}//============================Last SquelchLed13 ====================
int NewBearing()
{
byte cc[]={0,0,0,0,0};
byte x;
int d = cNodegrees ; //Degrees
unsigned long start1;
unsigned long start2;
unsigned long t = 4000;
start2 = micros();
start1 = start2 + t;
//Find Low state
do
{
// 7 to 0
if ((PIND & pinStrobe) != pinStrobe)
{
goto f;
break;//Found a not active strobe
}
}
while (micros() < start1);
return d;
f:
start2 = start1- (micros()-start2);
//Find High state
do
{
//Serial.print(x);Serial.println("--");
x=PIND;
if ((x & pinStrobe) == pinStrobe ) //Wait for a strobe
{
//if ((x & B01000000) > B01000000 ){cc[0]=1;}
//if ((x & B00100000) > B00100000){cc[1]=2;}
//if ((x & B00010000) > B00010000){cc[2]=4;}
//if ((x & B00001000) > B00001000){cc[3]=8;}
//if ((x & B00000100) > B00000100){cc[4]=16;}
if ((x & 64) == 64){cc[0]=1;}
if ((x & 32) == 32 ){cc[1]=2;}
if ((x & 16) == 16){cc[2]=4;}
if ((x & 8) == 8){cc[3]=8;}
if ((x & 4) == 4){cc[4]=16;}
d=cc[0]+cc[1]+cc[2]+cc[3]+cc[4];
d=int(d * 11.25);
break;
}
}
while(micros()<start2) ;
return d;
}//----------------------------Last New Bearing---------------------------------------------
//----------------------------------------Average Degrees------------------------------------
int Average(int d) {
//If d = 999 (cNoDegrees) then reset average and return last avDegrees witch is 999
//If d = 888 (cReset) then Reset all and put last avDegrees back in arrays
//If bAverage=false then return just d and set MultiPathAverage to false
//Always return avDegrees and Set bMultiPath
//Integer
static unsigned int sum[4] = {0, 0, 0, 0}; //Sum of counts for each kwadrant can be now 2^16=65536
static int c[4] = {0, 0, 0, 0}; //Amount of count
static int totalCount = 0; //Sum of all counts
static int avDegrees = cNodegrees; //Averaged degrees
int xx[4] = {0, 0, 0, 0}; //Adjacent kwadrants counts
int z = 0; //Most adjacent headings
int z1 = 0; //Other two kwandants headings Multipath
int y = 0; //Index where the most headings are
//Reset/clear and return cNodegrees or last avDegrees
//01-06-2015 No Averaging
if (bAverage == false) {
bMultiPathAverage=false;
return d;
}
//No Overflow in sum[]
if (totalCount >= 180)
{
for (byte i = 0; i < 4; i++)
{
sum[i] = 0;
c[i] = 0;
}
}
switch (d) {
case cNodegrees:
//Reset and Clear
for (byte i = 0; i < 4; i++)
{
sum[i] = 0;
c[i] = 0;
}
bMultiPathAverage = false;
avDegrees = cNodegrees;
return avDegrees; //Exit now
case cReset: //Reset and fill with avDegrees
//Reset
for (byte i = 0; i < 4; i++)
{
sum[i] = 0;
c[i] = 0;
}
//Fill with last avDegrees
d = avDegrees; //Put last degrees in again
}
if (d >= 0 && d < 90) {
sum[0] += d;
c[0]++;
}
if (d >= 90 && d < 180) {
sum[1] += d;
c[1]++;
}
if (d >= 180 && d < 270) {
sum[2] += d;
c[2]++;
}
if (d >= 270 && d <= 360) {
sum[3] += d;
c[3]++;
}
//No degrees found so exit function
totalCount = c[0] + c[1] + c[2] + c[3];
if (totalCount == 0)
{
bMultiPathAverage = false;
avDegrees = cNodegrees;
return avDegrees;
}
//Find 2 adjacent kwadrants with hold most heading counts
//Count all adjacents kwadrants
xx[0] = c[0] + c[1];
xx[1] = c[1] + c[2];
xx[2] = c[2] + c[3];
xx[3] = c[3] + c[0];
//Find out in witch two kwadrants the most headings are
for (byte i = 0; i < 4; i++) {
if (xx[i] > z) {
z = xx[i]; //Most adjacent Headings counts
y = i; //Witch 2 adjacent Array Index from xx[1]
}
}
//Check for multipath kwadrants
switch (z) {
case 0:
z1 = 2;
break;
case 1:
z1 = 3;
break;
case 2:
z1 = 0;
break;
case 3:
z1 = 1;
break;
}
if (xx[z] == xx[z1])
{
bMultiPathAverage = true;
}
else
{
bMultiPathAverage = false;
}
//Average the 2 most counts kwadrants
switch (y) {
case 0:
avDegrees = (sum[0] + sum[1]) / xx[y];
break;
case 1:
avDegrees = (sum[1] + sum[2]) / xx[y];
break;
case 2:
avDegrees = (sum[2] + sum[3]) / xx[y];
break;
case 3:
if (c[3] == 0 && c[1] > 0)
{
avDegrees = sum[1] / c[1];
}
else if (c[1] == 0 && c[3] > 0)
{
avDegrees = sum[3] / c[3];
}
else if (c[3] > 0 && c[1] > 0)
{
avDegrees = LimitDegrees360(((sum[3] / c[3]) + ((sum[0] / c[0]) + 360) / 2));
}
break;
}
return avDegrees;
}//===================================Last Average======================================
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
analogReference(DEFAULT);
pinMode(LED_BUILTIN, OUTPUT); //Squelch indicator
//DDRD= pinData;
//Data Pins
for(byte x=0;x <8;x++)
{
if( bitRead(pinData,x )==1)
{
if (bHC4050==true)
{
//Serial.print(x); Serial.print(" ");
pinMode( x, INPUT);
}
else
{
pinMode(x,INPUT_PULLUP);
}
}
}
for(byte x=0;x<8;x++)
{
if (bitRead(pinStrobe,x)==1)
{
if (bHC4050==true)
{
pinMode(x, INPUT);
}
else
{
pinMode(x,INPUT_PULLUP);
}
}
}
Message();
GetOffset();
Average(cNodegrees); //Init Average() returns cNoDegrees
}//------------------------------Last Setup==============================================
void loop() {
//Put your main code here, to run repeatedly:
//String
static String lastString;
//Integer
static int OldDegrees = cNodegrees;
int x = cNodegrees;
unsigned long t;
//Call SerialEvent once in a while
serialEvent();
if (bStringComplete==true)
{
if (inputString=="AV")
{
if (bAverage==false)
{
Serial.println(F("Average=true"));
bAverage=true;
Average(cNodegrees);
}
else
{
Serial.println(F("Average=false"));
bAverage=false;
bMultiPathAverage=false;
}
//Now clear inputString because all done
inputString="";
bStringComplete=false;
}
}
//Get potmeter calibration offset
if (GetOffset()==true)
{
if (OldDegrees !=cNodegrees)
{
Serial.print(Format3Degrees(Calibrate(OldDegrees)));
Serial.println(" ----Calibrate----");
}
}
if (bDemo==true)
{
x=GetDemo(110, 290); //begin and end degrees
}
else
{
//Squelch can be detected through degrees and showed by trigger LED_BUILTIN
x=NewBearing();
x=PA8W(x);//Squelch problem PA8W Doppler
}
//Average or not if bAverage=false
x=Average(x);
//Detect when squelch = closed
t=millis();
if (OldDegrees==cNodegrees)
{
SquelchOpenStart = t + cSquelchOpenMax;
DisplayAgreloTime = t-1;//Fast Display if squelch opens
}
//bMultiPathAverage, bAverage, cReset ????
//Reduce agrelo data over RS232
//------------------------------------------
if (t > DisplayAgreloTime)
{
DisplayAgreloTime = t + cDisplayAgreloTime;
if (bMultiPathAverage == false)
{
if (OldDegrees != x )
{
//Serial.println(Format3Degrees(x));
lastString=(Format3Degrees(Calibrate(x)));
Serial.println(lastString);
SquelchLed13(x);
OldDegrees=x;
}
else
{
if (lastString != strMulti && x != cNodegrees)
{
Serial.println(strMulti);
lastString = strMulti;
}
}
}
}
//---------------------------------------------
//Reset average after a while averaging ???
t=millis();
if (t > SquelchOpenStart)
{
SquelchOpenStart = t + cSquelchOpenMax;
Average(cReset);//Save only last Averaged degrees value
Serial.print ("TimeReset="); Serial.println(cSquelchOpenMax);
}
delay(10);
}//================================Last Loop ================================================