lauantai 3. syyskuuta 2016

Automaattinen sähkötysavain

Radioamatööri – lehden lokakuun numerossa on artikkelini Arduinolla toteutetusta automaattisesta sähkötysavaimesta. Artikkelissa käsitellään ainoastaan muutamia ohjelmatoteutuksen kohtia, sillä ohjelma olisi ollut turhan pitkä lehtiartikkeliin. Tässä on viimeisin ohjelmaversio. Tämä on vapaasti käytettävissa ja halutessa myös muutettavissa. Rivit 63, 64 ja 65 (sijaisevat asetusosassa) on joka tapauksessa muutettava vastaamaan kunkin radioamatöörin tarpeita. (Noissa on vakiolauseet esim. yleiskutsua, nimeä ja lopetusta varten.)






 

/* Nimi: CW_Test_16v21
Luotu: 11.2.2016
Luoja: Antti Isännäinen

KUVAUS:
Automaattiavain amatöörikäyttöön. Viiva vasemmalle, piste oikealle.
Lisäksi painikkeilla voi valita kolme valmista sanomaa esim: yleiskutsu,
nimi ja QTH sekä yhteyden lopetus kiitoksineen.
Nämä ovat vapaasti valittavissa, mutta ainoastaan ohjelmointivaiheessa
kirjoitettavissa selvätekstinä ja ladatavissa ohjelman käännöksen ja
latauksen yhteydessä. Ääkköset olen jättänyt pois, koska niillä ei ole
yhden merkin ASCII-koodia. Nekin on saatavissa sähkötysmerkeiksi, mutta
tekstissä toisilla merkeillä.
Sähkötysnopeus on säädettävissä potentiometrillä. Samoin suuriohmisille
kuulokkeille tarkoitettu myötäkuuntelun voimakkuus.
Kuunteluäänen korkeus on vakio, mutta määriteltävissä ohjelmointivaiheessa.

Versiossa 10 ensimmäistä kertaa oikea avain käytössä.

Espoossa 5.2.2016
Versio 20 käsittää lopullisen hardiksen, eli itetaidetta
Tyydyttävä toiminta versiolla 20.
Huomioi, ettei lähetyksen nopeuitta voi muuttaa kesken sanoman,
ainoastaan sanomien välillä. Käsin sähkötettäessä nopeutta voi muuttaa
merkkien välillä.

Espoossa 11.2.2016
Versiossa 21 muutetaan tauko hiukan pistettä lyhemmäksi, koska
se netin mukaan on elegantimpaa.
*/
// MÄÄRITTELYT:
int Int_Taajuus = 750; // Myötäkuuntelun taajuus
int Int_Nopeus = 0;
int Int_Piste = 0; // Pisteen kesto viiva/3
int Int_Vali = 0; // Merkkiväli Hiukan lyhempi kuin piste
// int Int_SanaVali = 3*Int_Nopeus;
int Seq_Sanoma = 0;
int p = 3; // piste
int v = 1; // viiva
int i = 0;
int j = 0;
int k = 0;

