Electronics > Projects, Designs, and Technical Stuff
Radio Direction Finding
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
Go to full version