Electronics > Projects, Designs, and Technical Stuff

Radio Direction Finding

<< < (29/39) > >>

PA3BNX:
Hello Every Body,

We are working on new Arduino Dopplers

To see our progress look at this
Dutch Forum

http://www.zendamateur.com/viewtopic.php?f=11&t=7271&start=480

PA3BNX:
Hello Every Body,

I am trying to build a Arduino Uno R3 based Doppler
that connects through USB to the PC and MyMapping.exe program.

So see the shield and my initial improved sketch

I updated the sketch and added a shield picture. ToDay 24-05-2015

Again updated the Sketch 01-05-2015
Fixed several issues

Still working on the code



--- Code: ---

/*
  ((C))PA3BNX
  Trying to create a SuperSimpleArduinoDoppler on Arduino Uno R3
  For this there is a special Arduino Com/USB input in MyMapping to show the headings on maps
  @12-04-2015
  @13-04-2015
  @15-04-2015
  @17-04-2015
  @22-04-2015
  @24-04-2015
  @25-04-2015
  @26-04-2015
  @27-04-2015
  @29-04-2015
  @01-05-2015
  Not ready yet!
  Try  max232 for Am WhatsonWatt DF to
  Need extra pin for that or use antPin ?
  Arrays are zero based !!!!
  Explaining Arduino pins.
  antPins[] Connect to antenna switcher pins
  refpa3bnx Connect to audio lowpass filter for soundcard referency input
  kPins[] Connect to kwadrant C's 4u7
  kPins[12] Connect to discharge transistor //Not yet done in hardware
  kPinAnalogue Connect to sum point of 4 cap's
 */

//Byte= 0>255
//Int=  -32768>32767

 //String Serial params
 String inputString = "";             //Received serial string
 
 //Boolean
 boolean bStringComplete = false;     //Complete '\n' rxed serial string 
 boolean bNoSetKpins = false;         //Do not change kPin[] because I am reading/empty them now
 boolean bMultiPathAverage = false;   //Multipath heading found in received headings from Averaged

//Const Integer
//Must be modified to right pin number arduino and arduino shield harddware
//Antenna Control Pins & refpa3bnx //Never use pins 0 and 1 because the UART must also function
//So I started with pin 2 to
byte antPin[4] = {2,3,4,5};           //Set antenna control pins (Not const because it can CCW/CW)
byte max232Pin[2] = {7,8};            //Set Max232Pin vor AM plate antenna
const byte refpa3bnx = 6;             //Pin for Referency frequency output to soundcard   

//Kwadrant Capicity switches & analogue SCF read pin
const byte kPin[5] = {9,10,11,12,13};  //4 pins caps 4u7 Last Pin in array = Discharge caps by bc547
const byte kPinAnalog = A0;            //A0 read voltage across one 4u7 cap pin A0 to A5
const int cOffset = 511;              // .5 * 1023 caps offset 

//Squelch Signals
const byte cSqlclosed = 0;
const byte cSqlclosed2open = 1;
const byte cSqlopen2closed = 2;
const byte cSqloverflow = 3;          //Capicitors are full
//

//NoDegreesMaxMinValues
const int cNodegrees = 999;           //Squelch No Signal or cSqlopen2closed
const int cMaxTime = 30;              //15 Sec/cMainLoopDelay Max time
const int cMainLoopDelay = 500;       //How fast the main loop runs in mSec
const int cMinAudioAmplitude = 100;   //There is enough signal to SinCosDetect

//Float const
//const float pi = 4 * atan(1);         //PI 3.14159
//const float rad = pi/180;
const float rad1 = 180/PI;              //57.295827
//const float TwoPi = 2 * pi;           //TWO_PI

 
//Integer
//Array with the 4 kwandrant analogue cap tensions These can be -511 to +511
int Cap[4] = {0,0,0,0};
int Calibrate= 0;                    //degrees default
byte sqlstatus = cSqlclosed;


//------------ISR Main Interrupt //This runs always--------------------
ISR(TIMER0_COMPA_vect)
{
 static byte c;
 //Do the Ant and Cap rotation here
 if (c==4){
  c=0;
 }
 SetAntPins(c);
 SetMax232Pins(c);
 SetKpinsHigh;
 c++;
}


