Re: Super Simple Sound Doppler Peiler
Geplaatst: 28 dec 2019, 22:03
Hallo Allemaal,
Alvast een verbeterde versie van de USB Arduino nano Agrelo converter
The function NewBearing() works now..
A squelch problem from the PA8W zerocrossdetector
also eleminated now..
So the squelch stays closed if is is jumping about yes oer no squelch.
Take and look and have fun..
Alvast een verbeterde versie van de USB Arduino nano Agrelo converter
The function NewBearing() works now..
A squelch problem from the PA8W zerocrossdetector
also eleminated now..
So the squelch stays closed if is is jumping about yes oer no squelch.
Take and look and have fun..
Code: Selecteer alles
/*
((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
PA8W fuction for keeping squelch at %999 due to error in zerocrossdetector pa8w doppler
*/
//Const
const byte pinData=B01111100;//7-0 //6 Data pins = 8, 4, 2, 1, .5 kHz
const byte pinStrobe = B10000000; //Strobe 7-0
const byte pinOffset = 0; //Pin offset Potmeter
//Const
const int cNodegrees = 999; //Squelch
const int cReset = 888; //Reset averaged with last degrees value only
const unsigned long cSquelchOpenMax = 5000; //Max averaged time in Averaged sub (mSec)
//Int
int Offset = 0; //For PA8W Doppler 2.3
unsigned long SquelchOpenStart = millis() + cSquelchOpenMax;
//Bool
const bool bHC4050 = true; //Use 4050 high low inverter So no PullUp R on input pins
const bool bDemo = false; //Simulates agrelo output
const bool bAverage = true; //Averaged Yes or No
bool bMultiPathAverage = false;
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++)
{
//Serial.println(i);
if (oldies[i]==cNodegrees)
{
x=cNodegrees;
}
}
return x;
}//Last PA8W
void Message()
{
Serial.println(F("((C))PA3BNX v1.00 USB Agrelo Doppler Interface"));
Serial.println(F("---------------------------------------------------"));
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("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 > 5)
{
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 = 2000;
start1 = micros() + (t - 1900);
start2 = micros() + t;
do
{
// 7 to 0
if ((PIND & pinStrobe) != pinStrobe)
{
goto f;
break;//Found a not active strobe
}
}
while (micros() < start1);
return d;
f:
do
{
x=PIND;
//Serial.print(x);Serial.println("--");
if ((x & pinStrobe) == pinStrobe ) //Wait for a strobe
{
//Serial.print(x);Serial.println("----");
//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
//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) {
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:
static int OldDegrees;
int x = cNodegrees;
//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
}
//Get Averaged Degrees
if (bAverage==true)
{
x=Average(x);
}
//Detect when squelch = closed
if (OldDegrees==cNodegrees)
{
SquelchOpenStart = millis() + cSquelchOpenMax;
}
//bMultiPathAverage, bAverage, cReset ????
//Reduce data over RS232
if (bMultiPathAverage ==false)
{
if (OldDegrees != x )
{
//Serial.println(Format3Degrees(x));
Serial.println(Format3Degrees(Calibrate(x)));
SquelchLed13(x);
OldDegrees=x;
}
}
//Reset average after a while averaging ???
if (millis() > SquelchOpenStart)
{
SquelchOpenStart = millis() + cSquelchOpenMax;
Average(cReset);//Save only last Averaged degrees value
Serial.println ("TimeReset");
}
delay(10);
}//================================Last Loop ================================================