5 Hälytinantureita Arduinon kautta Raspberryyn.
Arduino on mukava kapistus kun halutaan lukea antureiden tilatietoja.
Toki tämä onnistuisi Raspberryllä suoraankin, mutta on rahallisesti eri asia
tuhota testailuissa muutaman euron Arduino Nano, kuin usean kympin Raspberry.
Kytkennöissä aina pitäisi miettiä vikatilanteetkin, esimerkiksi jos anturin johdot oikosulkeutuu.
Tällöin koko Raspberry luonnollisesti sammuu, jos virran syöttö on sen kautta.
Eli lopullisessa ratkaisussa Arduinon virransyöttö voisi olla erillisellä kännykän muuntajalla.
Haluan kaikki laitteistoni keskenään yhteensopivaksi RS485-väylän kautta, joten päätin asian toteuttaa samalla sanomarakenteella kuin edellisetkin projektit.
Kytkentää voi kuitenkin yksinkertaistaa, jos haluaa että Raspberryn ja Arduinon välinen liikenne menee USB-kaapelin kautta.
Kykennässä on yksi liiketunnistin ja kaksi kytkintä esittämässä oven magneettikytkintä.
Yksinkertaistettu kytkentä:
Oletuksena Anturien tulot hälyttää silloin, kun se on HIGH arvossa.Joskus pitäisi kuitenkin hälyttää silloin, kun tulo on LOW tilassa.
Tulo muutetaan silloin käänteiseksi rivillä
const int tuloKaantaiset = B00000110;
tuon rivin oikeanpuoleisin bitti tarkoittaa rivin
const int tuloPinni[] = {12, 11, 10};
ensimmäistä anturia, eli 12.
Antureille voi antaa lyhyet, vaikka kolmikirjaimiset nimet, joilla ne tunnistaa helpommin:
const String anturinNimi[] {"ETE", "OVI", "KEI"};
Eli tässä esimerkissä anturia "ETE" ei muuteta käänteiseksi, mutta "OVI" ja "KEI" muutetaan.
Raspberryn päässä luettaessa tarkoittaa 1 aina että kyseinen anturi on hälyttävässä tilassa ja 0 että se ei ole hälyttävässä tilassa.
Koodi Arduinoon
[halyt.ino]
Raspberryssä
[vastaanota.py]
RS485-kytkentä voisi olla vaikkapa tällainen:
Arduinon lähettämä viestiliikenne on tämankaltaista:
>MCHETE=0;OVI=1;KEI=1;tc<
>MCHETE=1;OVI=1;KEI=1;uq<
>MCIETE=1;OVI=1;KEI=1;v&<
>MCHETE=0;OVI=1;KEI=1;tc<
>MCHETE=1;OVI=1;KEI=1;uq<
>MCHETE=0;OVI=1;KEI=1;tc<
>MCIETE=0;OVI=1;KEI=1;uv<
>MCHETE=1;OVI=1;KEI=1;uq<
>MCHETE=0;OVI=1;KEI=1;tc<
>MCIETE=0;OVI=1;KEI=1;uv<
||||| | |
||||| | Loppumerkki
||||| Tarkaste
||||Parametri
|||Sanoma
||Lähettäjä
|Vastaanottaja
Alkumerkki
Toki tämä onnistuisi Raspberryllä suoraankin, mutta on rahallisesti eri asia
tuhota testailuissa muutaman euron Arduino Nano, kuin usean kympin Raspberry.
Kytkennöissä aina pitäisi miettiä vikatilanteetkin, esimerkiksi jos anturin johdot oikosulkeutuu.
Tällöin koko Raspberry luonnollisesti sammuu, jos virran syöttö on sen kautta.
Eli lopullisessa ratkaisussa Arduinon virransyöttö voisi olla erillisellä kännykän muuntajalla.
Haluan kaikki laitteistoni keskenään yhteensopivaksi RS485-väylän kautta, joten päätin asian toteuttaa samalla sanomarakenteella kuin edellisetkin projektit.
Kytkentää voi kuitenkin yksinkertaistaa, jos haluaa että Raspberryn ja Arduinon välinen liikenne menee USB-kaapelin kautta.
Kykennässä on yksi liiketunnistin ja kaksi kytkintä esittämässä oven magneettikytkintä.
Yksinkertaistettu kytkentä:
Oletuksena Anturien tulot hälyttää silloin, kun se on HIGH arvossa.Joskus pitäisi kuitenkin hälyttää silloin, kun tulo on LOW tilassa.
Tulo muutetaan silloin käänteiseksi rivillä
const int tuloKaantaiset = B00000110;
tuon rivin oikeanpuoleisin bitti tarkoittaa rivin
const int tuloPinni[] = {12, 11, 10};
ensimmäistä anturia, eli 12.
Antureille voi antaa lyhyet, vaikka kolmikirjaimiset nimet, joilla ne tunnistaa helpommin:
const String anturinNimi[] {"ETE", "OVI", "KEI"};
Eli tässä esimerkissä anturia "ETE" ei muuteta käänteiseksi, mutta "OVI" ja "KEI" muutetaan.
Raspberryn päässä luettaessa tarkoittaa 1 aina että kyseinen anturi on hälyttävässä tilassa ja 0 että se ei ole hälyttävässä tilassa.
Koodi Arduinoon
[halyt.ino]
#define RS485ENABLE #RS485 käytössä Kommentoi tämä rivi, jos et halua RS485 käyttöön
const int tuloPinni[] = {12, 11, 10}; //määrittele tässä arduinon KAIKKI KÄYTETTÄVÄT sisääntulonastat
const String anturinNimi[] {"ETE", "OVI", "KEI"}; //antureiden nimet
const int tuloKaantaiset = B00000000; //ykkösellä merkityt tulot käännetään, eli LOW=hälytys huom! käänteinen järjestys tuloPinni nähden. eli tässä oikeanpuoleisin bitti on tuloPinni[] vasemmanpuoleisin
const int tulojenMaara = sizeof (tuloPinni) / sizeof(int); //Lasketaan tulopinnien määrä
String viimAnturientila = ""; //Anturien viimeisin tunnettu tilatieto muodossa "ETE=0;OVI=1;KEI=1;"
unsigned int kierros = 0; //Loopin suorituskierrosten laskija
const int lahetaKierros = 250; //Joka nn kierros lähetetään anturien tila, vaikka se ei olisi muuttunutkaan.
const char omaId = 'C'; //Tämän laitteen tunnus huomaa että '' eikä "" !
const char isantaId = 'M'; //Laite jolle lähetys osoitetaan
#ifdef RS485ENABLE
const int lahetysPin = 13; //tässä pinnissä RS485-moduulin ohjaus rx/tx #485#
#endif //RS485ENABLE
//------------------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
Serial.println(tulojenMaara);
#ifdef RS485ENABLE
pinMode(lahetysPin, OUTPUT); //RS485 RX/TX PINNI #485#
digitalWrite(lahetysPin, LOW); // RS485 vastaanotto-modeen #485#
#endif //RS485ENABLE
for (int a = 0; a < tulojenMaara; a++) { //Asetetaan tulopinnit inputeiksi
pinMode(tuloPinni[a], INPUT_PULLUP); //Käytetään Arduinon sisäisiä pullup-vastuksia
}
}
void loop() {
String tila = lueAnturienTila(); //Pyydetään anturien nykyinen tilatieto
if (tila != viimAnturientila) { //Jos anturien tila on muuttunut edellisestä tunnetusta
viimAnturientila = tila; //Tallennetaan tilamuutos
laheta('H', tila); //Lähetetään sanoma H (hälytys) ja parametrinä anturien tila
}
else if (kierros % lahetaKierros == 0) { //Joka nn kierros lähetetään anturien tieto, vaikka ei olisikaan muuttunut
laheta('I', tila); //Lähetetään sanoma I (info) ja parametrinä anturien tila
}
delay(50);
kierros++;
}
String lueAnturienTila() { //Palautetaan anturien tilatiedot muodossa "ETE=1;OVI=0;KEI=1;"
String anturienTilaPalauta = "";
for ( int a = 0; a < tulojenMaara; a++) { //Luetaan pinnien tilatiedot yksi kerrallaan
bool arvo = digitalRead(tuloPinni[a]); //Luetaan yksittäisen pinnin tila
if (bitRead(tuloKaantaiset, a)) { //Jos kyseisen anturin tilatieto kuuluu muuttaa käänteiseksi
arvo = !arvo; //Muutetaan anturin tilatieto käänteiseksi
}
anturienTilaPalauta += anturinNimi[a] + "=" + arvo + ";";
}
return anturienTilaPalauta;
}
//------------------------------------------------------------------------------------------
void laheta(char sanoma, String parametri) { //Parametreinä vain Sanoma ja Parametri.
String lahetaRivi = lisaaCRC(String(isantaId) + String(omaId) + String(sanoma) + parametri); //Lisätään itse vastaanottajaksi isäntäkone, lisätään oma tunnus
#ifdef RS485ENABLE
digitalWrite(lahetysPin, HIGH); // RS485 lähetystilaan
#endif //RS485ENABLE
Serial.println(lahetaRivi);
Serial.flush(); //odotetaan kunnes lähetys valmis
delay(50);
#ifdef RS485ENABLE
digitalWrite(lahetysPin, LOW); // RS485 vastaanottotilaan
#endif //RS485ENABLE
}
String lisaaCRC(String dataStr) {
byte sum1 = 0;
byte sum2 = 0;
for (int i = 0; i < dataStr.length(); i++) {
byte arvo = byte(dataStr[i]);
sum1 = (sum1 + arvo) % 94;
sum2 = (sum1 + sum2) % 94;
}
return String(">" + dataStr + String(char(sum1 + 33)) + String(char(sum2 + 33)) + "<");
}
Raspberryssä
[vastaanota.py]
#!/usr/bin/env python3
#>MCIETE=0;OVI=1;KEI=1;uv<
import serial, time
def laskeTarkiste(sanoma):
sum1 = 0;
sum2 = 0;
for a in range(len(sanoma)):
arvo = ord(sanoma[a]);
sum1 = (sum1 + arvo) % 94;
sum2 = (sum1 + sum2) % 94;
return ">"+sanoma+chr(sum1 + 33) + chr(sum2 + 33)+"<"
#------------------------------------------------------------------------------------------
sarjaportti=serial.Serial("/dev/ttyUSB0", baudrate=9600, timeout=0.05)
while True:
try:
arvo=(sarjaportti.readline().decode('iso-8859-1', errors='replace').replace("\r\n","")) #Luetaan sarjaportista String ilman rivinvaihtomerkkejä
if(len(arvo)>0):
sisalto=arvo[1:-3] #sanomat varsinainen sisältö ilman alku, varmenne ja loppu -merkkejä
lasketullaVarmisteella=laskeTarkiste(sisalto)
if(lasketullaVarmisteella == arvo): #saatu varmennemerkki täsmää itse lasketun kanssa
sanomanTyyppi=arvo[3] #I=määräajoin saatava tieto anturien tilasta, H=halytys
if(sanomanTyyppi=="I"):
print("Info:")
elif(sanomanTyyppi=="H"):
print("Hälytys:")
anturiData=arvo[4:-3] # ETE=0;OVI=1;KEI=1;
while(anturiData.find(";")>1): #käydään anturien arvoja läpi niin kauan kuin niitä riittää
antNimi=anturiData[0:3]
antArvo=anturiData[4:5]
print(antNimi+"="+antArvo)
loppu=anturiData.find(";") #anturin arvo päättyy ";"-merkkiin, etsitään sen paikka
anturiData=anturiData[loppu+1:] #Poistetaan jo käsitelty osuus merkkijonosta
print("-----")
else:
print("Saatiin sanoma, jossa on kuitenkin virhe tarkisteessa: "+arvo+ " LASKETTU: "+lasketullaVarmisteella)
except Exception as e:
print("***VIRHE***")
print(e)
time.sleep(0.2)
RS485-kytkentä voisi olla vaikkapa tällainen:
Arduinon lähettämä viestiliikenne on tämankaltaista:
>MCHETE=0;OVI=1;KEI=1;tc<
>MCHETE=1;OVI=1;KEI=1;uq<
>MCIETE=1;OVI=1;KEI=1;v&<
>MCHETE=0;OVI=1;KEI=1;tc<
>MCHETE=1;OVI=1;KEI=1;uq<
>MCHETE=0;OVI=1;KEI=1;tc<
>MCIETE=0;OVI=1;KEI=1;uv<
>MCHETE=1;OVI=1;KEI=1;uq<
>MCHETE=0;OVI=1;KEI=1;tc<
>MCIETE=0;OVI=1;KEI=1;uv<
||||| | |
||||| | Loppumerkki
||||| Tarkaste
||||Parametri
|||Sanoma
||Lähettäjä
|Vastaanottaja
Alkumerkki


Kommentit
Lähetä kommentti