//---------Functions now-------------------
//Max232Pins for AM Whatson Watt RDF
void SetMax232Pins(byte t){
  switch (t){
  case 0:
   digitalWrite(max232Pin[0],HIGH);
   digitalWrite(max232Pin[1],LOW);
   break;
  case 1:
   digitalWrite(max232Pin[0],HIGH);
   digitalWrite(max232Pin[1],HIGH);
   break;
  case 2:
   digitalWrite(max232Pin[0],LOW);
   digitalWrite(max232Pin[1],LOW);
   break;
  case 3:
   digitalWrite(max232Pin[0],LOW);
   digitalWrite(max232Pin[1],HIGH);
   break;
 }
}

//Antenna Control Lines Just counts 1234 1234 etc
void SetAntPins(byte t){
 switch (t){
  case 0:
  digitalWrite(antPin[0], HIGH);
  digitalWrite(antPin[3], LOW);
  digitalWrite(refpa3bnx,HIGH);
  break;
 case 1:
  digitalWrite(antPin[1], HIGH);
  digitalWrite(antPin[0], LOW);
  break;
 case 2:
  digitalWrite(antPin[2], HIGH);
  digitalWrite(antPin[1], LOW);
  digitalWrite(refpa3bnx,LOW);
  break;
 case 3:
  digitalWrite(antPin[3], HIGH);
  digitalWrite(antPin[2], LOW);
  break;
}
}

//Set kwadrant Cap Pins just High
void SetKpinsHigh(){
  if (bNoSetKpins==false){
   //Set all HIGH   
   for (int i=0 ;i<4;i++){
      digitalWrite(kPin[i],HIGH);
   }
  }
}

//Get the 4 analogue value's in Cap[]
void GetCapValues(){
  //All kwadrant Cap Pins HIGH
  for (byte i=0; i<4; i++)
 {
  digitalWrite(kPin[i],HIGH);
 } 
   
  //Read them one by one
  digitalWrite(kPin[0],LOW);
  Cap[0]  = analogRead(kPinAnalog)-cOffset; 
  digitalWrite(kPin[0],HIGH);
 
  digitalWrite(kPin[1],LOW);
  Cap[1]  = analogRead(kPinAnalog)-cOffset; 
  digitalWrite(kPin[1],HIGH);
 
  digitalWrite(kPin[2],LOW);
  Cap[2]  = analogRead(kPinAnalog)-cOffset; 
  digitalWrite(kPin[2],HIGH);
 
  digitalWrite(kPin[3],LOW);
  Cap[3] = analogRead(kPinAnalog)-cOffset; 
  digitalWrite(kPin[3],HIGH);
}


//Empty the 4 capicitors by discharging to 1/2 U
void EmptyCaps(){
 for (byte i=0; i<4; i++)
 {
  pinMode(kPin[i],LOW);
 } 
 digitalWrite(kPin[5],HIGH); //Discharge cap pin bc547
 delay(2100); //Let the 4 caps charge to 1/2 U  to 99%  5 * (22k * (4,7uF * 4))  2068 Sec
 digitalWrite(kPin[5],LOW);



//-------------Squelch-----------------------
int Squelch(){
//Return the sqlstatus
//Try Find a full cap   
 int x;
 
 //Find cap with highest voltage/tension
 //Biggest value = cOffset (511)
 for(byte i=0; i<4; i++)
 {
  if abs((Cap[i]) >= cOffset )
  {
   x = abs(Cap[i]);
  }
 }
 
 
 //See if there is a Full Cap
 //cOffset = Biggest value
 if (x >= cOffset)
 {
  return cSqloverflow;
 //Caps are full so need discharged
 }
 else if (x >= cMinAudioAmplitude)
 {
  return cSqlclosed2open;
 }
 else if (x < cMinAudioAmplitude)
 {
  return cSqlclosed;
 }

}

//Detect Multipath in SCF Caps
boolean MultiPathDetectSCF(){
//Calc average of 4 kwadrants
//If to large asymetric value return true
//Can it do also the Quality 1-9 ?
int x;
for (int i=0 ; i<4 ; i++){
  x += Cap[i];
}
//150 of max 510 is the MultiPath level ?
if (abs(x) > 150){ 
return true;
}
else
{
return false;
}
}

//Calibrate
int Cali(int degrees){
 return LimitDegrees360(degrees(Calibrate + degrees));
}


//Return Agrelo formatted string % and 3 digits always
  String Format3Degrees(int degrees){
  String str;
  int digits[3];
  int reminder; 
  digits[0]=degrees/100;
  reminder = degrees % 100;
  digits[1]= reminder/10;
  reminder = reminder % 10;
  digits[2]=reminder;
  str += '%';
  str += digits[0];
  str += digits[1];
  str += digits[2];
  return str;
}

//Limit Degrees 0 to 360 degrees
int LimitDegrees360(int d){
  //Limit degrees 0 to 360 here
 
if (d >= 360){
  return d - 360;
  }
  else if (d < 360)
  {
  return d;
  }
  else if (d < 0)
  {
  return 360 + d;
  }
  else
  {
  return cNodegrees; 
  }
}

//Average
int Average(int d){
  //If d = 999 (cNoDegrees) then reset average
  //Else return averaged degrees
 
  //Integer
  static int sum[4];     //Sum of counts for each kwadrant
  static int c[4];       //Cap tension/voltage in 4 kwadrant
  int xx[4] ={0,0,0,0};  //Adjacent kwadrants
  int z = 0;             //Most adjacent headings
  int z1 = 0;            //Other two kwandants headings
  int y = 0;             //Index where the most headings are
  int avDegrees;         //Averaged degrees


 //Limit amount off averaged headings
 if  (c[0]+c[1]+c[2]+c[3] > cMaxTime ){
  for (byte i=0; i<4 ; i++){
   sum[i]=0;
   c[i]=0;
  return cNodegrees;
 }
}


  if (d!=cNodegrees){
   
  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]++;
  }
  }
 else
 {
 //Reset
  for (byte i=0; i<4; i++){
  sum[i]=0;
  c[i]=0;
  bMultiPathAverage = false;
 }
 return cNodegrees;
}

  //Find 2 adjacent kwadrants with hold most counts
     
  //Count all adjacents kwadrants
  xx[1] = c[0]+c[1];
  xx[2] = c[1]+c[2];
  xx[3] = c[2]+c[3];
  xx[4] = 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 Headings
    y = i;     //Witch 2 adjacent Array Index
  }
 }
 