// Yksittäisten merkkien taulukot; ensin merkin pituus, sitten merkit
int A[] ={2,p,v,0,0,0};int B[] ={4,v,p,p,p,0};int C[] ={4,v,p,v,p,0};
int D[] ={3,v,p,p,0,0};int E[] ={1,p,0,0,0,0};int F[] ={4,p,p,v,p,0};
int G[] ={3,v,v,p,0,0};int H[] ={4,p,p,p,p,0};int I[] ={2,p,p,0,0,0};
int J[] ={4,p,v,v,v,0};int K[] ={3,v,p,v,0,0};int L[] ={4,p,v,p,p,0};
int M[] ={2,v,v,0,0,0};int N[] ={2,v,p,0,0,0};int O[] ={3,v,v,v,0,0};
int P[] ={4,p,v,v,p,0};int Q[] ={4,v,v,p,v,0};int R[] ={3,p,v,p,0,0};
int S[] ={3,p,p,p,0,0};int T[] ={1,v,0,0,0,0};int U[] ={3,p,p,v,0,0};
int V[] ={4,p,p,p,v,0};int W[] ={3,p,v,v,0,0};int X[] ={4,v,p,p,v,0};
int Y[] ={4,v,p,v,v,0};int Z[] ={4,v,v,p,p,0}; // 90 ASCII
int nol[] ={5,v,v,v,v,v}; int yks[] ={5,p,v,v,v,v}; int kak[] ={5,p,p,v,v,v};
int kol[] ={5,p,p,p,v,v}; int nel[] ={5,p,p,p,p,v}; int vii[] ={5,p,p,p,p,p};
int kuu[] ={5,v,p,p,p,p}; int sei[] ={5,v,v,p,p,p}; int kah[] ={5,v,v,v,p,p};
int yhd[] ={5,v,v,v,v,p};

int Arr_Merkki[6]; int Arr_ABC[36][6]; // Merkin ja merkkien välitaulukot

char Arr_Lause1[] = {"CQ CQ DE OH2WJ OH3YD OH6KVE PSE K "};
char Arr_Lause2[] = {"MY NAME ANTTI ANTTI ES QTH ESPOO QTH ESPOO "};
char Arr_Lause3[] = {"TNX FER QSO 73 73 GL ES CUAGN "};
int Int_Pituus1 = 0; int Int_Pituus2 = 0; int Int_Pituus3 = 0;
int Int_Merkki = 0; int Int_AsciiEro = 0;

// Liitynnät
const int Con_Key = 3;
const int Con_LED = 4;
const int Con_Aani = 5;
const int Con_Txt1 = 6; boolean Bol_Txt1 = false;
const int Con_LedPois = 7; boolean Bol_LedPois = false;
const int Con_Txt2 = 8; boolean Bol_Txt2 = false;
const int Con_RelePois = 9; boolean Bol_RelePois = false;
const int Con_Txt3 = 10; boolean Bol_Txt3 = false;
const int Con_Viiva = 11; boolean Bol_Viiva = false;
const int Con_Piste = 12; boolean Bol_Piste = false;
const int Con_AnaTulo = 0; int Int_AnaTulo = 0;

