/*********************************************** * * Raduino Firmware * AUTORE: Minutello Manuel * CALL: IU3IRR * **********************************************/ boolean enableDislayVoltage = false; // "true" se si vuole mostrare le tensioni di alimentazione, "false" sela seconda riga deve essere lasciata vuota String call = "IU3IRR"; //call dell operatore boolean showCall = true; // inserire "true" per mostrare il call dell operatore , "false" per non farlo //************************************************************************************************************************ //*************** solo tensioni o solo call , non entrambi o le scritte si sovrappongolo *********************** //*************** abilitando una di queste funzioni si produce un fischio ad *********************** //*************** alta frequenza all altoparlante a causa del rallentamento del microcontrollore *********************** //************************************************************************************************************************ // inpotazione delle librerie per interfacciarsi con i componenti e creazione dei rispettivi oggetti #include #include #include Si5351 si5351; #include LiquidCrystal lcd(8,9,10,11,12,13); char serial_in[32], c[30], b[30], printBuff[32]; // parametri seriali (non toccare) int count = 0; unsigned char serial_in_count = 0; byte PS_16 = (1 << ADPS2); // prescaler dell ADC per ridurre la sensibilità e quindi aumentare la velocità di campionamento byte PS_32 = (1 << ADPS2) | ( 1 << ADPS0); byte PS_128 = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); #define moveUp (6) //pin arduino per il pulsante di selezione ella sensibilità ( aumento step ) #define moveDown (5) //pin arduino per il pulsante di selezione ella sensibilità ( diminuzione step ) #define encoderButton (4) // bottone interno all' encoder, quando viene premuto blocca o sblocca la frequenza impostata #define clkPin (3) //input che cade prima in caso di rotazione in senso orario dell encoder #define dtPin (2) // pin che cade prima in caso di rotazione in senso antiorario dell encoder #define VccSense (A1) //pin in cui è collegato in partitore di tensione per la misura di tensione di alimentazione scheda #define VpaSense (A0) // pin in cui è collegato il partitore di tensione per la misura della tensione di alimentazione del PA #define TXr (7) // pin collegato al relè Tx/Rx, quando il pin è collegato a terra dal relè la frequenza viene bloccata #define LOWEST_FREQ (7000000l) // frequenza più bassa di lavoro ( per i 40m da 7 a 7.2Mhz ) #define HIGHEST_FREQ (7200000l) boolean Flock = false; // variabile usata dal programma ( non toccare ) byte lock[8] = { // questi sono i bit per creare il simbolo del lucchetto e del pad indicante la cifra variata dall encoder B01110, B10001, B10001, B11111, B11011, B11011, B01110, }; byte upperPad[8] = { B11111, B00000, B00000, B00000, B00000, B00000, B00000, B00000 }; unsigned long frequency = 7100000; // frequenza impostata all accensione unsigned long bfo_freq = 11998000L; // variabile usata dal programma ( non toccare) void printLine1(char *c){ // funzione per scrivere sull LCD if (strcmp(c, printBuff)){ lcd.setCursor(0, 0); lcd.print(c); strcpy(printBuff, c); count++; } } void printLine2(char *c){ // funzione per scrivere sull lcd la seconda riga lcd.setCursor(0, 1); lcd.print(c); } void updateDisplay(){ // funzione che scrive sull lcd la frequenza formattata sprintf(b, "%8.2ld", frequency); sprintf(c, "%s:%.2s.%.4s", "VFO" , b, b+2); printLine1(c); } void setFrequency(unsigned long f){ // funziona che imposta la frequenza al generatore uint64_t osc_f; si5351.set_freq((bfo_freq - f) * 100ULL, SI5351_CLK2); frequency = f; } unsigned long lastDispF; unsigned long multiplier; boolean turnDetect; boolean up; int pos = 1; int lastPos; void doTuning(){ // controlli per settare la posizione del pad e modificare di conseguenza la frequenza if((digitalRead(moveUp) == LOW) && (pos < 3)){ // se viene premuto il tasto per aumentare e nonè gia fuori limite pos = pos + 1; // muovi di una posizione su delay(150); // aspetta 150ms per evitare falsi contatti del pulsante } if((digitalRead(moveDown) == LOW) &&( pos > 1)){ // se viene premuto il tasto per diminuire e nonè gia fuori limite pos = pos - 1; // muovi di una posizione giu delay(150); // aspetta 150ms per evitare falsi contatti del pulsante //set multiplier by the position } if(pos != lastPos){ // viene aggiornato il display solo se la posizione è stata cambiata per evitare di rallentare la computazione lcd.setCursor(7,1); // setta la zona di scrittura a carattere sette riga 1 lcd.print(" "); // scrivi spazzi vuoti per cancellare quello che c'era già if(pos == 1){ // quindi imposta il moltiplicatore multiplier = 10000; //10Khz } else if(pos == 2){ multiplier = 1000; //1Khz; } else if(pos == 3){ multiplier = 100; //100hZ } lcd.setCursor( 7 + pos ,1); // setta la zona di scrittura a riga 1 eal carattere 7 + posizione del pad lcd.write(1); //scrivi la pad lastPos = pos; // ricarda l' ultima posizione impostata } if(turnDetect == true){ //se viene rilavata una rotazione controlla se sposta la frequenza fuori banda, se lo fa setta il limite banda e se non lo fa approva la variazione if((up == true) && (HIGHEST_FREQ > (frequency + multiplier))) frequency = frequency + multiplier; if((up == true) && (HIGHEST_FREQ < (frequency + multiplier))) frequency = HIGHEST_FREQ ; if((up == false) && (LOWEST_FREQ < (frequency - multiplier))) frequency = frequency - multiplier; if((up == false) && (LOWEST_FREQ > (frequency - multiplier))) frequency = LOWEST_FREQ; turnDetect = false; // ricorda che ha variato e che finche non si compie un altra rotazione non riesegue la funzione up = false; } // se la frequenza è stata cambiata aggiorna il display if(lastDispF != frequency){ if(showCall == true){ lcd.setCursor(0,1); lcd.print(call); } updateDisplay(); setFrequency(frequency); lastDispF = frequency; } } boolean currentState; // variabile usata dal sistema(non toccare) boolean manualLock(){ // funzione del blocco manuale, se viene premuto il pulsante dell encoder inverte lo stato dorrente ed aspetta 200ms per evitare falsi contatti del pulsante if((digitalRead(encoderButton) == LOW) && (currentState == false)){ currentState = true; delay(200); } if((digitalRead(encoderButton) == LOW) &&(currentState == true)){ currentState = false; delay(200); } return currentState; } void isr0(){// interrupt, viene istantaneamente eseguita quando l' encoder registra una rotazione ed imposta delle variabili con direzione ed avvia la sequanza per variare la frequenza up = ( digitalRead(clkPin) && ( !digitalRead(dtPin)) ) || (digitalRead(dtPin) && ( !digitalRead(clkPin)) ); turnDetect = true; } boolean VccLowShow; boolean VccLowShowed; // variabili usate dal sistema(non toccare) boolean VpaLowShow; boolean VpaLowShowed; float lastVcc; float lastVpa; void displayVoltage(){ // funzione per mostrare la tensione float Vcc = analogRead(VccSense) * (30.0 / 1023.0); // 30vF.S float Vpa = analogRead(VpaSense) * (30.0 / 1023.0); // legge le tensioni da o a 5v rapportate da 0 a 30v //**************************************************************************** if( (Vcc > (lastVcc + 0.1)) || ( Vcc < (lastVcc - 0.1)) && (Vcc > 10.0) ){ // mostra una variazione sullo schermo solo se la variazione è consistente, cosi da evitare rallentamenti lcd.setCursor(12,1); // setta la posizione in cui scrivere lcd.print(Vcc); // scrive la tensione lastVcc = Vcc; // ricorda la tensione momstrata per compararla a quella attuale e decidere se la variazione è consistente VccLowShowed = false; // ricorda che la batteria non è scarica } if(Vcc < 10.0) VccLowShow = false; else VccLowShow = true; if( (VccLowShow = false) && (VccLowShowed == false) ){ lcd.setCursor(12,1); lcd.print("low"); VccLowShowed = true; } //***************************************************************************** if( ((Vpa > (lastVpa + 0.1)) || ( Vpa < (lastVpa - 0.1) )) && ( Vpa > 10.0) ) { lcd.setCursor(0,1); lcd.print(Vpa); lastVpa = Vpa; VpaLowShowed = false; } if(Vpa < 10.0) VpaLowShow = false; else VpaLowShow = true; if((VpaLowShow == false) && (VpaLowShowed == false)){ lcd.setCursor(0,1); lcd.print("off "); VpaLowShowed = true; } } void setup() // funzione setup, viene eseguita una volta all avvio del programma { ADCSRA &= ~PS_128; // setta il prescaler all ADC per settare la velocità di campionamento ADCSRA |= PS_32; int32_t cal; attachInterrupt(digitalPinToInterrupt(clkPin) , isr0 , CHANGE); // crea la funzione di interrupt per l' encoder lcd.begin(16, 2); // inizializza l' LCD lcd.createChar(0, lock); // crea i caratteri per la pad ed il lucchetto lcd.createChar(1, upperPad); EEPROM.get(0,cal); // in fabbrica la EEPROM è stata caricara con una calibrazione, questo la importa e la applica si5351.init(SI5351_CRYSTAL_LOAD_8PF,25000000l, cal); // inizializzazione del generatore si5351.set_correction(cal); // imposta la calibrazione si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);// impostazioni varie del generaotre si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLB); si5351.output_enable(SI5351_CLK0, 0); si5351.output_enable(SI5351_CLK1, 0); si5351.output_enable(SI5351_CLK2, 1); si5351.set_freq(500000000l, SI5351_CLK2); pinMode(TXr , INPUT_PULLUP); // impostazioni di I/O , INPUT_PULLUP significa che sono considerati attivi quando la porta è collegata a terra ed inattivi quando è scollegata ( no resistenze esterne ) pinMode(moveUp , INPUT_PULLUP); pinMode(moveDown , INPUT_PULLUP); pinMode(clkPin , INPUT); pinMode(dtPin , INPUT); if(showCall == true){ // scrive ill call lcd.setCursor(0,1); lcd.print(call); } delay(10); } boolean disp1 = false; // variabili usate dal programma non toccare boolean disp2 = false; void loop(){ // funzione loop , viene eseguita a ripetizione if((manualLock() == true) || (digitalRead(TXr) == LOW)) Flock = true; // se la funzione lock è chiamata dall' entrata in tx o da operatore blocca else Flock= false; // altrimenti lascia sbloccato if(Flock == false){ // se la frequenza non è bloccata allora esegui le funzioni di variazioni doTuning(); if(disp1 == false){ // se ci sono cambiamenti i mostra a schermo disp1 = true; disp2 = false; lcd.setCursor(15,0); lcd.print(" "); } } if((Flock == true) && (disp2 == false)){ // se la frequenza è bloccata per TX o manualmente non cambiare la frequenza in ongi caso e mostra il lucchetto lcd.setCursor(15,0); lcd.write(byte(0)); disp2 = true; disp1 = false; } if(enableDislayVoltage == true)displayVoltage(); // mostra la tensione se richiesto }