//Check for multipath
switch(z){
case 0:
 z1 = 3;
 break;
case 1:
 z1 = 4;
 break;
case 2:
 z1 = 1;
 break;
case 3:
 z1 = 2;
 break;
}

if (z > z1){
bMultiPathAverage = true;
}
else
{
bMultiPathAverage = false;
}

 
 //Average the 2 most counts kwadrants
switch(y){
case  1:
 avDegrees = (sum[0] + sum[1]) / c[y];
 break;
case 2:
 avDegrees = (sum[1] + sum[2]) / c[y];
 break;
case 3:
 avDegrees = (sum[2] + sum[3]) / c[y];
 break;
case 4:
 if (c[3] == 0 && c[0] > 0){
 avDegrees = sum[0] / c[0];
 break;
 }
 if (c[3] > 0 && c[0] == 0){
 avDegrees = sum[3] / c[3];
 break;
 }
 if (c[3] > 0 && c[0] > 0 ){
 avDegrees = LimitDegrees360(((sum[3] / c[3]) + ((sum[0] / c[0]) + 360) / 2));
 break;
 }

 
if (d == cNodegrees){
  return avDegrees;
}
}


//SinCosDetector Find the degrees from the 4 Cap[] tensions
int SinCosDetector(){
  int SinSum;
  int CosSum;
  int x;
//In Cap[] is the tension value of 1 of the 4 C'S

SinSum = Cap[0] - Cap[2]; 
CosSum = Cap[1] - Cap[3];
 
if (SinSum == 0 && CosSum == 0){
 return cNodegrees;
}
else
{
 return LimitDegrees360(atan2(SinSum,CosSum) * rad1);
}
}

//=============SerialRx Event===========================
void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == '\n') {
      bStringComplete = true;
    }
     else
     {
     bStringComplete = false;
     }
  }
}

//===============
 

//------------------------------------Main Functions-----------------------------------------

//SetUp
void setup()
{
  // Loop over the pin array and set them all to output:
   Serial.begin(9600); // Opens serial port, sets data rate to 9600 bps
   Serial.println("((C))PA3BNX Arduino Doppler");
   Serial.println("%999"); //Squelch always closed at start
   pinMode(refpa3bnx,OUTPUT);
   digitalWrite(refpa3bnx,LOW);
   pinMode( kPinAnalog,INPUT); //Okay here ????
   pinMode(kPin[5],OUTPUT);    //Discharge Pin bc547
   digitalWrite(kPin[5],LOW);
   pinMode(max232Pin[0],OUTPUT);
   pinMode(max232Pin[1],OUTPUT);
   digitalWrite(max232Pin[0],LOW);
   digitalWrite(max232Pin[1],LOW);
   for (byte i=0; i<4; i++){
     pinMode(kPin[i],OUTPUT);
     pinMode(antPin[i] ,OUTPUT);
     digitalWrite(antPin[i],LOW); //antPin LOW
     digitalWrite(kPin[i],LOW);  //Set Cap pins to low so the can charge to 1/2U
   }
   Average(cNodegrees); //Reset all to 0
   EmptyCaps;           //All kPins to 1/2 U
 
 
   //Now start ISR interrupt
   // Timer0 is already used for millis() - we'll just interrupt somewhere
   // in the middle and call the "Compare A" function below
   OCR0A = 0xAF;
   TIMSK0 |= _BV(OCIE0A);
   // ToDo is there a default timer in microseconds to ?
   // Interrupt is called once a millisecond
   // I assume now doppler rotate frequency 4 mSec or 1/.004 = 250 Hz //Measured 244 Hz at refpa3bnx pin
 }