// ASETUKSET:
void setup(){ // Alustetaan muuttujat sekä määritellään I/O-tyyppi
Serial.begin(9600); // Alustetaan sarjaliikennne testiä varten
//while (!Serial) { ; } // Odottaa sarjaportin kytkeytymistä
pinMode(Con_Key, OUTPUT);
pinMode(Con_LED, OUTPUT);
pinMode(Con_Txt1, INPUT);
pinMode(Con_Txt2, INPUT);
pinMode(Con_Txt3, INPUT);
pinMode(Con_Viiva, INPUT);
pinMode(Con_Piste, INPUT);
pinMode(Con_LedPois, INPUT);
pinMode(Con_RelePois, INPUT);
// Ladataan kaksiulotteinen merkkitaulukko. Tarvitsee tehdä vain käynnistettäessä
for(i = 0; i < 6; i++){Arr_ABC[0][i] = A[i];} for(i = 0; i < 6; i++){Arr_ABC[1][i] = B[i];}
for(i = 0; i < 6; i++){Arr_ABC[2][i] = C[i];} for(i = 0; i < 6; i++){Arr_ABC[3][i] = D[i];}
for(i = 0; i < 6; i++){Arr_ABC[4][i] = E[i];} for(i = 0; i < 6; i++){Arr_ABC[5][i] = F[i];}
for(i = 0; i < 6; i++){Arr_ABC[6][i] = G[i];} for(i = 0; i < 6; i++){Arr_ABC[7][i] = H[i];}
for(i = 0; i < 6; i++){Arr_ABC[8][i] = I[i];} for(i = 0; i < 6; i++){Arr_ABC[9][i] = J[i];}
for(i = 0; i < 6; i++){Arr_ABC[10][i] = K[i];} for(i = 0; i < 6; i++){Arr_ABC[11][i] = L[i];}
for(i = 0; i < 6; i++){Arr_ABC[12][i] = M[i];} for(i = 0; i < 6; i++){Arr_ABC[13][i] = N[i];}
for(i = 0; i < 6; i++){Arr_ABC[14][i] = O[i];} for(i = 0; i < 6; i++){Arr_ABC[15][i] = P[i];}
for(i = 0; i < 6; i++){Arr_ABC[16][i] = Q[i];} for(i = 0; i < 6; i++){Arr_ABC[17][i] = R[i];}
for(i = 0; i < 6; i++){Arr_ABC[18][i] = S[i];} for(i = 0; i < 6; i++){Arr_ABC[19][i] = T[i];}
for(i = 0; i < 6; i++){Arr_ABC[20][i] = U[i];} for(i = 0; i < 6; i++){Arr_ABC[21][i] = V[i];}
for(i = 0; i < 6; i++){Arr_ABC[22][i] = W[i];} for(i = 0; i < 6; i++){Arr_ABC[23][i] = X[i];}
for(i = 0; i < 6; i++){Arr_ABC[24][i] = Y[i];} for(i = 0; i < 6; i++){Arr_ABC[25][i] = Z[i];}
for(i = 0; i < 6; i++){Arr_ABC[26][i] = nol[i];} for(i = 0; i < 6; i++){Arr_ABC[27][i] = yks[i];}
for(i = 0; i < 6; i++){Arr_ABC[28][i] = kak[i];} for(i = 0; i < 6; i++){Arr_ABC[29][i] = kol[i];}
for(i = 0; i < 6; i++){Arr_ABC[30][i] = nel[i];} for(i = 0; i < 6; i++){Arr_ABC[31][i] = vii[i];}
for(i = 0; i < 6; i++){Arr_ABC[32][i] = kuu[i];} for(i = 0; i < 6; i++){Arr_ABC[33][i] = sei[i];}
for(i = 0; i < 6; i++){Arr_ABC[34][i] = kah[i];} for(i = 0; i < 6; i++){Arr_ABC[35][i] = yhd[i];}
}// Asetuksen loppu

