#define reverseOffset 10 // this is a best guess at the difference between forward and reverse measurement #define detIntercept -50.0 // Intercept of detector dBm #define detCoupling -43.6 // Guess at coupling factor - n #define ADC2mV 4.96 // ADC mV per count 5070/1024 #define A2mV 178.0 // Current monitor scaling, nominally 200mV/A but measured reading 10% low #define detSlope 122.0 // slope of the detector chip mV/dB #define minTXtime 100L // minimum TX time // Define the extermal connection Pins // Digital #define ptt 2 // PTT input pin 2 #define LCDRX 4 #define LCDTX 3 #define Enable28V 5 // send low to switch FET to enable 28V #define forwardSwitch 12 // RF Switch forward #define reverseSwitch 13 // RF Switch reverse #define HealthyLED 6 // set high when all is well #define TripLED 7 // set high when its all hone horribly wrong #define TXLED 8 // LED to indicate TX status HIGH = TX #define PSU28VMonitor 9 // 28V monitor HIGH = 28V on Low = 28V off // Analogue #define RFLevel A0 // this is where we read both Forward and Reverse RF #define driverI A1 // Driver current pin A1 #define finalLI A2 // Left Final current A2 #define finalRI A3 // Right Final current A3 #define temperature A6 // temperature pin A6 // Limits #define maxForwardPower 51.0 // Forward power limit (dBm) #define maxReversePower 40.0 // Reverse power limit (dBm) #define maxDriver 8.0 // Driver current limit (A) #define maxLeftFinal 10.0 // Left final current limit (A) #define maxRightFinal 10.0 // Right final current limit (A) #define maxTemperature 65.0 // Temperature limit (C) // Global variables here volatile boolean pttState = false; // volatile for interrupt access float tempScale; float currentScale; float powerScale; unsigned long timer = 0; boolean pttEnable = true; unsigned long txtimer = 0; boolean transmitting = false; float DriverCurrent; float LeftFinalCurrent; float RightFinalCurrent; float Temperature; float ForwardPower; float ReversePower; boolean trip = false; boolean latch = false; boolean overCurrent = false; boolean overTemperature = false; boolean overDrive = false; boolean vswrFault = false; boolean PSU28VError = false; // define interrupt routine for PTT void pttInterrupt() { // PTT interrupt routine pttState = true; // Check for repeated interrupts due to bounces 10mS should be enough if( millis() - timer < 10L) return; timer = millis(); switchTX(); // Function to go to TX } void setup() { // Serial port 9600 baud Serial.begin(9600); Serial.println("G0MGX 13cm Linear Control"); Serial.println("Format: Status, Forward power(W), Reflected power (W), Temperature (C), Driver current (A), Left final current (A), Right final current (A)"); // Set up the digital I/O pins pinMode(ptt, INPUT_PULLUP); pinMode(PSU28VMonitor,INPUT_PULLUP); pinMode(Enable28V, OUTPUT); digitalWrite(Enable28V,LOW); pinMode(HealthyLED, OUTPUT); digitalWrite(HealthyLED,HIGH); pinMode(TripLED, OUTPUT); digitalWrite(TripLED, LOW); pinMode(TXLED, OUTPUT); digitalWrite(TXLED,LOW); // Scaling factors - only calculate once tempScale = ADC2mV / 20.0; // 20mV per C currentScale = ADC2mV / A2mV; // 180mV per Amp measured powerScale = ADC2mV / detSlope; //attach the interrupt for PTT pin attachInterrupt(digitalPinToInterrupt(ptt),pttInterrupt,FALLING); // hold the boat for a while delay(1000); switchRX(); } void loop() { if(digitalRead(ptt) != LOW) pttState = false; // Switch to receive if required assuming we have been transmitting for minimum time if(pttState == false && transmitting == true) if(millis() - txtimer > minTXtime) switchRX(); // now we take the various readings from the board getReadings(); // Do checks overTemperature = (Temperature > maxTemperature); overCurrent = checkCurrent(); overDrive = (ForwardPower > maxForwardPower); vswrFault = (ReversePower > maxReversePower); // decide if we have a trip condition trip = overTemperature || overCurrent || overDrive || vswrFault || PSU28VError; if (transmitting==true && trip==true) switchRX; // send comms to the serial monitor if we have tripped PrintTrip(); // set the outputs and lEDs accordingly // this doesnt return in the event of a trip setStatus(); // drop data down the serial monitor line printOut(); } void PrintTrip(void) { if (overTemperature) { Serial.print("Overtemp "); Serial.println(Temperature); } if (overCurrent) { Serial.print("Over Current, Driver: "); Serial.print(DriverCurrent); Serial.print(" Left: "); Serial.print(LeftFinalCurrent); Serial.print(" Right: "); Serial.println(RightFinalCurrent); } if (overDrive) { Serial.print("Over Diven"); Serial.println(ForwardPower); } if (vswrFault) { Serial.print("VSWR Fault "); Serial.println(ReversePower); } if(PSU28VError) { Serial.print("28V Error TX: "); Serial.print(transmitting); Serial.print(" 28VHigh : "); Serial.println(PSU28VError); } } //------------------------------------------------------------------------------------------- void switchTX(void) { // Switches to TX mode if PTT isn't blocked if(pttEnable) { txtimer = millis(); // Set TX timer digitalWrite(Enable28V, LOW); // Enable 28V line to main board via FET switch digitalWrite(TXLED,HIGH); // Switch on the TX LED delay(40); // Wait 40mS transmitting = true; } } //------------------------------------------------------------------------------------------------------ void switchRX(void) { // Switches to RX mode pttEnable = false; // Prevent going to TX while going to RX txtimer = 0; // Reset TX timer digitalWrite(Enable28V, HIGH); // Disable 28V supply digitalWrite(TXLED,LOW); // Switch off the TX LED delay(40); // Wait 40mS transmitting = false; pttEnable = true; } //------------------------------------------------------------------------------------------------------ bool checkCurrent(void) { // Determine if the current values read are within limits if(DriverCurrent > maxDriver || LeftFinalCurrent > maxLeftFinal || RightFinalCurrent > maxRightFinal) return (true); else return (false); } //------------------------------------------------------------------------------------------------------ void getReadings(void) { // Reads the values DriverCurrent = getCurrent(analogRead(driverI)); LeftFinalCurrent = getCurrent(analogRead(finalLI)); RightFinalCurrent = getCurrent(analogRead(finalRI)); Temperature = getTemperature(analogRead(temperature)); if ((transmitting==true && digitalRead(PSU28VMonitor)==0) || (transmitting==false && digitalRead(PSU28VMonitor)==1)) { PSU28VError = true; } else { PSU28VError = false; } // Power is more complicated as there is an RF switch // first we set up for a forward power reading // digitalWrite(forwardSwitch, HIGH); digitalWrite(reverseSwitch, LOW); delay(5); ForwardPower = getpowerdBm(analogRead(RFLevel)); // // now set up for a reverse power reading // digitalWrite(forwardSwitch, LOW); digitalWrite(reverseSwitch, HIGH); delay(5); ReversePower = getpowerdBm(analogRead(RFLevel)) - reverseOffset; } //------------------------------------------------------------------------------------------------------ void setStatus(void) { // act on the inputs we have established if (trip) { // trip condition digitalWrite(HealthyLED, LOW); digitalWrite(TripLED, HIGH); if (transmitting==true) switchRX; // once tripped we need a power cycle to recover while (1); } else { digitalWrite(HealthyLED, HIGH); digitalWrite(TripLED,LOW); } } //------------------------------------------------------------------------------------------------------ float getCurrent(int adc) { // Finds current from ADC reading 200mv/A return ((float)adc * currentScale); } //------------------------------------------------------------------------------------------------------ float getTemperature(int adc) { // Finds temperature from ADC reading 20mv/C 1000mV offset return ((float)adc * tempScale - 50.0); } //------------------------------------------------------------------------------------------------------ float getpowerdBm(int adc) { // Finds power for given ADC reading complicated // V = Slope x (Pin - Pintercept) - for raw chip V ~ 19.3 x (Pin + Poffset) // With gain of 6, V ~115(Pin + Poffset) return ((float) adc * powerScale + detIntercept); } //------------------------------------------------------------------------------------------------------ float getWatts(float dBm) { // Converts from dBm to Watts double result = pow(10, (dBm-detCoupling) / 10.0); return ((float)result); } //------------------------------------------------------------------------------------------------------ void printOut() { // this outputs a load of gubbins down the serial monitor port // float ForwardWatts = getWatts(ForwardPower);; float ReverseWatts = getWatts(ReversePower); if(transmitting) Serial.print("TX, "); else Serial.print("RX, "); Serial.print(ForwardWatts); Serial.print(", "); Serial.print(ReverseWatts); Serial.print(", "); Serial.print(Temperature); Serial.print(", "); Serial.print(DriverCurrent); Serial.print(", "); Serial.print(LeftFinalCurrent); Serial.print(", "); Serial.print(RightFinalCurrent); Serial.print(", "); Serial.println(); }