//Main Loop
void loop() {
  // ToDo
  // GetCapValues
  // Set the ant1,2,3,4 and refpa3bnx  pins ISR
  // Squelch status
  // OverFlow Reset the 4 kwadrant capicitors
  // Calibrate routine (add an degrees offset)
  // SinCosDetector
  // Send (averaged) and calibrated degrees out through the serialport
  // Receive remote serial cmd's like CW/CCW and Degrees 
 
   //Integer
   byte swap = antPin[1]; //90 degrees
   int t;   
   
   bNoSetKpins = true;
   GetCapValues();
   bNoSetKpins = false;
   SetKpinsHigh();
   
   sqlstatus = Squelch();      //Squelch status check
     
  if (sqlstatus == cSqloverflow || (t > cMaxTime))
  {
    t = 0;
    bNoSetKpins = true;
    EmptyCaps();
    bNoSetKpins= false;
    SetKpinsHigh(); 
  }
 else
 {
  //Relaxed sending degrees to serialport
 if (sqlstatus == cSqlopen2closed && bMultiPathAverage == false)
 {
   if (MultiPathDetectSCF == false){   
    Serial.println(Format3Degrees(Cali(Average(SinCosDetector()))));
    sqlstatus = cSqlclosed;
    }
  }
 }

//Try to read Calibration, CW/CCW, Timing Parameters
//000<cr> <lf> from MyMapping.exe as calibrate cmd

serialEvent;                     //Call SerialEvent once in a while

if (bStringComplete == true){ 

//Swap 90 and 270 degrees pins 
 
 if (inputString == "CCW"){
   if (swap != antPin[1])
   {
   swap=antPin[1];
   antPin[1]=antPin[3];
   antPin[3]=swap;
   }
  }
  else if (inputString == "CW")
  {
  if (swap != antPin[1])
  {
   swap=antPin[1];
   antPin[1]=antPin[3];
   antPin[3]=swap;
   }
  }
 else
 {
  Calibrate = inputString.toInt();
 }
  //Always Clear inputString Now
  inputString="";
}


//Do always every  loop
delay(cMainLoopDelay);       //Wait 500 mSec for next try ? fast enough I think
t += 1;                      //Total loops to compared against cMaxTime
}


//End of sketch
 
 
 

--- End code ---

PA3BNX:
Hello EveryBody,

I got from PE1KQP some very nice links
with documentry about radio WO2 and Radar










Have fun watching


PA3BNX:
Hello Every Body,

I got the Arduino mounted on a board with the PCB hole Shield
for a doppler am plate RDF (max232).

So now I can focus on the arduino sketch

Take a loo here PA8W made also a nice Arduino Doppler with 128 by 64 pixel screen.

https://www.youtube.com/watch?v=rzyIFLcg6-A&feature=youtu.be



PA3BNX:
Hello Every Body,

I worked again on the Arduino Sketch


It works.

I want to make 500 and 3000 Hz doppler rotation adjustments in it
with ISR timer interrupt

So I could send LOW or HIGH through serial USB/COM
and switch teh doppler rotation frequency.

(500Hz for nbfm and 3000Hz for wbfm)

Any hints how to do that


