Nämä
”maagiset valokupit” koostuvat elohopekytkimestä ja punaisesta
LEDistä. Ajatuksena on (siis sarja 37 tuottajan) vuorotellen
kirkastaa ja himmentää näitä kahta LEDiä. Minun on vaikeata
nähdä siinä mitään maagista. Ajattelinkin ensin hyljätä näiden
yksiköiden käytön. Sitten keksin, että jos kiinnitän nämä
heiluriin, niin silloin valot voisivat keikkua puolelta toiselle ja
kirkastua kohti ääriasentoa. Kuulostaa tosi yksinkertaiselta.
Onneksi en hylännyt, sillä edessä oli vaikeuksia, eli
nykykielellä: projekti oli varsin haastava.
Etualalla käynnistyspainike |
Tämä
olisikin ohjelmallisen sovelluksen paikka, eikä niinkään näiden
komponenttien esittely. Ohjelman käynnityessä pitää mitata
heilahdusajan puolikas (aika lepotilasta ääriasentoon ja takaisin),
puolittaa se ja muuntaa analogilähtöön (PWM = pulssin
leveysmodulaatio) LEDien kirkkausignaaliksi. Ihan hyvää
ohjelmointihaastetta.
Tätä
voisi kehitellä eteenpäinkin: voisi tilastoida heilunnan vakautta
lämpötilan ja kosteuden suhteen. Siitä voisi tehdä kellon
sijoittamalla heiluriin magneetin, mikä saisi Arduinon ohjaaman
sähkömagneetin antamia potkuja (vetää puoleensa erinapaiset ja
työntävät samannapaiset) kompensoimaan kitkaa, johtojen jäykkyyttä
ja imanvastusta. Ja mitä kaikkea muutakin? Tämä heiluri jaksoi
heilua itskseen noin 8 minuuttia.
![]() |
Elementtien kytkennät |
Kun
mittasin näitä komponetteja (KY-027) huomasin taas
epämääräisyyksiä. Juotin kaikki pisteet uudestaan ja tein
testiohjelman (Ohjelma26a), jolla oli helppo testata yksikkön
toiminta. Elohopeakytkin ohjaa LEDin päälle ja pois. Huomaa, että
kytkimen signaali on käänteinen. Siksi ohjelmassa on huutomerkki
(!) digitaaliluennan edessä (digitalWrite(Con_LED,
!digitalRead(Con_Kytkin));. Tällöin
kytkimen ollessa kiinni, LEDi palaa ja kytkimen ollessa auki se
sammuu. Elohopeakytkimessä ei tapahdu tyypillistä millisekunnin
luokkaa olevaa kytkinvärähtelyä, joten mitään varmistuslooppia
ei sitä varten tarvita. Elohopeapisara (Hg) on kuitenkin hyvin
elastinen ja siinä on vahva pintajännitys. Tämä merkitsee sitä,
että vaikka siinä ei ole lyhytaikaista värähtelyä, niin siinä
on aivan silmin nähden olevaa pomppimista. Siksi ohjelmassa pitää
varmista, että ohjelma reagoi juuri oikeaan aikaan tulevaan
kosketukseen tai katkoon, eikä niihin ”pomppimisen” aiheuttamiin
häiriöihin.
Tällä
kerralla ohjelma jakaantuu kolmeksi eri ohjelmaksi: 26a:lla testasin
ainostaan elohopeapisaran ja LEDin toiminnan. Ohjelmalla 26b etsin
tasapainoa elohopeakytkimien välille ja samalla mitaten
heilahdusaikaa (noin 1700ms. Ohjelma mittaa puolikkaita erikseen.).
Ohjelma 26c on se varsinainen tavoite, missä LEDien kirkkaus kasvaa
heilurin ääriasentoihin päin ja himmenee heilurin palatessa
keskiasentoon. Video havainnoi tätä paremmin (antinarduvideo26.
youtube.com). Aiemmin
mainitsin haastavuudesta. Lyhyitä ohjelmapätkiä syntyi; myös
versiot: d, e ja f, joilla hain sopivaa tapaa saada kirkastus ja
himmennys synkronoitua ajallisesti heilahdusliikkeeseen. Heilurin
asennosta saadaan signaali ainoastaan heilurin pystyasennosta, kun
elohopeakytkimet vaihtavat tilaansa. Tämänkin hetken luotettavuutta
häiritsi piraran pomppiminen.
LEDien
kirkkausohjaus on toteutettu sekvenssillä Vasen kirkastuu – vasen
himmenee – oikea kirkastuu – oikea himmenee jne. Sekvenssi
käynnistyy painamalla painiketta, mikä sijoittaa
sekvenssimuuttujaan (Seq_MittSek)
arvon yksi (1). Tähän ei enää palata, vaan viimeisestä
askeleesta hypätään askeleeseen 3. Painamisen jälkeen puolikas
heilahdusaika voidaan tulostaa ruudulle. Tämä suoritus on
askeleessa 2. Tulostus tapahtuu siis vain kerran käynnistyspainikkeen
painamisen jälkeen.
Analogialähtöä
ohjataan kokonaisluvulla välillä 0 .. 255 (8-bittinen muunnos).
Suora ohjaus kokonaisluvulla osoittautui hankalaksi, joten päädyin
muodostamaan ohjausarvon ensin liukuluvulla (float) ja sen
jälkeen sijoittamaan sen kokonaislukuun lähtöjen ohjausta varten.
Ennen kuin päädyin tähän ratkaisuun, kuljeskelin monenlaisia
turhauttavia ja epätyydyttäviä sivupolkuja. LEDien ja heilurin
synkronointi onnistui aluksi laskemalla karkeasti heilahdusajasta,
kokeilemalla ja sitkeästi hakemalla sopivaa arvoa.
OHJELMA
26a
/***************************************
*
Ohjelma26a
*
25.11.2016
*
Modulin (KY-027) toiminnan testaus.
*
Kun kytkin on kiinni, LED palaa.
**************************************/
//
MÄÄRITTELYT:
const
int Con_LED = 2;
const
int Con_Kytkin = 3;
//
ASETUKSET:
void
setup(){
pinMode(Con_Kytkin, INPUT);
pinMode(Con_LED,
OUTPUT);
}//
Asetuksen loppu
//
PÄÄLOOPPI
void
loop(){
digitalWrite(Con_LED,
!digitalRead(Con_Kytkin));
delay(1);
}
// Pääohjelma LOPPU
OHJELMA
26b
/***************************************
*
Ohjelma26b
*
29.11.2016
*
Modulin (KY-027) toiminnan testaus.
*
Painike käynnistää mittaussekvenssin
*
b-versiossa tasapainotetaan puoliskot
*
säätämällä elohopeakytkimien asennot
*
ja mittaamalla heilahdusajat
**************************************/
//
MÄÄRITTELYT:
//
I/O-määrittelyt
const
int Con_LED_Vas = 5;
const
int Con_Hg_Vas = 2;
boolean
Bol_Hg_Vas = false;
const
int Con_LED_Oik = 6;
const
int Con_Hg_Oik = 3;
boolean
Bol_Hg_Oik = false;
const
int Con_StartPain = 4;
boolean
Bol_StartPain = false;
const
int Con_LED_13 = 13;
//
Ajan mittauksen määrittely
unsigned
long Ulo_MilliSek = 0;
unsigned
long Ulo_AlkuVasen = 0;
unsigned
long Ulo_AikaVasen = 0;
unsigned
long Ulo_AlkuOikea = 0;
unsigned
long Ulo_AikaOikea = 0;
int Seq_MittSek = 0; // Mitataan heilahdusajat
//
Tulostuksen tahdistus
const
int Con_PrintViive = 1000;
int Int_PrintViive = Con_PrintViive;
//
ASETUKSET:
void
setup(){
Serial.begin(9600);
pinMode(Con_Hg_Vas, INPUT);
pinMode(Con_LED_Vas, OUTPUT);
pinMode(Con_Hg_Oik, INPUT);
pinMode(Con_LED_Oik, OUTPUT);
pinMode(Con_StartPain, INPUT);
pinMode(Con_LED_13, OUTPUT);
}//
Asetuksen loppu
//
FUNKTIOT
void
Fun_Tulostus(){
//
Serial.print("Painike :"); Serial.println(Bol_StartPain);
//
Serial.print("LEDi :"); Serial.println(Con_LED_13);
Serial.print("Vasen aika :");
Serial.println(Ulo_AikaVasen);
Serial.print("Oikean aika :"); Serial.println(Ulo_AikaOikea);
}
// Tulostus loppu
//
PÄÄLOOPPI
void loop(){
Ulo_MilliSek
= millis(); // Luetaan sisäinen kello
//
Painiketesti
Bol_StartPain
= digitalRead(Con_StartPain);
digitalWrite(Con_LED_13,
Bol_StartPain);
//
LEDien ohjaus elohopeakytkimistä
Bol_Hg_Vas
= !digitalRead(Con_Hg_Vas);
Bol_Hg_Oik
= !digitalRead(Con_Hg_Oik);
digitalWrite(Con_LED_Vas, Bol_Hg_Vas);
digitalWrite(Con_LED_Oik, Bol_Hg_Oik);
//
Aikojen käynnistys ja mittaus
if(Bol_StartPain
== true && Seq_MittSek == 0){
Seq_MittSek
= 1;
}
switch
(Seq_MittSek) {
case
1: // Vasemman elohopeakytkimen odotus
if(Bol_Hg_Vas
== true){
Ulo_AlkuVasen = Ulo_MilliSek;
delay(560);
// Eliminoidaan pisaran pomppiminen
Seq_MittSek
= 2;
}
break;
case
2: // Lasketaan vasen heilahdusaika
if(Bol_Hg_Vas
== false){
Ulo_AikaVasen = Ulo_MilliSek -
Ulo_AlkuVasen;
Seq_MittSek
= 3;
}
break;
case
3: // Käynnistetään oikean heilahdusaika
if(Bol_Hg_Oik
== true){
Ulo_AlkuOikea = Ulo_MilliSek;
delay(560);
// Eliminoidaan pisaran pomppiminen
Seq_MittSek
= 4;
}
break;
case
4: // Lasketaan oikea helahdusaika
if(Bol_Hg_Oik
== false){
Ulo_AikaOikea = Ulo_MilliSek -
Ulo_AlkuOikea;
Seq_MittSek
= 5;
}
break;
case
5:
Fun_Tulostus();
Seq_MittSek
= 0; //jos haluaa vain kertatulostuksen
break;
// uusi painaminen = seuraava tulostus
}
Int_PrintViive--;
if(Int_PrintViive == 0){
Fun_Tulostus();
Int_PrintViive
= Con_PrintViive;
}
// Tulostuskutsu loppu
delay(1);
}
// Pääohjelma LOPPU
OHJELMA
26c
/***************************************
*
Ohjelma26c
*
29.11.2016
*
Modulin (KY-027) toiminnan testaus.
*
c-versiossa muutetaan LEDien kirkkautta
*
analogialähtöjen avulla (PWM)
**************************************/
//
MÄÄRITTELYT:
//
I/O-määrittelyt
const
int Con_LED_Vas = 5;
const
int Con_Hg_Vas = 2;
int Int_LED_Ohjaus = 0;
float
Flo_LED_Ohjaus = 0.0;
float
Flo_Muutos = 0.58;
boolean
Bol_Hg_Vas = false;
const
int Con_LED_Oik = 6;
const
int Con_Hg_Oik = 3;
boolean
Bol_Hg_Oik = false;
const
int Con_StartPain = 4;
boolean
Bol_StartPain = false;
const
int Con_LED_13 = 13;
//
Ajan mittauksen määrittely
unsigned
long Ulo_MilliSek = 0;
unsigned
long Ulo_AlkuVasen = 0;
unsigned
long Ulo_AikaVasen = 0;
int Seq_MittSek = 0; // LEDien kirkkauden ohjaus
//
ASETUKSET:
void
setup(){
Serial.begin(9600);
pinMode(Con_Hg_Vas, INPUT);
pinMode(Con_Hg_Oik, INPUT);
pinMode(Con_StartPain, INPUT);
pinMode(Con_LED_13, OUTPUT);
}//
Asetuksen loppu
//
PÄÄLOOPPI
void
loop(){
Ulo_MilliSek
= millis(); // Luetaan sisäinen kello
//
Painiketesti
Bol_StartPain
= digitalRead(Con_StartPain);
digitalWrite(Con_LED_13,
Bol_StartPain);
//
LEDien ohjaus elohopeakytkimistä
Bol_Hg_Vas
= !digitalRead(Con_Hg_Vas);
Bol_Hg_Oik
= !digitalRead(Con_Hg_Oik);
//
Aikojen käynnistys ja mittaus
if(Bol_StartPain
== true && Seq_MittSek == 0){
Seq_MittSek
= 1;
}
switch
(Seq_MittSek) {
case
1: // Vasemman elohopeakytkimen odotus
if(Bol_Hg_Vas
== true ){
Ulo_AlkuVasen = Ulo_MilliSek;
delay(560);
// Eliminoidaan pisaran pomppiminen
Seq_MittSek
= 2;}
break;
case
2: // Lasketaan vasen heilahdusaika
if(Bol_Hg_Vas
== false){
Ulo_AikaVasen = Ulo_MilliSek -
Ulo_AlkuVasen;
Serial.print("Heilahdusaika :");
Serial.println(Ulo_AikaVasen);
Seq_MittSek
= 3;}
break;
case
3: // Odotetaan uutta heilahdusta vasemmalle
Int_LED_Ohjaus = 0;
if(Bol_Hg_Vas == true ){
Seq_MittSek
= 4;}
break;
case
4: // Vasen LED kirkastuu
analogWrite(Con_LED_Vas,
Int_LED_Ohjaus);
Flo_LED_Ohjaus = Flo_LED_Ohjaus +
Flo_Muutos;
Int_LED_Ohjaus = Flo_LED_Ohjaus;
Int_LED_Ohjaus =
constrain(Int_LED_Ohjaus, 0, 255);
if(Int_LED_Ohjaus == 255){
Seq_MittSek = 5;}
break;
case
5: // Vasen LED himmenee
Flo_LED_Ohjaus = Flo_LED_Ohjaus -
Flo_Muutos;
Int_LED_Ohjaus = Flo_LED_Ohjaus;
Int_LED_Ohjaus = constrain(Int_LED_Ohjaus, 0, 255);
analogWrite(Con_LED_Vas,
Int_LED_Ohjaus);
if(Int_LED_Ohjaus == 0 &&
Bol_Hg_Oik == true ){
Seq_MittSek = 6;}
break;
case
6: // Oikea LED kirkastuu
analogWrite(Con_LED_Oik,
Int_LED_Ohjaus);
Flo_LED_Ohjaus = Flo_LED_Ohjaus +
Flo_Muutos;
Int_LED_Ohjaus = Flo_LED_Ohjaus;
Int_LED_Ohjaus = constrain(Int_LED_Ohjaus, 0, 255);
if(Int_LED_Ohjaus == 255){
Seq_MittSek = 7;}
break;
case
7: // Oikea LED himmenee
Flo_LED_Ohjaus = Flo_LED_Ohjaus -
Flo_Muutos;
Int_LED_Ohjaus = Flo_LED_Ohjaus;
Int_LED_Ohjaus = constrain(Int_LED_Ohjaus, 0, 255);
analogWrite(Con_LED_Oik,
Int_LED_Ohjaus);
if(Int_LED_Ohjaus == 0 &&
Bol_Hg_Vas == true ){
Seq_MittSek = 3;}
break;
}
// Sekvenssi loppu
delay(1);
}
// Pääohjelma LOPPU
Ei kommentteja:
Lähetä kommentti