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 ================================================