--- Code: ---/*
  ((C))PA3BNX
  Arduino Uno REV 3 Sketch
  Look at http://www.pi4wag.nl/projecten/doppler-peiler-radio-direction-finder
  Trying to create a SuperSimpleArduinoDoppler on Arduino Uno R3
  For this there is a special Arduino Com/USB input in program MyMapping to show the Agrelo(%bbb<cr><lf>) headings on maps
  No adjustments on the arduino shield it self
  All adjustmenst like Calibrate-offset and CW/CCW through Serial Port
  Doppler frequency 500 - 3000 Hz ToDo
  Squelch level adjust ? ToDo
  Antenna test 1,2,3,4 Wait 3 seconds then restart scanning ?  ToDo
  Remote CMD's  ANT1 ANT2 ANT3 ANT4 CW CCW LOW HIGH (bbb Calibrate)
  @12-04-2015
  @13-04-2015
  @15-04-2015
  @17-04-2015
  @22-04-2015
  @24-04-2015
  @25-04-2015
  @26-04-2015
  @27-04-2015
  @29-04-2015
  @01-05-2015
  @02-05-2015
  @03-05-2015
  @05-05-2015
  @06-05-2015
  @08-05-2015
  @10-05-2015
  @12-05-2015
  Not quite ready yet but working!
  I want LOW and HIGH working Doppler ISR rotate Routines 500 Hz and 3000Hz(Now it runs only on 244 Hz)
  Arrays are zero based !!!!
  Explaining Arduino pins:
  antPins[4] Connect to antenna switcher pins
  refpa3bnx Connect to audio lowpass filter for soundcard referency input
  kPins[4] Connect to kwadrant C's 4u7
  kPinAnalogue Connect to sum point of 4 cap's
  max232Pin[2] for Am WhatsonWatt DF through max232 external chip + and - 12 V
 */

//Byte= 0>255
//Int=  -32768>32767

 //String Serial params
 String inputString="";             //Received serial string
 
 //Boolean
 boolean bStringComplete=false;     //Complete '\n' rxed serial string 
 boolean bNoSetKpins=false;         //Do not change kPin[] because I am reading/empty them now
 boolean bNoAntScan=false;          //Do not change antPins while testing one antenna
 boolean bMultiPathAverage=false;   //Multipath heading found in received headings from Averaged

//Const Integer
//Must be modified to right pin number arduino and arduino shield harddware
//Antenna Control Pins & refpa3bnx //Never use pins 0 and 1 because the UART must also function
//So I started with pin nbr 2 
byte antPin[4]={2,3,4,5};           //Set antenna control pins (Not const because it can be CCW/CW)
const byte max232Pin[2]={7,8};      //Set Max232Pin vor AM plate antenna
const byte refpa3bnx=6;             //Pin for Referency frequency output to soundcard   
const byte cHigh=9;                 //All kPins High Only Used in function SetKpins

//Kwadrant Capicity switches & analogue SCF read pin
const byte kPin[5]={9,10,11,12};    //4 pins caps 4u7
const byte kPinAnalog=0;            //A0 read voltage across one 4u7 cap pin A0 to A5
const int cOffset=511;              // .5 * 1023 caps offset 

//Squelch Signals
const byte cSqlclosed=0;
const byte cSqlclosed2open=1;
const byte cSqlopen2closed=2;
const byte cSqloverflow=3;          //Capicitors are full
//

//NoDegreesMaxMinValues
const int cNodegrees=999;           //Squelch No Signal or cSqlopen2closed Clear avDegrees and set avDegrees to cNodegrees
const int cReset=888;               //Clear Average and avDegrees
const int cMaxTime=60;              //15 Sec/cMainLoopDelay Max time 60 * 250 = 15 Sec
const int cMainLoopDelay=1000;      //How fast the main loop runs in mSec
const int cMinAudioAmplitude=60;    //There is enough signal to SinCosDetect
const int cMaxSymmetric=175;        //Max Sym in MultiPathSCF

//Float const
//const float pi = 4 * atan(1);     //PI 3.14159
//const float rad = pi/180;
const float rad1=180/PI;            //57.295827
//const float TwoPi = 2 * pi;       //TWO_PI

 
//Integer
//Array with the 4 kwandrant analogue cap tensions These can be -511 to +511
byte sqlstatus=cSqlclosed;
byte swap=antPin[1];                //90 degrees Loop
int Cap[4]={0,0,0,0};
int Calibrate=0;                    //Calibrate degrees default
int tMaxTime=0;                   //Used in Loop

 

//------------ISR Main Interrupt //This runs always--------------------
ISR(TIMER0_COMPA_vect)
{
 static byte c;
 //Do the Ant and Cap rotation here
 if (c==4){
  c=0;
 }
 if (bNoAntScan == false)
 {
 SetAntPins(c);
 SetKpins(c);
 SetMax232Pins(c);
 }
//Always increment
c++;
}

//---------Functions now-------------------