// PÄÄLOOPPI
void loop(){

// Tekstipainikkeiden luku
Bol_Txt1 = digitalRead(Con_Txt1);
Bol_Txt2 = digitalRead(Con_Txt2);
Bol_Txt3 = digitalRead(Con_Txt3);
Bol_Viiva = digitalRead(Con_Viiva);
Bol_Piste = digitalRead(Con_Piste);

// Nopeustiedon luku ja nopeuden käsittely
Int_AnaTulo = analogRead(Con_AnaTulo);
Int_Nopeus = map(Int_AnaTulo, 0, 1023, 100, 600);
//Serial.println(Int_Nopeus);
Int_Piste = Int_Nopeus / 3;
Int_Vali = Int_Piste * 8 / 10;

// Viivan lähetys avaimella
if(Bol_Viiva == true){
tone(Con_Aani, Int_Taajuus);
Bol_LedPois = digitalRead(Con_LedPois);
if(Bol_LedPois == false){ digitalWrite(Con_LED, HIGH);}
Bol_RelePois = digitalRead(Con_RelePois);
if(Bol_RelePois == false){digitalWrite(Con_Key, HIGH);}
delay(Int_Nopeus);
noTone(Con_Aani);
digitalWrite(Con_LED, LOW);
digitalWrite(Con_Key, LOW);
delay(Int_Vali); // merkkiväli
}// Viivan loppu

// Pisteen lähetys avaimella
if(Bol_Piste == true){
tone(Con_Aani, Int_Taajuus);
Bol_LedPois = digitalRead(Con_LedPois);
if(Bol_LedPois == false){ digitalWrite(Con_LED, HIGH);}
Bol_RelePois = digitalRead(Con_RelePois);
if(Bol_RelePois == false){digitalWrite(Con_Key, HIGH);}
delay(Int_Piste);
noTone(Con_Aani);
digitalWrite(Con_LED, LOW);
digitalWrite(Con_Key, LOW);
delay(Int_Vali); // merkkiväli
}// Pisteen loppu

// Sanomapainikkeiden runnistus
if(Bol_Txt1 == true){ Seq_Sanoma = 1;}
if(Bol_Txt2 == true){ Seq_Sanoma = 2;}
if(Bol_Txt3 == true){ Seq_Sanoma = 3;}

// Tekstin valinta
switch (Seq_Sanoma) {
case 1: // Ensimmäinen sanoma
for(k = 0; k < sizeof(Arr_Lause1)-1; k++){
Int_Merkki = Arr_Lause1[k];
if(Int_Merkki == 32){delay(Int_Nopeus * 2); // Tunnistetaan sanaväli (SPACE)
}else if(Int_Merkki < 65){Int_AsciiEro = 22;// Tunistetaan numero
Fun_Merkki(Int_Merkki - Int_AsciiEro);
}else {
Int_AsciiEro = 65; // Loput ovat kirjaimia
Fun_Merkki(Int_Merkki - Int_AsciiEro);}}
Seq_Sanoma = 4;
break;
case 2: // Toinen sanoma
for(k = 0; k < sizeof(Arr_Lause2)-1; k++){
Int_Merkki = Arr_Lause2[k];
if(Int_Merkki == 32){delay(Int_Nopeus * 2); // Tunnistetaan sanaväli (SPACE)
}else if(Int_Merkki < 65){Int_AsciiEro = 22;// Tunistetaan numero
Fun_Merkki(Int_Merkki - Int_AsciiEro);
}else {
Int_AsciiEro = 65; // Loput ovat kirjaimia
Fun_Merkki(Int_Merkki - Int_AsciiEro);}}
Seq_Sanoma = 4;
break;
case 3: // Kolmas sanoma
for(k = 0; k < sizeof(Arr_Lause3)-1; k++){
Int_Merkki = Arr_Lause3[k];
if(Int_Merkki == 32){delay(Int_Nopeus * 2); // Tunnistetaan sanaväli (SPACE)
}else if(Int_Merkki < 65){Int_AsciiEro = 22;// Tunistetaan numero
Fun_Merkki(Int_Merkki - Int_AsciiEro);
}else{
Int_AsciiEro = 65; // Loput ovat kirjaimia
Fun_Merkki(Int_Merkki - Int_AsciiEro);}}
Seq_Sanoma = 4;
break;
case 4: // Sanoman lähetyksen lopetus
Seq_Sanoma = 0;
break;
}
delay(1); // IO-stabilointia varten tämä lyhyt tauko
} // Pääohjelma LOPPU

// Merkkien muuntaminen sähkötykseksi
void Fun_Merkki(int x){
int Purku[6];
for(int i = 0; i < 6; i++){Purku[i] = Arr_ABC[x][i];}
for(int i = 0; i < Purku[0]; i++){
tone(Con_Aani, Int_Taajuus);
Bol_LedPois = digitalRead(Con_LedPois);
if(Bol_LedPois == false){ digitalWrite(Con_LED, HIGH);}
Bol_RelePois = digitalRead(Con_RelePois);
if(Bol_RelePois == false){digitalWrite(Con_Key, HIGH);}
delay(Int_Nopeus/Purku[i+1]);
noTone(Con_Aani);
digitalWrite(Con_LED, LOW);
digitalWrite(Con_Key, LOW);
delay(Int_Vali); // merkkiväli
}
delay(Int_Nopeus - Int_Nopeus/10*4); // Kirjainväli
}// Merkki-funktion loppu