//Listen/Test on each antenna separate for about 3 sec's
void AntTest(byte a){
 bNoAntScan = true;
 //Switch all Low
 for (byte i=0;i<4;i++)
 {
  digitalWrite(antPin[i],LOW); 
 }

 //Switch one High
 digitalWrite(antPin[a],HIGH);
 SetMax232Pins(a);
 delay(3000);
 //Switch again to Low
 digitalWrite(antPin[a],LOW);
 bNoAntScan = false;
 a+=1;
 Serial.print(F("Ant test ")); //F means keep Ant test in ROM
 Serial.println(a);
}

//Max232Pins for AM Wattson Watt RDF
void SetMax232Pins(byte t){
  switch (t){
  case 0:
   digitalWrite(max232Pin[0],HIGH);
   digitalWrite(max232Pin[1],LOW);
   break;
  case 1:
   digitalWrite(max232Pin[0],HIGH);
   digitalWrite(max232Pin[1],HIGH);
   break;
  case 2:
   digitalWrite(max232Pin[0],LOW);
   digitalWrite(max232Pin[1],LOW);
   break;
  case 3:
   digitalWrite(max232Pin[0],LOW);
   digitalWrite(max232Pin[1],HIGH);
   break;
 }
}

//Antenna Control Lines Just counts 1234 1234 etc
void SetAntPins(byte t){
 switch (t){
  case 0:
  digitalWrite(antPin[0], HIGH);
  digitalWrite(antPin[3], LOW);
  digitalWrite(refpa3bnx,HIGH);
  break;
 case 1:
  digitalWrite(antPin[1], HIGH);
  digitalWrite(antPin[0], LOW);
  break;
 case 2:
  digitalWrite(antPin[2], HIGH);
  digitalWrite(antPin[1], LOW);
  digitalWrite(refpa3bnx,LOW);
  break;
 case 3:
  digitalWrite(antPin[3], HIGH);
  digitalWrite(antPin[2], LOW);
  break;
 }
}

//Set kwadrant Cap Pins according to antPins
void SetKpins(byte t){
 
  //Nothing Todo now
  if (bNoSetKpins==true){return;}
 
  //Set all HIGH     
   for (byte i=0;i<4;i++)
  {
   digitalWrite(kPin[i],HIGH);
   } 
  //Set the pin LOW to charge the cap
  //Only if t not cHigh
   if (t != cHigh) {
    digitalWrite(kPin[t],LOW);
   }
  }


//Get the 4 analogue value's in Cap[]
void GetCapValues(){
  //This leaves all kPin[] HIGH when finished
 
  //Set all kwadrant Cap Pins HIGH
  for (byte i=0;i<4;i++)
  {
   digitalWrite(kPin[i],HIGH);
  } 
     
  //Read these one by one
  for (byte i=0;i<4;i++)
  {
  digitalWrite(kPin[i],LOW);
  //delayMicroseconds(100);
  Cap[i]=analogRead(kPinAnalog)-cOffset; 
  delayMicroseconds(150); //Ref say about .1 milli Sec to settel analogue
  digitalWrite(kPin[i],HIGH);
  }
}

//Empty the 4 capicitors by discharging to 1/2 U
//This function leaves all kPin[] = HIGH
void EmptyCaps(){
 Serial.println(F("EmptyCaps"));
 byte i; 
  for (i=0;i<4;i++)
 {
  digitalWrite(kPin[i],LOW);
 } 
 delay(1000);
 for (i=0;i<4;i++)
 {
  digitalWrite(kPin[i],HIGH);
 } 



//-------------Squelch-----------------------
int Squelch(){
//Return the sqlstatus
//Try Find a full cap   
 int x;
 int z;
 //Find cap with highest voltage/tension
 //Biggest value = cOffset (511)
 for(byte i=0;i<4;i++)
 {
   z=abs(Cap[i]);
   if (z>0);
  {
   x=z;
  }
 }
 
 //See if there is a Full Cap
 //cOffset = Biggest value
 if (x>=cOffset)
 {
  return cSqloverflow;
 //Caps are full so need discharged
 }
 else if (x>=cMinAudioAmplitude)
 {
  return cSqlclosed2open;
 }
 else if (sqlstatus==cSqlclosed2open && x<cMinAudioAmplitude)
 {
  return cSqlopen2closed;
 }
 else
 {
  return cSqlclosed;
 }
}

//Detect Multipath in SCF Caps
boolean MultiPathDetectSCF(){
//Calc average of 4 kwadrants
//If to large asymetric value return true
//Can it do also the Quality 1-9 ?
int x;
for (int i=0;i<4;i++){
  x+=Cap[i];
}
//150 of max 510 is the MultiPath level ?
if (abs(x)>cMaxSymmetric){ 
return true;
}
else
{
return false;
}
}

//Calibrate
int Cali(int d){
 return LimitDegrees360(Calibrate+d);
}


//Return Agrelo formatted string % and 3 digits always
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;
}

//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 cNodegrees;
  }
  else
   {
   int x;
   x = d % 360;
   if (x<0)
   {
   x += 360; 
   return x;
   } 
   }
}

//Average
int Average(int d){
  //If d = 999 (cNoDegrees) then reset average and return last avDegrees
  //If d = 888 (cReset) then Reset all and put last avDegrees back in arrays
 
  //Always return avDegrees and Set bMultiPath
 
  //Integer
  static int sum[4]={0,0,0,0};        //Sum of counts for each kwadrant
  static int c[4]={0,0,0,0};          //Cap tension/voltage in each kwadrant
  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
 
 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;
 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;
 }
     
   
  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
  if (c[0]+c[1]+c[2]+c[3] == 0)
  {
    bMultiPathAverage=false;
    avDegrees=cNodegrees;
    return avDegrees;
  } 
 
  //Find 2 adjacent kwadrants with hold most 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 Headings
    y=i;     //Witch 2 adjacent Array Index
  }
 }


//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=false;
}
else
{
bMultiPathAverage=true;
}
 
//Average the 2 most counts kwadrants
switch(y){
case  0:
 avDegrees=(sum[0]+sum[1])/c[y];
 break;
case 1:
 avDegrees=(sum[1]+sum[2])/c[y];
 break;
case 2:
 avDegrees=(sum[2]+sum[3])/c[y];
 break;
case 3:
 if (c[3]==0 && c[0]>0){
 avDegrees=sum[0]/c[0];
 break;
 }
 if (c[3]>0 && c[0]==0){
 avDegrees=sum[3]/c[3];
 break;
 }
 if (c[3]>0 && c[0]>0){
 avDegrees=LimitDegrees360(((sum[3]/c[3])+((sum[0]/c[0])+360)/2));
 break;
 }


  return avDegrees;
}


//SinCosDetector Find the degrees from the 4 Cap[] tensions
int SinCosDetector(){
  int SinSum;
  int CosSum;
   
  //In Cap[] is the tension value of 1 of the 4 C'S
 
 //Serial.println(Cap[0]);
 //Serial.println(Cap[1]);
 //Serial.println(Cap[2]);
 //Serial.println(Cap[3]);

  SinSum=Cap[0]-Cap[2]; 
  CosSum=Cap[1]-Cap[3];

  if (SinSum==0 && CosSum==0){
  return cNodegrees;//No Signal
  }
  else
  {
  //Serial.println(atan2(SinSum,CosSum)*rad1); //Added 90 degrees so it's the same as zerocrossdetection
  return LimitDegrees360((atan2(SinSum,CosSum)*rad1)+90);
  }
 }

//=============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;
     }
  }
}
//=======================================================

//=========================================
boolean CheckOnlyNbr(String str){
//Check for only numbers 0 to 9 in the string

//48=0 57=9
 for (unsigned j=0;j<str.length();j++){
   byte x=str.charAt(j);
   if ((x<48)||(x>57) )
  {
   return false;
  }
}
 return true;
}
 
//========================================
//------------------------------------Main Functions-----------------------------------------

//SetUp
void setup()
{
   Serial.begin(9600);                             // Opens serial port, sets data rate to 9600 bps
   Serial.println("((C))PA3BNX Arduino Doppler");
   Serial.println("%999");                         //Squelch always closed at start
   //Serial.println(Format3Degrees(cNodegrees));   //Squelch always closed at start
   pinMode(refpa3bnx,OUTPUT);
   digitalWrite(refpa3bnx,LOW);
   pinMode(max232Pin[0],OUTPUT);
   pinMode(max232Pin[1],OUTPUT);
   digitalWrite(max232Pin[0],LOW);
   digitalWrite(max232Pin[1],LOW);
   for (byte i=0;i<4;i++)
   {
     pinMode(antPin[i],OUTPUT);
     pinMode(kPin[i] ,OUTPUT);
     digitalWrite(antPin[i],LOW);                  //antPin LOW = OFF
     digitalWrite(kPin[i],LOW);                    //Set Cap pins to low so the can charge to 1/2U
   }
     
   // Now start ISR interrupt
   // Timer0 is already used for millis() - we'll just interrupt somewhere
   // in the middle and call the "Compare A" function below
   OCR0A=0xAF;
   TIMSK0|=_BV(OCIE0A);
   // ToDo is there a default timer in microseconds to ?
   // Interrupt is called once a millisecond
   // I assume now doppler rotate frequency 4 mSec or 1/.004 = 250 Hz //Measured 244 Hz at refpa3bnx pin
 }

//Main Loop
void loop() {
  // ToDo
  // GetCapValues
  // Squelch status
  // OverFlow Reset the 4 kwadrant capicitors
  // Calibrate routine (add an degrees offset)
  // SinCosDetector
  // Send (averaged) and calibrated degrees out through the serialport
  // Receive remote serial cmd's like CW/CCW and Degrees 
       
   
   bNoSetKpins=true;
   GetCapValues(); //Fill Values in Cap[] //Leaves all Kpins HIGH when finished
   bNoSetKpins=false;
   sqlstatus=Squelch();      //Squelch status check uses Cap[] values
 
   if (sqlstatus==cSqlclosed)
   {
    tMaxTime=0;
    Average(cNodegrees); //Clear all
   }
   else
   {
    tMaxTime+=1;             //Total loops to compared against cMaxTime
   }
 
 
  if (sqlstatus==cSqloverflow||(tMaxTime>=cMaxTime))
  {
    bNoSetKpins=true;
    EmptyCaps();//Leaves all Kpins HIGH
    bNoSetKpins=false;
   }
 else
 {
   //Not Ready here but working
   //Relaxed sending degrees to serialport
   boolean bSCF;
   byte x1;
   byte x2;
   //bSCF=MultiPathDetectSCF();
   x1=SinCosDetector();
   //Never add a MultiPath SCF value to Average
   if (bSCF==false)
   {
   x2=Average(x1);
   }
     
   if (sqlstatus==cSqlopen2closed)
   {
   if (bMultiPathAverage==false)
   {
   Serial.println(Format3Degrees(Cali(x2))); 
   {
   //Always Squelch Closed and Reset Average
   Serial.println(Format3Degrees(cNodegrees)); //Squelch Closed
   }
   }
   }
  else if (sqlstatus==cSqlclosed2open)
  {
   if (bMultiPathAverage==false)
   {
    Serial.println(Format3Degrees(Cali(x2)));
   }
  }
 } 
 

//Try to read Calibration, CW/CCW, Timing Parameters
//000<cr> <lf> from MyMapping.exe as calibrate cmd

serialEvent();          //Call SerialEvent once in a while

if (bStringComplete==true){ 
    //Swap 90 and 270 degrees pins 
 if (inputString=="CW")
   {
     Serial.println(inputString);
     if (swap!=antPin[1])
   {
   swap=antPin[1];
   antPin[1]=antPin[3];
   antPin[3]=swap;
   }
   }
  else if (inputString=="CCW")
  {
    Serial.println(inputString);
    if (swap!=antPin[3])
  {
   swap=antPin[3];
   antPin[3]=antPin[1];
   antPin[1]=swap;
  }
   }
  else if (inputString=="ANT1")
  {
  AntTest(0);
  }
  else if (inputString=="ANT2")
  {
  AntTest(1);
  }
  else if (inputString=="ANT3")
  {
  AntTest(2);
  }
  else if (inputString=="ANT4")
  {
  AntTest(3);
  }
  else if (inputString=="LOW")
  {
  //ToDo ISR 500 Hz
  } 
  else if (inputString=="HIGH")
  {
  //ToDo ISR 3000 Hz
  } 
  else
  {
  //Try Calibrate offset
  if (CheckOnlyNbr(inputString)==true)
  {
    int x;
    x=inputString.toInt();
    if (x>=0 && x <=360)
    {
    Calibrate=x;
    Serial.print(F("Calibrate="));
    Serial.println(Calibrate);
    }
   } 
  }
   //Now clear inputString because all done
   inputString="";
   bStringComplete=false;
}

//Do always every loop
//Reset
if(tMaxTime>=cMaxTime)
 {
 tMaxTime=0;
 if (sqlstatus==cSqlclosed2open)
 {
 Average(cReset); //Clear and Reset avDegrees
 }
 }

//Wait 250 a 1000 mSec for next try ? fast enough I think
delay(cMainLoopDelay);


} //End of sketch Last bracket of Loop
 


--- End code ---

Navigation

[0] Message Index

[#] Next page

[*] Previous page

There was an error while thanking
Thanking...
Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod